diff options
37 files changed, 2383 insertions, 324 deletions
@@ -1,3 +1,61 @@ +Tue Jul 21 12:42:01 1998 Owen Taylor <otaylor@redhat.com> + + * gdk/gdk.h gdk/gdkfont.c: Added gdk_text/string_extents() - + too calculate all the metrics at once of a string, including + things which weren't calculated before. + + * gtk/Makefile.am gtk/gtk.h gtk/gtktearoffmenu.[ch]: New + MenuItem type, that when put as the first thing in a + menu, makes the menu tearoff. Currently drawn as a + dashed line. + + * gtk/gtkmenuitem.h gtk/gtkcheckmenuitem.c: Added a flag + "hide_on_activate" to the MenuItem class structure to allow + check and radio buttons to be changed with <Space> without + hiding the menu. + + * gtk/gtkaccellabel.[ch]: Added new capabilities to set + a underline_group and underline_mods for the label - + accelerators added in the underline group matching + underline_mods will be displayed as an underline character. + + This doesn't work - Save As needs to be underlined + as Save _As. + + * gtk/gtkitemfactory.c: + - Create a AccelGroup for each MenuShell we create. + - If an '&' appears before a character 'c' in the path, + then make 'c' an accelerator in the menu's accel group, + and if the menuitem is menubar <alt>C an accelerator + in the itemfactory's accel group. + + * gtk/gtklabel.[ch]: Add support for a pattern arg - + which is a string. If an '_' appears in this string, + the corresponding position in the label is underlined. + + Add gtk_label_parse_uline() convenience function which + takes a string with embedded underlines, sets the + pattern and label, and returns the accelerator keyval. + + * gtk/gtkmenu.[ch]: Make menus no longer a toplevel widget. + Instead, they create a GtkWindow and add themselves + to that. (When torn off, another new feature, they + create another GtkWindow to hold the torn off menu) + + New function gtk_menu_set_tearoff_state() + + * gtk/gtkenums.h gtk/gtkmenushell.[ch] gtk/gtkenums.h: + Added action signals for keyboard navigation of menus. + + * gtk/gtkmenushell.c: Key press handler which activates + bindings for navigation, and accelerators, for handling + underline accelerators. Exported functions to select + and activate menu items in a menushell. + + * gtk/testgtk.c: Added a new "Item Factory" test which + tests GtkItemFactory and the new keyboard navigation + of menus. + Tue Aug 11 20:52:58 1998 Tim Janik <timj@gtk.org> * gtk/gtktypeutils.c (gtk_type_class_init): relookup nodes after @@ -68,6 +126,7 @@ Thu Aug 6 22:37:21 1998 Stefan Jeske <stefan@gtk.org> * gtk/gtkclist.c: Renamed my_merge and my_mergesort to gtk_clist_merge and gtk_clist_mergesort. :) +>>>>>>> 1.579 1998-08-06 Martin Baulig <martin@home-of-linux.org> * gtk/gtkclist.c: Renamed `merge' -> `my_merge' and @@ -391,6 +450,15 @@ Wed Jul 15 17:44:47 1998 Owen Taylor <otaylor@redhat.com> * Fix up line start cache when splitting a property during an insert. +Wed Jul 15 21:15:52 1998 Owen Taylor <otaylor@redhat.com> + + * gtk/gtkwidget.c: restauration => restoration + +Thu Jul 16 20:11:36 1998 Owen Taylor <otaylor@redhat.com> + + * gdk/gdkxid.c (gdk_xid_table_lookup): If xid_ht + hasn't been created yet, don't do the lookup. + 1998-07-20 Raph Levien <raph@acm.org> * gdk/gdkrgb.c: More cleanups in the config process. diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index 6c931162c5..268879630a 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -1,3 +1,61 @@ +Tue Jul 21 12:42:01 1998 Owen Taylor <otaylor@redhat.com> + + * gdk/gdk.h gdk/gdkfont.c: Added gdk_text/string_extents() - + too calculate all the metrics at once of a string, including + things which weren't calculated before. + + * gtk/Makefile.am gtk/gtk.h gtk/gtktearoffmenu.[ch]: New + MenuItem type, that when put as the first thing in a + menu, makes the menu tearoff. Currently drawn as a + dashed line. + + * gtk/gtkmenuitem.h gtk/gtkcheckmenuitem.c: Added a flag + "hide_on_activate" to the MenuItem class structure to allow + check and radio buttons to be changed with <Space> without + hiding the menu. + + * gtk/gtkaccellabel.[ch]: Added new capabilities to set + a underline_group and underline_mods for the label - + accelerators added in the underline group matching + underline_mods will be displayed as an underline character. + + This doesn't work - Save As needs to be underlined + as Save _As. + + * gtk/gtkitemfactory.c: + - Create a AccelGroup for each MenuShell we create. + - If an '&' appears before a character 'c' in the path, + then make 'c' an accelerator in the menu's accel group, + and if the menuitem is menubar <alt>C an accelerator + in the itemfactory's accel group. + + * gtk/gtklabel.[ch]: Add support for a pattern arg - + which is a string. If an '_' appears in this string, + the corresponding position in the label is underlined. + + Add gtk_label_parse_uline() convenience function which + takes a string with embedded underlines, sets the + pattern and label, and returns the accelerator keyval. + + * gtk/gtkmenu.[ch]: Make menus no longer a toplevel widget. + Instead, they create a GtkWindow and add themselves + to that. (When torn off, another new feature, they + create another GtkWindow to hold the torn off menu) + + New function gtk_menu_set_tearoff_state() + + * gtk/gtkenums.h gtk/gtkmenushell.[ch] gtk/gtkenums.h: + Added action signals for keyboard navigation of menus. + + * gtk/gtkmenushell.c: Key press handler which activates + bindings for navigation, and accelerators, for handling + underline accelerators. Exported functions to select + and activate menu items in a menushell. + + * gtk/testgtk.c: Added a new "Item Factory" test which + tests GtkItemFactory and the new keyboard navigation + of menus. + Tue Aug 11 20:52:58 1998 Tim Janik <timj@gtk.org> * gtk/gtktypeutils.c (gtk_type_class_init): relookup nodes after @@ -68,6 +126,7 @@ Thu Aug 6 22:37:21 1998 Stefan Jeske <stefan@gtk.org> * gtk/gtkclist.c: Renamed my_merge and my_mergesort to gtk_clist_merge and gtk_clist_mergesort. :) +>>>>>>> 1.579 1998-08-06 Martin Baulig <martin@home-of-linux.org> * gtk/gtkclist.c: Renamed `merge' -> `my_merge' and @@ -391,6 +450,15 @@ Wed Jul 15 17:44:47 1998 Owen Taylor <otaylor@redhat.com> * Fix up line start cache when splitting a property during an insert. +Wed Jul 15 21:15:52 1998 Owen Taylor <otaylor@redhat.com> + + * gtk/gtkwidget.c: restauration => restoration + +Thu Jul 16 20:11:36 1998 Owen Taylor <otaylor@redhat.com> + + * gdk/gdkxid.c (gdk_xid_table_lookup): If xid_ht + hasn't been created yet, don't do the lookup. + 1998-07-20 Raph Levien <raph@acm.org> * gdk/gdkrgb.c: More cleanups in the config process. diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 6c931162c5..268879630a 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,61 @@ +Tue Jul 21 12:42:01 1998 Owen Taylor <otaylor@redhat.com> + + * gdk/gdk.h gdk/gdkfont.c: Added gdk_text/string_extents() - + too calculate all the metrics at once of a string, including + things which weren't calculated before. + + * gtk/Makefile.am gtk/gtk.h gtk/gtktearoffmenu.[ch]: New + MenuItem type, that when put as the first thing in a + menu, makes the menu tearoff. Currently drawn as a + dashed line. + + * gtk/gtkmenuitem.h gtk/gtkcheckmenuitem.c: Added a flag + "hide_on_activate" to the MenuItem class structure to allow + check and radio buttons to be changed with <Space> without + hiding the menu. + + * gtk/gtkaccellabel.[ch]: Added new capabilities to set + a underline_group and underline_mods for the label - + accelerators added in the underline group matching + underline_mods will be displayed as an underline character. + + This doesn't work - Save As needs to be underlined + as Save _As. + + * gtk/gtkitemfactory.c: + - Create a AccelGroup for each MenuShell we create. + - If an '&' appears before a character 'c' in the path, + then make 'c' an accelerator in the menu's accel group, + and if the menuitem is menubar <alt>C an accelerator + in the itemfactory's accel group. + + * gtk/gtklabel.[ch]: Add support for a pattern arg - + which is a string. If an '_' appears in this string, + the corresponding position in the label is underlined. + + Add gtk_label_parse_uline() convenience function which + takes a string with embedded underlines, sets the + pattern and label, and returns the accelerator keyval. + + * gtk/gtkmenu.[ch]: Make menus no longer a toplevel widget. + Instead, they create a GtkWindow and add themselves + to that. (When torn off, another new feature, they + create another GtkWindow to hold the torn off menu) + + New function gtk_menu_set_tearoff_state() + + * gtk/gtkenums.h gtk/gtkmenushell.[ch] gtk/gtkenums.h: + Added action signals for keyboard navigation of menus. + + * gtk/gtkmenushell.c: Key press handler which activates + bindings for navigation, and accelerators, for handling + underline accelerators. Exported functions to select + and activate menu items in a menushell. + + * gtk/testgtk.c: Added a new "Item Factory" test which + tests GtkItemFactory and the new keyboard navigation + of menus. + Tue Aug 11 20:52:58 1998 Tim Janik <timj@gtk.org> * gtk/gtktypeutils.c (gtk_type_class_init): relookup nodes after @@ -68,6 +126,7 @@ Thu Aug 6 22:37:21 1998 Stefan Jeske <stefan@gtk.org> * gtk/gtkclist.c: Renamed my_merge and my_mergesort to gtk_clist_merge and gtk_clist_mergesort. :) +>>>>>>> 1.579 1998-08-06 Martin Baulig <martin@home-of-linux.org> * gtk/gtkclist.c: Renamed `merge' -> `my_merge' and @@ -391,6 +450,15 @@ Wed Jul 15 17:44:47 1998 Owen Taylor <otaylor@redhat.com> * Fix up line start cache when splitting a property during an insert. +Wed Jul 15 21:15:52 1998 Owen Taylor <otaylor@redhat.com> + + * gtk/gtkwidget.c: restauration => restoration + +Thu Jul 16 20:11:36 1998 Owen Taylor <otaylor@redhat.com> + + * gdk/gdkxid.c (gdk_xid_table_lookup): If xid_ht + hasn't been created yet, don't do the lookup. + 1998-07-20 Raph Levien <raph@acm.org> * gdk/gdkrgb.c: More cleanups in the config process. diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index 6c931162c5..268879630a 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,61 @@ +Tue Jul 21 12:42:01 1998 Owen Taylor <otaylor@redhat.com> + + * gdk/gdk.h gdk/gdkfont.c: Added gdk_text/string_extents() - + too calculate all the metrics at once of a string, including + things which weren't calculated before. + + * gtk/Makefile.am gtk/gtk.h gtk/gtktearoffmenu.[ch]: New + MenuItem type, that when put as the first thing in a + menu, makes the menu tearoff. Currently drawn as a + dashed line. + + * gtk/gtkmenuitem.h gtk/gtkcheckmenuitem.c: Added a flag + "hide_on_activate" to the MenuItem class structure to allow + check and radio buttons to be changed with <Space> without + hiding the menu. + + * gtk/gtkaccellabel.[ch]: Added new capabilities to set + a underline_group and underline_mods for the label - + accelerators added in the underline group matching + underline_mods will be displayed as an underline character. + + This doesn't work - Save As needs to be underlined + as Save _As. + + * gtk/gtkitemfactory.c: + - Create a AccelGroup for each MenuShell we create. + - If an '&' appears before a character 'c' in the path, + then make 'c' an accelerator in the menu's accel group, + and if the menuitem is menubar <alt>C an accelerator + in the itemfactory's accel group. + + * gtk/gtklabel.[ch]: Add support for a pattern arg - + which is a string. If an '_' appears in this string, + the corresponding position in the label is underlined. + + Add gtk_label_parse_uline() convenience function which + takes a string with embedded underlines, sets the + pattern and label, and returns the accelerator keyval. + + * gtk/gtkmenu.[ch]: Make menus no longer a toplevel widget. + Instead, they create a GtkWindow and add themselves + to that. (When torn off, another new feature, they + create another GtkWindow to hold the torn off menu) + + New function gtk_menu_set_tearoff_state() + + * gtk/gtkenums.h gtk/gtkmenushell.[ch] gtk/gtkenums.h: + Added action signals for keyboard navigation of menus. + + * gtk/gtkmenushell.c: Key press handler which activates + bindings for navigation, and accelerators, for handling + underline accelerators. Exported functions to select + and activate menu items in a menushell. + + * gtk/testgtk.c: Added a new "Item Factory" test which + tests GtkItemFactory and the new keyboard navigation + of menus. + Tue Aug 11 20:52:58 1998 Tim Janik <timj@gtk.org> * gtk/gtktypeutils.c (gtk_type_class_init): relookup nodes after @@ -68,6 +126,7 @@ Thu Aug 6 22:37:21 1998 Stefan Jeske <stefan@gtk.org> * gtk/gtkclist.c: Renamed my_merge and my_mergesort to gtk_clist_merge and gtk_clist_mergesort. :) +>>>>>>> 1.579 1998-08-06 Martin Baulig <martin@home-of-linux.org> * gtk/gtkclist.c: Renamed `merge' -> `my_merge' and @@ -391,6 +450,15 @@ Wed Jul 15 17:44:47 1998 Owen Taylor <otaylor@redhat.com> * Fix up line start cache when splitting a property during an insert. +Wed Jul 15 21:15:52 1998 Owen Taylor <otaylor@redhat.com> + + * gtk/gtkwidget.c: restauration => restoration + +Thu Jul 16 20:11:36 1998 Owen Taylor <otaylor@redhat.com> + + * gdk/gdkxid.c (gdk_xid_table_lookup): If xid_ht + hasn't been created yet, don't do the lookup. + 1998-07-20 Raph Levien <raph@acm.org> * gdk/gdkrgb.c: More cleanups in the config process. diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index 6c931162c5..268879630a 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,61 @@ +Tue Jul 21 12:42:01 1998 Owen Taylor <otaylor@redhat.com> + + * gdk/gdk.h gdk/gdkfont.c: Added gdk_text/string_extents() - + too calculate all the metrics at once of a string, including + things which weren't calculated before. + + * gtk/Makefile.am gtk/gtk.h gtk/gtktearoffmenu.[ch]: New + MenuItem type, that when put as the first thing in a + menu, makes the menu tearoff. Currently drawn as a + dashed line. + + * gtk/gtkmenuitem.h gtk/gtkcheckmenuitem.c: Added a flag + "hide_on_activate" to the MenuItem class structure to allow + check and radio buttons to be changed with <Space> without + hiding the menu. + + * gtk/gtkaccellabel.[ch]: Added new capabilities to set + a underline_group and underline_mods for the label - + accelerators added in the underline group matching + underline_mods will be displayed as an underline character. + + This doesn't work - Save As needs to be underlined + as Save _As. + + * gtk/gtkitemfactory.c: + - Create a AccelGroup for each MenuShell we create. + - If an '&' appears before a character 'c' in the path, + then make 'c' an accelerator in the menu's accel group, + and if the menuitem is menubar <alt>C an accelerator + in the itemfactory's accel group. + + * gtk/gtklabel.[ch]: Add support for a pattern arg - + which is a string. If an '_' appears in this string, + the corresponding position in the label is underlined. + + Add gtk_label_parse_uline() convenience function which + takes a string with embedded underlines, sets the + pattern and label, and returns the accelerator keyval. + + * gtk/gtkmenu.[ch]: Make menus no longer a toplevel widget. + Instead, they create a GtkWindow and add themselves + to that. (When torn off, another new feature, they + create another GtkWindow to hold the torn off menu) + + New function gtk_menu_set_tearoff_state() + + * gtk/gtkenums.h gtk/gtkmenushell.[ch] gtk/gtkenums.h: + Added action signals for keyboard navigation of menus. + + * gtk/gtkmenushell.c: Key press handler which activates + bindings for navigation, and accelerators, for handling + underline accelerators. Exported functions to select + and activate menu items in a menushell. + + * gtk/testgtk.c: Added a new "Item Factory" test which + tests GtkItemFactory and the new keyboard navigation + of menus. + Tue Aug 11 20:52:58 1998 Tim Janik <timj@gtk.org> * gtk/gtktypeutils.c (gtk_type_class_init): relookup nodes after @@ -68,6 +126,7 @@ Thu Aug 6 22:37:21 1998 Stefan Jeske <stefan@gtk.org> * gtk/gtkclist.c: Renamed my_merge and my_mergesort to gtk_clist_merge and gtk_clist_mergesort. :) +>>>>>>> 1.579 1998-08-06 Martin Baulig <martin@home-of-linux.org> * gtk/gtkclist.c: Renamed `merge' -> `my_merge' and @@ -391,6 +450,15 @@ Wed Jul 15 17:44:47 1998 Owen Taylor <otaylor@redhat.com> * Fix up line start cache when splitting a property during an insert. +Wed Jul 15 21:15:52 1998 Owen Taylor <otaylor@redhat.com> + + * gtk/gtkwidget.c: restauration => restoration + +Thu Jul 16 20:11:36 1998 Owen Taylor <otaylor@redhat.com> + + * gdk/gdkxid.c (gdk_xid_table_lookup): If xid_ht + hasn't been created yet, don't do the lookup. + 1998-07-20 Raph Levien <raph@acm.org> * gdk/gdkrgb.c: More cleanups in the config process. diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 6c931162c5..268879630a 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,61 @@ +Tue Jul 21 12:42:01 1998 Owen Taylor <otaylor@redhat.com> + + * gdk/gdk.h gdk/gdkfont.c: Added gdk_text/string_extents() - + too calculate all the metrics at once of a string, including + things which weren't calculated before. + + * gtk/Makefile.am gtk/gtk.h gtk/gtktearoffmenu.[ch]: New + MenuItem type, that when put as the first thing in a + menu, makes the menu tearoff. Currently drawn as a + dashed line. + + * gtk/gtkmenuitem.h gtk/gtkcheckmenuitem.c: Added a flag + "hide_on_activate" to the MenuItem class structure to allow + check and radio buttons to be changed with <Space> without + hiding the menu. + + * gtk/gtkaccellabel.[ch]: Added new capabilities to set + a underline_group and underline_mods for the label - + accelerators added in the underline group matching + underline_mods will be displayed as an underline character. + + This doesn't work - Save As needs to be underlined + as Save _As. + + * gtk/gtkitemfactory.c: + - Create a AccelGroup for each MenuShell we create. + - If an '&' appears before a character 'c' in the path, + then make 'c' an accelerator in the menu's accel group, + and if the menuitem is menubar <alt>C an accelerator + in the itemfactory's accel group. + + * gtk/gtklabel.[ch]: Add support for a pattern arg - + which is a string. If an '_' appears in this string, + the corresponding position in the label is underlined. + + Add gtk_label_parse_uline() convenience function which + takes a string with embedded underlines, sets the + pattern and label, and returns the accelerator keyval. + + * gtk/gtkmenu.[ch]: Make menus no longer a toplevel widget. + Instead, they create a GtkWindow and add themselves + to that. (When torn off, another new feature, they + create another GtkWindow to hold the torn off menu) + + New function gtk_menu_set_tearoff_state() + + * gtk/gtkenums.h gtk/gtkmenushell.[ch] gtk/gtkenums.h: + Added action signals for keyboard navigation of menus. + + * gtk/gtkmenushell.c: Key press handler which activates + bindings for navigation, and accelerators, for handling + underline accelerators. Exported functions to select + and activate menu items in a menushell. + + * gtk/testgtk.c: Added a new "Item Factory" test which + tests GtkItemFactory and the new keyboard navigation + of menus. + Tue Aug 11 20:52:58 1998 Tim Janik <timj@gtk.org> * gtk/gtktypeutils.c (gtk_type_class_init): relookup nodes after @@ -68,6 +126,7 @@ Thu Aug 6 22:37:21 1998 Stefan Jeske <stefan@gtk.org> * gtk/gtkclist.c: Renamed my_merge and my_mergesort to gtk_clist_merge and gtk_clist_mergesort. :) +>>>>>>> 1.579 1998-08-06 Martin Baulig <martin@home-of-linux.org> * gtk/gtkclist.c: Renamed `merge' -> `my_merge' and @@ -391,6 +450,15 @@ Wed Jul 15 17:44:47 1998 Owen Taylor <otaylor@redhat.com> * Fix up line start cache when splitting a property during an insert. +Wed Jul 15 21:15:52 1998 Owen Taylor <otaylor@redhat.com> + + * gtk/gtkwidget.c: restauration => restoration + +Thu Jul 16 20:11:36 1998 Owen Taylor <otaylor@redhat.com> + + * gdk/gdkxid.c (gdk_xid_table_lookup): If xid_ht + hasn't been created yet, don't do the lookup. + 1998-07-20 Raph Levien <raph@acm.org> * gdk/gdkrgb.c: More cleanups in the config process. diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 6c931162c5..268879630a 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,61 @@ +Tue Jul 21 12:42:01 1998 Owen Taylor <otaylor@redhat.com> + + * gdk/gdk.h gdk/gdkfont.c: Added gdk_text/string_extents() - + too calculate all the metrics at once of a string, including + things which weren't calculated before. + + * gtk/Makefile.am gtk/gtk.h gtk/gtktearoffmenu.[ch]: New + MenuItem type, that when put as the first thing in a + menu, makes the menu tearoff. Currently drawn as a + dashed line. + + * gtk/gtkmenuitem.h gtk/gtkcheckmenuitem.c: Added a flag + "hide_on_activate" to the MenuItem class structure to allow + check and radio buttons to be changed with <Space> without + hiding the menu. + + * gtk/gtkaccellabel.[ch]: Added new capabilities to set + a underline_group and underline_mods for the label - + accelerators added in the underline group matching + underline_mods will be displayed as an underline character. + + This doesn't work - Save As needs to be underlined + as Save _As. + + * gtk/gtkitemfactory.c: + - Create a AccelGroup for each MenuShell we create. + - If an '&' appears before a character 'c' in the path, + then make 'c' an accelerator in the menu's accel group, + and if the menuitem is menubar <alt>C an accelerator + in the itemfactory's accel group. + + * gtk/gtklabel.[ch]: Add support for a pattern arg - + which is a string. If an '_' appears in this string, + the corresponding position in the label is underlined. + + Add gtk_label_parse_uline() convenience function which + takes a string with embedded underlines, sets the + pattern and label, and returns the accelerator keyval. + + * gtk/gtkmenu.[ch]: Make menus no longer a toplevel widget. + Instead, they create a GtkWindow and add themselves + to that. (When torn off, another new feature, they + create another GtkWindow to hold the torn off menu) + + New function gtk_menu_set_tearoff_state() + + * gtk/gtkenums.h gtk/gtkmenushell.[ch] gtk/gtkenums.h: + Added action signals for keyboard navigation of menus. + + * gtk/gtkmenushell.c: Key press handler which activates + bindings for navigation, and accelerators, for handling + underline accelerators. Exported functions to select + and activate menu items in a menushell. + + * gtk/testgtk.c: Added a new "Item Factory" test which + tests GtkItemFactory and the new keyboard navigation + of menus. + Tue Aug 11 20:52:58 1998 Tim Janik <timj@gtk.org> * gtk/gtktypeutils.c (gtk_type_class_init): relookup nodes after @@ -68,6 +126,7 @@ Thu Aug 6 22:37:21 1998 Stefan Jeske <stefan@gtk.org> * gtk/gtkclist.c: Renamed my_merge and my_mergesort to gtk_clist_merge and gtk_clist_mergesort. :) +>>>>>>> 1.579 1998-08-06 Martin Baulig <martin@home-of-linux.org> * gtk/gtkclist.c: Renamed `merge' -> `my_merge' and @@ -391,6 +450,15 @@ Wed Jul 15 17:44:47 1998 Owen Taylor <otaylor@redhat.com> * Fix up line start cache when splitting a property during an insert. +Wed Jul 15 21:15:52 1998 Owen Taylor <otaylor@redhat.com> + + * gtk/gtkwidget.c: restauration => restoration + +Thu Jul 16 20:11:36 1998 Owen Taylor <otaylor@redhat.com> + + * gdk/gdkxid.c (gdk_xid_table_lookup): If xid_ht + hasn't been created yet, don't do the lookup. + 1998-07-20 Raph Levien <raph@acm.org> * gdk/gdkrgb.c: More cleanups in the config process. diff --git a/docs/widget_system.txt b/docs/widget_system.txt index e5f0328671..07a5532db6 100644 --- a/docs/widget_system.txt +++ b/docs/widget_system.txt @@ -391,7 +391,7 @@ When a widget receives the unmap signal, it must: 2) If the widget does not have a window, unmap all child widgets 3) Do any other functions related to taking the widget offscreen (for instance, removing popup windows...) - 3) Unset GTK_MAPPED + 4) Unset GTK_MAPPED The Unrealize signal @@ -517,6 +517,21 @@ gint gdk_text_height (GdkFont *font, gint gdk_char_height (GdkFont *font, gchar character); +void gdk_text_extents (GdkFont *font, + const gchar *text, + gint text_length, + gint *lbearing, + gint *rbearing, + gint *width, + gint *ascent, + gint *descent); +void gdk_string_extents (GdkFont *font, + const gchar *string, + gint *lbearing, + gint *rbearing, + gint *width, + gint *ascent, + gint *descent); /* Drawing */ diff --git a/gdk/gdkfont.c b/gdk/gdkfont.c index acc82f2b62..1b37930a73 100644 --- a/gdk/gdkfont.c +++ b/gdk/gdkfont.c @@ -328,6 +328,92 @@ gdk_string_measure (GdkFont *font, return gdk_text_measure (font, string, strlen (string)); } +void +gdk_text_extents (GdkFont *font, + const gchar *text, + gint text_length, + gint *lbearing, + gint *rbearing, + gint *width, + gint *ascent, + gint *descent) +{ + GdkFontPrivate *private; + XCharStruct overall; + XFontStruct *xfont; + XFontSet fontset; + XRectangle ink, logical; + int direction; + int font_ascent; + int font_descent; + + g_return_if_fail (font != NULL); + g_return_if_fail (text != NULL); + + private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + xfont = (XFontStruct *) private->xfont; + if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0)) + { + XTextExtents (xfont, text, text_length, + &direction, &font_ascent, &font_descent, + &overall); + } + else + { + XTextExtents16 (xfont, (XChar2b *) text, text_length / 2, + &direction, &font_ascent, &font_descent, + &overall); + } + if (lbearing) + *lbearing = overall.lbearing; + if (rbearing) + *rbearing = overall.rbearing; + if (width) + *width = overall.width; + if (ascent) + *ascent = overall.ascent; + if (descent) + *descent = overall.descent; + break; + case GDK_FONT_FONTSET: + fontset = (XFontSet) private->xfont; + XmbTextExtents (fontset, text, text_length, &ink, &logical); + if (lbearing) + *lbearing = -ink.x; + if (rbearing) + *rbearing = ink.y; + if (width) + *width = logical.width; + if (ascent) + *ascent = ink.height; + if (descent) + *descent = -ink.y; + break; + } + +} + +void +gdk_string_extents (GdkFont *font, + const gchar *string, + gint *lbearing, + gint *rbearing, + gint *width, + gint *ascent, + gint *descent) +{ + g_return_if_fail (font != NULL); + g_return_if_fail (string != NULL); + + gdk_text_extents (font, string, strlen (string), + lbearing, rbearing, width, ascent, descent); +} + + gint gdk_text_measure (GdkFont *font, const gchar *text, diff --git a/gdk/x11/gdkfont-x11.c b/gdk/x11/gdkfont-x11.c index acc82f2b62..1b37930a73 100644 --- a/gdk/x11/gdkfont-x11.c +++ b/gdk/x11/gdkfont-x11.c @@ -328,6 +328,92 @@ gdk_string_measure (GdkFont *font, return gdk_text_measure (font, string, strlen (string)); } +void +gdk_text_extents (GdkFont *font, + const gchar *text, + gint text_length, + gint *lbearing, + gint *rbearing, + gint *width, + gint *ascent, + gint *descent) +{ + GdkFontPrivate *private; + XCharStruct overall; + XFontStruct *xfont; + XFontSet fontset; + XRectangle ink, logical; + int direction; + int font_ascent; + int font_descent; + + g_return_if_fail (font != NULL); + g_return_if_fail (text != NULL); + + private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + xfont = (XFontStruct *) private->xfont; + if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0)) + { + XTextExtents (xfont, text, text_length, + &direction, &font_ascent, &font_descent, + &overall); + } + else + { + XTextExtents16 (xfont, (XChar2b *) text, text_length / 2, + &direction, &font_ascent, &font_descent, + &overall); + } + if (lbearing) + *lbearing = overall.lbearing; + if (rbearing) + *rbearing = overall.rbearing; + if (width) + *width = overall.width; + if (ascent) + *ascent = overall.ascent; + if (descent) + *descent = overall.descent; + break; + case GDK_FONT_FONTSET: + fontset = (XFontSet) private->xfont; + XmbTextExtents (fontset, text, text_length, &ink, &logical); + if (lbearing) + *lbearing = -ink.x; + if (rbearing) + *rbearing = ink.y; + if (width) + *width = logical.width; + if (ascent) + *ascent = ink.height; + if (descent) + *descent = -ink.y; + break; + } + +} + +void +gdk_string_extents (GdkFont *font, + const gchar *string, + gint *lbearing, + gint *rbearing, + gint *width, + gint *ascent, + gint *descent) +{ + g_return_if_fail (font != NULL); + g_return_if_fail (string != NULL); + + gdk_text_extents (font, string, strlen (string), + lbearing, rbearing, width, ascent, descent); +} + + gint gdk_text_measure (GdkFont *font, const gchar *text, diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 0828c1acbf..f61ae5d56e 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -84,6 +84,7 @@ libgtk_1_1_la_SOURCES = \ gtkstyle.c \ gtkstatusbar.c \ gtktable.c \ + gtktearoffmenuitem.c \ gtktext.c \ gtktipsquery.c \ gtktogglebutton.c \ @@ -190,6 +191,7 @@ gtkinclude_HEADERS = \ gtkstyle.h \ gtkstatusbar.h \ gtktable.h \ + gtktearoffmenuitem.h \ gtktext.h \ gtktipsquery.h \ gtktogglebutton.h \ diff --git a/gtk/gtk.defs b/gtk/gtk.defs index 181a95047d..024fcf5d0f 100644 --- a/gtk/gtk.defs +++ b/gtk/gtk.defs @@ -91,6 +91,12 @@ (exact GTK_MATCH_EXACT) (last GTK_MATCH_LAST)) +(define-enum GtkMenuDirectionType + (parent GTK_MENU_DIR_PARENT) + (child GTK_MENU_DIR_CHILD) + (next GTK_MENU_DIR_NEXT) + (prev GTK_MENU_DIR_PREV)) + (define-enum GtkMenuFactoryType (menu GTK_MENU_FACTORY_MENU) (menu-bar GTK_MENU_FACTORY_MENU_BAR) @@ -101,6 +101,7 @@ #include <gtk/gtkstyle.h> #include <gtk/gtkstatusbar.h> #include <gtk/gtktable.h> +#include <gtk/gtktearoffmenuitem.h> #include <gtk/gtktext.h> #include <gtk/gtktipsquery.h> #include <gtk/gtktogglebutton.h> diff --git a/gtk/gtkcheckmenuitem.c b/gtk/gtkcheckmenuitem.c index 62ff1644d8..c21050c269 100644 --- a/gtk/gtkcheckmenuitem.c +++ b/gtk/gtkcheckmenuitem.c @@ -151,6 +151,8 @@ gtk_check_menu_item_class_init (GtkCheckMenuItemClass *klass) menu_item_class->activate = gtk_check_menu_item_activate; menu_item_class->toggle_size = 12; + menu_item_class->hide_on_activate = FALSE; + klass->toggled = NULL; klass->draw_indicator = gtk_real_check_menu_item_draw_indicator; } diff --git a/gtk/gtkenums.h b/gtk/gtkenums.h index 86504ea756..bddc81bbe1 100644 --- a/gtk/gtkenums.h +++ b/gtk/gtkenums.h @@ -107,6 +107,15 @@ typedef enum GTK_MATCH_LAST } GtkMatchType; +/* Menu keyboard movement types */ +typedef enum +{ + GTK_MENU_DIR_PARENT, + GTK_MENU_DIR_CHILD, + GTK_MENU_DIR_NEXT, + GTK_MENU_DIR_PREV +} GtkMenuDirectionType; + typedef enum { GTK_MENU_FACTORY_MENU, diff --git a/gtk/gtkitem.c b/gtk/gtkitem.c index 869bc574f8..a4a6f6a7bd 100644 --- a/gtk/gtkitem.c +++ b/gtk/gtkitem.c @@ -190,7 +190,8 @@ gtk_item_realize (GtkWidget *widget) GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | - GDK_LEAVE_NOTIFY_MASK); + GDK_LEAVE_NOTIFY_MASK | + GDK_POINTER_MOTION_MASK); attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); diff --git a/gtk/gtkitemfactory.c b/gtk/gtkitemfactory.c index 0a624f0605..dd605d2344 100644 --- a/gtk/gtkitemfactory.c +++ b/gtk/gtkitemfactory.c @@ -27,8 +27,10 @@ #include "gtk/gtkmenuitem.h" #include "gtk/gtkradiomenuitem.h" #include "gtk/gtkcheckmenuitem.h" +#include "gtk/gtktearoffmenuitem.h" #include "gtk/gtkaccellabel.h" #include "gdk/gdkprivate.h" /* for gdk_progname */ +#include "gdk/gdkkeysyms.h" #include <string.h> #include <sys/stat.h> #include <fcntl.h> @@ -98,6 +100,8 @@ static const gchar *key_type_check_item = "<CheckItem>"; static GQuark quark_type_check_item = 0; static const gchar *key_type_toggle_item = "<ToggleItem>"; static GQuark quark_type_toggle_item = 0; +static const gchar *key_type_tearoff_item = "<Tearoff>"; +static GQuark quark_type_tearoff_item = 0; static const gchar *key_type_separator_item = "<Separator>"; static GQuark quark_type_separator_item = 0; static const gchar *key_type_branch = "<Branch>"; @@ -210,6 +214,7 @@ gtk_item_factory_class_init (GtkItemFactoryClass *class) quark_type_radio_item = g_quark_from_static_string (key_type_radio_item); quark_type_check_item = g_quark_from_static_string (key_type_check_item); quark_type_toggle_item = g_quark_from_static_string (key_type_toggle_item); + quark_type_tearoff_item = g_quark_from_static_string (key_type_tearoff_item); quark_type_separator_item = g_quark_from_static_string (key_type_separator_item); quark_type_branch = g_quark_from_static_string (key_type_branch); quark_type_last_branch = g_quark_from_static_string (key_type_last_branch); @@ -547,6 +552,7 @@ gtk_item_factory_construct (GtkItemFactory *ifactory, const gchar *path, GtkAccelGroup *accel_group) { + GtkAccelGroup *menu_group; guint len; g_return_if_fail (ifactory != NULL); @@ -579,6 +585,10 @@ gtk_item_factory_construct (GtkItemFactory *ifactory, NULL); gtk_object_ref (GTK_OBJECT (ifactory)); gtk_object_sink (GTK_OBJECT (ifactory)); + + menu_group = gtk_accel_group_new (); + gtk_accel_group_attach (menu_group, GTK_OBJECT (ifactory->widget)); + /* gtk_signal_connect_object_while_alive (GTK_OBJECT (ifactory->widget), "destroy", @@ -880,6 +890,44 @@ gtk_item_factory_get_widget_by_action (GtkItemFactory *ifactory, return NULL; } +static gboolean +gtk_item_factory_parse_path (gchar *str, + gchar **path, + gchar **parent_path, + gchar **item) +{ + gchar *p, *q; + + *path = g_strdup (str); + + p = q = *path; + while (*p) + { + if (*p != '_') + { + *q++ = *p; + } + p++; + } + *q = 0; + + *parent_path = g_strdup (*path); + p = strrchr (*parent_path, '/'); + if (!p) + { + g_warning ("GtkItemFactory: invalid entry path `%s'", str); + return FALSE; + } + *p = 0; + + p = strrchr (str, '/'); + p++; + + *item = g_strdup (p); + + return TRUE; +} + void gtk_item_factory_create_item (GtkItemFactory *ifactory, GtkItemFactoryEntry *entry, @@ -889,11 +937,15 @@ gtk_item_factory_create_item (GtkItemFactory *ifactory, GtkWidget *parent; GtkWidget *widget; GSList *radio_group; + gchar *name; gchar *parent_path; - gchar *p; + gchar *path; + guint accel_key; guint type_id; GtkType type; gchar *item_type_path; + GtkAccelGroup *parent_accel_group = NULL; + GSList *tmp_list; g_return_if_fail (ifactory != NULL); g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory)); @@ -923,6 +975,8 @@ gtk_item_factory_create_item (GtkItemFactory *ifactory, type = GTK_TYPE_RADIO_MENU_ITEM; else if (type_id == quark_type_check_item) type = GTK_TYPE_CHECK_MENU_ITEM; + else if (type_id == quark_type_tearoff_item) + type = GTK_TYPE_TEAROFF_MENU_ITEM; else if (type_id == quark_type_toggle_item) type = GTK_TYPE_CHECK_MENU_ITEM; else if (type_id == quark_type_separator_item) @@ -949,16 +1003,11 @@ gtk_item_factory_create_item (GtkItemFactory *ifactory, return; } } - - parent_path = g_strdup (entry->path); - p = strrchr (parent_path, '/'); - if (!p) - { - g_warning ("GtkItemFactory: invalid entry path `%s'", entry->path); - return; - } - *p = 0; + if (!gtk_item_factory_parse_path (entry->path, + &path, &parent_path, &name)) + return; + parent = gtk_item_factory_get_widget (ifactory, parent_path); if (!parent) { @@ -977,9 +1026,10 @@ gtk_item_factory_create_item (GtkItemFactory *ifactory, g_free (parent_path); g_return_if_fail (parent != NULL); - - p = strrchr (entry->path, '/'); - p++; + + tmp_list = gtk_accel_groups_from_object (GTK_OBJECT (parent)); + if (tmp_list) + parent_accel_group = tmp_list->data; widget = gtk_widget_new (type, "GtkWidget::visible", TRUE, @@ -993,22 +1043,50 @@ gtk_item_factory_create_item (GtkItemFactory *ifactory, if (GTK_IS_CHECK_MENU_ITEM (widget)) gtk_check_menu_item_set_show_toggle (GTK_CHECK_MENU_ITEM (widget), TRUE); - if (type_id != quark_type_separator_item && *p) + if ((type_id != quark_type_separator_item) && + (type_id != quark_type_tearoff_item) && + *name) { GtkWidget *label; - + label = gtk_widget_new (GTK_TYPE_ACCEL_LABEL, - "GtkLabel::label", p, "GtkWidget::visible", TRUE, "GtkWidget::parent", widget, "GtkAccelLabel::accel_widget", widget, "GtkMisc::xalign", 0.0, NULL); + + accel_key = gtk_label_parse_uline (GTK_LABEL (label), name); + + if ((accel_key != GDK_VoidSymbol) && GTK_IS_MENU_BAR (parent)) + { + gtk_widget_add_accelerator (widget, + "activate_item", + ifactory->accel_group, + accel_key, GDK_MOD1_MASK, + GTK_ACCEL_LOCKED); + } + + if ((accel_key != GDK_VoidSymbol) && parent_accel_group) + { + gtk_widget_add_accelerator (widget, + "activate_item", + parent_accel_group, + accel_key, 0, + GTK_ACCEL_LOCKED); + } } + + g_free (name); + if (type_id == quark_type_branch || type_id == quark_type_last_branch) { + GtkAccelGroup *menu_group; + + menu_group = gtk_accel_group_new (); + if (type_id == quark_type_last_branch) gtk_menu_item_right_justify (GTK_MENU_ITEM (widget)); @@ -1016,11 +1094,13 @@ gtk_item_factory_create_item (GtkItemFactory *ifactory, widget = gtk_widget_new (GTK_TYPE_MENU, NULL); + + gtk_accel_group_attach (menu_group, GTK_OBJECT (widget)); gtk_menu_item_set_submenu (GTK_MENU_ITEM (parent), widget); } gtk_item_factory_add_item (ifactory, - entry->path, entry->accelerator, + path, entry->accelerator, entry->callback, entry->callback_action, callback_data, callback_type, item_type_path, diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c index e96db1b3a6..9606ef549d 100644 --- a/gtk/gtklabel.c +++ b/gtk/gtklabel.c @@ -18,14 +18,26 @@ */ #include <string.h> #include "gtklabel.h" - +#include "gdk/gdkkeysyms.h" enum { ARG_0, ARG_LABEL, + ARG_PATTERN, ARG_JUSTIFY }; +typedef struct _GtkLabelRow GtkLabelRow; + +struct _GtkLabelRow { + gint index; + gint width; + gint height; + gint len; +}; + +GMemChunk *row_mem_chunk = NULL; + static void gtk_label_class_init (GtkLabelClass *klass); static void gtk_label_init (GtkLabel *label); static void gtk_label_set_arg (GtkObject *object, @@ -43,6 +55,7 @@ static void gtk_label_state_changed (GtkWidget *widget, guint previous_state); static void gtk_label_style_set (GtkWidget *widget, GtkStyle *previous_style); +static void gtk_label_free_rows (GtkLabel *label); @@ -87,6 +100,7 @@ gtk_label_class_init (GtkLabelClass *class) parent_class = gtk_type_class (gtk_misc_get_type ()); gtk_object_add_arg_type ("GtkLabel::label", GTK_TYPE_STRING, GTK_ARG_READWRITE, ARG_LABEL); + gtk_object_add_arg_type ("GtkLabel::pattern", GTK_TYPE_STRING, GTK_ARG_READWRITE, ARG_PATTERN); gtk_object_add_arg_type ("GtkLabel::justify", GTK_TYPE_JUSTIFICATION, GTK_ARG_READWRITE, ARG_JUSTIFY); object_class->set_arg = gtk_label_set_arg; @@ -113,6 +127,9 @@ gtk_label_set_arg (GtkObject *object, case ARG_LABEL: gtk_label_set (label, GTK_VALUE_STRING (*arg) ? GTK_VALUE_STRING (*arg) : ""); break; + case ARG_PATTERN: + gtk_label_set_pattern (label, GTK_VALUE_STRING (*arg)); + break; case ARG_JUSTIFY: gtk_label_set_justify (label, GTK_VALUE_ENUM (*arg)); break; @@ -135,6 +152,9 @@ gtk_label_get_arg (GtkObject *object, case ARG_LABEL: GTK_VALUE_STRING (*arg) = g_strdup (label->label); break; + case ARG_PATTERN: + GTK_VALUE_STRING (*arg) = g_strdup (label->pattern); + break; case ARG_JUSTIFY: GTK_VALUE_ENUM (*arg) = label->jtype; break; @@ -154,6 +174,7 @@ gtk_label_init (GtkLabel *label) label->max_width = 0; label->jtype = GTK_JUSTIFY_CENTER; label->needs_clear = FALSE; + label->pattern = NULL; gtk_label_set (label, ""); } @@ -181,18 +202,57 @@ gtk_label_set (GtkLabel *label, g_return_if_fail (label != NULL); g_return_if_fail (GTK_IS_LABEL (label)); g_return_if_fail (str != NULL); + + if (!row_mem_chunk) + row_mem_chunk = g_mem_chunk_create (GtkLabelRow, 64, G_ALLOC_AND_FREE); if (label->label) g_free (label->label); label->label = g_strdup (str); if (label->row) - g_slist_free (label->row); - label->row = NULL; - label->row = g_slist_append (label->row, label->label); + gtk_label_free_rows (label); + p = label->label; - while ((p = strchr(p, '\n'))) - label->row = g_slist_append (label->row, ++p); + do { + GtkLabelRow *row = g_chunk_new (GtkLabelRow, row_mem_chunk); + label->row = g_slist_append (label->row, row); + + row->index = p - label->label; + + p = strchr(p, '\n'); + if (p) + { + p++; + row->len = (p - label->label) - row->index; + } + else + row->len = strlen (label->label) - row->index; + } while (p); + + if (GTK_WIDGET_VISIBLE (label)) + { + if (GTK_WIDGET_MAPPED (label)) + gdk_window_clear_area (GTK_WIDGET (label)->window, + GTK_WIDGET (label)->allocation.x, + GTK_WIDGET (label)->allocation.y, + GTK_WIDGET (label)->allocation.width, + GTK_WIDGET (label)->allocation.height); + + gtk_widget_queue_resize (GTK_WIDGET (label)); + } +} + +void +gtk_label_set_pattern (GtkLabel *label, + const gchar *pattern) +{ + g_return_if_fail (label != NULL); + g_return_if_fail (GTK_IS_LABEL (label)); + + if (label->pattern) + g_free (label->pattern); + label->pattern = g_strdup (pattern); if (GTK_WIDGET_VISIBLE (label)) { @@ -255,17 +315,128 @@ gtk_label_finalize (GtkObject *object) label = GTK_LABEL (object); g_free (label->label); - g_slist_free (label->row); + gtk_label_free_rows (label); (* GTK_OBJECT_CLASS (parent_class)->finalize) (object); } +static gint +gtk_label_process_row (GtkLabel *label, + GtkLabelRow *row, + gint x, gint y, + gboolean draw) +{ + GtkWidget *widget = GTK_WIDGET (label); + + char lastc; + gint i, j; + gint offset; + gint height; + gint pattern_length; + + if (label->pattern) + pattern_length = strlen (label->pattern); + else + pattern_length = 0; + + offset = 0; + height = widget->style->font->ascent + widget->style->font->descent; + + if (draw) + { + if (label->jtype == GTK_JUSTIFY_CENTER) + offset = (label->max_width - row->width) / 2; + else if (label->jtype == GTK_JUSTIFY_RIGHT) + offset = (label->max_width - row->width); + } + + if (label->pattern && (row->index < pattern_length)) + lastc = label->pattern[0]; + else + lastc = ' '; + + j = 0; + for (i=1; i<=row->len; i++) + { + char c; + + if (label->pattern && (row->index + i < pattern_length)) + c = label->pattern[row->index+i]; + else + c = ' '; + + if ((i == row->len) || (lastc != c)) + { + gint width = 0; + + if (lastc == '_') + { + gint descent; + gint rbearing; + gint lbearing; + + gdk_text_extents (widget->style->font, + &label->label[row->index+j], i - j, + &lbearing, &rbearing, &width, NULL, &descent); + + if (draw) + { + if (widget->state == GTK_STATE_INSENSITIVE) + gdk_draw_line (widget->window, + widget->style->white_gc, + offset + x + lbearing, y + descent + 2, + offset + x + rbearing + 1, y + descent + 2); + + gdk_draw_line (widget->window, + widget->style->fg_gc[widget->state], + offset + x + lbearing - 1, y + descent + 1, + offset + x + rbearing, y + descent + 1); + } + + height = MAX (height, + widget->style->font->ascent + descent + 2); + } + else if (i != row->len) + { + width = gdk_text_width (widget->style->font, + &label->label[row->index+j], + i - j); + } + + if (draw) + { + if (widget->state == GTK_STATE_INSENSITIVE) + gdk_draw_text (widget->window, widget->style->font, + widget->style->white_gc, + offset + x + 1, y + 1, + &label->label[row->index+j], i - j); + + gdk_draw_text (widget->window, widget->style->font, + widget->style->fg_gc[widget->state], + offset + x, y, + &label->label[row->index+j], i - j); + } + + + offset += width; + + if (i != row->len) + { + lastc = c; + j = i; + } + } + } + + return height; +} + static void gtk_label_size_request (GtkWidget *widget, GtkRequisition *requisition) { GtkLabel *label; - GSList *row; + GSList *tmp_list; gint width; g_return_if_fail (widget != NULL); @@ -274,38 +445,35 @@ gtk_label_size_request (GtkWidget *widget, label = GTK_LABEL (widget); - row = label->row; + requisition->height = label->misc.ypad * 2; + + tmp_list = label->row; width = 0; - while (row) + while (tmp_list) { - if (row->next) - width = MAX (width, - gdk_text_width (GTK_WIDGET (label)->style->font, - row->data, - (gchar*) row->next->data - (gchar*) row->data - 1)); - else - width = MAX (width, gdk_string_width (GTK_WIDGET (label)->style->font, row->data)); - row = row->next; + GtkLabelRow *row = tmp_list->data; + + row->width = gdk_text_width (GTK_WIDGET (label)->style->font, + &label->label [row->index], + row->len); + width = MAX (width, row->width); + + requisition->height += gtk_label_process_row (label, row, 0, 0, FALSE) + 2; + + tmp_list = tmp_list->next; } label->max_width = width; requisition->width = width + label->misc.xpad * 2; - requisition->height = ((GTK_WIDGET (label)->style->font->ascent + - GTK_WIDGET (label)->style->font->descent + 2) * - g_slist_length(label->row) + - label->misc.ypad * 2); } - + static gint gtk_label_expose (GtkWidget *widget, GdkEventExpose *event) { GtkLabel *label; GtkMisc *misc; - GSList *row; - gint state; - gint offset; - gint len; + GSList *tmp_list; gint x, y; g_return_val_if_fail (widget != NULL, FALSE); @@ -317,13 +485,11 @@ gtk_label_expose (GtkWidget *widget, label = GTK_LABEL (widget); misc = GTK_MISC (widget); - state = widget->state; - /* * GC Clipping */ gdk_gc_set_clip_rectangle (widget->style->white_gc, &event->area); - gdk_gc_set_clip_rectangle (widget->style->fg_gc[state], &event->area); + gdk_gc_set_clip_rectangle (widget->style->fg_gc[widget->state], &event->area); /* We clear the whole allocation here so that if a partial * expose is triggered we don't just clear part and mess up @@ -351,59 +517,41 @@ gtk_label_expose (GtkWidget *widget, (widget->requisition.height - misc->ypad * 2)) * misc->yalign + widget->style->font->ascent) + 1.5; - row = label->row; - while (row && row->next) - { - len = (gchar*) row->next->data - (gchar*) row->data - 1; - offset = 0; - - if (label->jtype == GTK_JUSTIFY_CENTER) - offset = (label->max_width - gdk_text_width (widget->style->font, row->data, len)) / 2; - - else if (label->jtype == GTK_JUSTIFY_RIGHT) - offset = (label->max_width - gdk_text_width (widget->style->font, row->data, len)); - - if (state == GTK_STATE_INSENSITIVE) - gdk_draw_text (widget->window, widget->style->font, - widget->style->white_gc, - offset + x + 1, y + 1, row->data, len); - - gdk_draw_text (widget->window, widget->style->font, - widget->style->fg_gc[state], - offset + x, y, row->data, len); - row = row->next; - y += widget->style->font->ascent + widget->style->font->descent + 2; - } - /* * COMMENT: we can avoid gdk_text_width() calls here storing in label->row * the widths of the rows calculated in gtk_label_set. * Once we have a wrapping interface we can support GTK_JUSTIFY_FILL. */ - offset = 0; - - if (label->jtype == GTK_JUSTIFY_CENTER) - offset = (label->max_width - gdk_string_width (widget->style->font, row->data)) / 2; - - else if (label->jtype == GTK_JUSTIFY_RIGHT) - offset = (label->max_width - gdk_string_width (widget->style->font, row->data)); - - if (state == GTK_STATE_INSENSITIVE) - gdk_draw_string (widget->window, widget->style->font, - widget->style->white_gc, - offset + x + 1, y + 1, row->data); - - gdk_draw_string (widget->window, widget->style->font, - widget->style->fg_gc[state], - offset + x, y, row->data); + + tmp_list = label->row; + while (tmp_list) + { + y += gtk_label_process_row (label, tmp_list->data, x, y, TRUE) + 2; + tmp_list = tmp_list->next; + } gdk_gc_set_clip_mask (widget->style->white_gc, NULL); - gdk_gc_set_clip_mask (widget->style->fg_gc[state], NULL); + gdk_gc_set_clip_mask (widget->style->fg_gc[widget->state], NULL); } return TRUE; } +static void +gtk_label_free_rows (GtkLabel *label) +{ + GSList *tmp_list; + + tmp_list = label->row; + while (tmp_list) + { + g_mem_chunk_free (row_mem_chunk, tmp_list->data); + tmp_list = tmp_list->next; + } + g_slist_free (label->row); + label->row = NULL; +} + static void gtk_label_state_changed (GtkWidget *widget, guint previous_state) @@ -420,3 +568,67 @@ gtk_label_style_set (GtkWidget *widget, GTK_LABEL (widget)->needs_clear = TRUE; } +guint +gtk_label_parse_uline (GtkLabel *label, + const gchar *string) +{ + guint accel_key = GDK_VoidSymbol; + const gchar *p; + gchar *q, *r; + gchar *name, *pattern; + + gint length; + gboolean underscore; + + length = strlen (string); + + name = g_new (gchar, length+1); + pattern = g_new (gchar, length+1); + + underscore = FALSE; + + p = string; + q = name; + r = pattern; + underscore = FALSE; + + while (*p) + { + if (underscore) + { + if (*p == '_') + *r++ = ' '; + else + { + *r++ = '_'; + if (accel_key == GDK_VoidSymbol) + accel_key = gdk_keyval_to_lower (*p); + } + + *q++ = *p; + underscore = FALSE; + } + else + { + if (*p == '_') + underscore = TRUE; + else + { + *q++ = *p; + *r++ = ' '; + } + } + p++; + } + *q = 0; + + gtk_label_set (label, name); + gtk_label_set_pattern (label, pattern); + + g_free (name); + g_free (pattern); + + return accel_key; +} + + diff --git a/gtk/gtklabel.h b/gtk/gtklabel.h index 331b2a788f..17275dae9d 100644 --- a/gtk/gtklabel.h +++ b/gtk/gtklabel.h @@ -44,6 +44,8 @@ struct _GtkLabel GtkMisc misc; gchar *label; + gchar *pattern; + GSList *row; guint max_width : 16; guint jtype : 2; @@ -60,12 +62,22 @@ GtkType gtk_label_get_type (void); GtkWidget* gtk_label_new (const gchar *string); void gtk_label_set (GtkLabel *label, const gchar *string); +void gtk_label_set_pattern (GtkLabel *label, + const gchar *pattern); void gtk_label_set_justify (GtkLabel *label, GtkJustification jtype); void gtk_label_get (GtkLabel *label, gchar **string); +/* Convenience function to set the name and pattern by parsing + * a string with embedded underscores, and return the appropriate + * key symbol for the accelerator. + */ + +guint gtk_label_parse_uline (GtkLabel *label, + const gchar *string); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/gtk/gtkmenu.c b/gtk/gtkmenu.c index d3cb999e12..9025e071c3 100644 --- a/gtk/gtkmenu.c +++ b/gtk/gtkmenu.c @@ -18,10 +18,13 @@ */ #include <ctype.h> #include "gdk/gdkkeysyms.h" +#include "gtkbindings.h" +#include "gtklabel.h" #include "gtkmain.h" #include "gtkmenu.h" #include "gtkmenuitem.h" #include "gtksignal.h" +#include "gtkwindow.h" #define MENU_ITEM_CLASS(w) GTK_MENU_ITEM_CLASS (GTK_OBJECT (w)->klass) @@ -39,9 +42,6 @@ struct _GtkMenuAttachData static void gtk_menu_class_init (GtkMenuClass *klass); static void gtk_menu_init (GtkMenu *menu); static void gtk_menu_destroy (GtkObject *object); -static void gtk_menu_show (GtkWidget *widget); -static void gtk_menu_map (GtkWidget *widget); -static void gtk_menu_unmap (GtkWidget *widget); static void gtk_menu_realize (GtkWidget *widget); static void gtk_menu_size_request (GtkWidget *widget, GtkRequisition *requisition); @@ -52,14 +52,14 @@ static void gtk_menu_draw (GtkWidget *widget, GdkRectangle *area); static gint gtk_menu_expose (GtkWidget *widget, GdkEventExpose *event); -static gint gtk_menu_configure (GtkWidget *widget, - GdkEventConfigure *event); static gint gtk_menu_key_press (GtkWidget *widget, GdkEventKey *event); -static void gtk_menu_check_resize (GtkContainer *container); +static gint gtk_menu_motion_notify (GtkWidget *widget, + GdkEventMotion *event); static void gtk_menu_deactivate (GtkMenuShell *menu_shell); static void gtk_menu_show_all (GtkWidget *widget); static void gtk_menu_hide_all (GtkWidget *widget); +static void gtk_menu_position (GtkMenu *menu); static GtkMenuShellClass *parent_class = NULL; static const gchar *attach_data_key = "gtk-menu-attach-data"; @@ -97,6 +97,8 @@ gtk_menu_class_init (GtkMenuClass *class) GtkWidgetClass *widget_class; GtkContainerClass *container_class; GtkMenuShellClass *menu_shell_class; + + GtkBindingSet *binding_set; object_class = (GtkObjectClass*) class; widget_class = (GtkWidgetClass*) class; @@ -106,57 +108,89 @@ gtk_menu_class_init (GtkMenuClass *class) object_class->destroy = gtk_menu_destroy; - widget_class->show = gtk_menu_show; - widget_class->map = gtk_menu_map; - widget_class->unmap = gtk_menu_unmap; widget_class->realize = gtk_menu_realize; widget_class->draw = gtk_menu_draw; widget_class->size_request = gtk_menu_size_request; widget_class->size_allocate = gtk_menu_size_allocate; widget_class->expose_event = gtk_menu_expose; - widget_class->configure_event = gtk_menu_configure; widget_class->key_press_event = gtk_menu_key_press; + widget_class->motion_notify_event = gtk_menu_motion_notify; widget_class->show_all = gtk_menu_show_all; widget_class->hide_all = gtk_menu_hide_all; - container_class->check_resize = gtk_menu_check_resize; - menu_shell_class->submenu_placement = GTK_LEFT_RIGHT; menu_shell_class->deactivate = gtk_menu_deactivate; + + binding_set = gtk_binding_set_by_class (class); + gtk_binding_entry_add_signal (binding_set, + GDK_Up, 0, + "move_current", 1, + GTK_TYPE_MENU_DIRECTION_TYPE, + GTK_MENU_DIR_PREV); + gtk_binding_entry_add_signal (binding_set, + GDK_Down, 0, + "move_current", 1, + GTK_TYPE_MENU_DIRECTION_TYPE, + GTK_MENU_DIR_NEXT); + gtk_binding_entry_add_signal (binding_set, + GDK_Left, 0, + "move_current", 1, + GTK_TYPE_MENU_DIRECTION_TYPE, + GTK_MENU_DIR_PARENT); + gtk_binding_entry_add_signal (binding_set, + GDK_Right, 0, + "move_current", 1, + GTK_TYPE_MENU_DIRECTION_TYPE, + GTK_MENU_DIR_CHILD); } static void gtk_menu_init (GtkMenu *menu) { - GTK_WIDGET_SET_FLAGS (menu, GTK_TOPLEVEL); - - gtk_container_set_resize_mode (GTK_CONTAINER (menu), GTK_RESIZE_QUEUE); - menu->parent_menu_item = NULL; menu->old_active_menu_item = NULL; menu->accel_group = NULL; menu->position_func = NULL; menu->position_func_data = NULL; + menu->toplevel = gtk_window_new (GTK_WINDOW_POPUP); + gtk_signal_connect_object (GTK_OBJECT (menu->toplevel), "key_press_event", + GTK_SIGNAL_FUNC (gtk_menu_key_press), + GTK_OBJECT (menu)); + gtk_window_set_policy (GTK_WINDOW (menu->toplevel), + FALSE, FALSE, TRUE); + + gtk_container_add (GTK_CONTAINER (menu->toplevel), GTK_WIDGET (menu)); + + menu->tearoff_window = NULL; + menu->torn_off = FALSE; + MENU_NEEDS_RESIZE (menu) = TRUE; } static void gtk_menu_destroy (GtkObject *object) { + GtkMenu *menu; GtkMenuAttachData *data; g_return_if_fail (object != NULL); g_return_if_fail (GTK_IS_MENU (object)); + + menu = GTK_MENU (object); gtk_widget_ref (GTK_WIDGET (object)); data = gtk_object_get_data (object, attach_data_key); if (data) - gtk_menu_detach (GTK_MENU (object)); + gtk_menu_detach (menu); - gtk_menu_set_accel_group (GTK_MENU (object), NULL); + gtk_menu_set_accel_group (menu, NULL); + gtk_widget_destroy (menu->toplevel); + if (menu->tearoff_window) + gtk_widget_destroy (menu->tearoff_window); + if (GTK_OBJECT_CLASS (parent_class)->destroy) (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); @@ -283,22 +317,75 @@ gtk_menu_popup (GtkMenu *menu, guint button, guint32 activate_time) { + GtkWidget *widget; GtkWidget *xgrab_shell; GtkWidget *parent; + GdkEvent *current_event; + GtkMenuShell *menu_shell; g_return_if_fail (menu != NULL); g_return_if_fail (GTK_IS_MENU (menu)); - GTK_MENU_SHELL (menu)->parent_menu_shell = parent_menu_shell; - GTK_MENU_SHELL (menu)->active = TRUE; - GTK_MENU_SHELL (menu)->button = button; + widget = GTK_WIDGET (menu); + menu_shell = GTK_MENU_SHELL (menu); + + menu_shell->parent_menu_shell = parent_menu_shell; + menu_shell->active = TRUE; + menu_shell->button = button; + + /* If we are popping up the menu from something other than, a button + * press then, as a heuristic, we ignore enter events for the menu + * until we get a MOTION_NOTIFY. + */ + + current_event = gtk_get_current_event(); + if (current_event) + { + if ((current_event->type != GDK_BUTTON_PRESS) && + (current_event->type != GDK_ENTER_NOTIFY)) + menu_shell->ignore_enter = TRUE; + } + + if (menu->torn_off) + { + GdkPixmap *pixmap; + GdkGC *gc; + GdkGCValues gc_values; + + gc_values.subwindow_mode = GDK_INCLUDE_INFERIORS; + gc = gdk_gc_new_with_values (widget->window, + &gc_values, GDK_GC_SUBWINDOW); + + pixmap = gdk_pixmap_new (widget->window, + widget->requisition.width, + widget->requisition.height, + -1); + + gdk_draw_pixmap (pixmap, gc, + widget->window, + 0, 0, 0, 0, -1, -1); + gdk_gc_unref(gc); + + gdk_window_set_back_pixmap (menu->tearoff_window->window, pixmap, FALSE); + gdk_pixmap_unref (pixmap); + + gtk_container_remove (GTK_CONTAINER (menu->tearoff_window), widget); + gtk_container_add (GTK_CONTAINER (menu->toplevel), widget); + } menu->parent_menu_item = parent_menu_item; menu->position_func = func; menu->position_func_data = data; - GTK_MENU_SHELL (menu)->activate_time = activate_time; - + menu_shell->activate_time = activate_time; + + gtk_menu_position (menu); + + /* We need to show the menu _here_ because code expects to be + * able to tell if the menu is onscreen by looking at the + * GTK_WIDGET_VISIBLE (menu) + */ gtk_widget_show (GTK_WIDGET (menu)); + gtk_widget_show (menu->toplevel); /* Find the last viewable ancestor, and make an X grab on it */ @@ -328,12 +415,22 @@ gtk_menu_popup (GtkMenu *menu, if (xgrab_shell && (!GTK_MENU_SHELL (xgrab_shell)->have_xgrab)) { GdkCursor *cursor = gdk_cursor_new (GDK_ARROW); - - GTK_MENU_SHELL (xgrab_shell)->have_xgrab = - (gdk_pointer_grab (xgrab_shell->window, TRUE, - GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | - GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK, - NULL, cursor, activate_time) == 0); + + if ((gdk_pointer_grab (xgrab_shell->window, TRUE, + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | + GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | + GDK_POINTER_MOTION_MASK, + NULL, cursor, activate_time) == 0)) + { + if (gdk_keyboard_grab (xgrab_shell->window, TRUE, + activate_time) == 0) + GTK_MENU_SHELL (xgrab_shell)->have_xgrab = TRUE; + else + { + gdk_pointer_ungrab (activate_time); + } + } + gdk_cursor_destroy (cursor); } @@ -352,6 +449,7 @@ gtk_menu_popdown (GtkMenu *menu) menu_shell->parent_menu_shell = NULL; menu_shell->active = FALSE; + menu_shell->ignore_enter = FALSE; if (menu_shell->active_menu_item) { @@ -362,9 +460,26 @@ gtk_menu_popdown (GtkMenu *menu) /* The X Grab, if present, will automatically be removed when we hide * the window */ - gtk_widget_hide (GTK_WIDGET (menu)); + gtk_widget_hide (menu->toplevel); + + if (menu->torn_off) + { + if (GTK_BIN (menu->toplevel)->child) + gtk_widget_reparent (GTK_WIDGET (menu), menu->tearoff_window); + else + /* We popped up the menu from the tearoff, so we need to + * release the grab - we aren't actually hiding the menu. + */ + if (menu_shell->have_xgrab) + { + gdk_pointer_ungrab (GDK_CURRENT_TIME); + gdk_keyboard_ungrab (GDK_CURRENT_TIME); + } + } + else + gtk_widget_hide (GTK_WIDGET (menu)); + menu_shell->have_xgrab = FALSE; - gtk_grab_remove (GTK_WIDGET (menu)); } @@ -435,99 +550,77 @@ gtk_menu_set_accel_group (GtkMenu *menu, } -static void -gtk_menu_show (GtkWidget *widget) -{ - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_MENU (widget)); - - GTK_WIDGET_SET_FLAGS (widget, GTK_VISIBLE); - if (MENU_NEEDS_RESIZE (widget)) - gtk_container_check_resize (GTK_CONTAINER (widget)); - gtk_widget_map (widget); -} - void gtk_menu_reposition (GtkMenu *menu) { - GtkWidget *widget; - g_return_if_fail (menu != NULL); g_return_if_fail (GTK_IS_MENU (menu)); - widget = GTK_WIDGET (menu); - - if (GTK_WIDGET_DRAWABLE (menu)) - { - gint x, y; - - gdk_window_get_pointer (NULL, &x, &y, NULL); - - if (menu->position_func) - (* menu->position_func) (menu, &x, &y, menu->position_func_data); - else - { - gint screen_width; - gint screen_height; - - screen_width = gdk_screen_width (); - screen_height = gdk_screen_height (); - - x -= 2; - y -= 2; - - if ((x + widget->requisition.width) > screen_width) - x -= ((x + widget->requisition.width) - screen_width); - if (x < 0) - x = 0; - if ((y + widget->requisition.height) > screen_height) - y -= ((y + widget->requisition.height) - screen_height); - if (y < 0) - y = 0; - } - - gdk_window_move (widget->window, x, y); - } + if (GTK_WIDGET_DRAWABLE (menu) && !menu->torn_off) + gtk_menu_position (menu); } -static void -gtk_menu_map (GtkWidget *widget) + +void +gtk_menu_set_tearoff_state (GtkMenu *menu, + gboolean torn_off) { - GtkMenu *menu; - GtkMenuShell *menu_shell; - GtkWidget *child; - GList *children; - - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_MENU (widget)); - - menu = GTK_MENU (widget); - menu_shell = GTK_MENU_SHELL (widget); - GTK_WIDGET_SET_FLAGS (menu_shell, GTK_MAPPED); + g_return_if_fail (menu != NULL); + g_return_if_fail (GTK_IS_MENU (menu)); - gtk_menu_reposition (menu); - - children = menu_shell->children; - while (children) + if (menu->torn_off != torn_off) { - child = children->data; - children = children->next; + menu->torn_off = torn_off; - if (GTK_WIDGET_VISIBLE (child) && !GTK_WIDGET_MAPPED (child)) - gtk_widget_map (child); - } - - gdk_window_show (widget->window); -} + if (menu->torn_off) + { + if (GTK_WIDGET_VISIBLE (menu)) + gtk_menu_popdown (menu); -static void -gtk_menu_unmap (GtkWidget *widget) -{ - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_MENU (widget)); - - GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); - gdk_window_hide (widget->window); + if (!menu->tearoff_window) + { + GtkWidget *attach_widget; + + menu->tearoff_window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_signal_connect_object (GTK_OBJECT (menu->tearoff_window), + "key_press_event", + GTK_SIGNAL_FUNC (gtk_menu_key_press), + GTK_OBJECT (menu)); + gtk_widget_realize (menu->tearoff_window); + + attach_widget = gtk_menu_get_attach_widget (menu); + if (GTK_IS_MENU_ITEM (attach_widget)) + { + GtkWidget *child = GTK_BIN (attach_widget)->child; + if (GTK_IS_LABEL (child)) + { + gchar *ret; + gtk_label_get (GTK_LABEL (child), &ret); + gdk_window_set_title (menu->tearoff_window->window, ret); + } + } + + gdk_window_set_decorations (menu->tearoff_window->window, + GDK_DECOR_ALL | + GDK_DECOR_RESIZEH | + GDK_DECOR_MINIMIZE | + GDK_DECOR_MAXIMIZE); + gtk_window_set_policy (GTK_WINDOW (menu->tearoff_window), + FALSE, FALSE, TRUE); + } + gtk_widget_reparent (GTK_WIDGET (menu), menu->tearoff_window); + + gtk_menu_position (menu); + + gtk_widget_show (GTK_WIDGET (menu)); + gtk_widget_show (menu->tearoff_window); + } + else + { + gtk_widget_hide (menu->tearoff_window); + gtk_widget_reparent (GTK_WIDGET (menu), menu->toplevel); + } + } } static void @@ -541,6 +634,7 @@ gtk_menu_realize (GtkWidget *widget) GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + attributes.window_type = GDK_WINDOW_CHILD; attributes.x = widget->allocation.x; attributes.y = widget->allocation.y; attributes.width = widget->allocation.width; @@ -548,14 +642,11 @@ gtk_menu_realize (GtkWidget *widget) attributes.wclass = GDK_INPUT_OUTPUT; attributes.visual = gtk_widget_get_visual (widget); attributes.colormap = gtk_widget_get_colormap (widget); - attributes.window_type = GDK_WINDOW_TEMP; attributes.event_mask = gtk_widget_get_events (widget); - attributes.event_mask |= (GDK_EXPOSURE_MASK | - GDK_KEY_PRESS_MASK | - GDK_STRUCTURE_MASK); + attributes.event_mask |= (GDK_EXPOSURE_MASK | GDK_KEY_PRESS_MASK); attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; - widget->window = gdk_window_new (NULL, &attributes, attributes_mask); + widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); gdk_window_set_user_data (widget->window, widget); widget->style = gtk_style_attach (widget->style, widget->window); @@ -639,6 +730,11 @@ gtk_menu_size_allocate (GtkWidget *widget, menu_shell = GTK_MENU_SHELL (widget); widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + if (menu_shell->children) { @@ -665,13 +761,6 @@ gtk_menu_size_allocate (GtkWidget *widget, } } } - - if (GTK_WIDGET_REALIZED (widget)) - { - gdk_window_resize (widget->window, - widget->requisition.width, - widget->requisition.height); - } } static void @@ -759,55 +848,35 @@ gtk_menu_expose (GtkWidget *widget, } static gint -gtk_menu_configure (GtkWidget *widget, - GdkEventConfigure *event) +gtk_menu_key_press (GtkWidget *widget, + GdkEventKey *event) { - GtkAllocation allocation; + GtkMenuShell *menu_shell; + gboolean delete = FALSE; g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (GTK_IS_MENU (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); - - /* If the window was merely moved, do nothing */ - if ((widget->allocation.width == event->width) && - (widget->allocation.height == event->height)) - return FALSE; - - if (MENU_NEEDS_RESIZE (widget)) - { - MENU_NEEDS_RESIZE (widget) = FALSE; - allocation.x = 0; - allocation.y = 0; - allocation.width = event->width; - allocation.height = event->height; - - gtk_widget_size_allocate (widget, &allocation); + menu_shell = GTK_MENU_SHELL (widget); + + if (GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event)) + return TRUE; + + switch (event->keyval) + { + case GDK_Delete: + case GDK_KP_Delete: + case GDK_BackSpace: + delete = TRUE; + break; + default: + break; } - - return FALSE; -} -static gint -gtk_menu_key_press (GtkWidget *widget, - GdkEventKey *event) -{ - gboolean delete; - - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (GTK_IS_MENU (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - delete = (event->keyval == GDK_Delete || - event->keyval == GDK_KP_Delete || - event->keyval == GDK_BackSpace); - + /* Modify the accelerators */ if (delete || gtk_accelerator_valid (event->keyval, event->keyval)) { - GtkMenuShell *menu_shell; - - menu_shell = GTK_MENU_SHELL (widget); - if (menu_shell->active_menu_item && GTK_BIN (menu_shell->active_menu_item)->child && GTK_MENU_ITEM (menu_shell->active_menu_item)->submenu == NULL) @@ -861,32 +930,27 @@ gtk_menu_key_press (GtkWidget *widget, return FALSE; } -static void -gtk_menu_check_resize (GtkContainer *container) +static gint +gtk_menu_motion_notify (GtkWidget *widget, + GdkEventMotion *event) { - GtkAllocation allocation; - GtkWidget *widget; - - g_return_if_fail (container != NULL); - g_return_if_fail (GTK_IS_MENU (container)); + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_MENU (widget), FALSE); - widget = GTK_WIDGET (container); - - if (GTK_WIDGET_VISIBLE (container)) + if (GTK_MENU_SHELL (widget)->ignore_enter) + GTK_MENU_SHELL (widget)->ignore_enter = FALSE; + else { - MENU_NEEDS_RESIZE (container) = FALSE; - - gtk_widget_size_request (widget, &widget->requisition); - - allocation.x = widget->allocation.x; - allocation.y = widget->allocation.y; - allocation.width = widget->requisition.width; - allocation.height = widget->requisition.height; - - gtk_widget_size_allocate (widget, &allocation); + GdkEvent send_event; + + send_event.crossing.type = GDK_ENTER_NOTIFY; + send_event.crossing.window = event->window; + send_event.crossing.time = event->time; + + gtk_widget_event (widget, &send_event); } - else - MENU_NEEDS_RESIZE (container) = TRUE; + + return FALSE; } static void @@ -933,3 +997,51 @@ gtk_menu_hide_all (GtkWidget *widget) /* Hide children, but not self. */ gtk_container_foreach (container, (GtkCallback) gtk_widget_hide_all, NULL); } + +static void +gtk_menu_position (GtkMenu *menu) +{ + GtkWidget *widget; + gint x, y; + + g_return_if_fail (menu != NULL); + g_return_if_fail (GTK_IS_MENU (menu)); + + widget = GTK_WIDGET (menu); + + gdk_window_get_pointer (NULL, &x, &y, NULL); + + /* We need the requisition to figure out the right place to + * popup the menu. In fact, we always need to ask here, since + * if one a size_request was queued while we weren't popped up, + * the requisition won't have been recomputed yet. + */ + gtk_widget_size_request (widget, &widget->requisition); + + if (menu->position_func) + (* menu->position_func) (menu, &x, &y, menu->position_func_data); + else + { + gint screen_width; + gint screen_height; + + screen_width = gdk_screen_width (); + screen_height = gdk_screen_height (); + + x -= 2; + y -= 2; + + if ((x + widget->requisition.width) > screen_width) + x -= ((x + widget->requisition.width) - screen_width); + if (x < 0) + x = 0; + if ((y + widget->requisition.height) > screen_height) + y -= ((y + widget->requisition.height) - screen_height); + if (y < 0) + y = 0; + } + + gtk_widget_set_uposition (GTK_MENU_SHELL (menu)->active ? + menu->toplevel : menu->tearoff_window, + x, y); +} diff --git a/gtk/gtkmenu.h b/gtk/gtkmenu.h index ac47f54baf..8600627dd0 100644 --- a/gtk/gtkmenu.h +++ b/gtk/gtkmenu.h @@ -58,6 +58,11 @@ struct _GtkMenu GtkAccelGroup *accel_group; GtkMenuPositionFunc position_func; gpointer position_func_data; + + GtkWidget *toplevel; + GtkWidget *tearoff_window; + + guint torn_off : 1; }; struct _GtkMenuClass @@ -94,7 +99,8 @@ void gtk_menu_attach_to_widget (GtkMenu *menu, GtkMenuDetachFunc detacher); GtkWidget* gtk_menu_get_attach_widget (GtkMenu *menu); void gtk_menu_detach (GtkMenu *menu); - +void gtk_menu_set_tearoff_state (GtkMenu *menu, + gboolean torn_off); #ifdef __cplusplus } diff --git a/gtk/gtkmenubar.c b/gtk/gtkmenubar.c index 1983e3dd4a..3f04e5193b 100644 --- a/gtk/gtkmenubar.c +++ b/gtk/gtkmenubar.c @@ -16,6 +16,8 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ +#include "gdk/gdkkeysyms.h" +#include "gtkbindings.h" #include "gtkmain.h" #include "gtkmenubar.h" #include "gtkmenuitem.h" @@ -69,6 +71,8 @@ gtk_menu_bar_class_init (GtkMenuBarClass *class) GtkWidgetClass *widget_class; GtkMenuShellClass *menu_shell_class; + GtkBindingSet *binding_set; + widget_class = (GtkWidgetClass*) class; menu_shell_class = (GtkMenuShellClass*) class; @@ -78,6 +82,28 @@ gtk_menu_bar_class_init (GtkMenuBarClass *class) widget_class->expose_event = gtk_menu_bar_expose; menu_shell_class->submenu_placement = GTK_TOP_BOTTOM; + + binding_set = gtk_binding_set_by_class (class); + gtk_binding_entry_add_signal (binding_set, + GDK_Left, 0, + "move_current", 1, + GTK_TYPE_MENU_DIRECTION_TYPE, + GTK_MENU_DIR_PREV); + gtk_binding_entry_add_signal (binding_set, + GDK_Right, 0, + "move_current", 1, + GTK_TYPE_MENU_DIRECTION_TYPE, + GTK_MENU_DIR_NEXT); + gtk_binding_entry_add_signal (binding_set, + GDK_Up, 0, + "move_current", 1, + GTK_TYPE_MENU_DIRECTION_TYPE, + GTK_MENU_DIR_PARENT); + gtk_binding_entry_add_signal (binding_set, + GDK_Down, 0, + "move_current", 1, + GTK_TYPE_MENU_DIRECTION_TYPE, + GTK_MENU_DIR_CHILD); } static void diff --git a/gtk/gtkmenuitem.c b/gtk/gtkmenuitem.c index e4bf0f0f96..ba79c57db6 100644 --- a/gtk/gtkmenuitem.c +++ b/gtk/gtkmenuitem.c @@ -20,6 +20,7 @@ #include "gtkaccellabel.h" #include "gtkmain.h" #include "gtkmenu.h" +#include "gtkmenubar.h" #include "gtkmenuitem.h" #include "gtksignal.h" @@ -32,6 +33,7 @@ enum { ACTIVATE, + ACTIVATE_ITEM, LAST_SIGNAL }; @@ -51,6 +53,7 @@ static gint gtk_menu_item_expose (GtkWidget *widget, GdkEventExpose *event); static void gtk_real_menu_item_select (GtkItem *item); static void gtk_real_menu_item_deselect (GtkItem *item); +static void gtk_real_menu_item_activate_item (GtkMenuItem *item); static gint gtk_menu_item_select_timeout (gpointer data); static void gtk_menu_item_position_menu (GtkMenu *menu, gint *x, @@ -110,6 +113,14 @@ gtk_menu_item_class_init (GtkMenuItemClass *klass) gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0); + menu_item_signals[ACTIVATE_ITEM] = + gtk_signal_new ("activate_item", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkMenuItemClass, activate_item), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + gtk_object_class_add_signals (object_class, menu_item_signals, LAST_SIGNAL); object_class->destroy = gtk_menu_item_destroy; @@ -126,8 +137,10 @@ gtk_menu_item_class_init (GtkMenuItemClass *klass) item_class->deselect = gtk_real_menu_item_deselect; klass->activate = NULL; + klass->activate_item = gtk_real_menu_item_activate_item; klass->toggle_size = 0; + klass->hide_on_activate = TRUE; } static void @@ -493,8 +506,16 @@ gtk_real_menu_item_select (GtkItem *item) menu_item = GTK_MENU_ITEM (item); - if (menu_item->submenu && !GTK_WIDGET_VISIBLE (menu_item->submenu)) - menu_item->timer = gtk_timeout_add (SELECT_TIMEOUT, gtk_menu_item_select_timeout, menu_item); + /* if (menu_item->submenu && !GTK_WIDGET_VISIBLE (menu_item->submenu))*/ + if (menu_item->submenu) + { + /* Boy this is a hack! */ + GdkEvent *current_event = gtk_get_current_event(); + if (current_event && (current_event->type != GDK_ENTER_NOTIFY)) + gtk_menu_item_select_timeout (menu_item); + else + menu_item->timer = gtk_timeout_add (SELECT_TIMEOUT, gtk_menu_item_select_timeout, menu_item); + } gtk_widget_set_state (GTK_WIDGET (menu_item), GTK_STATE_PRELIGHT); gtk_widget_draw (GTK_WIDGET (menu_item), NULL); @@ -522,6 +543,38 @@ gtk_real_menu_item_deselect (GtkItem *item) gtk_widget_draw (GTK_WIDGET (menu_item), NULL); } +static void +gtk_real_menu_item_activate_item (GtkMenuItem *menu_item) +{ + GtkWidget *widget; + + g_return_if_fail (menu_item != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (menu_item)); + + widget = GTK_WIDGET (menu_item); + + if (widget->parent && + GTK_IS_MENU_SHELL (widget->parent)) + { + if (menu_item->submenu == NULL) + gtk_menu_shell_activate_item (GTK_MENU_SHELL (widget->parent), + widget, TRUE); + else + { + GtkMenuShell *menu_shell = GTK_MENU_SHELL (widget->parent); + + if (!menu_shell->active) + { + gtk_grab_add (GTK_WIDGET (menu_shell)); + menu_shell->have_grab = TRUE; + menu_shell->active = TRUE; + } + + gtk_menu_shell_select_item (GTK_MENU_SHELL (widget->parent), widget); + } + } +} + static gint gtk_menu_item_select_timeout (gpointer data) { @@ -538,6 +591,16 @@ gtk_menu_item_select_timeout (gpointer data) GTK_MENU_SHELL (GTK_WIDGET (menu_item)->parent)->button, 0); + /* This is a bit of a hack - we want to select the first item + * of menus hanging of a menu bar, but not for cascading submenus + */ + if (GTK_IS_MENU_BAR (GTK_WIDGET (menu_item)->parent)) + { + GtkMenuShell *submenu = GTK_MENU_SHELL (menu_item->submenu); + if (submenu->children) + gtk_menu_shell_select_item (submenu, submenu->children->data); + } + return FALSE; } diff --git a/gtk/gtkmenuitem.h b/gtk/gtkmenuitem.h index 82a9244fe0..fdfafed310 100644 --- a/gtk/gtkmenuitem.h +++ b/gtk/gtkmenuitem.h @@ -63,8 +63,16 @@ struct _GtkMenuItemClass GtkItemClass parent_class; guint toggle_size; + /* If the following flag is true, then we should always hide + * the menu when the MenuItem is activated. Otherwise, the + * it is up to the caller. For instance, when navigating + * a menu with the keyboard, <Space> doesn't hide, but + * <Return> does. + */ + guint hide_on_activate : 1; - void (* activate) (GtkMenuItem *menu_item); + void (* activate) (GtkMenuItem *menu_item); + void (* activate_item) (GtkMenuItem *menu_item); }; diff --git a/gtk/gtkmenushell.c b/gtk/gtkmenushell.c index d37155d5da..333e1c1297 100644 --- a/gtk/gtkmenushell.c +++ b/gtk/gtkmenushell.c @@ -16,8 +16,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ +#include "gdk/gdkkeysyms.h" +#include "gtkbindings.h" #include "gtkmain.h" #include "gtkmenuitem.h" +#include "gtktearoffmenuitem.h" /* FIXME */ #include "gtkmenushell.h" #include "gtksignal.h" @@ -29,9 +32,73 @@ enum { DEACTIVATE, SELECTION_DONE, + MOVE_CURRENT, + ACTIVATE_CURRENT, + CANCEL, LAST_SIGNAL }; +typedef void (*GtkMenuShellSignal1) (GtkObject *object, + GtkMenuDirectionType arg1, + gpointer data); +typedef void (*GtkMenuShellSignal2) (GtkObject *object, + gboolean arg1, + gpointer data); + +/* Terminology: + * + * A menu item can be "selected", this means that it is displayed + * in the prelight state, and if it has a submenu, that submenu + * will be popped up. + * + * A menu is "active" when it is visible onscreen and the user + * is selecting from it. A menubar is not active until the user + * clicks on one of its menuitems. When a menu is active, + * passing the mouse over a submenu will pop it up. + * + * menu_shell->active_menu_item, is however, not an "active" + * menu item (there is no such thing) but rather, the selected + * menu item in that MenuShell, if there is one. + * + * There is also is a concept of the current menu and a current + * menu item. The current menu item is the selected menu item + * that is furthest down in the heirarchy. (Every active menu_shell + * does not necessarily contain a selected menu item, but if + * it does, then menu_shell->parent_menu_shell must also contain + * a selected menu item. The current menu is the menu that + * contains the current menu_item. It will always have a GTK + * grab and receive all key presses. + * + * + * Action signals: + * + * ::move_current (GtkMenuDirection *dir) + * Moves the current menu item in direction 'dir': + * + * GTK_MENU_DIR_PARENT: To the parent menu shell + * GTK_MENU_DIR_CHILD: To the child menu shell (if this item has + * a submenu. + * GTK_MENU_DIR_NEXT/PREV: To the next or previous item + * in this menu. + * + * As a a bit of a hack to get movement between menus and + * menubars working, if submenu_placement is different for + * the menu and its MenuShell then the following apply: + * + * - For 'parent' the current menu is not just moved to + * the parent, but moved to the previous entry in the parent + * - For 'child', if there is no child, then current is + * moved to the next item in the parent. + * + * + * ::activate_current (GBoolean *force_hide) + * Activate the current item. If 'force_hide' is true, hide + * the current menu item always. Otherwise, only hide + * it if menu_item->klass->hide_on_activate is true. + * + * ::cancel () + * Cancels the current selection + */ static void gtk_menu_shell_class_init (GtkMenuShellClass *klass); static void gtk_menu_shell_init (GtkMenuShell *menu_shell); @@ -41,6 +108,8 @@ static gint gtk_menu_shell_button_press (GtkWidget *widget, GdkEventButton *event); static gint gtk_menu_shell_button_release (GtkWidget *widget, GdkEventButton *event); +static gint gtk_menu_shell_key_press (GtkWidget *widget, + GdkEventKey *event); static gint gtk_menu_shell_enter_notify (GtkWidget *widget, GdkEventCrossing *event); static gint gtk_menu_shell_leave_notify (GtkWidget *widget, @@ -57,8 +126,14 @@ static gint gtk_menu_shell_is_item (GtkMenuShell *menu_shell, GtkWidget *child); static GtkWidget *gtk_menu_shell_get_item (GtkMenuShell *menu_shell, GdkEvent *event); -static GtkType gtk_menu_shell_child_type (GtkContainer *container); +static GtkType gtk_menu_shell_child_type (GtkContainer *container); +static void gtk_menu_shell_deselect (GtkMenuShell *menu_shell); +static void gtk_real_menu_shell_move_current (GtkMenuShell *menu_shell, + GtkMenuDirectionType direction); +static void gtk_real_menu_shell_activate_current (GtkMenuShell *menu_shell, + gboolean force_hide); +static void gtk_real_menu_shell_cancel (GtkMenuShell *menu_shell); static GtkContainerClass *parent_class = NULL; static guint menu_shell_signals[LAST_SIGNAL] = { 0 }; @@ -96,6 +171,8 @@ gtk_menu_shell_class_init (GtkMenuShellClass *klass) GtkWidgetClass *widget_class; GtkContainerClass *container_class; + GtkBindingSet *binding_set; + object_class = (GtkObjectClass*) klass; widget_class = (GtkWidgetClass*) klass; container_class = (GtkContainerClass*) klass; @@ -116,12 +193,37 @@ gtk_menu_shell_class_init (GtkMenuShellClass *klass) GTK_SIGNAL_OFFSET (GtkMenuShellClass, selection_done), gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0); + menu_shell_signals[MOVE_CURRENT] = + gtk_signal_new ("move_current", + GTK_RUN_LAST | GTK_RUN_ACTION, + object_class->type, + GTK_SIGNAL_OFFSET (GtkMenuShellClass, move_current), + gtk_marshal_NONE__ENUM, + GTK_TYPE_NONE, 1, + GTK_TYPE_MENU_DIRECTION_TYPE); + menu_shell_signals[ACTIVATE_CURRENT] = + gtk_signal_new ("activate_current", + GTK_RUN_LAST | GTK_RUN_ACTION, + object_class->type, + GTK_SIGNAL_OFFSET (GtkMenuShellClass, activate_current), + gtk_marshal_NONE__BOOL, + GTK_TYPE_NONE, 1, + GTK_TYPE_BOOL); + menu_shell_signals[CANCEL] = + gtk_signal_new ("cancel", + GTK_RUN_LAST | GTK_RUN_ACTION, + object_class->type, + GTK_SIGNAL_OFFSET (GtkMenuShellClass, cancel), + gtk_marshal_NONE__NONE, + GTK_TYPE_NONE, 0); + gtk_object_class_add_signals (object_class, menu_shell_signals, LAST_SIGNAL); widget_class->map = gtk_menu_shell_map; widget_class->realize = gtk_menu_shell_realize; widget_class->button_press_event = gtk_menu_shell_button_press; widget_class->button_release_event = gtk_menu_shell_button_release; + widget_class->key_press_event = gtk_menu_shell_key_press; widget_class->enter_notify_event = gtk_menu_shell_enter_notify; widget_class->leave_notify_event = gtk_menu_shell_leave_notify; @@ -133,6 +235,24 @@ gtk_menu_shell_class_init (GtkMenuShellClass *klass) klass->submenu_placement = GTK_TOP_BOTTOM; klass->deactivate = gtk_real_menu_shell_deactivate; klass->selection_done = NULL; + klass->move_current = gtk_real_menu_shell_move_current; + klass->activate_current = gtk_real_menu_shell_activate_current; + klass->cancel = gtk_real_menu_shell_cancel; + + binding_set = gtk_binding_set_by_class (klass); + gtk_binding_entry_add_signal (binding_set, + GDK_Escape, 0, + "cancel", 0); + gtk_binding_entry_add_signal (binding_set, + GDK_Return, 0, + "activate_current", 1, + GTK_TYPE_BOOL, + TRUE); + gtk_binding_entry_add_signal (binding_set, + GDK_space, 0, + "activate_current", 1, + GTK_TYPE_BOOL, + FALSE); } static GtkType @@ -282,6 +402,7 @@ gtk_menu_shell_realize (GtkWidget *widget) attributes.event_mask |= (GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | + GDK_KEY_PRESS_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); @@ -388,16 +509,7 @@ gtk_menu_shell_button_release (GtkWidget *widget, { if (GTK_MENU_ITEM (menu_item)->submenu == NULL) { - gtk_menu_shell_deactivate (menu_shell); - - /* flush the x-queue, so any grabs are removed and - * the menu is actually taken down - */ - gdk_flush (); - gtk_widget_activate (menu_item); - - gtk_signal_emit (GTK_OBJECT (menu_shell), menu_shell_signals[SELECTION_DONE]); - + gtk_menu_shell_activate_item (menu_shell, menu_item, TRUE); return TRUE; } } @@ -434,6 +546,32 @@ gtk_menu_shell_button_release (GtkWidget *widget, } static gint +gtk_menu_shell_key_press (GtkWidget *widget, + GdkEventKey *event) +{ + GtkMenuShell *menu_shell; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_MENU_SHELL (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + menu_shell = GTK_MENU_SHELL (widget); + + if (!menu_shell->active_menu_item && menu_shell->parent_menu_shell) + return gtk_widget_event (menu_shell->parent_menu_shell, (GdkEvent *)event); + + if (gtk_bindings_activate (GTK_OBJECT (widget), + event->keyval, + event->state)) + return TRUE; + + if (gtk_accel_groups_activate (GTK_OBJECT (widget), event->keyval, event->state)) + return TRUE; + + return FALSE; +} + +static gint gtk_menu_shell_enter_notify (GtkWidget *widget, GdkEventCrossing *event) { @@ -445,7 +583,8 @@ gtk_menu_shell_enter_notify (GtkWidget *widget, g_return_val_if_fail (event != NULL, FALSE); menu_shell = GTK_MENU_SHELL (widget); - if (menu_shell->active) + + if (menu_shell->active && !menu_shell->ignore_enter) { menu_item = gtk_get_event_widget ((GdkEvent*) event); @@ -459,15 +598,7 @@ gtk_menu_shell_enter_notify (GtkWidget *widget, if ((event->detail != GDK_NOTIFY_INFERIOR) && (GTK_WIDGET_STATE (menu_item) != GTK_STATE_PRELIGHT)) { - if (menu_shell->active_menu_item) - gtk_menu_item_deselect (GTK_MENU_ITEM (menu_shell->active_menu_item)); - - menu_shell->active_menu_item = menu_item; - gtk_menu_item_set_placement (GTK_MENU_ITEM (menu_shell->active_menu_item), - MENU_SHELL_CLASS (menu_shell)->submenu_placement); - gtk_menu_item_select (GTK_MENU_ITEM (menu_shell->active_menu_item)); - if (GTK_MENU_ITEM (menu_shell->active_menu_item)->submenu) - gtk_widget_activate (menu_shell->active_menu_item); + gtk_menu_shell_select_item (menu_shell, menu_item); } } else if (menu_shell->parent_menu_shell) @@ -516,8 +647,7 @@ gtk_menu_shell_leave_notify (GtkWidget *widget, if ((event->detail != GDK_NOTIFY_INFERIOR) && (GTK_WIDGET_STATE (menu_item) != GTK_STATE_NORMAL)) { - gtk_menu_item_deselect (GTK_MENU_ITEM (menu_shell->active_menu_item)); - menu_shell->active_menu_item = NULL; + gtk_menu_shell_deselect (menu_shell); } } else if (menu_shell->parent_menu_shell) @@ -613,6 +743,7 @@ gtk_real_menu_shell_deactivate (GtkMenuShell *menu_shell) { menu_shell->have_xgrab = FALSE; gdk_pointer_ungrab (GDK_CURRENT_TIME); + gdk_keyboard_ungrab (GDK_CURRENT_TIME); } } } @@ -655,3 +786,181 @@ gtk_menu_shell_get_item (GtkMenuShell *menu_shell, return NULL; } +/* Handlers for action signals */ + +void +gtk_menu_shell_select_item (GtkMenuShell *menu_shell, + GtkWidget *menu_item) +{ + g_return_if_fail (menu_shell != NULL); + g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell)); + g_return_if_fail (menu_item != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (menu_item)); + + if (menu_shell->active_menu_item) + gtk_menu_item_deselect (GTK_MENU_ITEM (menu_shell->active_menu_item)); + + menu_shell->active_menu_item = menu_item; + gtk_menu_item_set_placement (GTK_MENU_ITEM (menu_shell->active_menu_item), + MENU_SHELL_CLASS (menu_shell)->submenu_placement); + gtk_menu_item_select (GTK_MENU_ITEM (menu_shell->active_menu_item)); + + /* This allows the bizarre radio buttons-with-submenus-display-history + * behavior + */ + if (GTK_MENU_ITEM (menu_shell->active_menu_item)->submenu) + gtk_widget_activate (menu_shell->active_menu_item); +} + +static void +gtk_menu_shell_deselect (GtkMenuShell *menu_shell) +{ + gtk_menu_item_deselect (GTK_MENU_ITEM (menu_shell->active_menu_item)); + menu_shell->active_menu_item = NULL; +} + +void +gtk_menu_shell_activate_item (GtkMenuShell *menu_shell, + GtkWidget *menu_item, + gboolean force_deactivate) +{ + gboolean deactivate = force_deactivate; + + g_return_if_fail (menu_shell != NULL); + g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell)); + g_return_if_fail (menu_item != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (menu_item)); + + if (!deactivate) + { + deactivate = GTK_MENU_ITEM_CLASS (GTK_OBJECT (menu_item)->klass)->hide_on_activate; + } + + if (deactivate) + { + gtk_menu_shell_deactivate (menu_shell); + + /* flush the x-queue, so any grabs are removed and + * the menu is actually taken down + */ + gdk_flush (); + } + gtk_widget_activate (menu_item); + + if (deactivate) + gtk_signal_emit (GTK_OBJECT (menu_shell), menu_shell_signals[SELECTION_DONE]); +} + +/* Distance should be +/- 1 */ +static void +gtk_menu_shell_move_selected (GtkMenuShell *menu_shell, + gint distance) +{ + if (menu_shell->active_menu_item) + { + GList *node = g_list_find (menu_shell->children, + menu_shell->active_menu_item); + GList *start_node = node; + + if (distance > 0) + { + node = node->next; + while (node != start_node && + (!node || !GTK_WIDGET_SENSITIVE (node->data))) + { + if (!node) + node = menu_shell->children; + else + node = node->next; + } + } + else + { + node = node->prev; + while (node != start_node && + (!node || !GTK_WIDGET_SENSITIVE (node->data))) + { + if (!node) + node = g_list_last (menu_shell->children); + else + node = node->prev; + } + } + + if (node) + gtk_menu_shell_select_item (menu_shell, node->data); + } +} + +static void +gtk_real_menu_shell_move_current (GtkMenuShell *menu_shell, + GtkMenuDirectionType direction) +{ + GtkMenuShell *parent_menu_shell = NULL; + + if (menu_shell->parent_menu_shell) + parent_menu_shell = GTK_MENU_SHELL (menu_shell->parent_menu_shell); + + switch (direction) + { + case GTK_MENU_DIR_PARENT: + if (parent_menu_shell) + { + if (GTK_MENU_SHELL_CLASS (GTK_OBJECT (parent_menu_shell)->klass)->submenu_placement == + GTK_MENU_SHELL_CLASS (GTK_OBJECT (menu_shell)->klass)->submenu_placement) + gtk_menu_shell_deselect (menu_shell); + else + gtk_menu_shell_move_selected (parent_menu_shell, -1); + } + break; + + case GTK_MENU_DIR_CHILD: + if (GTK_BIN (menu_shell->active_menu_item)->child && + GTK_MENU_ITEM (menu_shell->active_menu_item)->submenu) + { + menu_shell = GTK_MENU_SHELL (GTK_MENU_ITEM (menu_shell->active_menu_item)->submenu); + if (menu_shell->children) + gtk_menu_shell_select_item (menu_shell, menu_shell->children->data); + } + else + { + /* Try to find a menu running the opposite direction */ + while (parent_menu_shell && + (GTK_MENU_SHELL_CLASS (GTK_OBJECT (parent_menu_shell)->klass)->submenu_placement == + GTK_MENU_SHELL_CLASS (GTK_OBJECT (menu_shell)->klass)->submenu_placement)) + parent_menu_shell = GTK_MENU_SHELL (parent_menu_shell->parent_menu_shell); + + if (parent_menu_shell) + gtk_menu_shell_move_selected (parent_menu_shell, 1); + } + break; + + case GTK_MENU_DIR_PREV: + gtk_menu_shell_move_selected (menu_shell, -1); + break; + case GTK_MENU_DIR_NEXT: + gtk_menu_shell_move_selected (menu_shell, 1); + break; + } +} + +static void +gtk_real_menu_shell_activate_current (GtkMenuShell *menu_shell, + gboolean force_hide) +{ + if (menu_shell->active_menu_item && + GTK_MENU_ITEM (menu_shell->active_menu_item)->submenu == NULL) + { + gtk_menu_shell_activate_item (menu_shell, + menu_shell->active_menu_item, + force_hide); + } +} + +static void +gtk_real_menu_shell_cancel (GtkMenuShell *menu_shell) +{ + gtk_menu_shell_deactivate (menu_shell); + gtk_signal_emit (GTK_OBJECT (menu_shell), menu_shell_signals[SELECTION_DONE]); +} + diff --git a/gtk/gtkmenushell.h b/gtk/gtkmenushell.h index 808e50ab81..965551e31c 100644 --- a/gtk/gtkmenushell.h +++ b/gtk/gtkmenushell.h @@ -54,6 +54,7 @@ struct _GtkMenuShell guint button : 2; guint ignore_leave : 1; guint menu_flag : 1; + guint ignore_enter : 1; guint32 activate_time; }; @@ -66,6 +67,12 @@ struct _GtkMenuShellClass void (*deactivate) (GtkMenuShell *menu_shell); void (*selection_done) (GtkMenuShell *menu_shell); + + void (*move_current) (GtkMenuShell *menu_shell, + GtkMenuDirectionType direction); + void (*activate_current) (GtkMenuShell *menu_shell, + gboolean force_hide); + void (*cancel) (GtkMenuShell *menu_shell); }; @@ -78,6 +85,11 @@ void gtk_menu_shell_insert (GtkMenuShell *menu_shell, GtkWidget *child, gint position); void gtk_menu_shell_deactivate (GtkMenuShell *menu_shell); +void gtk_menu_shell_select_item (GtkMenuShell *menu_shell, + GtkWidget *menu_item); +void gtk_menu_shell_activate_item (GtkMenuShell *menu_shell, + GtkWidget *menu_item, + gboolean force_deactivate); #ifdef __cplusplus diff --git a/gtk/gtktearoffmenuitem.c b/gtk/gtktearoffmenuitem.c new file mode 100644 index 0000000000..432754d5be --- /dev/null +++ b/gtk/gtktearoffmenuitem.c @@ -0,0 +1,250 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 "gtkmenu.h" +#include "gtksignal.h" +#include "gtktearoffmenuitem.h" + +#define ARROW_SIZE 10 +#define TEAR_LENGTH 5 +#define BORDER_SPACING 3 + +static void gtk_tearoff_menu_item_class_init (GtkTearoffMenuItemClass *klass); +static void gtk_tearoff_menu_item_init (GtkTearoffMenuItem *tearoff_menu_item); +static void gtk_tearoff_menu_item_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_tearoff_menu_item_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_tearoff_menu_item_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gtk_tearoff_menu_item_activate (GtkMenuItem *menu_item); +static gint gtk_tearoff_menu_item_delete_cb (GtkMenuItem *menu_item, + GdkEventAny *event); + +GtkType +gtk_tearoff_menu_item_get_type (void) +{ + static GtkType tearoff_menu_item_type = 0; + + if (!tearoff_menu_item_type) + { + GtkTypeInfo tearoff_menu_item_info = + { + "GtkTearoffMenuItem", + sizeof (GtkTearoffMenuItem), + sizeof (GtkTearoffMenuItemClass), + (GtkClassInitFunc) gtk_tearoff_menu_item_class_init, + (GtkObjectInitFunc) gtk_tearoff_menu_item_init, + /* reserved_1 */ NULL, + /* reserved_2 */ NULL, + (GtkClassInitFunc) NULL, + }; + + tearoff_menu_item_type = gtk_type_unique (gtk_menu_item_get_type (), &tearoff_menu_item_info); + } + + return tearoff_menu_item_type; +} + +GtkWidget* +gtk_tearoff_menu_item_new (void) +{ + return GTK_WIDGET (gtk_type_new (gtk_tearoff_menu_item_get_type ())); +} + +static void +gtk_tearoff_menu_item_class_init (GtkTearoffMenuItemClass *klass) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkMenuItemClass *menu_item_class; + + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + menu_item_class = (GtkMenuItemClass*) klass; + + widget_class->draw = gtk_tearoff_menu_item_draw; + widget_class->expose_event = gtk_tearoff_menu_item_expose; + widget_class->size_request = gtk_tearoff_menu_item_size_request; + + menu_item_class->activate = gtk_tearoff_menu_item_activate; +} + +static void +gtk_tearoff_menu_item_init (GtkTearoffMenuItem *tearoff_menu_item) +{ + tearoff_menu_item->torn_off = FALSE; +} + +static void +gtk_tearoff_menu_item_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkTearoffMenuItem *tearoff; + + tearoff = GTK_TEAROFF_MENU_ITEM (widget); + + requisition->width = (GTK_CONTAINER (widget)->border_width + + widget->style->klass->xthickness + + BORDER_SPACING) * 2; + requisition->height = (GTK_CONTAINER (widget)->border_width + + widget->style->klass->ythickness) * 2; + + if (tearoff->torn_off) + { + requisition->height += ARROW_SIZE; + } + else + { + requisition->height += widget->style->klass->ythickness; + } +} + +static void +gtk_tearoff_menu_item_paint (GtkWidget *widget, + GdkRectangle *area) +{ + GtkMenuItem *menu_item; + GtkTearoffMenuItem *tearoff_item; + GtkShadowType shadow_type; + gint width, height; + gint x, y; + gint right_max; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_TEAROFF_MENU_ITEM (widget)); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + menu_item = GTK_MENU_ITEM (widget); + tearoff_item = GTK_TEAROFF_MENU_ITEM (widget); + + gtk_style_set_background (widget->style, widget->window, widget->state); + gdk_window_clear_area (widget->window, area->x, area->y, area->width, area->height); + + x = GTK_CONTAINER (menu_item)->border_width; + y = GTK_CONTAINER (menu_item)->border_width; + width = widget->allocation.width - x * 2; + height = widget->allocation.height - y * 2; + right_max = x + width; + + if (widget->state == GTK_STATE_PRELIGHT) + gtk_draw_shadow (widget->style, + widget->window, + GTK_STATE_PRELIGHT, + GTK_SHADOW_OUT, + x, y, width, height); + + if (tearoff_item->torn_off) + { + gint arrow_x; + + if (widget->state == GTK_STATE_PRELIGHT) + shadow_type = GTK_SHADOW_IN; + else + shadow_type = GTK_SHADOW_OUT; + + if (menu_item->toggle_size > ARROW_SIZE) + { + arrow_x = x + (menu_item->toggle_size - ARROW_SIZE)/2; + x += menu_item->toggle_size + BORDER_SPACING; + } + else + { + arrow_x = ARROW_SIZE / 2; + x += 2 * ARROW_SIZE; + } + + gtk_draw_arrow (widget->style, widget->window, + widget->state, shadow_type, GTK_ARROW_LEFT, FALSE, + arrow_x, y + height / 2 - 5, + ARROW_SIZE, ARROW_SIZE); + } + + while (x < right_max) + { + gtk_draw_hline (widget->style, widget->window, GTK_STATE_NORMAL, + x, MIN (x+TEAR_LENGTH, right_max), + y + (height - widget->style->klass->ythickness)/2); + x += 2 * TEAR_LENGTH; + } + } +} + +static void +gtk_tearoff_menu_item_draw (GtkWidget *widget, + GdkRectangle *area) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_TEAROFF_MENU_ITEM (widget)); + g_return_if_fail (area != NULL); + + gtk_tearoff_menu_item_paint (widget, area); +} + +static gint +gtk_tearoff_menu_item_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_TEAROFF_MENU_ITEM (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + gtk_tearoff_menu_item_paint (widget, &event->area); + + return FALSE; +} + +static gint +gtk_tearoff_menu_item_delete_cb (GtkMenuItem *menu_item, GdkEventAny *event) +{ + gtk_tearoff_menu_item_activate (menu_item); + return TRUE; +} + +static void +gtk_tearoff_menu_item_activate (GtkMenuItem *menu_item) +{ + GtkTearoffMenuItem *tearoff_menu_item; + + g_return_if_fail (menu_item != NULL); + g_return_if_fail (GTK_IS_TEAROFF_MENU_ITEM (menu_item)); + + tearoff_menu_item = GTK_TEAROFF_MENU_ITEM (menu_item); + tearoff_menu_item->torn_off = !tearoff_menu_item->torn_off; + + if (GTK_IS_MENU (GTK_WIDGET (menu_item)->parent)) + { + GtkMenu *menu = GTK_MENU (GTK_WIDGET (menu_item)->parent); + gboolean need_connect; + + need_connect = (tearoff_menu_item->torn_off && !menu->tearoff_window); + + gtk_menu_set_tearoff_state (GTK_MENU (GTK_WIDGET (menu_item)->parent), + tearoff_menu_item->torn_off); + + if (need_connect) + gtk_signal_connect_object (GTK_OBJECT (menu->tearoff_window), + "delete_event", + GTK_SIGNAL_FUNC (gtk_tearoff_menu_item_delete_cb), + GTK_OBJECT (menu_item)); + } + + gtk_widget_queue_resize (GTK_WIDGET (menu_item)); +} + diff --git a/gtk/gtktearoffmenuitem.h b/gtk/gtktearoffmenuitem.h new file mode 100644 index 0000000000..614d361fec --- /dev/null +++ b/gtk/gtktearoffmenuitem.h @@ -0,0 +1,64 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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. + */ +#ifndef __GTK_MENU_TEAROFF_ITEM_H__ +#define __GTK_MENU_TEAROFF_ITEM_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkmenuitem.h> + + +#ifdef __cplusplus +extern "C" { +#pragma } +#endif /* __cplusplus */ + + +#define GTK_TYPE_TEAROFF_MENU_ITEM (gtk_tearoff_menu_item_get_type ()) +#define GTK_TEAROFF_MENU_ITEM(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_TEAROFF_MENU_ITEM, GtkTearoffMenuItem)) +#define GTK_TEAROFF_MENU_ITEM_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_TEAROFF_MENU_ITEM, GtkTearoffMenuItemClass)) +#define GTK_IS_TEAROFF_MENU_ITEM(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_TEAROFF_MENU_ITEM)) +#define GTK_IS_TEAROFF_MENU_ITEM_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_TEAROFF_MENU_ITEM)) + + +typedef struct _GtkTearoffMenuItem GtkTearoffMenuItem; +typedef struct _GtkTearoffMenuItemClass GtkTearoffMenuItemClass; + +struct _GtkTearoffMenuItem +{ + GtkMenuItem menu_item; + + guint torn_off : 1; +}; + +struct _GtkTearoffMenuItemClass +{ + GtkMenuItemClass parent_class; +}; + + +GtkType gtk_tearoff_menu_item_get_type (void); +GtkWidget* gtk_tearoff_menu_item_new (void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_TEAROFF_MENU_ITEM_H__ */ diff --git a/gtk/gtktoolbar.c b/gtk/gtktoolbar.c index c38ca05fea..6e62117ad3 100644 --- a/gtk/gtktoolbar.c +++ b/gtk/gtktoolbar.c @@ -775,6 +775,8 @@ gtk_toolbar_insert_element (GtkToolbar *toolbar, gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (child->widget), FALSE); } + GTK_WIDGET_UNSET_FLAGS (child->widget, GTK_CAN_FOCUS); + if (callback) gtk_signal_connect (GTK_OBJECT (child->widget), "clicked", callback, user_data); diff --git a/gtk/gtktypebuiltins.h b/gtk/gtktypebuiltins.h index 156a4aa5f3..ca787940c2 100644 --- a/gtk/gtktypebuiltins.h +++ b/gtk/gtktypebuiltins.h @@ -13,6 +13,7 @@ extern GtkType GTK_TYPE_CURVE_TYPE; extern GtkType GTK_TYPE_DIRECTION_TYPE; extern GtkType GTK_TYPE_JUSTIFICATION; extern GtkType GTK_TYPE_MATCH_TYPE; +extern GtkType GTK_TYPE_MENU_DIRECTION_TYPE; extern GtkType GTK_TYPE_MENU_FACTORY_TYPE; extern GtkType GTK_TYPE_METRIC_TYPE; extern GtkType GTK_TYPE_ORIENTATION; diff --git a/gtk/gtktypebuiltins_evals.c b/gtk/gtktypebuiltins_evals.c index ba0eee19d5..53d010f897 100644 --- a/gtk/gtktypebuiltins_evals.c +++ b/gtk/gtktypebuiltins_evals.c @@ -95,6 +95,13 @@ static GtkEnumValue _gtk_match_type_values[] = { { GTK_MATCH_LAST, "GTK_MATCH_LAST", "last" }, { 0, NULL, NULL } }; +static GtkEnumValue _gtk_menu_direction_type_values[] = { + { GTK_MENU_DIR_PARENT, "GTK_MENU_DIR_PARENT", "parent" }, + { GTK_MENU_DIR_CHILD, "GTK_MENU_DIR_CHILD", "child" }, + { GTK_MENU_DIR_NEXT, "GTK_MENU_DIR_NEXT", "next" }, + { GTK_MENU_DIR_PREV, "GTK_MENU_DIR_PREV", "prev" }, + { 0, NULL, NULL } +}; static GtkEnumValue _gtk_menu_factory_type_values[] = { { GTK_MENU_FACTORY_MENU, "GTK_MENU_FACTORY_MENU", "menu" }, { GTK_MENU_FACTORY_MENU_BAR, "GTK_MENU_FACTORY_MENU_BAR", "menu-bar" }, diff --git a/gtk/gtktypebuiltins_ids.c b/gtk/gtktypebuiltins_ids.c index feb499a9ac..f348794a93 100644 --- a/gtk/gtktypebuiltins_ids.c +++ b/gtk/gtktypebuiltins_ids.c @@ -26,6 +26,8 @@ GTK_TYPE_ENUM, _gtk_justification_values }, { "GtkMatchType", >K_TYPE_MATCH_TYPE, GTK_TYPE_ENUM, _gtk_match_type_values }, + { "GtkMenuDirectionType", >K_TYPE_MENU_DIRECTION_TYPE, + GTK_TYPE_ENUM, _gtk_menu_direction_type_values }, { "GtkMenuFactoryType", >K_TYPE_MENU_FACTORY_TYPE, GTK_TYPE_ENUM, _gtk_menu_factory_type_values }, { "GtkMetricType", >K_TYPE_METRIC_TYPE, diff --git a/gtk/gtktypebuiltins_vars.c b/gtk/gtktypebuiltins_vars.c index e0ae2a8a49..921dfeb271 100644 --- a/gtk/gtktypebuiltins_vars.c +++ b/gtk/gtktypebuiltins_vars.c @@ -13,6 +13,7 @@ GtkType GTK_TYPE_CURVE_TYPE = 0; GtkType GTK_TYPE_DIRECTION_TYPE = 0; GtkType GTK_TYPE_JUSTIFICATION = 0; GtkType GTK_TYPE_MATCH_TYPE = 0; +GtkType GTK_TYPE_MENU_DIRECTION_TYPE = 0; GtkType GTK_TYPE_MENU_FACTORY_TYPE = 0; GtkType GTK_TYPE_METRIC_TYPE = 0; GtkType GTK_TYPE_ORIENTATION = 0; diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 6479639959..f22179a5a7 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -113,7 +113,7 @@ typedef struct _GtkStateData GtkStateData; struct _GtkStateData { GtkStateType state; - guint state_restauration : 1; + guint state_restoration : 1; guint parent_sensitive : 1; }; @@ -2479,7 +2479,7 @@ gtk_widget_set_state (GtkWidget *widget, GtkStateData data; data.state = state; - data.state_restauration = FALSE; + data.state_restoration = FALSE; if (widget->parent) data.parent_sensitive = (GTK_WIDGET_IS_SENSITIVE (widget->parent) != FALSE); else @@ -2524,7 +2524,7 @@ gtk_widget_set_sensitive (GtkWidget *widget, GTK_WIDGET_UNSET_FLAGS (widget, GTK_SENSITIVE); data.state = GTK_WIDGET_STATE (widget); } - data.state_restauration = TRUE; + data.state_restoration = TRUE; if (widget->parent) data.parent_sensitive = (GTK_WIDGET_IS_SENSITIVE (widget->parent) != FALSE); @@ -2566,7 +2566,7 @@ gtk_widget_set_parent (GtkWidget *widget, data.state = GTK_WIDGET_STATE (parent); else data.state = GTK_WIDGET_STATE (widget); - data.state_restauration = FALSE; + data.state_restoration = FALSE; data.parent_sensitive = (GTK_WIDGET_IS_SENSITIVE (parent) != FALSE); gtk_widget_propagate_state (widget, &data); @@ -3767,7 +3767,7 @@ gtk_widget_propagate_state (GtkWidget *widget, if (GTK_WIDGET_IS_SENSITIVE (widget)) { - if (data->state_restauration) + if (data->state_restoration) GTK_WIDGET_STATE (widget) = GTK_WIDGET_SAVED_STATE (widget); else GTK_WIDGET_STATE (widget) = data->state; @@ -3775,7 +3775,7 @@ gtk_widget_propagate_state (GtkWidget *widget, else { GTK_WIDGET_STATE (widget) = GTK_STATE_INSENSITIVE; - if (!data->state_restauration && + if (!data->state_restoration && data->state != GTK_STATE_INSENSITIVE) GTK_WIDGET_SAVED_STATE (widget) = data->state; } @@ -3783,7 +3783,7 @@ gtk_widget_propagate_state (GtkWidget *widget, else { GTK_WIDGET_UNSET_FLAGS (widget, GTK_PARENT_SENSITIVE); - if (!data->state_restauration) + if (!data->state_restoration) { if (data->state != GTK_STATE_INSENSITIVE) GTK_WIDGET_SAVED_STATE (widget) = data->state; diff --git a/gtk/testgtk.c b/gtk/testgtk.c index dec2fa2d9b..6962c27a29 100644 --- a/gtk/testgtk.c +++ b/gtk/testgtk.c @@ -1949,7 +1949,7 @@ create_tooltips (void) */ static GtkWidget* -create_menu (int depth) +create_menu (gint depth, gboolean tearoff) { GtkWidget *menu; GtkWidget *menuitem; @@ -1963,6 +1963,13 @@ create_menu (int depth) menu = gtk_menu_new (); group = NULL; + if (tearoff) + { + menuitem = gtk_tearoff_menu_item_new (); + gtk_menu_append (GTK_MENU (menu), menuitem); + gtk_widget_show (menuitem); + } + for (i = 0, j = 1; i < 5; i++, j++) { sprintf (buf, "item %2d - %d", depth, j); @@ -1975,7 +1982,7 @@ create_menu (int depth) if (i == 3) gtk_widget_set_sensitive (menuitem, FALSE); - gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), create_menu (depth - 1)); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), create_menu (depth - 1, TRUE)); } return menu; @@ -2007,6 +2014,9 @@ create_menus (void) GTK_SIGNAL_FUNC (gtk_true), NULL); + accel_group = gtk_accel_group_new (); + gtk_accel_group_attach (accel_group, GTK_OBJECT (window)); + gtk_window_set_title (GTK_WINDOW (window), "menus"); gtk_container_border_width (GTK_CONTAINER (window), 0); @@ -2019,7 +2029,7 @@ create_menus (void) gtk_box_pack_start (GTK_BOX (box1), menubar, FALSE, TRUE, 0); gtk_widget_show (menubar); - menu = create_menu (2); + menu = create_menu (2, TRUE); menuitem = gtk_menu_item_new_with_label ("test\nline2"); gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), menu); @@ -2027,12 +2037,12 @@ create_menus (void) gtk_widget_show (menuitem); menuitem = gtk_menu_item_new_with_label ("foo"); - gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), create_menu (3)); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), create_menu (3, TRUE)); gtk_menu_bar_append (GTK_MENU_BAR (menubar), menuitem); gtk_widget_show (menuitem); - + menuitem = gtk_menu_item_new_with_label ("bar"); - gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), create_menu (4)); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), create_menu (4, TRUE)); gtk_menu_item_right_justify (GTK_MENU_ITEM (menuitem)); gtk_menu_bar_append (GTK_MENU_BAR (menubar), menuitem); gtk_widget_show (menuitem); @@ -2042,8 +2052,7 @@ create_menus (void) gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); gtk_widget_show (box2); - menu = create_menu (1); - accel_group = gtk_accel_group_get_default (); + menu = create_menu (1, FALSE); gtk_menu_set_accel_group (GTK_MENU (menu), accel_group); menuitem = gtk_check_menu_item_new_with_label ("Accelerate Me"); @@ -2112,6 +2121,99 @@ create_menus (void) gtk_widget_destroy (window); } +static GtkItemFactoryEntry menu_items[] = +{ + { "/_File", NULL, NULL, 0, "<Branch>" }, + { "/File/tearoff1", NULL, NULL, 0, "<Tearoff>" }, + { "/File/_New", "<control>N", NULL, 0 }, + { "/File/_Open", "<control>O", NULL, 0 }, + { "/File/_Save", "<control>S", NULL, 0 }, + { "/File/Save _As...", NULL, NULL, 0 }, + { "/File/sep1", NULL, NULL, 0, "<Separator>" }, + { "/File/_Quit", "<control>Q", NULL, 0 }, + + { "/_Preferences", NULL, NULL, 0, "<Branch>" }, + { "/_Preferences/_Color", NULL, NULL, 0, "<Branch>" }, + { "/_Preferences/Color/_Red", NULL, NULL, 0, "<RadioItem>" }, + { "/_Preferences/Color/_Green", NULL, NULL, 0, "<RadioItem>" }, + { "/_Preferences/Color/_Blue", NULL, NULL, 0, "<RadioItem>" }, + { "/_Preferences/_Shape", NULL, NULL, 0, "<Branch>" }, + { "/_Preferences/Shape/_Square", NULL, NULL, 0, "<RadioItem>" }, + { "/_Preferences/Shape/_Rectangle", NULL, NULL, 0, "<RadioItem>" }, + { "/_Preferences/Shape/_Oval", NULL, NULL, 0, "<RadioItem>" }, + + { "/_Help", NULL, NULL, 0, "<LastBranch>" }, + { "/Help/_About", NULL, NULL, 0 }, +}; + +static int nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]); + +static void +create_item_factory (void) +{ + static GtkWidget *window = NULL; + + if (!window) + { + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *separator; + GtkWidget *label; + GtkWidget *button; + GtkAccelGroup *accel_group; + GtkItemFactory *item_factory; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC(gtk_widget_destroyed), + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete-event", + GTK_SIGNAL_FUNC (gtk_true), + NULL); + + accel_group = gtk_accel_group_new (); + item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>", accel_group); + gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL); + gtk_accel_group_attach (accel_group, GTK_OBJECT (window)); + gtk_window_set_title (GTK_WINDOW (window), "Item Factory"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + + gtk_box_pack_start (GTK_BOX (box1), + gtk_item_factory_get_widget (item_factory, "<main>"), + FALSE, FALSE, 0); + + label = gtk_label_new ("Type\n<alt>\nto start"); + gtk_widget_set_usize (label, 200, 200); + gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5); + gtk_box_pack_start (GTK_BOX (box1), label, TRUE, TRUE, 0); + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + + gtk_widget_show_all (window); + } + else + gtk_widget_destroy (window); +} + /* * GtkScrolledWindow */ @@ -3145,6 +3247,7 @@ create_list (void) separator = gtk_hseparator_new (); gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + box2 = gtk_vbox_new (FALSE, 10); gtk_container_border_width (GTK_CONTAINER (box2), 10); gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); @@ -7291,6 +7394,7 @@ create_main_window (void) { "font selection", create_font_selection }, { "gamma curve", create_gamma_curve }, { "handle box", create_handle_box }, + { "item factory", create_item_factory }, { "list", create_list }, { "menus", create_menus }, { "modal window", create_modal_window }, diff --git a/tests/testgtk.c b/tests/testgtk.c index dec2fa2d9b..6962c27a29 100644 --- a/tests/testgtk.c +++ b/tests/testgtk.c @@ -1949,7 +1949,7 @@ create_tooltips (void) */ static GtkWidget* -create_menu (int depth) +create_menu (gint depth, gboolean tearoff) { GtkWidget *menu; GtkWidget *menuitem; @@ -1963,6 +1963,13 @@ create_menu (int depth) menu = gtk_menu_new (); group = NULL; + if (tearoff) + { + menuitem = gtk_tearoff_menu_item_new (); + gtk_menu_append (GTK_MENU (menu), menuitem); + gtk_widget_show (menuitem); + } + for (i = 0, j = 1; i < 5; i++, j++) { sprintf (buf, "item %2d - %d", depth, j); @@ -1975,7 +1982,7 @@ create_menu (int depth) if (i == 3) gtk_widget_set_sensitive (menuitem, FALSE); - gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), create_menu (depth - 1)); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), create_menu (depth - 1, TRUE)); } return menu; @@ -2007,6 +2014,9 @@ create_menus (void) GTK_SIGNAL_FUNC (gtk_true), NULL); + accel_group = gtk_accel_group_new (); + gtk_accel_group_attach (accel_group, GTK_OBJECT (window)); + gtk_window_set_title (GTK_WINDOW (window), "menus"); gtk_container_border_width (GTK_CONTAINER (window), 0); @@ -2019,7 +2029,7 @@ create_menus (void) gtk_box_pack_start (GTK_BOX (box1), menubar, FALSE, TRUE, 0); gtk_widget_show (menubar); - menu = create_menu (2); + menu = create_menu (2, TRUE); menuitem = gtk_menu_item_new_with_label ("test\nline2"); gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), menu); @@ -2027,12 +2037,12 @@ create_menus (void) gtk_widget_show (menuitem); menuitem = gtk_menu_item_new_with_label ("foo"); - gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), create_menu (3)); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), create_menu (3, TRUE)); gtk_menu_bar_append (GTK_MENU_BAR (menubar), menuitem); gtk_widget_show (menuitem); - + menuitem = gtk_menu_item_new_with_label ("bar"); - gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), create_menu (4)); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), create_menu (4, TRUE)); gtk_menu_item_right_justify (GTK_MENU_ITEM (menuitem)); gtk_menu_bar_append (GTK_MENU_BAR (menubar), menuitem); gtk_widget_show (menuitem); @@ -2042,8 +2052,7 @@ create_menus (void) gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); gtk_widget_show (box2); - menu = create_menu (1); - accel_group = gtk_accel_group_get_default (); + menu = create_menu (1, FALSE); gtk_menu_set_accel_group (GTK_MENU (menu), accel_group); menuitem = gtk_check_menu_item_new_with_label ("Accelerate Me"); @@ -2112,6 +2121,99 @@ create_menus (void) gtk_widget_destroy (window); } +static GtkItemFactoryEntry menu_items[] = +{ + { "/_File", NULL, NULL, 0, "<Branch>" }, + { "/File/tearoff1", NULL, NULL, 0, "<Tearoff>" }, + { "/File/_New", "<control>N", NULL, 0 }, + { "/File/_Open", "<control>O", NULL, 0 }, + { "/File/_Save", "<control>S", NULL, 0 }, + { "/File/Save _As...", NULL, NULL, 0 }, + { "/File/sep1", NULL, NULL, 0, "<Separator>" }, + { "/File/_Quit", "<control>Q", NULL, 0 }, + + { "/_Preferences", NULL, NULL, 0, "<Branch>" }, + { "/_Preferences/_Color", NULL, NULL, 0, "<Branch>" }, + { "/_Preferences/Color/_Red", NULL, NULL, 0, "<RadioItem>" }, + { "/_Preferences/Color/_Green", NULL, NULL, 0, "<RadioItem>" }, + { "/_Preferences/Color/_Blue", NULL, NULL, 0, "<RadioItem>" }, + { "/_Preferences/_Shape", NULL, NULL, 0, "<Branch>" }, + { "/_Preferences/Shape/_Square", NULL, NULL, 0, "<RadioItem>" }, + { "/_Preferences/Shape/_Rectangle", NULL, NULL, 0, "<RadioItem>" }, + { "/_Preferences/Shape/_Oval", NULL, NULL, 0, "<RadioItem>" }, + + { "/_Help", NULL, NULL, 0, "<LastBranch>" }, + { "/Help/_About", NULL, NULL, 0 }, +}; + +static int nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]); + +static void +create_item_factory (void) +{ + static GtkWidget *window = NULL; + + if (!window) + { + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *separator; + GtkWidget *label; + GtkWidget *button; + GtkAccelGroup *accel_group; + GtkItemFactory *item_factory; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC(gtk_widget_destroyed), + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete-event", + GTK_SIGNAL_FUNC (gtk_true), + NULL); + + accel_group = gtk_accel_group_new (); + item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>", accel_group); + gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL); + gtk_accel_group_attach (accel_group, GTK_OBJECT (window)); + gtk_window_set_title (GTK_WINDOW (window), "Item Factory"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + + gtk_box_pack_start (GTK_BOX (box1), + gtk_item_factory_get_widget (item_factory, "<main>"), + FALSE, FALSE, 0); + + label = gtk_label_new ("Type\n<alt>\nto start"); + gtk_widget_set_usize (label, 200, 200); + gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5); + gtk_box_pack_start (GTK_BOX (box1), label, TRUE, TRUE, 0); + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + + gtk_widget_show_all (window); + } + else + gtk_widget_destroy (window); +} + /* * GtkScrolledWindow */ @@ -3145,6 +3247,7 @@ create_list (void) separator = gtk_hseparator_new (); gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + box2 = gtk_vbox_new (FALSE, 10); gtk_container_border_width (GTK_CONTAINER (box2), 10); gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); @@ -7291,6 +7394,7 @@ create_main_window (void) { "font selection", create_font_selection }, { "gamma curve", create_gamma_curve }, { "handle box", create_handle_box }, + { "item factory", create_item_factory }, { "list", create_list }, { "menus", create_menus }, { "modal window", create_modal_window }, |