Re: Visual bell



On Fri, 2002-10-18 at 19:24, Havoc Pennington wrote:
> 
> Bill Haneman <bill haneman sun com> writes: 
> > My guess is that since the window-border flashing is an obvious
> > possibility, and any app can flash the screen (by posting a big window
> > and then unposting it), the most likely candidate is Metacity.
> > 
> > What do you think, Havoc?  I can probably provide a patch for this, with
> > conditional compilation so that Metacity doesn't have to depend on XKB. 
> > However I think you would be the right person to decide how a
> > "window-decoration-centric" visual bell feature should look and be
> > implemented in Metacity.
> > 
> 
> Sure, it sounds fine to me. We just need to get it spec'd out how the
> WM knows to display a bell. i.e. does metacity listen for some Xkb
> signal, or do we need to add a client message and support it in
> gdk_beep(), or what.

The best approach (works for all apps and toolkits on an X desktop) is
to listen for XkbBellNotify.  It probably should be user-configurable as
to whether Metacity silences the 'audible bell' at the same time (by
setting XkbAudibleBellMask to 0 in a call to XkbChangeEnabledControls).

Also it should be user-configurable as to what the visual bell does; I
suggest the following options for starters:

1) flash the screen;
2) flash the toplevel-window border of the window that sent the bell.

#2 could be implemented (initially) as just a toggle between focussed
and unfocussed window visuals, and back.  That would skirt the issues
below having to do with how a window border is "flashed".  Note that the
XkbBellNotify events have a "window" parameter that allows you to
determine the origin of the bell (I suppose it could be 'None' in some
cases, in which case perhaps the currently-focussed window or the
topmost window could be flashed).

I attach a small C program that implements #1 above, as a standalone
program.  I tried doing this in GTK+/GDK, so that I could make a
Metacity patch, but it appears that GTK+ keeps XKB events to itself, by
and large, and thus they are not available to a GdkFilterFunc (see
gdkevents-x11.c).  Perhaps you and Owen could agree to a small GDK patch
that would propagate XKB events to filter-clients, in which case you
could trap them in Metacity's filterfunc.  Otherwise, you will have to
open your own connection to the XServer :-(

Best regards,

Bill

> If you want to flash window borders, ideally we could think of a way
> to do this in a theme-agnostic fashion (such as lightening the whole
> border, or something); otherwise we'll need to break the theme format
> to require themes to explicitly define a "flash on" state.  The
> problem here is knowing which window to flash, though. (Unless you
> want to flash them all, but that seems bizarre.)
> 
> Havoc
> 

/*
 * AT-SPI - Assistive Technology Service Provider Interface
 * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
 *
 * Copyright 2001, 2002 Sun Microsystems Inc.,
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/XKBlib.h>

static	Display *display;
static  Window flash_window = None;

static void
visual_bell_notify (XkbAnyEvent *xkb_ev)
{
	Window root;
	int width, height;
	root = RootWindow (display, DefaultScreen (display));
	width = DisplayWidth (display, DefaultScreen (display));
	height = DisplayHeight (display, DefaultScreen (display));
	if (flash_window == None)
	{
		flash_window = XCreateSimpleWindow (display, root,
						    0, 0, width, height,
						    0, 0L, 0L);
		XSelectInput (display, flash_window, ExposureMask);
		XMapWindow (display, flash_window);
	}
	else
	{
		/* just draw something in the window */
		GC gc = XCreateGC (display, flash_window, 0, NULL);
		XSetForeground (display, gc,
				WhitePixel (display, DefaultScreen (display)));
		XFillRectangle (display, flash_window, gc,
				0, 0, width, height);
		XSetForeground (display, gc,
				BlackPixel (display, DefaultScreen (display)));
		XFillRectangle (display, flash_window, gc,
				0, 0, width, height);
	}
	XFlush (display);
}

int main (int argc, char **argv)
{
	XEvent xev;
	int ir, xkb_base_event_type, reason_return;
	char *display_name = getenv ("DISPLAY");

	if (!display_name) display_name = ":0.0";
	
	display = XkbOpenDisplay (display_name,
				  &xkb_base_event_type,
				  &ir, NULL, NULL, &reason_return);
	if (!display)
	{
		fprintf (stderr, "Could not connect to display! (%d)\n",
			 reason_return);
		exit (-1);
	}
	
	XkbSelectEvents (display,
			 XkbUseCoreKbd,
			 XkbBellNotifyMask,
			 XkbBellNotifyMask);

	/* comment this out to prevent bell on startup */
	XkbBell (display, None, 100, None);

	while (1)
	{
		XNextEvent (display, &xev);
		if (xev.type == Expose)
		{
			XExposeEvent *exev = (XExposeEvent *) &xev;
			if (exev->window == flash_window)
			{
				XDestroyWindow (display, flash_window);
				flash_window = None;
                                /* discard pending bells */
				XSync (display, True); 
				XFlush (display);
			}
		}
		else if (xev.type == xkb_base_event_type)
		{
			XkbAnyEvent *xkb_ev = (XkbAnyEvent *) &xev;
			
			switch (xkb_ev->xkb_type)
			{
			case XkbBellNotify:
				/* flash something */
				visual_bell_notify (xkb_ev);
				break;
			default:
			}
		}
	}
}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]