bell.c

Go to the documentation of this file.
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
00002 
00003 /* Metacity visual bell */
00004 
00005 /* 
00006  * Copyright (C) 2002 Sun Microsystems Inc.
00007  * Copyright (C) 2005, 2006 Elijah Newren
00008  * 
00009  * This program is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU General Public License as
00011  * published by the Free Software Foundation; either version 2 of the
00012  * License, or (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful, but
00015  * WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * General Public License for more details.
00018  * 
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
00022  * 02111-1307, USA.
00023  */
00024 
00051 #include <config.h>
00052 #include "bell.h"
00053 #include "screen-private.h"
00054 #include "prefs.h"
00055 
00074 static void
00075 bell_flash_screen (MetaDisplay *display, 
00076                         MetaScreen  *screen)
00077 {
00078   Window root = screen->xroot;
00079   int width = screen->rect.width;
00080   int height = screen->rect.height;
00081   
00082   if (screen->flash_window == None)
00083     {
00084       Visual *visual = (Visual *)CopyFromParent;
00085       XSetWindowAttributes xswa;
00086       int depth = CopyFromParent;
00087       xswa.save_under = True;
00088       xswa.override_redirect = True;
00089       /* 
00090        * TODO: use XGetVisualInfo and determine which is an
00091        * overlay, if one is present, and use the Overlay visual
00092        * for this window (for performance reasons).  
00093        * Not sure how to tell this yet... 
00094        */
00095       screen->flash_window = XCreateWindow (display->xdisplay, root,
00096                                             0, 0, width, height,
00097                                             0, depth,
00098                                             InputOutput,
00099                                             visual,
00100                                     /* note: XSun doesn't like SaveUnder here */
00101                                             CWSaveUnder | CWOverrideRedirect,
00102                                             &xswa);
00103       XSelectInput (display->xdisplay, screen->flash_window, ExposureMask);
00104       XMapWindow (display->xdisplay, screen->flash_window);
00105       XSync (display->xdisplay, False);
00106       XFlush (display->xdisplay);
00107       XUnmapWindow (display->xdisplay, screen->flash_window);
00108     }
00109   else
00110     {
00111       /* just draw something in the window */
00112       GC gc = XCreateGC (display->xdisplay, screen->flash_window, 0, NULL);
00113       XMapWindow (display->xdisplay, screen->flash_window);
00114       XSetForeground (display->xdisplay, gc,
00115                       WhitePixel (display->xdisplay, 
00116                                   XScreenNumberOfScreen (screen->xscreen)));
00117       XFillRectangle (display->xdisplay, screen->flash_window, gc,
00118                       0, 0, width, height);
00119       XSetForeground (display->xdisplay, gc,
00120                       BlackPixel (display->xdisplay, 
00121                                   XScreenNumberOfScreen (screen->xscreen)));
00122       XFillRectangle (display->xdisplay, screen->flash_window, gc,
00123                       0, 0, width, height);
00124       XFlush (display->xdisplay);
00125       XSync (display->xdisplay, False);
00126       XUnmapWindow (display->xdisplay, screen->flash_window);
00127       XFreeGC (display->xdisplay, gc);
00128     }
00129 
00130   if (meta_prefs_get_focus_mode () != META_FOCUS_MODE_CLICK &&
00131       !display->mouse_mode)
00132     meta_display_increment_focus_sentinel (display);
00133   XFlush (display->xdisplay);
00134 }
00135 
00146 #ifdef HAVE_XKB
00147 static void
00148 bell_flash_fullscreen (MetaDisplay *display, 
00149                             XkbAnyEvent *xkb_ev)
00150 {
00151   XkbBellNotifyEvent *xkb_bell_ev = (XkbBellNotifyEvent *) xkb_ev;
00152   MetaScreen *screen;
00153 
00154   g_assert (xkb_ev->xkb_type == XkbBellNotify);
00155   if (xkb_bell_ev->window != None)
00156     {
00157       screen = meta_display_screen_for_xwindow (display, xkb_bell_ev->window);
00158       if (screen)
00159         bell_flash_screen (display, screen);
00160     }
00161   else 
00162     {
00163       GSList *screen_list = display->screens;
00164       while (screen_list) 
00165         {
00166           screen = (MetaScreen *) screen_list->data;
00167           bell_flash_screen (display, screen);
00168           screen_list = screen_list->next;
00169         }
00170     }
00171 }
00172 
00187 static gboolean 
00188 bell_unflash_frame (gpointer data)
00189 {
00190   MetaFrame *frame = (MetaFrame *) data;
00191   frame->is_flashing = 0;
00192   meta_frame_queue_draw (frame);
00193   return FALSE;
00194 }
00195 
00207 static void
00208 bell_flash_window_frame (MetaWindow *window)
00209 {
00210   g_assert (window->frame != NULL);
00211   window->frame->is_flashing = 1;
00212   meta_frame_queue_draw (window->frame);
00213   g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE, 100, 
00214       bell_unflash_frame, window->frame, NULL);
00215 }
00216 
00224 static void
00225 bell_flash_frame (MetaDisplay *display, 
00226                        XkbAnyEvent *xkb_ev)
00227 {
00228   XkbBellNotifyEvent *xkb_bell_event = (XkbBellNotifyEvent *) xkb_ev;
00229   MetaWindow *window;
00230   
00231   g_assert (xkb_ev->xkb_type == XkbBellNotify);
00232   window = meta_display_lookup_x_window (display, xkb_bell_event->window);
00233   if (!window && (display->focus_window) && (display->focus_window->frame))
00234     {
00235       window = display->focus_window;
00236     }
00237   if (window)
00238     {
00239       bell_flash_window_frame (window);
00240     }
00241   else /* revert to fullscreen flash if there's no focussed window */
00242     {
00243       bell_flash_fullscreen (display, xkb_ev);
00244     }
00245 }
00246 
00258 static void
00259 bell_visual_notify (MetaDisplay *display, 
00260                          XkbAnyEvent *xkb_ev)
00261 {
00262   switch (meta_prefs_get_visual_bell_type ()) 
00263     {
00264     case META_VISUAL_BELL_FULLSCREEN_FLASH:
00265       bell_flash_fullscreen (display, xkb_ev);
00266       break;
00267     case META_VISUAL_BELL_FRAME_FLASH:
00268       bell_flash_frame (display, xkb_ev); /* does nothing yet */
00269       break;
00270     case META_VISUAL_BELL_INVALID:
00271       /* do nothing */
00272       break;
00273     }
00274 }
00275 
00276 void
00277 meta_bell_notify (MetaDisplay *display, 
00278                   XkbAnyEvent *xkb_ev)
00279 {
00280   /* flash something */
00281   if (meta_prefs_get_visual_bell ()) 
00282     bell_visual_notify (display, xkb_ev);
00283 }
00284 #endif /* HAVE_XKB */
00285 
00286 void
00287 meta_bell_set_audible (MetaDisplay *display, gboolean audible)
00288 {
00289 #ifdef HAVE_XKB
00290   XkbChangeEnabledControls (display->xdisplay,
00291                             XkbUseCoreKbd,
00292                             XkbAudibleBellMask,
00293                             audible ? XkbAudibleBellMask : 0);
00294 #endif  
00295 }
00296 
00297 gboolean
00298 meta_bell_init (MetaDisplay *display)
00299 {
00300 #ifdef HAVE_XKB
00301   int xkb_base_error_type, xkb_opcode;
00302 
00303   if (!XkbQueryExtension (display->xdisplay, &xkb_opcode, 
00304                           &display->xkb_base_event_type, 
00305                           &xkb_base_error_type, 
00306                           NULL, NULL))
00307     {
00308       display->xkb_base_event_type = -1;
00309       g_message ("could not find XKB extension.");
00310       return FALSE;
00311     }
00312   else 
00313     {
00314       unsigned int mask = XkbBellNotifyMask;
00315       gboolean visual_bell_auto_reset = FALSE; 
00316       /* TRUE if and when non-broken version is available */
00317       XkbSelectEvents (display->xdisplay,
00318                        XkbUseCoreKbd,
00319                        XkbBellNotifyMask,
00320                        XkbBellNotifyMask);
00321       XkbChangeEnabledControls (display->xdisplay,
00322                                 XkbUseCoreKbd,
00323                                 XkbAudibleBellMask,
00324                                 meta_prefs_bell_is_audible () 
00325                                 ? XkbAudibleBellMask : 0);
00326       if (visual_bell_auto_reset) {
00327         XkbSetAutoResetControls (display->xdisplay,
00328                                  XkbAudibleBellMask,
00329                                  &mask,
00330                                  &mask);
00331       }
00332       return TRUE;
00333     }
00334 #endif
00335   return FALSE;
00336 }
00337 
00338 void
00339 meta_bell_shutdown (MetaDisplay *display)
00340 {
00341 #ifdef HAVE_XKB
00342   /* TODO: persist initial bell state in display, reset here */
00343   XkbChangeEnabledControls (display->xdisplay,
00344                             XkbUseCoreKbd,
00345                             XkbAudibleBellMask,
00346                             XkbAudibleBellMask);
00347 #endif
00348 }
00349 
00358 void
00359 meta_bell_notify_frame_destroy (MetaFrame *frame)
00360 {
00361   if (frame->is_flashing) 
00362     g_source_remove_by_funcs_user_data (&g_timeout_funcs, frame);
00363 }

Generated on Sat Aug 23 22:04:16 2008 for metacity by  doxygen 1.5.5