Commit e7e47a8b authored by Bill Haneman's avatar Bill Haneman
Browse files

Added visual bell feature, fix for 99886.

parent 32a8bf50
2002-12-16 Bill Haneman <bill.haneman@sun.com>
* configure.in:
Check for XKB extension.
* src/Makefile.am:
Added bell.c and bell.h to metacity sources.
* src/common.h:
(MetaFrameFlags):
Added META_FRAME_IS_FLASHING flag.
* src/frame.h:
(MetaFrame): Added is_flashing field.
* src/frame.c:
(meta_window_ensure_frame):
Initialize the is_flashing flag to FALSE.
(meta_frame_get_flags):
Handle the FRAME_IS_FLASHING flag.
(meta_window_destroy_frame):
Call meta_bell_notify_frame_destroy.
* src/prefs.h:
(MetaPreference):
Added META_PREF_VISUAL_BELL, META_PREF_AUDIBLE_BELL,
META_PREF_VISUAL_BELL_TYPE.
(MetaVisualBellType): New enum.
(meta_prefs_get_visual_bell, meta_prefs_bell_is_audible):
(meta_prefs_get_visual_bell_type):
New accessor declarations.
* src/prefs.c:
(#includes): Include "display.h", since we now call
meta_displays_list() in our update func.
(#defines):
Define KEY_VISUAL_BELL, KEY_AUDIBLE_BELL,
and KEY_VISUAL_BELL_TYPE.
(provide_visual_bell, bell_is_audible, visual_bell_type):
New static state variables.
(update_visual_bell): New method to update visual-bell
boolean settings from keys "visual_bell" and "audible_bell".
(update_visual_bell_type):
New method to update visual-bell type setting.
(visual_bell_type_from_string) :
New method to convert from gconf string to visual-bell
type enum. Only currently recognized values are "fullscreen"
and "frame_flash".
(change_notify):
Handle changes to visual and audible bell properties.
(meta_prefs_get_visual_bell, meta_prefs_bell_is_audible):
(meta_prefs_get_visual_bell_type):
New accessor definitions.
(meta_prefs_init): Added a second call to notify_add,
listens to "/desktop/gnome/interface" as well as "apps/metacity".
Also call the update funcs for the new visual-bell gconf keys.
(meta_preference_to_string):
Handle the visual/audible bell cases.
* src/bell.h:
(meta_bell_notify);
New method, calls a visual notifucation
method based on the visual-bell-type, or none if the type
is unrecognized or invalid.
(meta_bell_set_audible):
New public method for setting the audible bell setting,
used in updater for new gconf key "audible_bell".
(meta_bell_init):
Initialize the bell notification for a display.
(meta_bell_shutdown):
Shutdown the bell notification for a display.
(meta_bell_notify_frame_destroy):
Remove pending idle handlers on notification.
* src/bell.c:
Include "bell.h", and conditionally include <Xll/Xkblib.h>.
(meta_bell_set_audible):
If XKB is present, enable/disable the audible system
bell based on the gconf key /desktop/gnome/interface/audible_bell.
(meta_bell_init):
Query and initialize XKB if present, register for notification
on the bell, and set audible bell according to gconf settings.
(meta_bell_flash_screen):
Maps and unmaps a fullscreen X window (painted white, then
black), which causes a fullscreen 'flash' transient.
(meta_bell_flash_window_frame):
Flashes the titlebar of a specified window.
(meta_bell_flash_frame):
Calls meta_bell_flash_window_frame on the window which
was the source of the current bell event, or the currently
focussed window if the event source cannot be determined.
(meta_bell_unflash_frame):
Restore the frame's appearance to normal.
(meta_bell_flash_fullscreen):
Call meta_bell_flash_fullscreen for all screens.
(meta_bell_shutdown):
New method.
(meta_bell_notify_frame_destroy):
Remove pending idle handlers on notification,
testing for frame->is_flashing first.
* src/display.h:
(MetaDisplay): Added xkb_base_event_type field.
* src/display.c:
Check for XKB and include "X11/XKBlib.h" if present.
(meta_display_open): Call meta_bell_init.
(event_callback): Call meta_bell_notify
when event comes from XKB and is XkbBellNotify
(prefs_changed_callback):
Handle META_PREF_AUDIBLE_BELL notification.
* src/screen.h:
(MetaScreen): Add flash_window field.
* src/screen.c:
(meta_screen_new):
Initialize flash_window field.
* src/theme.c:
(theme_get_style):
New heuristic for focus-style, to invert sense of focus
flag when META_FRAME_IS_FLASHING flag is set.
* src/metacity.schemas.in:
Added scheme information for
/apps/metacity/general/visual_bell,
/apps/metacity/general/audible_bell, and
/apps/metacity/general/visual_bell_type.
2002-12-16 Havoc Pennington <hp@pobox.com>
* src/window-props.c (init_wm_name): argh, screwed that up. get
......
......@@ -221,6 +221,17 @@ if test "x$found_shape" = "xyes"; then
AC_DEFINE(HAVE_SHAPE, , [Have the shape extension library])
fi
found_xkb=no
AC_CHECK_LIB(X11, XkbQueryExtension,
[AC_CHECK_HEADER(X11/XKBlib.h,
found_xkb=yes)],
, $ALL_X_LIBS)
if test "x$found_xkb" = "xyes"; then
AC_DEFINE(HAVE_XKB, , [Have keyboard extension library])
fi
RANDR_LIBS=
found_randr=no
AC_CHECK_LIB(Xrandr, XRRUpdateConfiguration,
......
......@@ -11,6 +11,8 @@ EGGFILES= \
metacity_SOURCES= \
async-getprop.c \
async-getprop.h \
bell.h \
bell.c \
common.h \
core.c \
core.h \
......
/* Metacity visual bell */
/*
* Copyright (C) 2002 Sun Microsystems Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include <config.h>
#include "bell.h"
#include "screen.h"
#include "prefs.h"
static void
meta_bell_flash_screen (MetaDisplay *display,
MetaScreen *screen)
{
Window root = screen->xroot;
int width = screen->width;
int height = screen->height;
if (screen->flash_window == None)
{
Visual *visual = CopyFromParent;
XSetWindowAttributes xswa;
int depth = CopyFromParent;
xswa.save_under = True;
xswa.override_redirect = True;
/*
* TODO: use XGetVisualInfo and determine which is an
* overlay, if one is present, and use the Overlay visual
* for this window (for performance reasons).
* Not sure how to tell this yet...
*/
screen->flash_window = XCreateWindow (display->xdisplay, root,
0, 0, width, height,
0, depth,
InputOutput,
visual,
/* note: XSun doesn't like SaveUnder here */
CWSaveUnder | CWOverrideRedirect,
&xswa);
XSelectInput (display->xdisplay, screen->flash_window, ExposureMask);
XMapWindow (display->xdisplay, screen->flash_window);
XSync (display->xdisplay, False);
XFlush (display->xdisplay);
XUnmapWindow (display->xdisplay, screen->flash_window);
}
else
{
/* just draw something in the window */
GC gc = XCreateGC (display->xdisplay, screen->flash_window, 0, NULL);
XMapWindow (display->xdisplay, screen->flash_window);
XSetForeground (display->xdisplay, gc,
WhitePixel (display->xdisplay,
XScreenNumberOfScreen (screen->xscreen)));
XFillRectangle (display->xdisplay, screen->flash_window, gc,
0, 0, width, height);
XSetForeground (display->xdisplay, gc,
BlackPixel (display->xdisplay,
XScreenNumberOfScreen (screen->xscreen)));
XFillRectangle (display->xdisplay, screen->flash_window, gc,
0, 0, width, height);
XFlush (display->xdisplay);
XSync (display->xdisplay, False);
XUnmapWindow (display->xdisplay, screen->flash_window);
}
XFlush (display->xdisplay);
}
#ifdef HAVE_XKB
static void
meta_bell_flash_fullscreen (MetaDisplay *display,
XkbAnyEvent *xkb_ev)
{
XkbBellNotifyEvent *xkb_bell_ev = (XkbBellNotifyEvent *) xkb_ev;
MetaScreen *screen;
g_assert (xkb_ev->xkb_type == XkbBellNotify);
if (xkb_bell_ev->window != None)
{
screen = meta_display_screen_for_xwindow (display, xkb_bell_ev->window);
if (screen)
meta_bell_flash_screen (display, screen);
}
else
{
GSList *screen_list = display->screens;
while (screen_list)
{
screen = (MetaScreen *) screen_list->data;
meta_bell_flash_screen (display, screen);
screen_list = screen_list->next;
}
}
}
static gboolean
meta_bell_unflash_frame (gpointer data)
{
MetaFrame *frame = (MetaFrame *) data;
frame->is_flashing = 0;
meta_frame_queue_draw (frame);
return FALSE;
}
static void
meta_bell_flash_window_frame (MetaWindow *window)
{
g_assert (window->frame != NULL);
window->frame->is_flashing = 1;
meta_frame_queue_draw (window->frame);
g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE, 100,
meta_bell_unflash_frame, window->frame, NULL);
}
static void
meta_bell_flash_frame (MetaDisplay *display,
XkbAnyEvent *xkb_ev)
{
XkbBellNotifyEvent *xkb_bell_event = (XkbBellNotifyEvent *) xkb_ev;
MetaWindow *window;
g_assert (xkb_ev->xkb_type == XkbBellNotify);
window = meta_display_lookup_x_window (display, xkb_bell_event->window);
if (!window && (display->focus_window->frame))
{
window = display->focus_window;
}
if (window)
{
meta_bell_flash_window_frame (window);
}
else /* revert to fullscreen flash if there's no focussed window */
{
meta_bell_flash_fullscreen (display, xkb_ev);
}
}
static void
meta_bell_visual_notify (MetaDisplay *display,
XkbAnyEvent *xkb_ev)
{
switch (meta_prefs_get_visual_bell_type ())
{
case META_VISUAL_BELL_FULLSCREEN_FLASH:
meta_bell_flash_fullscreen (display, xkb_ev);
break;
case META_VISUAL_BELL_FRAME_FLASH:
meta_bell_flash_frame (display, xkb_ev); /* does nothing yet */
break;
case META_VISUAL_BELL_INVALID:
/* do nothing */
break;
}
}
void
meta_bell_notify (MetaDisplay *display,
XkbAnyEvent *xkb_ev)
{
/* flash something */
if (meta_prefs_get_visual_bell ())
meta_bell_visual_notify (display, xkb_ev);
}
#endif
void
meta_bell_set_audible (MetaDisplay *display, gboolean audible)
{
#ifdef HAVE_XKB
XkbChangeEnabledControls (display->xdisplay,
XkbUseCoreKbd,
XkbAudibleBellMask,
audible ? XkbAudibleBellMask : 0);
#endif
}
gboolean
meta_bell_init (MetaDisplay *display)
{
#ifdef HAVE_XKB
int xkb_base_error_type, xkb_opcode;
if (!XkbQueryExtension (display->xdisplay, &xkb_opcode,
&display->xkb_base_event_type,
&xkb_base_error_type,
NULL, NULL))
{
display->xkb_base_event_type = -1;
g_message ("could not find XKB extension.");
return FALSE;
}
else
{
unsigned int mask = XkbBellNotifyMask;
gboolean visual_bell_auto_reset = FALSE;
/* TRUE if and when non-broken version is available */
XkbSelectEvents (display->xdisplay,
XkbUseCoreKbd,
XkbBellNotifyMask,
XkbBellNotifyMask);
XkbChangeEnabledControls (display->xdisplay,
XkbUseCoreKbd,
XkbAudibleBellMask,
meta_prefs_bell_is_audible ()
? XkbAudibleBellMask : 0);
if (visual_bell_auto_reset) {
XkbSetAutoResetControls (display->xdisplay,
XkbAudibleBellMask,
&mask,
&mask);
}
return TRUE;
}
#endif
return FALSE;
}
void
meta_bell_shutdown (MetaDisplay *display)
{
#ifdef HAVE_XKB
/* TODO: persist initial bell state in display, reset here */
XkbChangeEnabledControls (display->xdisplay,
XkbUseCoreKbd,
XkbAudibleBellMask,
XkbAudibleBellMask);
#endif
}
void
meta_bell_notify_frame_destroy (MetaFrame *frame)
{
if (frame->is_flashing)
g_idle_remove_by_data (frame);
}
/* Metacity visual bell */
/*
* Copyright (C) 2002 Sun Microsystems Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifdef HAVE_XKB
#include <X11/XKBlib.h>
#endif
#include "display.h"
#include "frame.h"
#ifdef HAVE_XKB
void meta_bell_notify (MetaDisplay *display, XkbAnyEvent *xkb_ev);
#endif
void meta_bell_set_audible (MetaDisplay *display, gboolean audible);
gboolean meta_bell_init (MetaDisplay *display);
void meta_bell_shutdown (MetaDisplay *display);
void meta_bell_notify_frame_destroy (MetaFrame *frame);
......@@ -42,7 +42,8 @@ typedef enum
META_FRAME_MAXIMIZED = 1 << 9,
META_FRAME_ALLOWS_SHADE = 1 << 10,
META_FRAME_ALLOWS_MOVE = 1 << 11,
META_FRAME_FULLSCREEN = 1 << 12
META_FRAME_FULLSCREEN = 1 << 12,
META_FRAME_IS_FLASHING = 1 << 13
} MetaFrameFlags;
typedef enum
......
......@@ -34,6 +34,7 @@
#include "prefs.h"
#include "resizepopup.h"
#include "workspace.h"
#include "bell.h"
#include <X11/Xatom.h>
#include <X11/cursorfont.h>
#ifdef HAVE_SOLARIS_XINERAMA
......@@ -42,6 +43,9 @@
#ifdef HAVE_XFREE_XINERAMA
#include <X11/extensions/Xinerama.h>
#endif
#ifdef HAVE_XKB
#include <X11/XKBlib.h>
#endif
#include <string.h>
#define USE_GDK_DISPLAY
......@@ -305,6 +309,8 @@ meta_display_open (const char *name)
/* we have to go ahead and do this so error handlers work */
all_displays = g_slist_prepend (all_displays, display);
meta_bell_init (display);
meta_display_init_keys (display);
update_window_grab_modifiers (display);
......@@ -1822,6 +1828,19 @@ event_callback (XEvent *event,
}
break;
default:
#ifdef HAVE_XKB
if (event->type == display->xkb_base_event_type)
{
XkbAnyEvent *xkb_ev = (XkbAnyEvent *) event;
switch (xkb_ev->xkb_type)
{
case XkbBellNotify:
meta_bell_notify (display, xkb_ev);
break;
}
}
#endif
break;
}
......@@ -3846,4 +3865,9 @@ prefs_changed_callback (MetaPreference pref,
g_slist_free (windows);
}
else if (pref == META_PREF_AUDIBLE_BELL)
{
MetaDisplay *display = data;
meta_bell_set_audible (display, meta_prefs_bell_is_audible ());
}
}
......@@ -245,6 +245,9 @@ struct _MetaDisplay
MetaRectangle grab_current_window_pos;
MetaResizePopup *grab_resize_popup;
GTimeVal grab_last_moveresize_time;
#ifdef HAVE_XKB
int xkb_base_event_type;
#endif
#ifdef HAVE_XSYNC
/* alarm monitoring client's _METACITY_UPDATE_COUNTER */
XSyncAlarm grab_update_alarm;
......
......@@ -21,6 +21,7 @@
#include <config.h>
#include "frame.h"
#include "bell.h"
#include "errors.h"
#include "keybindings.h"
......@@ -58,6 +59,7 @@ meta_window_ensure_frame (MetaWindow *window)
frame->current_cursor = 0;
frame->mapped = FALSE;
frame->is_flashing = FALSE;
attrs.event_mask = EVENT_MASK;
......@@ -159,6 +161,7 @@ meta_window_destroy_frame (MetaWindow *window)
frame = window->frame;
meta_bell_notify_frame_destroy (frame);
meta_ui_remove_frame (window->screen->ui, frame->xwindow);
/* Unparent the client window; it may be destroyed,
......@@ -255,6 +258,9 @@ meta_frame_get_flags (MetaFrame *frame)
if (frame->window->fullscreen)
flags |= META_FRAME_FULLSCREEN;
if (frame->is_flashing)
flags |= META_FRAME_IS_FLASHING;
return flags;
}
......
......@@ -57,6 +57,7 @@ struct _MetaFrame
int bottom_height;
guint mapped : 1;
guint is_flashing : 1; /* used by the visual bell flash */
};
void meta_window_ensure_frame (MetaWindow *window);
......
......@@ -177,6 +177,57 @@
</locale>
</schema>
<schema>
<key>/apps/metacity/visual_bell</key>
<applyto>/apps/metacity/general/visual_bell</applyto>
<owner>metacity</owner>
<type>bool</type>
<default>false</default>
<locale name="C">
<short>Enable Visual Bell</short>
<long>Turns on a visual indication when an application or the system
issues a 'bell' or 'beep'; useful for the hard-of-hearing and for use
in noisy environments, or when 'audible bell' is off.
</long>
</locale>
</schema>
<schema>
<key>/schemas/apps/metacity/general/audible_bell</key>
<applyto>/apps/metacity/general/audible_bell</applyto>
<owner>metacity</owner>
<type>bool</type>
<default>true</default>
<locale name="C">
<short>System Bell is Audible</short>
<long>Determines whether applications or the system can generate audible
'beeps'; may be used in conjunction with 'visual bell' to
allow silent 'beeps'.
</long>
</locale>
</schema>
<schema>
<key>/schemas/apps/metacity/general/visual_bell_type</key>
<applyto>/apps/metacity/general/visual_bell_type</applyto>
<owner>metacity</owner>
<type>string</type>
<default>fullscreen</default>
<locale name="C">
<short>Visual Bell Type</short>
<long>
Tells Metacity how to implement the visual indication that
the system bell or another application 'bell' indicator has
been rung. Currently there are two valid values, "fullscreen",
which causes a fullscreen white-black flash, and "frame_flash" which
causes the titlebar of the application which sent the bell signal to
flash. If the application which sent the bell is unknown (as is
usually the case for the default "system beep"), the currently
focussed window's titlebar is flashed.
</long>
</locale>
</schema>
<schema>
<key>/schemas/apps/metacity/workspace_names/name</key>
<applyto>/apps/metacity/workspace_names/name_1</applyto>
......
......@@ -54,6 +54,10 @@
#define KEY_WORKSPACE_NAME_PREFIX "/apps/metacity/workspace_names/name_"
#define KEY_VISUAL_BELL "/apps/metacity/general/visual_bell"
#define KEY_AUDIBLE_BELL "/apps/metacity/general/audible_bell"
#define KEY_VISUAL_BELL_TYPE "/apps/metacity/general/visual_bell_type"
#ifdef HAVE_GCONF
static GConfClient *default_client = NULL;
static GList *changes = NULL;
......@@ -73,6 +77,9 @@ static gboolean application_based = FALSE;