Re: how to determine if a window has been entered/exited



Sven/Oliver:

> Brian Cameron <Brian Cameron sun com> writes:
> 
> > 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 think you should be able to differentiate between these events by
> looking at the GdkNotifyType which is part of the GdkCrossing
> structure.

Unfortunately this doesn't seem to be the case. Using a few programs
to check, I notice that the detail is either NotifyVirtual or
NotifyAncestor when I move the mouse into the window.  You can see
this using the example GTK_MODULE that I sent in my last email.
Just run gnome-calculator as follows, for example:

  gnome-calculator --gtk-module=/path/dwellmouselistener.so

The "detail" value seems to be NotifyAncestor if the mouse is moving
into an area of the screen that is considered a part of the GtkWindow
(like the areas around the calculator buttons).  It is NotifyVirtual
otherwise. 

Using gnome-calculator for an example, I get "NotifyVirtual" if I
move into the menubar or the numerical display area of the screen
and I get "NotifyAncestor" if I move into the area where the buttons
are located.  The difference seems to be that the areas around the
buttons are considered a part of the GtkWindow whereas the menubar
and numerical display area don't have such space around them.  I
notice similar behavior with other programs.

I can get other "NotifyAncestor" enter events to happen moving around 
within the window.  I can't seem to find a situation where I can get
"MotionVirtual" to happen without entering the window from outside
the border.  So it doesn't seem that this is the full solution, 
unless there is something I am still missing.

I have also tried calling gdk_window_get_frame_extents and comparing
the values with the x_root and y_root that are passed in with the 
event.  I was hoping that I could use these to help me determine if
the mouse truly entered or left the window.  Unfortunately I notice
that this doesn't work either.  Sometimes you leave the window and
it tells you that the x_root and y_root are still inside the window.
sigh...  The new attachment shows this problem.

So Oliver's suggestion to use NotifyInferior doesn't seem to be 
a help, nor do I see how to use this GdkNotifyType in general
to determine the situation either.

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 guint enter_signal_id = 0;
static guint leave_signal_id = 0;

static void create_event_watcher ();
			
/* using emission-hook */
static gboolean
leave_enter_emission_hook (GSignalInvocationHint	*ihint,
                           guint			n_param_values,
                           const GValue			*param_values,
                           gpointer			data)
{
  GObject *object;
  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))
    {
      GtkWidget *widget = GTK_WIDGET(object);
      GtkWindow *window = GTK_WINDOW(object);
      GdkRectangle rect;
      int x_root, y_root;

      gdk_window_get_frame_extents (widget->window, &rect);

      x_root = (int)event->x_root;
      y_root = (int)event->y_root;

      if (x_root > rect.x && x_root < rect.x + rect.width &&
          y_root > rect.y && y_root < rect.y + rect.height)
        {
           printf ("inside! %d %d %d %d %d %d\n", rect.x, rect.y, rect.width, rect.height, x_root, y_root);
        }
      else
        {
           printf ("outside! %d %d %d %d %d %d\n", rect.x, rect.y, rect.width, rect.height, x_root, y_root);
        }
/*
      printf("%d %d %d %d\n", rect.x, rect.y, rect.width, rect.height);
      printf("%f %f\n", event->x_root, event->y_root);
*/

      if (ihint->signal_id == enter_signal_id)
         printf("enter - ");
      else if (ihint->signal_id == leave_signal_id)
         printf("leave - ");
      else
         printf("error - ");
 
      printf("emission-hook: %p %p %p\n", object, event->window, event->subwindow);
   }

  return TRUE;
}

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

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

        /* set up emission hook */
        gtk_type_class (GTK_TYPE_WIDGET);
        enter_signal_id = g_signal_lookup("enter-notify-event", GTK_TYPE_WIDGET);
        leave_signal_id = g_signal_lookup("leave-notify-event", GTK_TYPE_WIDGET);

        g_signal_add_emission_hook(enter_signal_id, 0, 
          leave_enter_emission_hook, NULL, (GDestroyNotify) NULL); 
        g_signal_add_emission_hook(leave_signal_id, 0,
          leave_enter_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]