how to determine if a window has been entered/exited



Gtk+ experts:

For accessibility purposes, I am trying to write a GTK_MODULE that will
detect when the mouse has crossed the border of a window.  In other
words, when the mouse moves from outside the window border to inside
the window, or from inside the window to outside the window border.

I have tried using enter-notify-event and leave-notify-event signals
on the toplevel GtkWindows, and this does not work.  The problem is 
easily explained by using the gnome-calculator as an example.  The
area  around the buttons is considered a part of the GtkWindow, so
you get window enter events each time you leave a button, and you
get window leave events each time you enter a button.

Since the GdkCrossing structure only gives you the x/y location
at the time that the event was generated, it seems impossible to use
this to determine if the user entered the window from outside window
or if the user entered the window from a button (and the similar
problem for leaving).

I have attached an example program where I try and use different
techniques to access the information from the enter/leave events.
All approaches in this sample have the same issues.

Is there any way to detect that the mouse has moved from outside the
window border into the window, or from inside the window border to
outside the window?

Brian
/* GDM - The Gnome Display Manager
 * Copyright (C) 1999, 2000 Martin K. Petersen <mkp mkp net>
 *
 * This file Copyright (c) 2003 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 <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>

#include <glib.h>
#include <gmodule.h>
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include <gtk/gtk.h>
#include <gnome.h>
/*
#include <glib-object.h>
*/

#include <config.h>

/*
 * Note that CONFIGFILE will have to be changed to something more generic
 * if this module is ever moved outside of gdm.
 */

#define CONFIGFILE EXPANDED_SYSCONFDIR "/gdm/modules/AccessKeyMouseEvents"
#define	iseol(ch)	((ch) == '\r' || (ch) == '\f' || (ch) == '\0' || \
			(ch) == '\n')

typedef enum
{
	BINDING_TYPE_KEY	= 1 << 0,
	BINDING_TYPE_MOUSE	= 1 << 1
} BindingType;

typedef struct {
	guint keysym;
	GdkModifierType state;
	guint keycode;
} Key;

typedef struct {
	guint number;
	GdkModifierType state;
} Button;

union Input {
	Key key;
	Button button;
};

typedef struct {
	BindingType type;
	union Input input;
	char *binding_str;
	GSList *actions;
	guint n_times;
	guint duration;
	guint timeout;
} Binding;

static int lineno = 0;
static GSList *binding_list = NULL;
extern char **environ;

static void create_event_watcher ();
			
/* test using filter */

GdkFilterReturn
enter_filter (GdkXEvent *gdk_xevent,
		    GdkEvent *event,
		    gpointer data)
{
	XEvent *xevent = (XEvent *)gdk_xevent;

	if (xevent->type != EnterNotify)
	 	return GDK_FILTER_CONTINUE;

        printf("filter: %p %p\n", xevent->xcrossing.window, xevent->xcrossing.subwindow);
        printf ("%d %d %d %d - ",
          xevent->xcrossing.x,
          xevent->xcrossing.y,
          xevent->xcrossing.x_root,
          xevent->xcrossing.y_root);

        if (xevent->xcrossing.detail == NotifyAncestor)
        	printf("NotifyAncestor\n");
        if (xevent->xcrossing.detail == NotifyInferior)
        	printf("NotifyInferior\n");
        if (xevent->xcrossing.detail == NotifyVirtual)
        	printf("NotifyVirtual\n");
        if (xevent->xcrossing.detail == NotifyNonlinear)
        	printf("NotifyNonlinear\n");
        if (xevent->xcrossing.detail == NotifyNonlinearVirtual)
        	printf("NotifyNonlinearVirtual\n");



  return GDK_FILTER_CONTINUE;
}

/* using emission-hook */
static gboolean
enter_emission_hook (GSignalInvocationHint	*ihint,
                     guint			n_param_values,
                     const GValue		*param_values,
                     gpointer			data)
{
  GObject *object;
  GtkWindow *window;
  GdkEventCrossing *event;

  object = g_value_get_object (param_values + 0);
  event = g_value_get_boxed (param_values + 1);

  if (GTK_IS_WINDOW(object) && GTK_WIDGET_TOPLEVEL(object))
      printf("window     - emission-hook: %p %p %p\n", object, event->window, event->subwindow);
  else
      printf("non-window - emission-hook: %p %p %p\n", object, event->window, event->subwindow);

  return TRUE;
}

/* Using signal-connect */

gboolean
signal_connect_enter_cb (GtkWidget *widget,
          GdkEventCrossing *event,
          gpointer user_data)
{
   if (GTK_IS_WINDOW(widget) && GTK_WIDGET_TOPLEVEL(widget))
       printf("window     - signal-connect: %p %p %p\n", widget, event->window, event->subwindow);
   else
       printf("non-window - signal-connect: %p %p %p\n", widget, event->window, event->subwindow);
}

/* this emission hook is used to set up the signal-connect situation.  It connects any
   window that is shown to the enter-notify-event signal. */

static gboolean
show_event_emission_hook (GSignalInvocationHint		*ihint,
				  guint			 n_param_values,
				  const GValue		*param_values,
				  gpointer		 data)
{
  GObject *object;
  GtkWidget *widget;

  object = g_value_get_object (param_values + 0);

  if (!GTK_IS_WINDOW (object))
    return TRUE;

  widget = GTK_WIDGET(object);

  g_signal_connect(widget, "enter-notify-event", G_CALLBACK(signal_connect_enter_cb), NULL);
}

static void create_event_watcher ()
{
	GSList *li;
	GdkDisplay *display;
        guint signal_id;

	display = gdk_display_get_default();
	if (!display) {
		return;
	}

        /* set up filter */
	gdk_window_add_filter (NULL, enter_filter, NULL);

        gtk_type_class (GTK_TYPE_WIDGET);

        /* set up emission hook */
        g_signal_add_emission_hook(
          g_signal_lookup("enter-notify-event", GTK_TYPE_WIDGET), 0,
          enter_emission_hook, NULL, (GDestroyNotify) NULL); 

        /* set up emission hook that will then set up the direct g_connect on the window */
        gtk_type_class (GTK_TYPE_WINDOW);

        signal_id  = g_signal_lookup ("show", GTK_TYPE_WINDOW);
        g_signal_add_emission_hook (signal_id, 0,
           show_event_emission_hook, NULL, (GDestroyNotify) NULL);

	return;
}

/* The init function for this gtk module */
G_MODULE_EXPORT void gtk_module_init(int *argc, char* argv[]);

void gtk_module_init(int *argc, char* argv[])
{
	create_event_watcher();
}		

/* EOF */



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