Re: Preliminary submenu patch
- From: Owen Taylor <otaylor redhat com>
- To: Nils Barth <nils_barth post harvard edu>
- Cc: gtk-devel-list redhat com
- Subject: Re: Preliminary submenu patch
- Date: 08 Jun 2000 16:28:03 -0400
Nils Barth <nils_barth@post.harvard.edu> writes:
> Attached find a preliminary patch to improve submenu navigation, a la
> Mac.
>
> It deals properly with mouse movement and with keystrokes:
> when the pointer leaves a menu item, it creates a GdkRegion (the
> triangular region that I've been going on about), and then every
> menu_motion event and menu_shell enter/leave event checks the pointer
> to see that it's in the region. If so, the event is ignored. If not
> (or if the pointer is NULL) it kills the region and the event is
> procesed as usual.
I hate to say it, but this patch doesn't work at all for me.
I see no effect at all. (Using current CVS GTK+). I'm not sure
what is going on - I haven't tried to debug.
But I've made some stylistic comments on the patch as well
and tried to answer your questions.
Regards,
Owen
> Any keyboard action kills the region.
> The region is stored as a static pointer in gtkmenushell.c
>
> Note that testgtk was very helpful in bug hunting and in code design:
> it showed bugs in early attempts I had never thought of.
>
> Questions:
> (1) What's the proper way of dereferencing a GdkRegion?
gdk_region_destroy()
> (2) I haven't implemented a timeout -- I was thinking of copying the
> code from gtk_real_menu_item_select -- is this right? (David?)
that's a timeout, yes.
> (3) Currently, it's ugly in that to share a function between
> gtkmenushell and gtkmenu, I make public functions available.
There always have been "private" functions in GTK+ header files.
They should be marked as such with a comment. With GTK+-1.4, we
have the added convention of beginning such functions with a
underscore:
_gtk_menu_shell_motion_notify()
One reason for this doing is that we can eventually control exports
using a regexp on function name.
> Would an acceptable better way be to add a line like:
>
> if (GTK_WIDGET_CLASS (parent_class)->motion_notify_event (widget, event))
> return TRUE;
>
> to gtkmenu.c:gtk_menu_motion_notify_event ()
> and then make gtk_menu_shell_motion_notify_event () which just
> called
> if (gtk_menu_shell_navigating ((gint) event->x_root, (gint)
> event->y_root))
> return TRUE;
> ? (I didn't do this b/c it involved adding new signal handlers, and I wanted
> to make sure this was kosher).
New signal handlers? I don't quite follow. But, no, I don't like this
approach, because I don't see this as a natural behavior for a motion
event for a generic MenuShell descendent.
> Index: gtkmenu.c
> ===================================================================
> RCS file: /cvs/gnome/gtk+/gtk/gtkmenu.c,v
> retrieving revision 1.45
> diff -u -r1.45 gtkmenu.c
> --- gtkmenu.c 2000/05/21 06:13:34 1.45
> +++ gtkmenu.c 2000/06/07 13:05:32
> @@ -30,11 +30,11 @@
> #include "gtklabel.h"
> #include "gtkmain.h"
> #include "gtkmenu.h"
> +#include "gtkmenushell.h"
This is not needed, gtkmenu.h includes gtkmenushell.h.
> #include "gtkmenuitem.h"
> #include "gtksignal.h"
> #include "gtkwindow.h"
>
> -
> #define MENU_ITEM_CLASS(w) GTK_MENU_ITEM_GET_CLASS (w)
> #define MENU_NEEDS_RESIZE(m) GTK_MENU_SHELL (m)->menu_flag
>
> @@ -1103,14 +1103,24 @@
> }
>
> static gint
> -gtk_menu_motion_notify (GtkWidget *widget,
> - GdkEventMotion *event)
> +gtk_menu_motion_notify (GtkWidget *widget,
> + GdkEventMotion *event)
> {
> + GtkMenu *menu;
> + GtkMenuShell *menu_shell;
> +
> g_return_val_if_fail (widget != NULL, FALSE);
> g_return_val_if_fail (GTK_IS_MENU (widget), FALSE);
>
> - if (GTK_MENU_SHELL (widget)->ignore_enter)
> - GTK_MENU_SHELL (widget)->ignore_enter = FALSE;
> + menu = GTK_MENU (widget);
> +
> +/* start */
> + if (gtk_menu_shell_navigating ((gint) event->x_root, (gint) event->y_root))
> + return TRUE;
> + menu_shell = GTK_MENU_SHELL (widget);
> +/* end */
Obviously these comments would have to be removed before the final
result. Stylistically I don't particularly like the explicit casts in
here. Explicit casts prevent the compiler from using its intelligence
to decide if the cast is reasonably or not.
> + if (menu_shell->ignore_enter)
> + menu_shell->ignore_enter = FALSE;
> else
> {
> gint width, height;
> @@ -1125,11 +1135,10 @@
> send_event.crossing.window = event->window;
> send_event.crossing.time = event->time;
> send_event.crossing.send_event = TRUE;
> -
> +
> gtk_widget_event (widget, &send_event);
> }
> }
> -
It's easier if you don't make random line insertions/deletions in a line
like this.
[...]
> +static GdkRegion *navigation_region = NULL;
I don't like the general approach of having a global region like this.
It seems to me that the region should be stored in the GtkMenu
structure. The "triangular region" only applies to navigation within
a single menu, right? Actually, I'm not sure why the handling of the
navigation is in GtkMenuShell at all - not GtkMenu. The behavior
is specialized to vertical menus, right?
There are quite a few stylistic problems in the following.
The basic GTK+ style is the GNU style, with a few additions. Indentation
follow the GNU style. We don't yet have a coding-style document,
but:
pango/docs/TEXT/coding-style.txt
is reasonably close to the GTK+ style.
> +void
> +gtk_menu_shell_stop_navigating ()
> +{
> + /* FIXME: Should I deallocate the region? */
> + navigation_region = NULL;
> +}
> +
> +gboolean
> +gtk_menu_shell_navigating (gint event_x, gint event_y)
> +{
> + if (navigation_region)
> + {
> + if (gdk_region_point_in (navigation_region, event_x, event_y))
> + return TRUE;
> + else
> + {
> + gtk_menu_shell_stop_navigating ();
> + return FALSE;
> + }
> + }
> + return FALSE;
> +}
> +
> +static void
> +gtk_menu_shell_set_navigation_region (GtkMenuItem *menu_item,
> + GdkEventCrossing *event)
> +{
> + gint submenu_left = 0, submenu_right = 0;
> + gint submenu_top = 0, submenu_bottom = 0;
> + gint width = 0, height = 0;
> + GdkPoint point[3];
> + GtkWidget *event_widget;
> +
> + g_return_if_fail (menu_item->submenu != NULL);
> + g_return_if_fail (event != NULL);
> +
> + event_widget = gtk_get_event_widget ((GdkEvent*) event);
> +
> + gdk_window_get_root_origin (menu_item->submenu->window,
> + &submenu_left, &submenu_top);
> + gdk_window_get_size (menu_item->submenu->window, &width, &height);
> + submenu_right = submenu_left + width;
> + submenu_bottom = submenu_top + height;
> + gdk_window_get_size (event_widget->window, &width, &height);
> + /* FIXME: 6 is a magic number -- why does it work? */
> + if ((event->x >= 0) && (event->x <= width - 6)
> + && !((event->y < 0) && (event->y_root <= submenu_top))
> + && !((event->y >= 0) && (event->y_root >= submenu_bottom)))
> + {
> + /* Set navigation region */
> + point[0].x = (gint16) event->x_root;
GdkPoint is gint, not gint16 now.
[...]
> }
>
> static void
> Index: gtkmenushell.h
> ===================================================================
> RCS file: /cvs/gnome/gtk+/gtk/gtkmenushell.h,v
> retrieving revision 1.8
> diff -u -r1.8 gtkmenushell.h
> --- gtkmenushell.h 2000/02/13 08:16:47 1.8
> +++ gtkmenushell.h 2000/06/07 13:05:33
> @@ -55,7 +55,8 @@
> GList *children;
> GtkWidget *active_menu_item;
> GtkWidget *parent_menu_shell;
> -
> +
> +/* GdkRegion *navigation_region; */
> guint active : 1;
> guint have_grab : 1;
> guint have_xgrab : 1;
> @@ -99,8 +100,9 @@
> void gtk_menu_shell_activate_item (GtkMenuShell *menu_shell,
> GtkWidget *menu_item,
> gboolean force_deactivate);
> -
> -
> +void gtk_menu_shell_stop_navigating ();
> +gboolean gtk_menu_shell_navigating (gint event_x,
> + gint event_y);
> #ifdef __cplusplus
> }
> #endif /* __cplusplus */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]