diff options
56 files changed, 3349 insertions, 2127 deletions
@@ -1,3 +1,69 @@ +Mon Nov 12 23:08:37 2001 Tim Janik <timj@gtk.org> + + * gtk/maketypes.awk: fix type utils generation on unix. + + * gtk/gtkaccelmap.[hc]: new files, implementing a global accelerator + registry. + + * gtk/gtkaccelgroup.[hc]: major API/implementation revamp: + removed GTK_ACCEL_SIGNAL_VISIBLE, gtk_accel_group_get_default, + gtk_accel_group_get_entry, gtk_accel_group_(un)lock_entry, + gtk_accel_group_add/remove, gtk_accel_group_handle_add/remove, + gtk_accel_group_create_add/remove, gtk_accel_group_entries_from_object. + introduced ::accel_changed signal for change notification, and + gtk_accel_group_connect/disconnect to connect closures to accel groups. + made gtk_accel_group_attach/detach and gtk_accel_group_activate private + functions. + deprecated gtk_accel_group_ref/unref. + + * gtk/gtkaccellabel.[hc]: changes to make accellabels pay attention + to accel group changed notification and basically operate on closures. + removed gtk_accel_label_get_accel_object and + gtk_accel_label_set_accel_object. + introduced gtk_accel_label_set_accel_closure, and for convenience, + gtk_accel_label_set_accel_widget. + + * gtk/gtkitemfactory.[hc]: removed accelerator propagation code + which mostly moved into gtkaccelmap.[hc]. + removed gtk_item_factory_parse_rc*, gtk_item_factory_dump_* + and gtk_item_factory_print_func. + + * gtk/gtkmain.c: call _gtk_accel_map_init(). + + * gtk/gtkmenuitem.[hc]: introduced gtk_menu_item_set_accel_path(), + that associates an accelerator path with menu items, through which + persistent accelerator settings on menu items are enabled. + + * gtk/gtkmenu.[hc]: added gtk_menu_set_accel_path() so accelerator + paths of menu item can be default constructed to allow installation + of accelerators on menu items that don't come with an accelerator + binding by default. + + * gtk/gtksettings.c: fix STRING type rc settings by special casing + them appropriately in the parser. + + * gtk/gtksignal.[hc]: allow a class function offset of 0 for + gtk_signal_newv(). + + * gtk/gtkwidget.[hc]: accelerator API revamp. + removed ::accelerator_add/remove signals, gtk_widget_accelerator_signal, + gtk_widget_accelerators_locked, gtk_widget_remove_accelerators and + gtk_widget_(un)lock_accelerators. + accelerators maintained through gtk_widget_add/remove_accelerator() + are not runtime changable now, the correct sequence to setup a + widget for runtime changable accelerators is now: + gtk_accel_map_add_entry(accel_path, key, mods); + _gtk_widget_set_accel_path(widget, accel_path, accel_group); + + * gtk/gtkwindow.[hc]: accelerator changes, proxy and coalesce accel + group changes (as well as mnemonic changes) through the new signal + ::accels_changed. + +Sat Nov 10 12:08:56 2001 Tim Janik <timj@gtk.org> + + * gtk/gtksettings.c (_gtk_settings_parse_convert): properly handle + GString->string conversions. + Mon Nov 12 19:33:52 2001 Owen Taylor <otaylor@redhat.com> * gtk/gtkmessagedialog.c (gtk_message_dialog_new): Warn diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index 51ac8c00f..31c26db01 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -1,3 +1,69 @@ +Mon Nov 12 23:08:37 2001 Tim Janik <timj@gtk.org> + + * gtk/maketypes.awk: fix type utils generation on unix. + + * gtk/gtkaccelmap.[hc]: new files, implementing a global accelerator + registry. + + * gtk/gtkaccelgroup.[hc]: major API/implementation revamp: + removed GTK_ACCEL_SIGNAL_VISIBLE, gtk_accel_group_get_default, + gtk_accel_group_get_entry, gtk_accel_group_(un)lock_entry, + gtk_accel_group_add/remove, gtk_accel_group_handle_add/remove, + gtk_accel_group_create_add/remove, gtk_accel_group_entries_from_object. + introduced ::accel_changed signal for change notification, and + gtk_accel_group_connect/disconnect to connect closures to accel groups. + made gtk_accel_group_attach/detach and gtk_accel_group_activate private + functions. + deprecated gtk_accel_group_ref/unref. + + * gtk/gtkaccellabel.[hc]: changes to make accellabels pay attention + to accel group changed notification and basically operate on closures. + removed gtk_accel_label_get_accel_object and + gtk_accel_label_set_accel_object. + introduced gtk_accel_label_set_accel_closure, and for convenience, + gtk_accel_label_set_accel_widget. + + * gtk/gtkitemfactory.[hc]: removed accelerator propagation code + which mostly moved into gtkaccelmap.[hc]. + removed gtk_item_factory_parse_rc*, gtk_item_factory_dump_* + and gtk_item_factory_print_func. + + * gtk/gtkmain.c: call _gtk_accel_map_init(). + + * gtk/gtkmenuitem.[hc]: introduced gtk_menu_item_set_accel_path(), + that associates an accelerator path with menu items, through which + persistent accelerator settings on menu items are enabled. + + * gtk/gtkmenu.[hc]: added gtk_menu_set_accel_path() so accelerator + paths of menu item can be default constructed to allow installation + of accelerators on menu items that don't come with an accelerator + binding by default. + + * gtk/gtksettings.c: fix STRING type rc settings by special casing + them appropriately in the parser. + + * gtk/gtksignal.[hc]: allow a class function offset of 0 for + gtk_signal_newv(). + + * gtk/gtkwidget.[hc]: accelerator API revamp. + removed ::accelerator_add/remove signals, gtk_widget_accelerator_signal, + gtk_widget_accelerators_locked, gtk_widget_remove_accelerators and + gtk_widget_(un)lock_accelerators. + accelerators maintained through gtk_widget_add/remove_accelerator() + are not runtime changable now, the correct sequence to setup a + widget for runtime changable accelerators is now: + gtk_accel_map_add_entry(accel_path, key, mods); + _gtk_widget_set_accel_path(widget, accel_path, accel_group); + + * gtk/gtkwindow.[hc]: accelerator changes, proxy and coalesce accel + group changes (as well as mnemonic changes) through the new signal + ::accels_changed. + +Sat Nov 10 12:08:56 2001 Tim Janik <timj@gtk.org> + + * gtk/gtksettings.c (_gtk_settings_parse_convert): properly handle + GString->string conversions. + Mon Nov 12 19:33:52 2001 Owen Taylor <otaylor@redhat.com> * gtk/gtkmessagedialog.c (gtk_message_dialog_new): Warn diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 51ac8c00f..31c26db01 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,69 @@ +Mon Nov 12 23:08:37 2001 Tim Janik <timj@gtk.org> + + * gtk/maketypes.awk: fix type utils generation on unix. + + * gtk/gtkaccelmap.[hc]: new files, implementing a global accelerator + registry. + + * gtk/gtkaccelgroup.[hc]: major API/implementation revamp: + removed GTK_ACCEL_SIGNAL_VISIBLE, gtk_accel_group_get_default, + gtk_accel_group_get_entry, gtk_accel_group_(un)lock_entry, + gtk_accel_group_add/remove, gtk_accel_group_handle_add/remove, + gtk_accel_group_create_add/remove, gtk_accel_group_entries_from_object. + introduced ::accel_changed signal for change notification, and + gtk_accel_group_connect/disconnect to connect closures to accel groups. + made gtk_accel_group_attach/detach and gtk_accel_group_activate private + functions. + deprecated gtk_accel_group_ref/unref. + + * gtk/gtkaccellabel.[hc]: changes to make accellabels pay attention + to accel group changed notification and basically operate on closures. + removed gtk_accel_label_get_accel_object and + gtk_accel_label_set_accel_object. + introduced gtk_accel_label_set_accel_closure, and for convenience, + gtk_accel_label_set_accel_widget. + + * gtk/gtkitemfactory.[hc]: removed accelerator propagation code + which mostly moved into gtkaccelmap.[hc]. + removed gtk_item_factory_parse_rc*, gtk_item_factory_dump_* + and gtk_item_factory_print_func. + + * gtk/gtkmain.c: call _gtk_accel_map_init(). + + * gtk/gtkmenuitem.[hc]: introduced gtk_menu_item_set_accel_path(), + that associates an accelerator path with menu items, through which + persistent accelerator settings on menu items are enabled. + + * gtk/gtkmenu.[hc]: added gtk_menu_set_accel_path() so accelerator + paths of menu item can be default constructed to allow installation + of accelerators on menu items that don't come with an accelerator + binding by default. + + * gtk/gtksettings.c: fix STRING type rc settings by special casing + them appropriately in the parser. + + * gtk/gtksignal.[hc]: allow a class function offset of 0 for + gtk_signal_newv(). + + * gtk/gtkwidget.[hc]: accelerator API revamp. + removed ::accelerator_add/remove signals, gtk_widget_accelerator_signal, + gtk_widget_accelerators_locked, gtk_widget_remove_accelerators and + gtk_widget_(un)lock_accelerators. + accelerators maintained through gtk_widget_add/remove_accelerator() + are not runtime changable now, the correct sequence to setup a + widget for runtime changable accelerators is now: + gtk_accel_map_add_entry(accel_path, key, mods); + _gtk_widget_set_accel_path(widget, accel_path, accel_group); + + * gtk/gtkwindow.[hc]: accelerator changes, proxy and coalesce accel + group changes (as well as mnemonic changes) through the new signal + ::accels_changed. + +Sat Nov 10 12:08:56 2001 Tim Janik <timj@gtk.org> + + * gtk/gtksettings.c (_gtk_settings_parse_convert): properly handle + GString->string conversions. + Mon Nov 12 19:33:52 2001 Owen Taylor <otaylor@redhat.com> * gtk/gtkmessagedialog.c (gtk_message_dialog_new): Warn diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index 51ac8c00f..31c26db01 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,69 @@ +Mon Nov 12 23:08:37 2001 Tim Janik <timj@gtk.org> + + * gtk/maketypes.awk: fix type utils generation on unix. + + * gtk/gtkaccelmap.[hc]: new files, implementing a global accelerator + registry. + + * gtk/gtkaccelgroup.[hc]: major API/implementation revamp: + removed GTK_ACCEL_SIGNAL_VISIBLE, gtk_accel_group_get_default, + gtk_accel_group_get_entry, gtk_accel_group_(un)lock_entry, + gtk_accel_group_add/remove, gtk_accel_group_handle_add/remove, + gtk_accel_group_create_add/remove, gtk_accel_group_entries_from_object. + introduced ::accel_changed signal for change notification, and + gtk_accel_group_connect/disconnect to connect closures to accel groups. + made gtk_accel_group_attach/detach and gtk_accel_group_activate private + functions. + deprecated gtk_accel_group_ref/unref. + + * gtk/gtkaccellabel.[hc]: changes to make accellabels pay attention + to accel group changed notification and basically operate on closures. + removed gtk_accel_label_get_accel_object and + gtk_accel_label_set_accel_object. + introduced gtk_accel_label_set_accel_closure, and for convenience, + gtk_accel_label_set_accel_widget. + + * gtk/gtkitemfactory.[hc]: removed accelerator propagation code + which mostly moved into gtkaccelmap.[hc]. + removed gtk_item_factory_parse_rc*, gtk_item_factory_dump_* + and gtk_item_factory_print_func. + + * gtk/gtkmain.c: call _gtk_accel_map_init(). + + * gtk/gtkmenuitem.[hc]: introduced gtk_menu_item_set_accel_path(), + that associates an accelerator path with menu items, through which + persistent accelerator settings on menu items are enabled. + + * gtk/gtkmenu.[hc]: added gtk_menu_set_accel_path() so accelerator + paths of menu item can be default constructed to allow installation + of accelerators on menu items that don't come with an accelerator + binding by default. + + * gtk/gtksettings.c: fix STRING type rc settings by special casing + them appropriately in the parser. + + * gtk/gtksignal.[hc]: allow a class function offset of 0 for + gtk_signal_newv(). + + * gtk/gtkwidget.[hc]: accelerator API revamp. + removed ::accelerator_add/remove signals, gtk_widget_accelerator_signal, + gtk_widget_accelerators_locked, gtk_widget_remove_accelerators and + gtk_widget_(un)lock_accelerators. + accelerators maintained through gtk_widget_add/remove_accelerator() + are not runtime changable now, the correct sequence to setup a + widget for runtime changable accelerators is now: + gtk_accel_map_add_entry(accel_path, key, mods); + _gtk_widget_set_accel_path(widget, accel_path, accel_group); + + * gtk/gtkwindow.[hc]: accelerator changes, proxy and coalesce accel + group changes (as well as mnemonic changes) through the new signal + ::accels_changed. + +Sat Nov 10 12:08:56 2001 Tim Janik <timj@gtk.org> + + * gtk/gtksettings.c (_gtk_settings_parse_convert): properly handle + GString->string conversions. + Mon Nov 12 19:33:52 2001 Owen Taylor <otaylor@redhat.com> * gtk/gtkmessagedialog.c (gtk_message_dialog_new): Warn diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index 51ac8c00f..31c26db01 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,69 @@ +Mon Nov 12 23:08:37 2001 Tim Janik <timj@gtk.org> + + * gtk/maketypes.awk: fix type utils generation on unix. + + * gtk/gtkaccelmap.[hc]: new files, implementing a global accelerator + registry. + + * gtk/gtkaccelgroup.[hc]: major API/implementation revamp: + removed GTK_ACCEL_SIGNAL_VISIBLE, gtk_accel_group_get_default, + gtk_accel_group_get_entry, gtk_accel_group_(un)lock_entry, + gtk_accel_group_add/remove, gtk_accel_group_handle_add/remove, + gtk_accel_group_create_add/remove, gtk_accel_group_entries_from_object. + introduced ::accel_changed signal for change notification, and + gtk_accel_group_connect/disconnect to connect closures to accel groups. + made gtk_accel_group_attach/detach and gtk_accel_group_activate private + functions. + deprecated gtk_accel_group_ref/unref. + + * gtk/gtkaccellabel.[hc]: changes to make accellabels pay attention + to accel group changed notification and basically operate on closures. + removed gtk_accel_label_get_accel_object and + gtk_accel_label_set_accel_object. + introduced gtk_accel_label_set_accel_closure, and for convenience, + gtk_accel_label_set_accel_widget. + + * gtk/gtkitemfactory.[hc]: removed accelerator propagation code + which mostly moved into gtkaccelmap.[hc]. + removed gtk_item_factory_parse_rc*, gtk_item_factory_dump_* + and gtk_item_factory_print_func. + + * gtk/gtkmain.c: call _gtk_accel_map_init(). + + * gtk/gtkmenuitem.[hc]: introduced gtk_menu_item_set_accel_path(), + that associates an accelerator path with menu items, through which + persistent accelerator settings on menu items are enabled. + + * gtk/gtkmenu.[hc]: added gtk_menu_set_accel_path() so accelerator + paths of menu item can be default constructed to allow installation + of accelerators on menu items that don't come with an accelerator + binding by default. + + * gtk/gtksettings.c: fix STRING type rc settings by special casing + them appropriately in the parser. + + * gtk/gtksignal.[hc]: allow a class function offset of 0 for + gtk_signal_newv(). + + * gtk/gtkwidget.[hc]: accelerator API revamp. + removed ::accelerator_add/remove signals, gtk_widget_accelerator_signal, + gtk_widget_accelerators_locked, gtk_widget_remove_accelerators and + gtk_widget_(un)lock_accelerators. + accelerators maintained through gtk_widget_add/remove_accelerator() + are not runtime changable now, the correct sequence to setup a + widget for runtime changable accelerators is now: + gtk_accel_map_add_entry(accel_path, key, mods); + _gtk_widget_set_accel_path(widget, accel_path, accel_group); + + * gtk/gtkwindow.[hc]: accelerator changes, proxy and coalesce accel + group changes (as well as mnemonic changes) through the new signal + ::accels_changed. + +Sat Nov 10 12:08:56 2001 Tim Janik <timj@gtk.org> + + * gtk/gtksettings.c (_gtk_settings_parse_convert): properly handle + GString->string conversions. + Mon Nov 12 19:33:52 2001 Owen Taylor <otaylor@redhat.com> * gtk/gtkmessagedialog.c (gtk_message_dialog_new): Warn diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 51ac8c00f..31c26db01 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,69 @@ +Mon Nov 12 23:08:37 2001 Tim Janik <timj@gtk.org> + + * gtk/maketypes.awk: fix type utils generation on unix. + + * gtk/gtkaccelmap.[hc]: new files, implementing a global accelerator + registry. + + * gtk/gtkaccelgroup.[hc]: major API/implementation revamp: + removed GTK_ACCEL_SIGNAL_VISIBLE, gtk_accel_group_get_default, + gtk_accel_group_get_entry, gtk_accel_group_(un)lock_entry, + gtk_accel_group_add/remove, gtk_accel_group_handle_add/remove, + gtk_accel_group_create_add/remove, gtk_accel_group_entries_from_object. + introduced ::accel_changed signal for change notification, and + gtk_accel_group_connect/disconnect to connect closures to accel groups. + made gtk_accel_group_attach/detach and gtk_accel_group_activate private + functions. + deprecated gtk_accel_group_ref/unref. + + * gtk/gtkaccellabel.[hc]: changes to make accellabels pay attention + to accel group changed notification and basically operate on closures. + removed gtk_accel_label_get_accel_object and + gtk_accel_label_set_accel_object. + introduced gtk_accel_label_set_accel_closure, and for convenience, + gtk_accel_label_set_accel_widget. + + * gtk/gtkitemfactory.[hc]: removed accelerator propagation code + which mostly moved into gtkaccelmap.[hc]. + removed gtk_item_factory_parse_rc*, gtk_item_factory_dump_* + and gtk_item_factory_print_func. + + * gtk/gtkmain.c: call _gtk_accel_map_init(). + + * gtk/gtkmenuitem.[hc]: introduced gtk_menu_item_set_accel_path(), + that associates an accelerator path with menu items, through which + persistent accelerator settings on menu items are enabled. + + * gtk/gtkmenu.[hc]: added gtk_menu_set_accel_path() so accelerator + paths of menu item can be default constructed to allow installation + of accelerators on menu items that don't come with an accelerator + binding by default. + + * gtk/gtksettings.c: fix STRING type rc settings by special casing + them appropriately in the parser. + + * gtk/gtksignal.[hc]: allow a class function offset of 0 for + gtk_signal_newv(). + + * gtk/gtkwidget.[hc]: accelerator API revamp. + removed ::accelerator_add/remove signals, gtk_widget_accelerator_signal, + gtk_widget_accelerators_locked, gtk_widget_remove_accelerators and + gtk_widget_(un)lock_accelerators. + accelerators maintained through gtk_widget_add/remove_accelerator() + are not runtime changable now, the correct sequence to setup a + widget for runtime changable accelerators is now: + gtk_accel_map_add_entry(accel_path, key, mods); + _gtk_widget_set_accel_path(widget, accel_path, accel_group); + + * gtk/gtkwindow.[hc]: accelerator changes, proxy and coalesce accel + group changes (as well as mnemonic changes) through the new signal + ::accels_changed. + +Sat Nov 10 12:08:56 2001 Tim Janik <timj@gtk.org> + + * gtk/gtksettings.c (_gtk_settings_parse_convert): properly handle + GString->string conversions. + Mon Nov 12 19:33:52 2001 Owen Taylor <otaylor@redhat.com> * gtk/gtkmessagedialog.c (gtk_message_dialog_new): Warn diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 51ac8c00f..31c26db01 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,69 @@ +Mon Nov 12 23:08:37 2001 Tim Janik <timj@gtk.org> + + * gtk/maketypes.awk: fix type utils generation on unix. + + * gtk/gtkaccelmap.[hc]: new files, implementing a global accelerator + registry. + + * gtk/gtkaccelgroup.[hc]: major API/implementation revamp: + removed GTK_ACCEL_SIGNAL_VISIBLE, gtk_accel_group_get_default, + gtk_accel_group_get_entry, gtk_accel_group_(un)lock_entry, + gtk_accel_group_add/remove, gtk_accel_group_handle_add/remove, + gtk_accel_group_create_add/remove, gtk_accel_group_entries_from_object. + introduced ::accel_changed signal for change notification, and + gtk_accel_group_connect/disconnect to connect closures to accel groups. + made gtk_accel_group_attach/detach and gtk_accel_group_activate private + functions. + deprecated gtk_accel_group_ref/unref. + + * gtk/gtkaccellabel.[hc]: changes to make accellabels pay attention + to accel group changed notification and basically operate on closures. + removed gtk_accel_label_get_accel_object and + gtk_accel_label_set_accel_object. + introduced gtk_accel_label_set_accel_closure, and for convenience, + gtk_accel_label_set_accel_widget. + + * gtk/gtkitemfactory.[hc]: removed accelerator propagation code + which mostly moved into gtkaccelmap.[hc]. + removed gtk_item_factory_parse_rc*, gtk_item_factory_dump_* + and gtk_item_factory_print_func. + + * gtk/gtkmain.c: call _gtk_accel_map_init(). + + * gtk/gtkmenuitem.[hc]: introduced gtk_menu_item_set_accel_path(), + that associates an accelerator path with menu items, through which + persistent accelerator settings on menu items are enabled. + + * gtk/gtkmenu.[hc]: added gtk_menu_set_accel_path() so accelerator + paths of menu item can be default constructed to allow installation + of accelerators on menu items that don't come with an accelerator + binding by default. + + * gtk/gtksettings.c: fix STRING type rc settings by special casing + them appropriately in the parser. + + * gtk/gtksignal.[hc]: allow a class function offset of 0 for + gtk_signal_newv(). + + * gtk/gtkwidget.[hc]: accelerator API revamp. + removed ::accelerator_add/remove signals, gtk_widget_accelerator_signal, + gtk_widget_accelerators_locked, gtk_widget_remove_accelerators and + gtk_widget_(un)lock_accelerators. + accelerators maintained through gtk_widget_add/remove_accelerator() + are not runtime changable now, the correct sequence to setup a + widget for runtime changable accelerators is now: + gtk_accel_map_add_entry(accel_path, key, mods); + _gtk_widget_set_accel_path(widget, accel_path, accel_group); + + * gtk/gtkwindow.[hc]: accelerator changes, proxy and coalesce accel + group changes (as well as mnemonic changes) through the new signal + ::accels_changed. + +Sat Nov 10 12:08:56 2001 Tim Janik <timj@gtk.org> + + * gtk/gtksettings.c (_gtk_settings_parse_convert): properly handle + GString->string conversions. + Mon Nov 12 19:33:52 2001 Owen Taylor <otaylor@redhat.com> * gtk/gtkmessagedialog.c (gtk_message_dialog_new): Warn diff --git a/demos/gtk-demo/appwindow.c b/demos/gtk-demo/appwindow.c index c052bcbc6..5020152ff 100644 --- a/demos/gtk-demo/appwindow.c +++ b/demos/gtk-demo/appwindow.c @@ -213,8 +213,8 @@ do_appwindow (void) */ accel_group = gtk_accel_group_new (); - gtk_accel_group_attach (accel_group, G_OBJECT (window)); - gtk_accel_group_unref (accel_group); + gtk_window_add_accel_group (window, accel_group); + g_object_unref (accel_group); item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>", accel_group); diff --git a/demos/gtk-demo/item_factory.c b/demos/gtk-demo/item_factory.c index 34f3cb51d..390f4a75c 100644 --- a/demos/gtk-demo/item_factory.c +++ b/demos/gtk-demo/item_factory.c @@ -68,7 +68,7 @@ do_item_factory (void) item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>", accel_group); g_object_set_data_full (G_OBJECT (window), "<main>", item_factory, (GDestroyNotify) g_object_unref); - gtk_accel_group_attach (accel_group, G_OBJECT (window)); + gtk_window_add_accel_group (window, accel_group); gtk_window_set_title (GTK_WINDOW (window), "Item Factory"); gtk_container_set_border_width (GTK_CONTAINER (window), 0); gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL); diff --git a/demos/gtk-demo/menus.c b/demos/gtk-demo/menus.c index 99899a7d3..60e20e135 100644 --- a/demos/gtk-demo/menus.c +++ b/demos/gtk-demo/menus.c @@ -98,7 +98,7 @@ do_menus (void) G_CALLBACK (gtk_true), NULL); accel_group = gtk_accel_group_new (); - gtk_accel_group_attach (accel_group, G_OBJECT (window)); + gtk_window_add_accel_group (window, accel_group); gtk_window_set_title (GTK_WINDOW (window), "menus"); gtk_container_set_border_width (GTK_CONTAINER (window), 0); @@ -150,7 +150,7 @@ do_menus (void) accel_group, GDK_F1, 0, - GTK_ACCEL_VISIBLE | GTK_ACCEL_SIGNAL_VISIBLE); + GTK_ACCEL_VISIBLE); menuitem = gtk_check_menu_item_new_with_label ("Accelerator Locked"); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); gtk_widget_show (menuitem); @@ -175,7 +175,6 @@ do_menus (void) GDK_F3, 0, GTK_ACCEL_VISIBLE); - gtk_widget_lock_accelerators (menuitem); optionmenu = gtk_option_menu_new (); gtk_option_menu_set_menu (GTK_OPTION_MENU (optionmenu), menu); diff --git a/docs/reference/ChangeLog b/docs/reference/ChangeLog index 963916c9c..6a8b1c513 100644 --- a/docs/reference/ChangeLog +++ b/docs/reference/ChangeLog @@ -1,3 +1,7 @@ +Mon Nov 12 23:06:38 2001 Tim Janik <timj@gtk.org> + + * added gtkaccelmap.sgml. other updates. + 2001-11-11 Matthias Clasen <matthiasc@poet.de> * gdk-pixbuf/gdk-pixbuf-rendering.sgml, diff --git a/docs/reference/gtk/gtk-docs.sgml b/docs/reference/gtk/gtk-docs.sgml index fd0c2acdb..50ee7a9be 100644 --- a/docs/reference/gtk/gtk-docs.sgml +++ b/docs/reference/gtk/gtk-docs.sgml @@ -126,7 +126,8 @@ <!entity gtk-Styles SYSTEM "sgml/gtkstyle.sgml"> <!entity gtk-Themes SYSTEM "sgml/gtkthemes.sgml"> <!entity gtk-Resource-Files SYSTEM "sgml/gtkrc.sgml"> -<!entity gtk-Keyboard-Accelerators SYSTEM "sgml/gtkaccelgroup.sgml"> +<!entity GtkAccelGroup SYSTEM "sgml/gtkaccelgroup.sgml"> +<!entity gtk-accel-map SYSTEM "sgml/gtkaccelmap.sgml"> <!entity gtk-Selections SYSTEM "sgml/gtkselection.sgml"> <!entity gtk-Clipboards SYSTEM "sgml/gtkclipboard.sgml"> <!entity gtk-Drag-and-Drop SYSTEM "sgml/gtkdnd.sgml"> @@ -248,7 +249,8 @@ that is, GUI components such as #GtkButton or #GtkTextView. <title>GTK+ Core Reference</title> >k-General; - >k-Keyboard-Accelerators; + &GtkAccelGroup; + >k-accel-map; >k-Clipboards; >k-Drag-and-Drop; >k-Stock-Items; diff --git a/docs/reference/gtk/gtk-sections.txt b/docs/reference/gtk/gtk-sections.txt index 37dbea2ec..e184fd744 100644 --- a/docs/reference/gtk/gtk-sections.txt +++ b/docs/reference/gtk/gtk-sections.txt @@ -2,6 +2,52 @@ <INCLUDE>gtk/gtk.h</INCLUDE> <SECTION> +<FILE>gtkaccelgroup</FILE> +<TITLE>Keyboard Accelerators</TITLE> +GtkAccelGroup +gtk_accel_group_get_type +gtk_accel_group_new +gtk_accel_group_connect +gtk_accel_group_disconnect +gtk_accel_group_query +gtk_accel_group_activate +gtk_accel_groups_activate +gtk_accel_group_lock +gtk_accel_group_unlock +gtk_accelerator_valid +gtk_accelerator_parse +gtk_accelerator_name +gtk_accelerator_set_default_mod_mask +gtk_accelerator_get_default_mod_mask +<SUBSECTION Private> +<SUBSECTION Standard> +GtkAccelGroupClass +GTK_TYPE_ACCEL_GROUP +GTK_ACCEL_GROUP +GTK_IS_ACCEL_GROUP +GTK_ACCEL_GROUP_CLASS +GTK_IS_ACCEL_GROUP_CLASS +GTK_ACCEL_GROUP_GET_CLASS +</SECTION> + +<SECTION> +<FILE>gtkaccelmap</FILE> +<TITLE>Accelerator Maps</TITLE> +GtkAccelMapNotify +GtkAccelMapForeach +gtk_accel_map_add_entry +gtk_accel_map_lookup_entry +gtk_accel_map_change_entry +gtk_accel_map_add_notifer +gtk_accel_map_remove_notifer +gtk_accel_map_load +gtk_accel_map_save +gtk_accel_map_foreach +gtk_accel_map_load_fd +gtk_accel_map_save_fd +</SECTION> + +<SECTION> <FILE>gtkaccellabel</FILE> <TITLE>GtkAccelLabel</TITLE> GtkAccelLabel @@ -1428,6 +1474,7 @@ gtk_menu_reorder_child gtk_menu_popup gtk_menu_set_accel_group gtk_menu_get_accel_group +gtk_menu_set_accel_path gtk_menu_set_title gtk_menu_get_tearoff_state gtk_menu_get_title @@ -1481,6 +1528,7 @@ gtk_menu_item_new_with_label gtk_menu_item_new_with_mnemonic gtk_menu_item_set_right_justified gtk_menu_item_set_submenu +gtk_menu_item_set_accel_path gtk_menu_item_remove_submenu gtk_menu_item_select gtk_menu_item_deselect @@ -3881,49 +3929,6 @@ GtkRcContext </SECTION> <SECTION> -<FILE>gtkaccelgroup</FILE> -<TITLE>Keyboard Accelerators</TITLE> -GtkAccelGroup -gtk_accel_group_new -gtk_accel_group_get_default -gtk_accel_group_ref -gtk_accel_group_unref -gtk_accel_group_activate -gtk_accel_groups_activate -gtk_accel_group_attach -gtk_accel_group_detach -gtk_accel_group_add -gtk_accel_group_remove -gtk_accel_group_lock -gtk_accel_group_unlock -gtk_accelerator_valid -gtk_accelerator_parse -gtk_accelerator_name -gtk_accelerator_set_default_mod_mask -gtk_accelerator_get_default_mod_mask -<SUBSECTION Private> -GtkAccelEntry -gtk_accel_group_get_type -gtk_accel_group_get_entry -gtk_accel_group_lock_entry -gtk_accel_group_unlock_entry -gtk_accel_group_handle_add -gtk_accel_group_handle_remove -gtk_accel_group_create_add -gtk_accel_group_create_remove -gtk_accel_groups_from_object -gtk_accel_group_entries_from_object -<SUBSECTION Standard> -GtkAccelGroupClass -GTK_ACCEL_GROUP -GTK_TYPE_ACCEL_GROUP -GTK_ACCEL_GROUP_CLASS -GTK_ACCEL_GROUP_GET_CLASS -GTK_IS_ACCEL_GROUP -GTK_IS_ACCEL_GROUP_CLASS -</SECTION> - -<SECTION> <FILE>gtkselection</FILE> <TITLE>Selections</TITLE> GtkTargetEntry diff --git a/docs/reference/gtk/tmpl/gtk-unused.sgml b/docs/reference/gtk/tmpl/gtk-unused.sgml index 91412b12e..86e08b9c7 100644 --- a/docs/reference/gtk/tmpl/gtk-unused.sgml +++ b/docs/reference/gtk/tmpl/gtk-unused.sgml @@ -495,9 +495,9 @@ This is a private struct used by GTK+ internally, don't worry about it. @object: @signal_id: -<!-- ##### ARG GtkAccelLabel:accel-widget ##### --> +<!-- ##### ARG GtkAccelLabel:accel-object ##### --> <para> -The widget whose accelerators are to be shown by the #GtkAccelLabel. + </para> @@ -1186,6 +1186,29 @@ produce superscript and subscript. @parent: @priv: +<!-- ##### USER_FUNCTION GtkTreeViewDraggableFunc ##### --> +<para> + +</para> + +@tree_view: +@context: +@path: +@user_data: +@Returns: + +<!-- ##### USER_FUNCTION GtkTreeViewDroppableFunc ##### --> +<para> + +</para> + +@tree_view: +@context: +@path: +@pos: +@user_data: +@Returns: + <!-- ##### ARG GtkVScale:adjustment ##### --> <para> the #GtkAdjustment which sets the range of the scale. @@ -1207,6 +1230,18 @@ the #GtkAdjustment which sets the range of the scale. @arg1: @Returns: +<!-- ##### SIGNAL GtkWidget::add-accelerator ##### --> +<para> + +</para> + +@widget: the object which received the signal. +@accel_signal_id: +@accel_group: +@accel_key: +@accel_mods: +@accel_flags: + <!-- ##### SIGNAL GtkWidget::debug-msg ##### --> <para> @@ -1237,6 +1272,16 @@ the #GtkAdjustment which sets the range of the scale. @widget: the object which received the signal. +<!-- ##### SIGNAL GtkWidget::remove-accelerator ##### --> +<para> + +</para> + +@widget: the object which received the signal. +@accel_group: +@accel_key: +@accel_mods: + <!-- ##### ARG GtkWidget:height ##### --> <para> @@ -1273,6 +1318,37 @@ If the window shrinks automatically when widgets within it shrink. </para> +<!-- ##### FUNCTION gtk_accel_group_activate ##### --> +<para> + +</para> + +@accel_group: +@accel_key: +@accel_mods: +@Returns: + +<!-- ##### FUNCTION gtk_accel_group_add ##### --> +<para> + +</para> + +@accel_group: +@path: +@accel_key: +@accel_mods: +@accel_flags: +@object: +@accel_signal: + +<!-- ##### FUNCTION gtk_accel_group_attach ##### --> +<para> + +</para> + +@accel_group: +@object: + <!-- ##### FUNCTION gtk_accel_group_create_add ##### --> <para> @@ -1293,6 +1369,14 @@ If the window shrinks automatically when widgets within it shrink. @handler_offset: @Returns: +<!-- ##### FUNCTION gtk_accel_group_detach ##### --> +<para> + +</para> + +@accel_group: +@object: + <!-- ##### FUNCTION gtk_accel_group_entries_from_object ##### --> <para> @@ -1301,6 +1385,13 @@ If the window shrinks automatically when widgets within it shrink. @object: @Returns: +<!-- ##### FUNCTION gtk_accel_group_get_default ##### --> +<para> + +</para> + +@Returns: + <!-- ##### FUNCTION gtk_accel_group_get_entry ##### --> <para> @@ -1342,6 +1433,24 @@ If the window shrinks automatically when widgets within it shrink. @accel_key: @accel_mods: +<!-- ##### MACRO gtk_accel_group_ref ##### --> +<para> + +</para> + +@Returns: +@accel_group: + +<!-- ##### FUNCTION gtk_accel_group_remove ##### --> +<para> + +</para> + +@accel_group: +@accel_key: +@accel_mods: +@object: + <!-- ##### FUNCTION gtk_accel_group_unlock_entry ##### --> <para> @@ -1351,6 +1460,13 @@ If the window shrinks automatically when widgets within it shrink. @accel_key: @accel_mods: +<!-- ##### MACRO gtk_accel_group_unref ##### --> +<para> + +</para> + +@accel_group: + <!-- ##### FUNCTION gtk_accel_groups_from_object ##### --> <para> @@ -1359,6 +1475,22 @@ If the window shrinks automatically when widgets within it shrink. @object: @Returns: +<!-- ##### FUNCTION gtk_accel_label_get_accel_object ##### --> +<para> + +</para> + +@accel_label: +@Returns: + +<!-- ##### FUNCTION gtk_accel_label_set_accel_object ##### --> +<para> + +</para> + +@accel_label: +@accel_object: + <!-- ##### FUNCTION gtk_arg_copy ##### --> <para> It will either copy data into an existing argument or allocate a new argument @@ -1905,6 +2037,54 @@ Get the type of GtkIdentifier. @Returns: +<!-- ##### FUNCTION gtk_item_factory_dump_items ##### --> +<para> + +</para> + +@path_pspec: +@modified_only: +@print_func: +@func_data: + +<!-- ##### FUNCTION gtk_item_factory_dump_rc ##### --> +<para> + +</para> + +@file_name: +@path_pspec: +@modified_only: + +<!-- ##### FUNCTION gtk_item_factory_parse_rc ##### --> +<para> + +</para> + +@file_name: + +<!-- ##### FUNCTION gtk_item_factory_parse_rc_scanner ##### --> +<para> + +</para> + +@scanner: + +<!-- ##### FUNCTION gtk_item_factory_parse_rc_string ##### --> +<para> + +</para> + +@rc_string: + +<!-- ##### FUNCTION gtk_item_factory_print_func ##### --> +<para> + +</para> + +@FILE_pointer: +@string: + <!-- ##### FUNCTION gtk_label_set_markup_with_accel ##### --> <para> @@ -2715,6 +2895,31 @@ a gtk_object_unref(). @width: @size: +<!-- ##### FUNCTION gtk_tree_view_set_rows_drag_dest ##### --> +<para> + +</para> + +@tree_view: +@targets: +@n_targets: +@actions: +@location_droppable_func: +@user_data: + +<!-- ##### FUNCTION gtk_tree_view_set_rows_drag_source ##### --> +<para> + +</para> + +@tree_view: +@start_button_mask: +@targets: +@n_targets: +@actions: +@row_draggable_func: +@user_data: + <!-- ##### FUNCTION gtk_type_check_class_cast ##### --> <para> Given a GtkTypeClass pointer @klass, and a GtkType @cast_type, make @@ -2829,6 +3034,25 @@ Set the varargs type for a fundamental type @foreign_type. fundamental type. @varargs_type: Must be a GtkType which is either structured or flag, or NONE. +<!-- ##### FUNCTION gtk_widget_accelerator_signal ##### --> +<para> + +</para> + +@widget: +@accel_group: +@accel_key: +@accel_mods: +@Returns: + +<!-- ##### FUNCTION gtk_widget_accelerators_locked ##### --> +<para> + +</para> + +@widget: +@Returns: + <!-- ##### FUNCTION gtk_widget_activate_mnemonic ##### --> <para> @@ -2847,6 +3071,13 @@ fundamental type. @width: @height: +<!-- ##### FUNCTION gtk_widget_lock_accelerators ##### --> +<para> + +</para> + +@widget: + <!-- ##### FUNCTION gtk_widget_pop_style ##### --> <para> @@ -2869,6 +3100,15 @@ fundamental type. @style: +<!-- ##### FUNCTION gtk_widget_remove_accelerators ##### --> +<para> + +</para> + +@widget: +@accel_signal: +@visible_only: + <!-- ##### FUNCTION gtk_widget_set_default_style ##### --> <para> @@ -2876,6 +3116,13 @@ fundamental type. @style: +<!-- ##### FUNCTION gtk_widget_unlock_accelerators ##### --> +<para> + +</para> + +@widget: + <!-- ##### FUNCTION gtk_window_activate_mnemonic ##### --> <para> diff --git a/docs/reference/gtk/tmpl/gtkaccelgroup.sgml b/docs/reference/gtk/tmpl/gtkaccelgroup.sgml index a0fc59a52..b069f7e73 100644 --- a/docs/reference/gtk/tmpl/gtkaccelgroup.sgml +++ b/docs/reference/gtk/tmpl/gtkaccelgroup.sgml @@ -1,9 +1,9 @@ <!-- ##### SECTION Title ##### --> -Keyboard Accelerators +Keyboard Accelerator Groups <!-- ##### SECTION Short_Description ##### --> -global keyboard accelerators (for an entire #GtkWindow) +Groups of global keyboard accelerators for an entire #GtkWindow <!-- ##### SECTION Long_Description ##### --> <para> @@ -11,14 +11,15 @@ A #GtkAccelGroup represents a group of keyboard accelerators, typically attached to a toplevel #GtkWindow (with gtk_window_add_accel_group()). Usually you won't need to create a #GtkAccelGroup directly; instead, when using #GtkItemFactory, GTK+ -automatically sets up the accelerators for your menus. +automatically sets up the accelerators for your menus in the item +factory's #GtkAccelGroup. </para> <para> Note that <firstterm>accelerators</firstterm> are different from <firstterm>mnemonics</firstterm>. Accelerators are shortcuts for activating a menu item; they appear alongside the menu item they're a -shortcut for, for example "Ctrl+Q" might appear alongside the "Quit" +shortcut for. For example "Ctrl+Q" might appear alongside the "Quit" menu item. Mnemonics are shortcuts for GUI elements such as text entries or buttons; they appear as underlined characters. See gtk_label_new_with_mnemonic(). Menu items can have both accelerators @@ -27,16 +28,17 @@ and mnemonics, of course. <!-- ##### SECTION See_Also ##### --> <para> -gtk_label_new_with_mnemonic(), gtk_window_add_accel_group() +gtk_window_add_accel_group(), gtk_accel_map_change_entry(), +gtk_item_factory_new(), gtk_label_new_with_mnemonic() </para> <!-- ##### STRUCT GtkAccelGroup ##### --> <para> -On opaque data type representing a group of accelerators. +An object representing and maintaining a group of accelerators. </para> -<!-- ##### FUNCTION gtk_accel_group_new ##### --> +<!-- ##### FUNCTION gtk_accel_group_get_type ##### --> <para> </para> @@ -44,32 +46,15 @@ On opaque data type representing a group of accelerators. @Returns: -<!-- ##### FUNCTION gtk_accel_group_get_default ##### --> -<para> - -</para> - -@Returns: - - -<!-- ##### FUNCTION gtk_accel_group_ref ##### --> +<!-- ##### FUNCTION gtk_accel_group_new ##### --> <para> </para> -@accel_group: @Returns: -<!-- ##### FUNCTION gtk_accel_group_unref ##### --> -<para> - -</para> - -@accel_group: - - -<!-- ##### FUNCTION gtk_accel_group_activate ##### --> +<!-- ##### FUNCTION gtk_accel_group_connect ##### --> <para> </para> @@ -77,39 +62,25 @@ On opaque data type representing a group of accelerators. @accel_group: @accel_key: @accel_mods: -@Returns: +@accel_flags: +@closure: +@accel_path_quark: +<!-- # Unused Parameters # --> +@path_quark: -<!-- ##### FUNCTION gtk_accel_groups_activate ##### --> +<!-- ##### FUNCTION gtk_accel_group_disconnect ##### --> <para> </para> -@object: +@accel_group: @accel_key: @accel_mods: @Returns: -<!-- ##### FUNCTION gtk_accel_group_attach ##### --> -<para> - -</para> - -@accel_group: -@object: - - -<!-- ##### FUNCTION gtk_accel_group_detach ##### --> -<para> - -</para> - -@accel_group: -@object: - - -<!-- ##### FUNCTION gtk_accel_group_add ##### --> +<!-- ##### FUNCTION gtk_accel_group_query ##### --> <para> </para> @@ -117,19 +88,20 @@ On opaque data type representing a group of accelerators. @accel_group: @accel_key: @accel_mods: -@accel_flags: -@object: -@accel_signal: +@n_entries: +@Returns: -<!-- ##### FUNCTION gtk_accel_group_remove ##### --> +<!-- ##### FUNCTION gtk_accel_groups_activate ##### --> <para> </para> -@accel_group: +@acceleratable: @accel_key: @accel_mods: +@Returns: +<!-- # Unused Parameters # --> @object: diff --git a/docs/reference/gtk/tmpl/gtkaccellabel.sgml b/docs/reference/gtk/tmpl/gtkaccellabel.sgml index a434252bb..4587cf751 100644 --- a/docs/reference/gtk/tmpl/gtkaccellabel.sgml +++ b/docs/reference/gtk/tmpl/gtkaccellabel.sgml @@ -94,7 +94,7 @@ Creates a new #GtkAccelLabel. @Returns: a new #GtkAccelLabel. -<!-- ##### FUNCTION gtk_accel_label_get_accel_object ##### --> +<!-- ##### FUNCTION gtk_accel_label_get_accel_widget ##### --> <para> </para> @@ -103,24 +103,7 @@ Creates a new #GtkAccelLabel. @Returns: -<!-- ##### FUNCTION gtk_accel_label_set_accel_object ##### --> -<para> - -</para> - -@accel_label: -@accel_object: - - -<!-- ##### MACRO gtk_accel_label_get_accel_widget ##### --> -<para> - -</para> - -@accel_label: - - -<!-- ##### MACRO gtk_accel_label_set_accel_widget ##### --> +<!-- ##### FUNCTION gtk_accel_label_set_accel_widget ##### --> <para> Sets the widget whose accelerators are to be shown. </para> @@ -151,8 +134,13 @@ accelerators are added or removed from the associated widget. @Returns: always returns %FALSE. -<!-- ##### ARG GtkAccelLabel:accel-object ##### --> +<!-- ##### ARG GtkAccelLabel:accel-closure ##### --> <para> </para> +<!-- ##### ARG GtkAccelLabel:accel-widget ##### --> +<para> +The widget whose accelerators are to be shown by the #GtkAccelLabel. +</para> + diff --git a/docs/reference/gtk/tmpl/gtkcolorsel.sgml b/docs/reference/gtk/tmpl/gtkcolorsel.sgml index 73907ce28..5bb58e122 100644 --- a/docs/reference/gtk/tmpl/gtkcolorsel.sgml +++ b/docs/reference/gtk/tmpl/gtkcolorsel.sgml @@ -225,7 +225,7 @@ time. </para> -@colorsel: +@colorsel: @color: @@ -234,8 +234,8 @@ time. </para> -@colorsel: -@color: +@colorsel: +@color: <!-- ##### SIGNAL GtkColorSelection::color-changed ##### --> diff --git a/docs/reference/gtk/tmpl/gtkcombo.sgml b/docs/reference/gtk/tmpl/gtkcombo.sgml index 8034f9cb7..4f6ed7b6f 100644 --- a/docs/reference/gtk/tmpl/gtkcombo.sgml +++ b/docs/reference/gtk/tmpl/gtkcombo.sgml @@ -178,7 +178,7 @@ worried about differences in case. </para> @combo: a #GtkCombo. -@val: %TRUE if the text in the list items is case sensitive. +@val: %TRUE if the text in the list items is case sensitive. <!-- ##### FUNCTION gtk_combo_set_item_string ##### --> diff --git a/docs/reference/gtk/tmpl/gtkdialog.sgml b/docs/reference/gtk/tmpl/gtkdialog.sgml index f677af775..7eb449fe1 100644 --- a/docs/reference/gtk/tmpl/gtkdialog.sgml +++ b/docs/reference/gtk/tmpl/gtkdialog.sgml @@ -169,7 +169,7 @@ Creates a new dialog box. Widgets should not be packed into this #GtkWindow directly, but into the vbox and action_area, as described above. </para> -@Returns: a new #GtkDialog. +@Returns: a new #GtkDialog. <!-- ##### FUNCTION gtk_dialog_new_with_buttons ##### --> diff --git a/docs/reference/gtk/tmpl/gtkenums.sgml b/docs/reference/gtk/tmpl/gtkenums.sgml index 6c19bccb7..304ae8d02 100644 --- a/docs/reference/gtk/tmpl/gtkenums.sgml +++ b/docs/reference/gtk/tmpl/gtkenums.sgml @@ -20,7 +20,6 @@ Public enumerated types used throughout GTK+. </para> @GTK_ACCEL_VISIBLE: -@GTK_ACCEL_SIGNAL_VISIBLE: @GTK_ACCEL_LOCKED: @GTK_ACCEL_MASK: diff --git a/docs/reference/gtk/tmpl/gtkitemfactory.sgml b/docs/reference/gtk/tmpl/gtkitemfactory.sgml index abda89259..57c1fd8f7 100644 --- a/docs/reference/gtk/tmpl/gtkitemfactory.sgml +++ b/docs/reference/gtk/tmpl/gtkitemfactory.sgml @@ -84,11 +84,6 @@ GtkItemFactory </para> @path: -@accelerator_key: -@accelerator_mods: -@modified: -@in_propagation: -@dummy: @widgets: <!-- ##### FUNCTION gtk_item_factory_new ##### --> @@ -113,30 +108,6 @@ GtkItemFactory @accel_group: -<!-- ##### FUNCTION gtk_item_factory_parse_rc ##### --> -<para> - -</para> - -@file_name: - - -<!-- ##### FUNCTION gtk_item_factory_parse_rc_string ##### --> -<para> - -</para> - -@rc_string: - - -<!-- ##### FUNCTION gtk_item_factory_parse_rc_scanner ##### --> -<para> - -</para> - -@scanner: - - <!-- ##### FUNCTION gtk_item_factory_add_foreign ##### --> <para> @@ -207,36 +178,6 @@ GtkItemFactory @Returns: -<!-- ##### FUNCTION gtk_item_factory_dump_items ##### --> -<para> - -</para> - -@path_pspec: -@modified_only: -@print_func: -@func_data: - - -<!-- ##### FUNCTION gtk_item_factory_dump_rc ##### --> -<para> - -</para> - -@file_name: -@path_pspec: -@modified_only: - - -<!-- ##### FUNCTION gtk_item_factory_print_func ##### --> -<para> - -</para> - -@FILE_pointer: -@string: - - <!-- ##### FUNCTION gtk_item_factory_create_item ##### --> <para> diff --git a/docs/reference/gtk/tmpl/gtkmenu.sgml b/docs/reference/gtk/tmpl/gtkmenu.sgml index 8bb20423d..eb37062f0 100644 --- a/docs/reference/gtk/tmpl/gtkmenu.sgml +++ b/docs/reference/gtk/tmpl/gtkmenu.sgml @@ -96,9 +96,9 @@ Creates a new #GtkMenu. Adds a new #GtkMenuItem to the end of the menu's item list. </para> -<!-- # Unused Parameters # --> @menu: a #GtkMenu. @child: The #GtkMenuItem to add. +<!-- # Unused Parameters # --> @m: @c: @@ -108,9 +108,9 @@ Adds a new #GtkMenuItem to the end of the menu's item list. Adds a new #GtkMenuItem to the beginning of the menu's item list. </para> -<!-- # Unused Parameters # --> @menu: a #GtkMenu. @child: The #GtkMenuItem to add. +<!-- # Unused Parameters # --> @menu_child: @m: @c: @@ -122,10 +122,10 @@ Adds a new #GtkMenuItem to the menu's item list at the position indicated by @position. </para> -<!-- # Unused Parameters # --> @menu: a #GtkMenu. @child: The #GtkMenuItem to add. @pos: +<!-- # Unused Parameters # --> @position: The position in the item list where @child is added. Positions are numbered from 0 to n-1. @@ -162,6 +162,9 @@ at the current pointer position. <!-- ##### FUNCTION gtk_menu_set_accel_group ##### --> <para> Set the #GtkAccelGroup which holds global accelerators for the menu. +This accelerator group needs to also be added to all windows that +this menu is being used in with gtk_window_add_accel_group(), in order +for those windows to support all the accelerators contained in this group. </para> @menu: a #GtkMenu. @@ -178,6 +181,15 @@ See gtk_menu_set_accel_group(). @Returns: the #GtkAccelGroup associated with the menu. +<!-- ##### FUNCTION gtk_menu_set_accel_path ##### --> +<para> + +</para> + +@menu: +@accel_path: + + <!-- ##### FUNCTION gtk_menu_set_title ##### --> <para> Sets the title string for the menu. The title is displayed when the menu diff --git a/docs/reference/gtk/tmpl/gtkmenuitem.sgml b/docs/reference/gtk/tmpl/gtkmenuitem.sgml index 76b4e8639..d65e13a75 100644 --- a/docs/reference/gtk/tmpl/gtkmenuitem.sgml +++ b/docs/reference/gtk/tmpl/gtkmenuitem.sgml @@ -83,6 +83,15 @@ Sets the widget submenu, or changes it. @submenu: the submenu +<!-- ##### FUNCTION gtk_menu_item_set_accel_path ##### --> +<para> + +</para> + +@menu_item: +@accel_path: + + <!-- ##### FUNCTION gtk_menu_item_remove_submenu ##### --> <para> Removes the widget's submenu. diff --git a/docs/reference/gtk/tmpl/gtkpaned.sgml b/docs/reference/gtk/tmpl/gtkpaned.sgml index f3a7e01e0..95369862d 100644 --- a/docs/reference/gtk/tmpl/gtkpaned.sgml +++ b/docs/reference/gtk/tmpl/gtkpaned.sgml @@ -112,6 +112,9 @@ Old name for gtk_paned_set_handle_size() Old name for gtk_paned_set_gutter_size() </para> +@p: +@s: + <!-- ##### FUNCTION gtk_paned_pack1 ##### --> <para> diff --git a/docs/reference/gtk/tmpl/gtktoolbar.sgml b/docs/reference/gtk/tmpl/gtktoolbar.sgml index 9ee5eb854..74562454d 100644 --- a/docs/reference/gtk/tmpl/gtktoolbar.sgml +++ b/docs/reference/gtk/tmpl/gtktoolbar.sgml @@ -47,8 +47,8 @@ Widgets can be visibly grouped by adding gaps between widgets using gtk_toolbar_ to a #GtkToolbar. </para> -@GTK_TOOLBAR_CHILD_SPACE: a space in the style of the toolbar's #GtkToolbarSpaceStyle. -@GTK_TOOLBAR_CHILD_BUTTON: a #GtkButton. +@GTK_TOOLBAR_CHILD_SPACE: a space in the style of the toolbar's #GtkToolbarSpaceStyle. +@GTK_TOOLBAR_CHILD_BUTTON: a #GtkButton. @GTK_TOOLBAR_CHILD_TOGGLEBUTTON: a #GtkToggleButton. @GTK_TOOLBAR_CHILD_RADIOBUTTON: a #GtkRadioButton. @GTK_TOOLBAR_CHILD_WIDGET: a standard #GtkWidget. diff --git a/docs/reference/gtk/tmpl/gtktreednd.sgml b/docs/reference/gtk/tmpl/gtktreednd.sgml index 842769a89..9414655b6 100644 --- a/docs/reference/gtk/tmpl/gtktreednd.sgml +++ b/docs/reference/gtk/tmpl/gtktreednd.sgml @@ -43,6 +43,7 @@ GtkTreeView drag-and-drop </para> @g_iface: +@row_draggable: @drag_data_get: @drag_data_delete: diff --git a/docs/reference/gtk/tmpl/gtktreeview.sgml b/docs/reference/gtk/tmpl/gtktreeview.sgml index 3234cc1c0..b8480449e 100644 --- a/docs/reference/gtk/tmpl/gtktreeview.sgml +++ b/docs/reference/gtk/tmpl/gtktreeview.sgml @@ -49,18 +49,6 @@ GtkTreeView @Returns: -<!-- ##### USER_FUNCTION GtkTreeViewDraggableFunc ##### --> -<para> - -</para> - -@tree_view: -@context: -@path: -@user_data: -@Returns: - - <!-- ##### USER_FUNCTION GtkTreeViewMappingFunc ##### --> <para> @@ -71,19 +59,6 @@ GtkTreeView @user_data: -<!-- ##### USER_FUNCTION GtkTreeViewDroppableFunc ##### --> -<para> - -</para> - -@tree_view: -@context: -@path: -@pos: -@user_data: -@Returns: - - <!-- ##### USER_FUNCTION GtkTreeViewSearchEqualFunc ##### --> <para> @@ -559,33 +534,6 @@ GtkTreeView @wy: -<!-- ##### FUNCTION gtk_tree_view_set_rows_drag_source ##### --> -<para> - -</para> - -@tree_view: -@start_button_mask: -@targets: -@n_targets: -@actions: -@row_draggable_func: -@user_data: - - -<!-- ##### FUNCTION gtk_tree_view_set_rows_drag_dest ##### --> -<para> - -</para> - -@tree_view: -@targets: -@n_targets: -@actions: -@location_droppable_func: -@user_data: - - <!-- ##### FUNCTION gtk_tree_view_unset_rows_drag_source ##### --> <para> diff --git a/docs/reference/gtk/tmpl/gtkwidget.sgml b/docs/reference/gtk/tmpl/gtkwidget.sgml index 4781aee5f..76769b73b 100644 --- a/docs/reference/gtk/tmpl/gtkwidget.sgml +++ b/docs/reference/gtk/tmpl/gtkwidget.sgml @@ -527,27 +527,6 @@ GtkWidget @accel_group: @accel_key: @accel_mods: - - -<!-- ##### FUNCTION gtk_widget_remove_accelerators ##### --> -<para> - -</para> - -@widget: -@accel_signal: -@visible_only: - - -<!-- ##### FUNCTION gtk_widget_accelerator_signal ##### --> -<para> - -</para> - -@widget: -@accel_group: -@accel_key: -@accel_mods: @Returns: @@ -1000,14 +979,6 @@ GtkWidget @Returns: -<!-- ##### FUNCTION gtk_widget_lock_accelerators ##### --> -<para> - -</para> - -@widget: - - <!-- ##### FUNCTION gtk_widget_modify_style ##### --> <para> @@ -1207,23 +1178,6 @@ GtkWidget @Returns: -<!-- ##### FUNCTION gtk_widget_unlock_accelerators ##### --> -<para> - -</para> - -@widget: - - -<!-- ##### FUNCTION gtk_widget_accelerators_locked ##### --> -<para> - -</para> - -@widget: -@Returns: - - <!-- ##### FUNCTION gtk_widget_mnemonic_activate ##### --> <para> @@ -1456,17 +1410,12 @@ GtkWidget @requisition: -<!-- ##### SIGNAL GtkWidget::add-accelerator ##### --> +<!-- ##### SIGNAL GtkWidget::accel-closures-changed ##### --> <para> </para> @widget: the object which received the signal. -@accel_signal_id: -@accel_group: -@accel_key: -@accel_mods: -@accel_flags: <!-- ##### SIGNAL GtkWidget::button-press-event ##### --> <para> @@ -1834,16 +1783,6 @@ a widget changes from un-anchored to anchored or vice-versa. @widget: the object which received the signal. -<!-- ##### SIGNAL GtkWidget::remove-accelerator ##### --> -<para> - -</para> - -@widget: the object which received the signal. -@accel_group: -@accel_key: -@accel_mods: - <!-- ##### SIGNAL GtkWidget::scroll-event ##### --> <para> diff --git a/docs/reference/gtk/tmpl/gtkwindow.sgml b/docs/reference/gtk/tmpl/gtkwindow.sgml index 66ea51639..b8111b436 100644 --- a/docs/reference/gtk/tmpl/gtkwindow.sgml +++ b/docs/reference/gtk/tmpl/gtkwindow.sgml @@ -694,6 +694,13 @@ it's larger @height: +<!-- ##### SIGNAL GtkWindow::accels-changed ##### --> +<para> + +</para> + +@window: the object which received the signal. + <!-- ##### SIGNAL GtkWindow::activate-default ##### --> <para> diff --git a/gtk/Makefile.am b/gtk/Makefile.am index bef5917e0..bbe5fa6fe 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -86,6 +86,7 @@ gtk_public_h_sources = @STRIP_BEGIN@ \ gtk.h \ gtkaccelgroup.h \ gtkaccellabel.h \ + gtkaccelmap.h \ gtkaccessible.h \ gtkadjustment.h \ gtkalignment.h \ @@ -244,6 +245,7 @@ gtk_private_h_sources = @STRIP_BEGIN@ \ # GTK+ C sources to build the library from gtk_c_sources = @STRIP_BEGIN@ \ gtkaccelgroup.c \ + gtkaccelmap.c \ gtkaccellabel.c \ gtkaccessible.c \ gtkadjustment.c \ @@ -31,6 +31,7 @@ #include <gdk/gdk.h> #include <gtk/gtkaccelgroup.h> #include <gtk/gtkaccellabel.h> +#include <gtk/gtkaccelmap.h> #include <gtk/gtkaccessible.h> #include <gtk/gtkadjustment.h> #include <gtk/gtkalignment.h> diff --git a/gtk/gtkaccelgroup.c b/gtk/gtkaccelgroup.c index 0464ecd7c..a8c36b764 100644 --- a/gtk/gtkaccelgroup.c +++ b/gtk/gtkaccelgroup.c @@ -1,8 +1,5 @@ /* GTK - The GIMP Toolkit - * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald - * - * GtkAccelGroup: Accelerator manager for GtkObjects. - * Copyright (C) 1998 Tim Janik + * Copyright (C) 1998, 2001 Tim Janik * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -26,79 +23,37 @@ * files for a list of changes. These files are distributed with * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */ - -#include <ctype.h> -#include <string.h> #include "gtkaccelgroup.h" +#include "gtkaccelmap.h" #include "gdk/gdkkeysyms.h" #include "gtksignal.h" -#include "gtkwidget.h" - - -/* --- signals --- */ -typedef void (*GtkSignalAddAccelerator) (GObject *object, - guint accel_signal_id, - GtkAccelGroup *accel_group, - guint accel_key, - GdkModifierType accel_mods, - GtkAccelFlags accel_flags, - gpointer func_data); -typedef void (*GtkSignalRemoveAccelerator) (GObject *object, - GtkAccelGroup *accel_group, - guint accel_key, - GdkModifierType accel_mods, - gpointer func_data); + +#include <ctype.h> +#include <string.h> +#include <stdlib.h> + + +/* --- prototypes --- */ +static void gtk_accel_group_class_init (GtkAccelGroupClass *class); +static void gtk_accel_group_init (GtkAccelGroup *accel_group); +static void gtk_accel_group_finalize (GObject *object); + /* --- variables --- */ -static GtkAccelGroup *default_accel_group = NULL; +static GObjectClass *parent_class = NULL; +static guint signal_accel_activate = 0; +static guint signal_accel_changed = 0; +static guint quark_acceleratable_groups = 0; static guint default_accel_mod_mask = (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK); -static const gchar *accel_groups_key = "gtk-accel-groups"; -static guint accel_groups_key_id = 0; -static const gchar *accel_entries_key = "gtk-accel-entries"; -static guint accel_entries_key_id = 0; -static GHashTable *accel_entry_hash_table = NULL; -static GMemChunk *accel_entries_mem_chunk = NULL; - -static GObjectClass *parent_class = NULL; /* --- functions --- */ -static gboolean -gtk_accel_entries_equal (gconstpointer a, - gconstpointer b) -{ - const GtkAccelEntry *e1; - const GtkAccelEntry *e2; - - e1 = a; - e2 = b; - - return ((e1->accel_group == e2->accel_group) && - (e1->accelerator_key == e2->accelerator_key) && - (e1->accelerator_mods == e2->accelerator_mods)); -} - -static guint -gtk_accel_entries_hash (gconstpointer a) -{ - const GtkAccelEntry *e; - guint h; - - e = a; - - h = (gulong) e->accel_group; - h ^= e->accelerator_key << 16; - h ^= e->accelerator_key >> 16; - h ^= e->accelerator_mods; - - return h; -} - -static void gtk_accel_group_class_init (GObjectClass *class); -static void gtk_accel_group_init (GtkAccelGroup *accel_group); - +/** + * gtk_accel_map_change_entry + * @returns: the type ID for accelerator groups + */ GType gtk_accel_group_get_type (void) { @@ -106,15 +61,14 @@ gtk_accel_group_get_type (void) if (!object_type) { - static const GTypeInfo object_info = - { + static const GTypeInfo object_info = { sizeof (GtkAccelGroupClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) gtk_accel_group_class_init, NULL, /* clas_finalize */ NULL, /* class_data */ - sizeof(GtkAccelGroup), + sizeof (GtkAccelGroup), 0, /* n_preallocs */ (GInstanceInitFunc) gtk_accel_group_init, }; @@ -127,120 +81,90 @@ gtk_accel_group_get_type (void) return object_type; } -static void -gtk_accel_group_finalize (GObject *object) +static gboolean +accel_activate_accumulator (GSignalInvocationHint *ihint, + GValue *return_accu, + const GValue *handler_return, + gpointer data) { - GtkAccelGroup *accel_group = GTK_ACCEL_GROUP(object); + gboolean continue_emission; + gboolean handler_val; - if (accel_group == default_accel_group) - g_warning (G_STRLOC "default accel group should not be finalized"); + /* handler returns whether the accelerator was handled */ + handler_val = g_value_get_boolean (handler_return); - (* G_OBJECT_CLASS (parent_class)->finalize) (object); -} + /* record that as result for this emission */ + g_value_set_boolean (return_accu, handler_val); -static void -gtk_accel_group_class_init (GObjectClass *class) -{ - parent_class = g_type_class_ref (G_TYPE_OBJECT); + /* don't continue if accelerator was handled */ + continue_emission = !handler_val; - class->finalize = gtk_accel_group_finalize; + return continue_emission; } static void -gtk_accel_group_init (GtkAccelGroup *accel_group) +gtk_accel_group_class_init (GtkAccelGroupClass *class) { - if (!accel_groups_key_id) - { - accel_groups_key_id = g_quark_from_static_string (accel_groups_key); - accel_entries_key_id = g_quark_from_static_string (accel_entries_key); - - accel_entry_hash_table = g_hash_table_new (gtk_accel_entries_hash, - gtk_accel_entries_equal); - - accel_entries_mem_chunk = g_mem_chunk_create (GtkAccelEntry, 64, G_ALLOC_AND_FREE); - } - - accel_group->lock_count = 0; - accel_group->modifier_mask = gtk_accelerator_get_default_mod_mask (); - accel_group->attach_objects = NULL; + GObjectClass *object_class = G_OBJECT_CLASS (class); + + parent_class = g_type_class_peek_parent (class); + + quark_acceleratable_groups = g_quark_from_static_string ("gtk-acceleratable-accel-groups"); + + object_class->finalize = gtk_accel_group_finalize; + + class->accel_changed = NULL; + signal_accel_activate = g_signal_new ("accel_activate", + G_OBJECT_CLASS_TYPE (class), + G_SIGNAL_DETAILED, + 0, + accel_activate_accumulator, NULL, + gtk_marshal_BOOLEAN__OBJECT_UINT_UINT, + G_TYPE_BOOLEAN, 3, G_TYPE_OBJECT, G_TYPE_UINT, G_TYPE_UINT); + signal_accel_changed = g_signal_new ("accel_changed", + G_OBJECT_CLASS_TYPE (class), + G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED, + G_STRUCT_OFFSET (GtkAccelGroupClass, accel_changed), + NULL, NULL, + gtk_marshal_VOID__UINT_UINT_BOXED, + G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_CLOSURE); } -/** - * gtk_accel_group_new: - * - * Creates a new #GtkAccelGroup. - * - * Return value: a new #GtkAccelGroup - **/ -GtkAccelGroup* -gtk_accel_group_new (void) +static void +gtk_accel_group_finalize (GObject *object) { - GtkAccelGroup *accel_group; + GtkAccelGroup *accel_group = GTK_ACCEL_GROUP (object); - accel_group = (GtkAccelGroup *)g_object_new(GTK_TYPE_ACCEL_GROUP, NULL); + g_free (accel_group->priv_accels); - return accel_group; + G_OBJECT_CLASS (parent_class)->finalize (object); } -/** - * gtk_accel_group_get_default: - * - * Gets the global default accelerator group; this is a fallback - * used for all objects when gtk_accel_groups_activate() is called - * on them. As such it's probably not appropriate for most uses. - * (Accelerators are normally specific to a document window or the - * like, rather than global to an application.) - * - * The returned value does not have its reference count incremented, - * and should not be unreferenced. - * - * Return value: the default accelerator group - **/ -GtkAccelGroup* -gtk_accel_group_get_default (void) +static void +gtk_accel_group_init (GtkAccelGroup *accel_group) { - if (!default_accel_group) - default_accel_group = gtk_accel_group_new (); - - return default_accel_group; + accel_group->lock_count = 0; + accel_group->modifier_mask = gtk_accelerator_get_default_mod_mask (); + accel_group->acceleratables = NULL; + accel_group->n_accels = 0; + accel_group->priv_accels = NULL; } /** - * gtk_accel_group_ref: - * @accel_group: a #GtkAccelGroup + * gtk_accel_group_new + * @returns: a new #GtkAccelGroup object * - * This is simply equivalent to g_object_ref (G_OBJECT (@accel_group)), - * and exists for historical reasons only. - * - * Return value: @accel_group - **/ + * Creates a new #GtkAccelGroup. + */ GtkAccelGroup* -gtk_accel_group_ref (GtkAccelGroup *accel_group) -{ - g_return_val_if_fail (GTK_IS_ACCEL_GROUP(accel_group), NULL); - - return (GtkAccelGroup *)g_object_ref(accel_group); -} - -/** - * gtk_accel_group_unref: - * @accel_group: a #GtkAccelGroup - * - * This is simply equivalent to g_object_unref (G_OBJECT (@accel_group)), - * and exists for historical reasons only. - * - **/ -void -gtk_accel_group_unref (GtkAccelGroup *accel_group) +gtk_accel_group_new (void) { - g_return_if_fail (GTK_IS_ACCEL_GROUP(accel_group)); - - g_object_unref(accel_group); + return g_object_new (GTK_TYPE_ACCEL_GROUP, NULL); } static void -gtk_accel_group_object_destroy (GSList *free_list, - GObject *where_the_object_was) +accel_group_weak_ref_detach (GSList *free_list, + GObject *stale_object) { GSList *slist; @@ -249,646 +173,488 @@ gtk_accel_group_object_destroy (GSList *free_list, GtkAccelGroup *accel_group; accel_group = slist->data; - accel_group->attach_objects = g_slist_remove (accel_group->attach_objects, where_the_object_was); + accel_group->acceleratables = g_slist_remove (accel_group->acceleratables, stale_object); g_object_unref (accel_group); } g_slist_free (free_list); } -/** - * gtk_accel_group_attach: - * @accel_group: a #GtkAccelGroup - * @object: object to attach accelerators to - * - * Associate @accel_group with @object, such that calling - * gtk_accel_groups_activate() on @object will activate accelerators - * in @accel_group. - * - * After calling this function, you still own a reference to both - * @accel_group and @object; gtk_accel_group_attach() will not - * "adopt" a reference to either one. - * - **/ void -gtk_accel_group_attach (GtkAccelGroup *accel_group, - GObject *object) +_gtk_accel_group_attach (GtkAccelGroup *accel_group, + GObject *object) { GSList *slist; - g_return_if_fail (GTK_IS_ACCEL_GROUP(accel_group)); + g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group)); g_return_if_fail (G_IS_OBJECT (object)); - g_return_if_fail (g_slist_find (accel_group->attach_objects, object) == NULL); + g_return_if_fail (g_slist_find (accel_group->acceleratables, object) == NULL); - accel_group->attach_objects = g_slist_prepend (accel_group->attach_objects, object); g_object_ref (accel_group); - slist = g_object_get_qdata (object, accel_groups_key_id); + accel_group->acceleratables = g_slist_prepend (accel_group->acceleratables, object); + slist = g_object_get_qdata (object, quark_acceleratable_groups); if (slist) - g_object_weak_unref(object, - (GWeakNotify)gtk_accel_group_object_destroy, - slist); + g_object_weak_unref (object, + (GWeakNotify) accel_group_weak_ref_detach, + slist); slist = g_slist_prepend (slist, accel_group); - g_object_set_qdata (object, accel_groups_key_id, slist); - g_object_weak_ref(object, - (GWeakNotify)gtk_accel_group_object_destroy, - slist); + g_object_set_qdata (object, quark_acceleratable_groups, slist); + g_object_weak_ref (object, + (GWeakNotify) accel_group_weak_ref_detach, + slist); } -/** - * gtk_accel_group_detach: - * @accel_group: a #GtkAccelGroup - * @object: a #GObject - * - * Reverses the effects of gtk_accel_group_attach(). - * - **/ void -gtk_accel_group_detach (GtkAccelGroup *accel_group, - GObject *object) +_gtk_accel_group_detach (GtkAccelGroup *accel_group, + GObject *object) { GSList *slist; - g_return_if_fail (GTK_IS_ACCEL_GROUP(accel_group)); + g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group)); g_return_if_fail (G_IS_OBJECT (object)); - g_return_if_fail (g_slist_find (accel_group->attach_objects, object) != NULL); + g_return_if_fail (g_slist_find (accel_group->acceleratables, object) != NULL); - accel_group->attach_objects = g_slist_remove (accel_group->attach_objects, object); - g_object_unref (accel_group); - slist = g_object_get_qdata (object, accel_groups_key_id); - g_object_weak_unref(object, - (GWeakNotify)gtk_accel_group_object_destroy, - slist); + accel_group->acceleratables = g_slist_remove (accel_group->acceleratables, object); + slist = g_object_get_qdata (object, quark_acceleratable_groups); + g_object_weak_unref (object, + (GWeakNotify) accel_group_weak_ref_detach, + slist); slist = g_slist_remove (slist, accel_group); - g_object_set_qdata (object, accel_groups_key_id, slist); + g_object_set_qdata (object, quark_acceleratable_groups, slist); if (slist) - g_object_weak_ref(object, - (GWeakNotify)gtk_accel_group_object_destroy, - slist); + g_object_weak_ref (object, + (GWeakNotify) accel_group_weak_ref_detach, + slist); + g_object_unref (accel_group); +} + +GSList* +gtk_accel_groups_from_acceleratable (GObject *object) +{ + g_return_val_if_fail (G_IS_OBJECT (object), NULL); + + return g_object_get_qdata (object, quark_acceleratable_groups); +} + +GtkAccelKey* +gtk_accel_group_find (GtkAccelGroup *accel_group, + gboolean (*find_func) (GtkAccelKey *key, + GClosure *closure, + gpointer data), + gpointer data) +{ + GtkAccelKey *key = NULL; + guint i; + + g_return_val_if_fail (GTK_IS_ACCEL_GROUP (accel_group), NULL); + g_return_val_if_fail (find_func != NULL, NULL); + + g_object_ref (accel_group); + for (i = 0; i < accel_group->n_accels; i++) + if (find_func (&accel_group->priv_accels[i].key, + accel_group->priv_accels[i].closure, + data)) + { + key = &accel_group->priv_accels[i].key; + break; + } + g_object_unref (accel_group); + + return key; } /** - * gtk_accel_group_lock: + * gtk_accel_group_lock * @accel_group: a #GtkAccelGroup * - * Prevents the addition of new accelerators to @accel_group. - * Primarily used to avoid the "dynamic accelerator editing" feature - * of #GtkMenu. + * Locking an acelerator group prevents the accelerators contained + * within it to be changed during runtime. Refer to + * gtk_accel_map_change_entry() about runtime accelerator changes. * * If called more than once, @accel_group remains locked until * gtk_accel_group_unlock() has been called an equivalent number * of times. - * - **/ + */ void -gtk_accel_group_lock (GtkAccelGroup *accel_group) +gtk_accel_group_lock (GtkAccelGroup *accel_group) { - g_return_if_fail (GTK_IS_ACCEL_GROUP(accel_group)); + g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group)); accel_group->lock_count += 1; } /** - * gtk_accel_group_unlock: + * gtk_accel_group_unlock * @accel_group: a #GtkAccelGroup * - * Allows the addition of new accelerators to @accel_group. - * Primarily used to enable the "dynamic accelerator editing" feature - * of #GtkMenu. - * - **/ + * This function undoes the last call to gtk_accel_group_lock() + * on this @accel_group. + */ void -gtk_accel_group_unlock (GtkAccelGroup *accel_group) +gtk_accel_group_unlock (GtkAccelGroup *accel_group) { - g_return_if_fail (GTK_IS_ACCEL_GROUP(accel_group)); - - if (accel_group->lock_count) - accel_group->lock_count -= 1; -} + g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group)); + g_return_if_fail (accel_group->lock_count > 0); -static GtkAccelEntry* -gtk_accel_group_lookup (GtkAccelGroup *accel_group, - guint accel_key, - GdkModifierType accel_mods) -{ - GtkAccelEntry key_entry = { 0 }; - - key_entry.accel_group = accel_group; - key_entry.accelerator_key = gdk_keyval_to_lower (accel_key); - key_entry.accelerator_mods = accel_mods & accel_group->modifier_mask; - - return g_hash_table_lookup (accel_entry_hash_table, &key_entry); + accel_group->lock_count -= 1; } -/** - * gtk_accel_group_activate: - * @accel_group: a #GtkAccelGroup - * @accel_key: keyval from a key event - * @accel_mods: modifier mask from a key event - * - * Checks whether a key event matches an accelerator in @accel_group; - * if so, activates the accelerator, and returns %TRUE. Returns - * %FALSE if no match. - * - * gtk_accel_groups_activate() should normally be used instead of - * this function. - * - * Return value: %TRUE if an accelerator was activated - **/ -gboolean -gtk_accel_group_activate (GtkAccelGroup *accel_group, - guint accel_key, - GdkModifierType accel_mods) +static void +accel_tag_func (gpointer data, + GClosure *closure) { - GtkAccelEntry *entry; - - g_return_val_if_fail (GTK_IS_ACCEL_GROUP(accel_group), FALSE); - - entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods); - if (entry && entry->signal_id && - (!GTK_IS_WIDGET (entry->object) || GTK_WIDGET_IS_SENSITIVE (entry->object))) - { - g_signal_emit (entry->object, entry->signal_id, 0); - return TRUE; - } - return FALSE; + /* GtkAccelGroup *accel_group = data; */ } -/** - * gtk_accel_groups_activate: - * @object: a #GObject - * @accel_key: accelerator keyval from a key event - * @accel_mods: keyboard state mask from a key event - * - * Finds the first accelerator in any #GtkAccelGroup attached - * to @object that matches @accel_key and @accel_mods, and - * activates that accelerator. If no accelerators are found - * in groups attached to @object, this function also tries - * the default #GtkAccelGroup (see gtk_accel_group_get_default()). - * If an accelerator is activated, returns %TRUE, otherwise - * %FALSE. - * - * Return value: %TRUE if an accelerator was activated - **/ -gboolean -gtk_accel_groups_activate (GObject *object, - guint accel_key, - GdkModifierType accel_mods) +static int +bsearch_compare_accels (const void *d1, + const void *d2) { - g_return_val_if_fail (G_IS_OBJECT (object), FALSE); - - if (gtk_accelerator_valid (accel_key, accel_mods)) - { - GSList *slist; - - for (slist = gtk_accel_groups_from_object (object); slist; slist = slist->next) - if (gtk_accel_group_activate (slist->data, accel_key, accel_mods)) - return TRUE; - return gtk_accel_group_activate (gtk_accel_group_get_default (), accel_key, accel_mods); - } - - return FALSE; + const GtkAccelGroupEntry *entry1 = d1; + const GtkAccelGroupEntry *entry2 = d2; + + if (entry1->key.accel_key == entry2->key.accel_key) + return entry1->key.accel_mods < entry2->key.accel_mods ? -1 : entry1->key.accel_mods > entry2->key.accel_mods; + else + return entry1->key.accel_key < entry2->key.accel_key ? -1 : 1; } -void -gtk_accel_group_lock_entry (GtkAccelGroup *accel_group, - guint accel_key, - GdkModifierType accel_mods) +static void +quick_accel_add (GtkAccelGroup *accel_group, + guint accel_key, + GdkModifierType accel_mods, + GtkAccelFlags accel_flags, + GClosure *closure, + GQuark path_quark) { - GtkAccelEntry *entry; - - g_return_if_fail (GTK_IS_ACCEL_GROUP(accel_group)); - - entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods); - if (entry) - entry->accel_flags |= GTK_ACCEL_LOCKED; + guint pos, i = accel_group->n_accels++; + GtkAccelGroupEntry key; + + key.key.accel_key = accel_key; + key.key.accel_mods = accel_mods; + for (pos = 0; pos < i; pos++) + if (bsearch_compare_accels (&key, accel_group->priv_accels + pos) < 0) + break; + accel_group->priv_accels = g_renew (GtkAccelGroupEntry, accel_group->priv_accels, accel_group->n_accels); + g_memmove (accel_group->priv_accels + pos + 1, accel_group->priv_accels + pos, + (i - pos) * sizeof (accel_group->priv_accels[0])); + accel_group->priv_accels[pos].key.accel_key = accel_key; + accel_group->priv_accels[pos].key.accel_mods = accel_mods; + accel_group->priv_accels[pos].key.accel_flags = accel_flags; + accel_group->priv_accels[pos].closure = g_closure_ref (closure); + accel_group->priv_accels[pos].accel_path_quark = path_quark; + g_closure_sink (closure); + + /* tag closure for backwards lookup */ + g_closure_add_invalidate_notifier (closure, accel_group, accel_tag_func); } -void -gtk_accel_group_unlock_entry (GtkAccelGroup *accel_group, - guint accel_key, - GdkModifierType accel_mods) +static GtkAccelGroupEntry* +quick_accel_find (GtkAccelGroup *accel_group, + guint accel_key, + GdkModifierType accel_mods, + guint *count_p) { - GtkAccelEntry *entry; - - g_return_if_fail (GTK_IS_ACCEL_GROUP(accel_group)); + GtkAccelGroupEntry *entry; + GtkAccelGroupEntry key; + + if (!accel_group->n_accels) + return NULL; + + key.key.accel_key = accel_key; + key.key.accel_mods = accel_mods; + entry = bsearch (&key, accel_group->priv_accels, accel_group->n_accels, + sizeof (accel_group->priv_accels[0]), bsearch_compare_accels); - entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods); - if (entry) - entry->accel_flags &= ~GTK_ACCEL_LOCKED; + if (!entry) + return NULL; + + /* step back to the first member */ + for (; entry > accel_group->priv_accels; entry--) + if (entry[-1].key.accel_key != accel_key || + entry[-1].key.accel_mods != accel_mods) + break; + /* count equal members */ + for (*count_p = 0; entry + *count_p < accel_group->priv_accels + accel_group->n_accels; (*count_p)++) + if (entry[*count_p].key.accel_key != accel_key || + entry[*count_p].key.accel_mods != accel_mods) + break; + return entry; } -GtkAccelEntry* -gtk_accel_group_get_entry (GtkAccelGroup *accel_group, - guint accel_key, - GdkModifierType accel_mods) +static GSList* +quick_accel_remove (GtkAccelGroup *accel_group, + guint accel_key, + GdkModifierType accel_mods) { - g_return_val_if_fail (GTK_IS_ACCEL_GROUP(accel_group), 0); - - return gtk_accel_group_lookup (accel_group, accel_key, accel_mods); + guint i, n; + GtkAccelGroupEntry *entry = quick_accel_find (accel_group, accel_key, accel_mods, &n); + guint pos = entry - accel_group->priv_accels; + GSList *clist = NULL; + + if (!entry) + return NULL; + for (i = 0; i < n; i++) + { + g_closure_remove_invalidate_notifier (entry[i].closure, accel_group, accel_tag_func); + clist = g_slist_prepend (clist, entry[i].closure); + } + + accel_group->n_accels -= n; + g_memmove (entry, entry + n, + (accel_group->n_accels - pos) * sizeof (accel_group->priv_accels[0])); + + return clist; } /** - * gtk_accel_group_add: - * @accel_group: a #GtkAccelGroup - * @accel_key: accelerator keyval - * @accel_mods: accelerator modifiers - * @accel_flags: accelerator flags - * @object: object that @accel_signal will be emitted on - * @accel_signal: name of a #G_SIGNAL_ACTION signal to emit - * - * Adds an accelerator to @accel_group. When the accelerator is - * activated, the @accel_signal signal will be emitted on @object. - * - * So for example, to click a button when Ctrl+a is pressed, you would - * write: gtk_accel_group_add (accel_group, GDK_a, GDK_CONTROL_MASK, - * 0, G_OBJECT (button), "clicked"). + * gtk_accel_group_connect + * @accel_group: the ccelerator group to install an accelerator in + * @accel_key: key value of the accelerator + * @accel_mods: modifier combination of the accelerator + * @accel_flags: a flag mask to configure this accelerator + * @closure: closure to be executed upon accelerator activation + * @accel_path_quark: accelerator path quark from GtkAccelMapNotify * - * @accel_flags is not particularly useful, always pass 0 for - * normal applications. - * - * @object must be an object that specifically supports accelerators, - * such as #GtkWidget. - **/ + * Install an accelerator in this group. When @accel_group is being activated + * in response to a call to gtk_accel_groups_activate(), @closure will be + * invoked if the @accel_key and @accel_mods from gtk_accel_groups_activate() + * match those of this connection. + * The signature used for the @closure is that of #GtkAccelGroupActivate. + * If this connection is made in response to an accelerator path change (see + * gtk_accel_map_change_entry()) from a #GtkAccelMapNotify notifier, + * @accel_path_quark must be passed on from the notifier into this function, + * it should be 0 otherwise. + */ void -gtk_accel_group_add (GtkAccelGroup *accel_group, - guint accel_key, - GdkModifierType accel_mods, - GtkAccelFlags accel_flags, - GObject *object, - const gchar *accel_signal) +gtk_accel_group_connect (GtkAccelGroup *accel_group, + guint accel_key, + GdkModifierType accel_mods, + GtkAccelFlags accel_flags, + GClosure *closure, + GQuark accel_path_quark) { - guint accel_signal_id = 0; - guint add_accelerator_signal_id = 0; - guint remove_accelerator_signal_id = 0; - gchar *signal; - GSignalQuery query; - GSList *slist; - GSList *groups; - GSList *attach_objects; - GtkAccelEntry *entry; - - g_return_if_fail (GTK_IS_ACCEL_GROUP(accel_group)); - g_return_if_fail (G_IS_OBJECT (object)); - g_return_if_fail (accel_signal != NULL); - - /* check for required signals in the objects branch - */ - signal = (gchar*) accel_signal; - accel_signal_id = g_signal_lookup (signal, G_OBJECT_TYPE (object)); - if (accel_signal_id) - { - signal = "add-accelerator"; - add_accelerator_signal_id = g_signal_lookup (signal, G_OBJECT_TYPE (object)); - } - if (add_accelerator_signal_id) - { - signal = "remove-accelerator"; - remove_accelerator_signal_id = g_signal_lookup (signal, G_OBJECT_TYPE (object)); - } - if (!accel_signal_id || - !add_accelerator_signal_id || - !remove_accelerator_signal_id) - { - g_warning ("gtk_accel_group_add(): could not find signal \"%s\"" - "in the `%s' class ancestry", - signal, - g_type_name (G_OBJECT_TYPE (object))); - return; - } - g_signal_query (accel_signal_id, &query); - if (!query.signal_id || query.n_params > 0) - { - g_warning ("gtk_accel_group_add(): signal \"%s\" in the `%s' class ancestry" - "cannot be used as accelerator signal %s", - accel_signal, - g_type_name (G_OBJECT_TYPE (object)), - query.n_params > 0 ? "(extraneous parameters are not supported)" : ""); - return; - } + gchar *accel_name; + GQuark accel_quark; + + g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group)); + g_return_if_fail (closure != NULL); + g_return_if_fail (accel_key > 0); + + accel_name = gtk_accelerator_name (accel_key, accel_mods); + accel_quark = g_quark_from_string (accel_name); + g_free (accel_name); + + quick_accel_add (accel_group, accel_key, accel_mods, accel_flags, closure, accel_path_quark); + + /* setup handler */ + g_signal_connect_closure_by_id (accel_group, signal_accel_activate, accel_quark, closure, FALSE); + + /* and notify */ + g_signal_emit (accel_group, signal_accel_changed, accel_quark, accel_key, accel_mods, closure); +} + +static gboolean +accel_group_disconnect_closure (GtkAccelGroup *accel_group, + guint accel_key, + GdkModifierType accel_mods, + GClosure *closure) +{ + gchar *accel_name; + GQuark accel_quark; + GSList *clist , *slist; + gboolean removed_some = FALSE; + + accel_name = gtk_accelerator_name (accel_key, accel_mods); + accel_quark = g_quark_from_string (accel_name); + g_free (accel_name); + + clist = quick_accel_remove (accel_group, accel_key, accel_mods); + if (!clist) + return FALSE; - /* prematurely abort if the group/entry is already locked - */ - if (accel_group->lock_count > 0) - return; - entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods); - if (entry && entry->accel_flags & GTK_ACCEL_LOCKED) - return; - - /* make sure our structures stay alive - */ g_object_ref (accel_group); - g_object_ref (object); - - /* remove an existing entry - */ - if (entry) - g_signal_emit (entry->object, remove_accelerator_signal_id, 0, - accel_group, - gdk_keyval_to_lower (accel_key), - accel_mods & accel_group->modifier_mask); - - /* abort if the entry still exists - */ - entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods); - if (entry) - { - g_object_unref (accel_group); - g_object_unref (object); - - return; - } - - /* collect accel groups and remove existing entries - */ - attach_objects = accel_group->attach_objects; - groups = NULL; - for (attach_objects = accel_group->attach_objects; attach_objects; attach_objects = attach_objects->next) - { - GSList *tmp_groups; - - tmp_groups = g_object_get_qdata (attach_objects->data, accel_groups_key_id); - while (tmp_groups) - { - groups = g_slist_prepend (groups, tmp_groups->data); - g_object_ref (tmp_groups->data); - tmp_groups = tmp_groups->next; - } - } - for (slist = groups; slist; slist = slist->next) - { - GtkAccelGroup *tmp_group; - - tmp_group = slist->data; - - /* we only remove the accelerator if neccessary - */ - if (tmp_group->lock_count == 0) - { - entry = gtk_accel_group_lookup (tmp_group, accel_key, accel_mods); - if (entry && !(entry->accel_flags & GTK_ACCEL_LOCKED)) - g_signal_emit (entry->object, remove_accelerator_signal_id, 0, - tmp_group, - gdk_keyval_to_lower (accel_key), - accel_mods & tmp_group->modifier_mask); - } - g_object_unref (tmp_group); - } - g_slist_free (groups); - - /* now install the new accelerator - */ - entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods); - if (!entry) - g_signal_emit (object, add_accelerator_signal_id, 0, - accel_signal_id, - accel_group, - gdk_keyval_to_lower (accel_key), - accel_mods & accel_group->modifier_mask, - accel_flags & GTK_ACCEL_MASK); - - /* and release the structures again - */ + + for (slist = clist; slist; slist = slist->next) + if (!closure || slist->data == (gpointer) closure) + { + g_signal_handlers_disconnect_matched (accel_group, G_SIGNAL_MATCH_CLOSURE | G_SIGNAL_MATCH_ID, + signal_accel_activate, 0, + slist->data, NULL, NULL); + /* and notify */ + g_signal_emit (accel_group, signal_accel_changed, accel_quark, accel_key, accel_mods, slist->data); + + /* remove quick_accel_add() ref_count */ + g_closure_unref (slist->data); + + removed_some = TRUE; + } + g_slist_free (clist); + g_object_unref (accel_group); - g_object_unref (object); + + return removed_some; } -static void -gtk_accel_group_delete_entries (GSList *entries) +/** + * gtk_accel_group_disconnect + * @accel_group: the ccelerator group to install an accelerator in + * @accel_key: key value of the accelerator + * @accel_mods: modifier combination of the accelerator + * @returns: %TRUE if there was an accelerator which could be removed, %FALSE otherwise + * + * Remove an accelerator previously installed through + * gtk_accel_group_connect(). + */ +gboolean +gtk_accel_group_disconnect (GtkAccelGroup *accel_group, + guint accel_key, + GdkModifierType accel_mods) { - GSList *slist; - - /* we remove all entries of this object the hard - * way (i.e. without signal emission). - */ - for (slist = entries; slist; slist = slist->next) - { - GtkAccelEntry *entry; - - entry = slist->data; - - g_hash_table_remove (accel_entry_hash_table, entry); - g_object_unref (entry->accel_group); - g_chunk_free (entry, accel_entries_mem_chunk); - } - g_slist_free (entries); + g_return_val_if_fail (GTK_IS_ACCEL_GROUP (accel_group), FALSE); + + return accel_group_disconnect_closure (accel_group, accel_key, accel_mods, NULL); } -void -gtk_accel_group_handle_add (GObject *object, - guint accel_signal_id, - GtkAccelGroup *accel_group, - guint accel_key, - GdkModifierType accel_mods, - GtkAccelFlags accel_flags) +GtkAccelGroupEntry* +gtk_accel_group_query (GtkAccelGroup *accel_group, + guint accel_key, + GdkModifierType accel_mods, + guint *n_entries) { - GtkAccelEntry *entry; - - g_return_if_fail (G_IS_OBJECT (object)); - g_return_if_fail (GTK_IS_ACCEL_GROUP(accel_group)); - g_return_if_fail (accel_signal_id > 0); + GtkAccelGroupEntry *entries; + guint n; - if (!gtk_accelerator_valid (accel_key, accel_mods)) - return; - - entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods); - if (!entry) - { - GSList *slist; - - g_object_ref (accel_group); - - entry = g_chunk_new (GtkAccelEntry, accel_entries_mem_chunk); - entry->accel_group = accel_group; - entry->accelerator_key = gdk_keyval_to_lower (accel_key); - entry->accelerator_mods = accel_mods & accel_group->modifier_mask; - entry->accel_flags = accel_flags & GTK_ACCEL_MASK; - entry->object = object; - entry->signal_id = accel_signal_id; - - g_hash_table_insert (accel_entry_hash_table, entry, entry); - - slist = g_object_steal_qdata (object, accel_entries_key_id); - slist = g_slist_prepend (slist, entry); - g_object_set_qdata_full (object, accel_entries_key_id, slist, - (GDestroyNotify) gtk_accel_group_delete_entries); - } + g_return_val_if_fail (GTK_IS_ACCEL_GROUP (accel_group), NULL); + + entries = quick_accel_find (accel_group, accel_key, accel_mods, &n); + + if (n_entries) + *n_entries = entries ? n : 0; + + return entries; } -/** - * gtk_accel_group_remove: - * @accel_group: a #GtkAccelGroup - * @accel_key: accelerator keyval - * @accel_mods: accelerator modifiers - * @object: object the accelerator activates - * - * Removes an accelerator. The @accel_key, @accel_mods, and @object - * arguments are the same ones used to add the accelerator - * with gtk_accel_group_add(). - * - **/ -void -gtk_accel_group_remove (GtkAccelGroup *accel_group, - guint accel_key, - GdkModifierType accel_mods, - GObject *object) +static gboolean +find_accel_closure (GtkAccelKey *key, + GClosure *closure, + gpointer data) { - GtkAccelEntry *entry; - guint remove_accelerator_signal_id = 0; - - g_return_if_fail (GTK_IS_ACCEL_GROUP(accel_group)); - g_return_if_fail (G_IS_OBJECT (object)); - - /* check for required signals in the objects branch - */ - remove_accelerator_signal_id = g_signal_lookup ("remove-accelerator", G_OBJECT_TYPE (object)); - if (!remove_accelerator_signal_id) - { - g_warning ("gtk_accel_group_remove(): could not find signal \"%s\"" - "in the `%s' class ancestry", - "remove-accelerator", - g_type_name (G_OBJECT_TYPE (object))); - return; - } - - /* prematurely abort if the entry is locked - */ - if (accel_group->lock_count > 0) - return; - entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods); - if (!entry || - entry->accel_flags & GTK_ACCEL_LOCKED) - return; - if (entry->object != object) - { - g_warning ("gtk_accel_group_remove(): invalid object reference for accel-group entry"); - return; - } - - /* make sure our structures stay alive - */ - g_object_ref (accel_group); - g_object_ref (object); - - /* remove the entry - */ - g_signal_emit (entry->object, remove_accelerator_signal_id, 0, - accel_group, - gdk_keyval_to_lower (accel_key), - accel_mods & accel_group->modifier_mask); - - /* and release the structures again - */ - g_object_unref (accel_group); - g_object_unref (object); + return data == (gpointer) closure; } -void -gtk_accel_group_handle_remove (GObject *object, - GtkAccelGroup *accel_group, - guint accel_key, - GdkModifierType accel_mods) +gboolean +gtk_accel_groups_disconnect_closure (GClosure *closure) { - GtkAccelEntry *entry; - - g_return_if_fail (G_IS_OBJECT (object)); - g_return_if_fail (GTK_IS_ACCEL_GROUP(accel_group)); - - entry = gtk_accel_group_lookup (accel_group, accel_key, accel_mods); - if (entry) + GtkAccelGroup *group; + + g_return_val_if_fail (closure != NULL, FALSE); + + group = gtk_accel_group_from_accel_closure (closure); + if (group) { - if (entry->object == object) + GtkAccelKey *key = gtk_accel_group_find (group, find_accel_closure, closure); + + /* sigh, not finding the key can unexpectedly happen if someone disposes + * accel groups. that's highly recommended to _not_ do though. + */ + if (key) { - GSList *slist; - - g_hash_table_remove (accel_entry_hash_table, entry); - - slist = g_object_steal_qdata (object, accel_entries_key_id); - if (slist) - { - slist = g_slist_remove (slist, entry); - if (slist) - g_object_set_qdata_full (object, accel_entries_key_id, slist, - (GDestroyNotify) gtk_accel_group_delete_entries); - - g_object_unref (accel_group); - - g_chunk_free (entry, accel_entries_mem_chunk); - } + accel_group_disconnect_closure (group, key->accel_key, key->accel_mods, closure); + return TRUE; } - else - g_warning ("gtk_accel_group_handle_remove(): invalid object reference for accel-group entry"); } - else - g_warning ("gtk_accel_group_handle_remove(): attempt to remove unexisting accel-group entry"); + return FALSE; } -guint -gtk_accel_group_create_add (GType class_type, - GSignalFlags signal_flags, - guint handler_offset) +GtkAccelGroup* +gtk_accel_group_from_accel_closure (GClosure *closure) { - g_return_val_if_fail (G_TYPE_IS_OBJECT (class_type), 0); - - return g_signal_new ("add-accelerator", - class_type, - signal_flags, - handler_offset, - (GSignalAccumulator) NULL, NULL, - gtk_marshal_VOID__UINT_OBJECT_UINT_FLAGS_FLAGS, - G_TYPE_NONE, 5, - G_TYPE_UINT, - GTK_TYPE_ACCEL_GROUP, - G_TYPE_UINT, - GDK_TYPE_MODIFIER_TYPE, - GTK_TYPE_ACCEL_FLAGS); + guint i; + + g_return_val_if_fail (closure != NULL, NULL); + + /* a few remarks on wat we do here. in general, we need a way to back-lookup + * accel_groups from closures that are being used in accel groups. this could + * be done e.g via a hashtable. it is however cheaper (memory wise) to just + * store a NOP notifier on the closure itself that contains the accel group + * as data which, besides needing to peek a bit at closure internals, works + * just as good. + */ + for (i = 0; i < G_CLOSURE_N_NOTIFIERS (closure); i++) + if (closure->notifiers[i].notify == accel_tag_func) + return closure->notifiers[i].data; + + return NULL; } -guint -gtk_accel_group_create_remove (GType class_type, - GSignalFlags signal_flags, - guint handler_offset) +gboolean +_gtk_accel_group_activate (GtkAccelGroup *accel_group, + GQuark accel_quark, + GObject *acceleratable, + guint accel_key, + GdkModifierType accel_mods) { - g_return_val_if_fail (G_TYPE_IS_OBJECT (class_type), 0); - - return g_signal_new ("remove-accelerator", - class_type, - signal_flags, - handler_offset, - (GSignalAccumulator) NULL, NULL, - gtk_marshal_VOID__OBJECT_UINT_FLAGS, - G_TYPE_NONE, 3, - GTK_TYPE_ACCEL_GROUP, - G_TYPE_UINT, - GDK_TYPE_MODIFIER_TYPE); + gboolean was_handled; + + g_return_val_if_fail (GTK_IS_ACCEL_GROUP (accel_group), FALSE); + + was_handled = FALSE; + g_signal_emit (accel_group, signal_accel_activate, accel_quark, + acceleratable, accel_key, accel_mods, &was_handled); + + return was_handled; } -GSList* -gtk_accel_groups_from_object (GObject *object) +/** + * gtk_accel_groups_activate: + * @acceleratable: usually a #GtkWindow + * @accel_key: accelerator keyval from a key event + * @accel_mods: keyboard state mask from a key event + * @returns: %TRUE if the accelerator was handled, %FALSE otherwise + * + * Finds the first accelerator in any #GtkAccelGroup attached + * to @acceleratable that matches @accel_key and @accel_mods, and + * activates that accelerator. + * If an accelerator was activated and handled this keypress, %TRUE + * is returned. + */ +gboolean +gtk_accel_groups_activate (GObject *acceleratable, + guint accel_key, + GdkModifierType accel_mods) { - g_return_val_if_fail (G_IS_OBJECT (object), NULL); + g_return_val_if_fail (G_IS_OBJECT (acceleratable), FALSE); - return g_object_get_qdata (object, accel_groups_key_id); -} + if (gtk_accelerator_valid (accel_key, accel_mods)) + { + gchar *accel_name; + GQuark accel_quark; + GSList *slist; -GSList* -gtk_accel_group_entries_from_object (GObject *object) -{ - g_return_val_if_fail (G_IS_OBJECT (object), NULL); + accel_name = gtk_accelerator_name (accel_key, accel_mods); + accel_quark = g_quark_from_string (accel_name); + g_free (accel_name); + + for (slist = gtk_accel_groups_from_acceleratable (acceleratable); slist; slist = slist->next) + if (_gtk_accel_group_activate (slist->data, accel_quark, acceleratable, accel_key, accel_mods)) + return TRUE; + } - return g_object_get_qdata (object, accel_entries_key_id); + return FALSE; } /** - * gtk_accelerator_valid: - * @keyval: a GDK keyval + * gtk_accelerator_valid + * @keyval: a GDK keyval * @modifiers: modifier mask + * @returns: %TRUE if the accelerator is valid * * Determines whether a given keyval and modifier mask constitute * a valid keyboard accelerator. For example, the GDK_a keyval * plus GDK_CONTROL_MASK is valid - this is a "Ctrl+a" accelerator. - * But you can't use the NumLock key as an accelerator. - * - * Return value: %TRUE if the accelerator is valid - **/ + * But by default (see gtk_accelerator_set_default_mod_mask()) you + * cannot use the NumLock key as an accelerator modifier. + */ gboolean gtk_accelerator_valid (guint keyval, GdkModifierType modifiers) @@ -1018,10 +784,10 @@ is_release (const gchar *string) } /** - * gtk_accelerator_parse: - * @accelerator: string representing an accelerator - * @accelerator_key: return location for accelerator keyval - * @accelerator_mods: return location for accelerator mod mask + * gtk_accelerator_parse + * @accelerator: string representing an accelerator + * @accelerator_key: return location for accelerator keyval + * @accelerator_mods: return location for accelerator modifier mask * * Parses a string representing an accelerator. The * format looks like "<Control>a" or "<Shift><Alt>F1" or @@ -1031,11 +797,11 @@ is_release (const gchar *string) * * If the parse fails, @accelerator_key and @accelerator_mods will * be set to 0 (zero). - **/ + */ void -gtk_accelerator_parse (const gchar *accelerator, - guint *accelerator_key, - GdkModifierType*accelerator_mods) +gtk_accelerator_parse (const gchar *accelerator, + guint *accelerator_key, + GdkModifierType *accelerator_mods) { guint keyval; GdkModifierType mods; @@ -1136,19 +902,18 @@ gtk_accelerator_parse (const gchar *accelerator, } /** - * gtk_accelerator_name: - * @accelerator_key: an accelerator keyval - * @accelerator_mods: modifier mask + * gtk_accelerator_name + * @accelerator_key: accelerator keyval + * @accelerator_mods: accelerator modifier mask + * @returns: a newly allocated accelerator name * * Converts an accelerator keyval and modifier mask * into a string parseable by gtk_accelerator_parse(). * For example, if you pass in GDK_q and GDK_CONTROL_MASK, * this function returns "<Control>q". * - * The caller of this function must free the return value. - * - * Return value: the new accelerator name - **/ + * The caller of this function must free the returned string. + */ gchar* gtk_accelerator_name (guint accelerator_key, GdkModifierType accelerator_mods) @@ -1240,18 +1005,17 @@ gtk_accelerator_name (guint accelerator_key, } /** - * gtk_accelerator_set_default_mod_mask: - * @default_mod_mask: a modifier mask + * gtk_accelerator_set_default_mod_mask + * @default_mod_mask: accelerator modifier mask * * Sets the modifiers that will be considered significant for keyboard * accelerators. The default mod mask is #GDK_CONTROL_MASK | * #GDK_SHIFT_MASK | #GDK_MOD1_MASK, that is, Control, Shift, and Alt. - * Other modifiers will be ignored by #GtkAccelGroup. + * Other modifiers will by default be ignored by #GtkAccelGroup. * * The default mod mask should be changed on application startup, - * before creating any accelerator groups. - * - **/ + * before using any accelerator groups. + */ void gtk_accelerator_set_default_mod_mask (GdkModifierType default_mod_mask) { @@ -1259,12 +1023,11 @@ gtk_accelerator_set_default_mod_mask (GdkModifierType default_mod_mask) } /** - * gtk_accelerator_get_default_mod_mask: + * gtk_accelerator_get_default_mod_mask + * @returns: the default accelerator modifier mask * * Gets the value set by gtk_accelerator_set_default_mod_mask(). - * - * Return value: the default modifier mask. - **/ + */ guint gtk_accelerator_get_default_mod_mask (void) { diff --git a/gtk/gtkaccelgroup.h b/gtk/gtkaccelgroup.h index d3e8d1fb4..5fca1a33b 100644 --- a/gtk/gtkaccelgroup.h +++ b/gtk/gtkaccelgroup.h @@ -1,8 +1,5 @@ /* GTK - The GIMP Toolkit - * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald - * - * GtkAccelGroup: Accelerator manager for GtkObjects. - * Copyright (C) 1998 Tim Janik + * Copyright (C) 1998, 2001 Tim Janik * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -32,13 +29,12 @@ #include <gdk/gdk.h> -#include <gtk/gtkobject.h> #include <gtk/gtkenums.h> - G_BEGIN_DECLS +/* --- type macros --- */ #define GTK_TYPE_ACCEL_GROUP (gtk_accel_group_get_type ()) #define GTK_ACCEL_GROUP(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GTK_TYPE_ACCEL_GROUP, GtkAccelGroup)) #define GTK_ACCEL_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_ACCEL_GROUP, GtkAccelGroupClass)) @@ -47,136 +43,113 @@ G_BEGIN_DECLS #define GTK_ACCEL_GROUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_ACCEL_GROUP, GtkAccelGroupClass)) -typedef struct _GtkAccelGroup GtkAccelGroup; -typedef struct _GtkAccelGroupClass GtkAccelGroupClass; -typedef struct _GtkAccelEntry GtkAccelEntry; - +/* --- accel flags --- */ typedef enum { - /* should the accelerator appear in - * the widget's display? - */ - GTK_ACCEL_VISIBLE = 1 << 0, - /* should the signal associated with - * this accelerator be also visible? - */ - GTK_ACCEL_SIGNAL_VISIBLE = 1 << 1, - /* may the accelerator be removed - * again? - */ - GTK_ACCEL_LOCKED = 1 << 2, + GTK_ACCEL_VISIBLE = 1 << 0, /* display in GtkAccelLabel? */ + GTK_ACCEL_LOCKED = 1 << 1, /* is it removable? */ GTK_ACCEL_MASK = 0x07 } GtkAccelFlags; + +/* --- typedefs & structures --- */ +typedef struct _GtkAccelGroup GtkAccelGroup; +typedef struct _GtkAccelGroupClass GtkAccelGroupClass; +typedef struct _GtkAccelKey GtkAccelKey; +typedef struct _GtkAccelGroupEntry GtkAccelGroupEntry; +typedef gboolean (*GtkAccelGroupActivate) (GtkAccelGroup *accel_group, + GObject *acceleratable, + guint keyval, + GdkModifierType modifier); struct _GtkAccelGroup { - GObject parent; - guint lock_count; - GdkModifierType modifier_mask; - GSList *attach_objects; + GObject parent; + guint lock_count; + GdkModifierType modifier_mask; + GSList *acceleratables; + guint n_accels; + GtkAccelGroupEntry *priv_accels; }; - struct _GtkAccelGroupClass { GObjectClass parent_class; -}; -struct _GtkAccelEntry + void (*accel_changed) (GtkAccelGroup *accel_group, + guint keyval, + GdkModifierType modifier, + GClosure *accel_closure); +}; +struct _GtkAccelKey { - /* key portion - */ - GtkAccelGroup *accel_group; - guint accelerator_key; - GdkModifierType accelerator_mods; - - GtkAccelFlags accel_flags; - GObject *object; - guint signal_id; + guint accel_key; + GdkModifierType accel_mods; + guint accel_flags : 16; }; -/* Accelerators - */ -gboolean gtk_accelerator_valid (guint keyval, - GdkModifierType modifiers) G_GNUC_CONST; -void gtk_accelerator_parse (const gchar *accelerator, - guint *accelerator_key, - GdkModifierType *accelerator_mods); -gchar* gtk_accelerator_name (guint accelerator_key, - GdkModifierType accelerator_mods); -void gtk_accelerator_set_default_mod_mask (GdkModifierType default_mod_mask); -guint gtk_accelerator_get_default_mod_mask (void); - - -/* Accelerator Groups - */ +/* -- Accelerator Groups --- */ GType gtk_accel_group_get_type (void); GtkAccelGroup* gtk_accel_group_new (void); -GtkAccelGroup* gtk_accel_group_get_default (void); -GtkAccelGroup* gtk_accel_group_ref (GtkAccelGroup *accel_group); -void gtk_accel_group_unref (GtkAccelGroup *accel_group); void gtk_accel_group_lock (GtkAccelGroup *accel_group); void gtk_accel_group_unlock (GtkAccelGroup *accel_group); -gboolean gtk_accel_groups_activate (GObject *object, +void gtk_accel_group_connect (GtkAccelGroup *accel_group, guint accel_key, - GdkModifierType accel_mods); - -/* internal functions - */ -gboolean gtk_accel_group_activate (GtkAccelGroup *accel_group, + GdkModifierType accel_mods, + GtkAccelFlags accel_flags, + GClosure *closure, + GQuark accel_path_quark); +gboolean gtk_accel_group_disconnect (GtkAccelGroup *accel_group, guint accel_key, GdkModifierType accel_mods); -void gtk_accel_group_attach (GtkAccelGroup *accel_group, +gboolean gtk_accel_groups_disconnect_closure (GClosure *closure); + + +/* --- GtkActivatable glue --- */ +void _gtk_accel_group_attach (GtkAccelGroup *accel_group, GObject *object); -void gtk_accel_group_detach (GtkAccelGroup *accel_group, +void _gtk_accel_group_detach (GtkAccelGroup *accel_group, GObject *object); - -/* Accelerator Group Entries (internal) - */ -GtkAccelEntry* gtk_accel_group_get_entry (GtkAccelGroup *accel_group, - guint accel_key, - GdkModifierType accel_mods); -void gtk_accel_group_lock_entry (GtkAccelGroup *accel_group, - guint accel_key, - GdkModifierType accel_mods); -void gtk_accel_group_unlock_entry (GtkAccelGroup *accel_group, +gboolean gtk_accel_groups_activate (GObject *acceleratable, guint accel_key, GdkModifierType accel_mods); -void gtk_accel_group_add (GtkAccelGroup *accel_group, - guint accel_key, - GdkModifierType accel_mods, - GtkAccelFlags accel_flags, - GObject *object, - const gchar *accel_signal); -void gtk_accel_group_remove (GtkAccelGroup *accel_group, - guint accel_key, - GdkModifierType accel_mods, - GObject *object); +GSList* gtk_accel_groups_from_acceleratable (GObject *object); +GtkAccelKey* gtk_accel_group_find (GtkAccelGroup *accel_group, + gboolean (*find_func) (GtkAccelKey *key, + GClosure *closure, + gpointer data), + gpointer data); +GtkAccelGroup* gtk_accel_group_from_accel_closure (GClosure *closure); -/* Accelerator Signals (internal) - */ -void gtk_accel_group_handle_add (GObject *object, - guint accel_signal_id, - GtkAccelGroup *accel_group, + +/* --- Accelerators--- */ +gboolean gtk_accelerator_valid (guint keyval, + GdkModifierType modifiers) G_GNUC_CONST; +void gtk_accelerator_parse (const gchar *accelerator, + guint *accelerator_key, + GdkModifierType *accelerator_mods); +gchar* gtk_accelerator_name (guint accelerator_key, + GdkModifierType accelerator_mods); +void gtk_accelerator_set_default_mod_mask (GdkModifierType default_mod_mask); +guint gtk_accelerator_get_default_mod_mask (void); + + +/* --- internal --- */ +GtkAccelGroupEntry* gtk_accel_group_query (GtkAccelGroup *accel_group, guint accel_key, GdkModifierType accel_mods, - GtkAccelFlags accel_flags); -void gtk_accel_group_handle_remove (GObject *object, - GtkAccelGroup *accel_group, - guint accel_key, - GdkModifierType accel_mods); -guint gtk_accel_group_create_add (GType class_type, - GSignalFlags signal_flags, - guint handler_offset); -guint gtk_accel_group_create_remove (GType class_type, - GSignalFlags signal_flags, - guint handler_offset); - -/* Miscellaneous (internal) - */ -GSList* gtk_accel_groups_from_object (GObject *object); -GSList* gtk_accel_group_entries_from_object (GObject *object); + guint *n_entries); +struct _GtkAccelGroupEntry +{ + GtkAccelKey key; + GClosure *closure; + GQuark accel_path_quark; +}; + +#ifndef GTK_DISABLE_DEPRECATED +#define gtk_accel_group_ref g_object_ref +#define gtk_accel_group_unref g_object_unref +#endif /* GTK_DISABLE_DEPRECATED */ G_END_DECLS diff --git a/gtk/gtkaccellabel.c b/gtk/gtkaccellabel.c index 82b4f35be..bee1060bd 100644 --- a/gtk/gtkaccellabel.c +++ b/gtk/gtkaccellabel.c @@ -26,17 +26,19 @@ * files for a list of changes. These files are distributed with * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */ - -#include <string.h> -#include <ctype.h> +#include "gtkaccellabel.h" +#include "gtkaccelmap.h" #include "gtkmain.h" #include "gtksignal.h" -#include "gtkaccellabel.h" #include "gtkintl.h" +#include <string.h> +#include <ctype.h> + enum { PROP_0, - PROP_ACCEL_OBJECT + PROP_ACCEL_CLOSURE, + PROP_ACCEL_WIDGET }; static void gtk_accel_label_class_init (GtkAccelLabelClass *klass); @@ -90,33 +92,17 @@ static void gtk_accel_label_class_init (GtkAccelLabelClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS (class); - GtkObjectClass *object_class; - GtkWidgetClass *widget_class; - GtkMiscClass *misc_class; - GtkLabelClass *label_class; + GtkObjectClass *object_class = GTK_OBJECT_CLASS (class); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); accel_label_class = class; - object_class = (GtkObjectClass*) class; - widget_class = (GtkWidgetClass*) class; - misc_class = (GtkMiscClass*) class; - label_class = (GtkLabelClass*) class; - - parent_class = gtk_type_class (GTK_TYPE_LABEL); + parent_class = g_type_class_peek_parent (class); gobject_class->finalize = gtk_accel_label_finalize; gobject_class->set_property = gtk_accel_label_set_property; gobject_class->get_property = gtk_accel_label_get_property; object_class->destroy = gtk_accel_label_destroy; - - g_object_class_install_property (G_OBJECT_CLASS(object_class), - PROP_ACCEL_OBJECT, - g_param_spec_object ("accel_object", - _("Accelerator object"), - _("The object monitored by this accelerator label"), - G_TYPE_OBJECT, - G_PARAM_READABLE | G_PARAM_WRITABLE)); - widget_class->size_request = gtk_accel_label_size_request; widget_class->expose_event = gtk_accel_label_expose_event; @@ -129,6 +115,21 @@ gtk_accel_label_class_init (GtkAccelLabelClass *class) class->mod_separator = g_strdup ("+"); class->accel_seperator = g_strdup (" / "); class->latin1_to_char = TRUE; + + g_object_class_install_property (G_OBJECT_CLASS (object_class), + PROP_ACCEL_CLOSURE, + g_param_spec_object ("accel_closure", + _("Accelerator Closure"), + _("The closure to be monitored for accelerator changes"), + GTK_TYPE_WIDGET, + G_PARAM_READABLE | G_PARAM_WRITABLE)); + g_object_class_install_property (G_OBJECT_CLASS (object_class), + PROP_ACCEL_WIDGET, + g_param_spec_object ("accel_widget", + _("Accelerator Widget"), + _("The widget to be monitored for accelerator changes"), + GTK_TYPE_WIDGET, + G_PARAM_READABLE | G_PARAM_WRITABLE)); } static void @@ -143,8 +144,11 @@ gtk_accel_label_set_property (GObject *object, switch (prop_id) { - case PROP_ACCEL_OBJECT: - gtk_accel_label_set_accel_object (accel_label, g_value_get_object (value)); + case PROP_ACCEL_CLOSURE: + gtk_accel_label_set_accel_closure (accel_label, g_value_get_boxed (value)); + break; + case PROP_ACCEL_WIDGET: + gtk_accel_label_set_accel_widget (accel_label, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -152,10 +156,11 @@ gtk_accel_label_set_property (GObject *object, } } -static void gtk_accel_label_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) +static void +gtk_accel_label_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) { GtkAccelLabel *accel_label; @@ -163,8 +168,11 @@ static void gtk_accel_label_get_property (GObject *object, switch (prop_id) { - case PROP_ACCEL_OBJECT: - g_value_set_object (value, accel_label->accel_object); + case PROP_ACCEL_CLOSURE: + g_value_set_boxed (value, accel_label->accel_closure); + break; + case PROP_ACCEL_WIDGET: + g_value_set_object (value, accel_label->accel_widget); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -177,7 +185,9 @@ gtk_accel_label_init (GtkAccelLabel *accel_label) { accel_label->queue_id = 0; accel_label->accel_padding = 3; - accel_label->accel_object = NULL; + accel_label->accel_widget = NULL; + accel_label->accel_closure = NULL; + accel_label->accel_group = NULL; accel_label->accel_string = NULL; gtk_accel_label_refetch (accel_label); @@ -206,7 +216,8 @@ gtk_accel_label_destroy (GtkObject *object) accel_label = GTK_ACCEL_LABEL (object); - gtk_accel_label_set_accel_object (accel_label, NULL); + gtk_accel_label_set_accel_widget (accel_label, NULL); + gtk_accel_label_set_accel_closure (accel_label, NULL); GTK_OBJECT_CLASS (parent_class)->destroy (object); } @@ -214,33 +225,34 @@ gtk_accel_label_destroy (GtkObject *object) static void gtk_accel_label_finalize (GObject *object) { - GtkAccelLabel *accel_label; - - g_return_if_fail (GTK_IS_ACCEL_LABEL (object)); - - accel_label = GTK_ACCEL_LABEL (object); - + GtkAccelLabel *accel_label = GTK_ACCEL_LABEL (object); + + if (accel_label->queue_id) + { + gtk_idle_remove (accel_label->queue_id); + accel_label->queue_id = 0; + } g_free (accel_label->accel_string); G_OBJECT_CLASS (parent_class)->finalize (object); } /** - * gtk_accel_label_get_accel_object: + * gtk_accel_label_get_accel_widget: * @accel_label: a #GtkAccelLabel * * Fetches the widget monitored by this accelerator label. See - * gtk_accel_label_set_accel_object(). + * gtk_accel_label_set_accel_widget(). * * Return value: the object monitored by the accelerator label, * or %NULL. **/ -GObject * -gtk_accel_label_get_accel_object (GtkAccelLabel *accel_label) +GtkWidget* +gtk_accel_label_get_accel_widget (GtkAccelLabel *accel_label) { g_return_val_if_fail (GTK_IS_ACCEL_LABEL (accel_label), NULL); - return accel_label->accel_object; + return accel_label->accel_widget; } guint @@ -337,6 +349,55 @@ gtk_accel_label_expose_event (GtkWidget *widget, } static void +refetch_widget_accel_closure (GtkAccelLabel *accel_label) +{ + GSList *slist; + + g_return_if_fail (GTK_IS_ACCEL_LABEL (accel_label)); + g_return_if_fail (GTK_IS_WIDGET (accel_label->accel_widget)); + + for (slist = _gtk_widget_get_accel_closures (accel_label->accel_widget); slist; slist = slist->next) + if (gtk_accel_group_from_accel_closure (slist->data)) + { + /* we just take the first correctly used closure */ + gtk_accel_label_set_accel_closure (accel_label, slist->data); + return; + } + gtk_accel_label_set_accel_closure (accel_label, NULL); +} + +void +gtk_accel_label_set_accel_widget (GtkAccelLabel *accel_label, + GtkWidget *accel_widget) +{ + g_return_if_fail (GTK_IS_ACCEL_LABEL (accel_label)); + if (accel_widget) + g_return_if_fail (GTK_IS_WIDGET (accel_widget)); + + if (accel_widget != accel_label->accel_widget) + { + if (accel_label->accel_widget) + { + gtk_accel_label_set_accel_closure (accel_label, NULL); + g_signal_handlers_disconnect_by_func (accel_label->accel_widget, + G_CALLBACK (refetch_widget_accel_closure), + accel_label); + g_object_unref (accel_label->accel_widget); + } + accel_label->accel_widget = accel_widget; + if (accel_label->accel_widget) + { + g_object_ref (accel_label->accel_widget); + g_signal_connect_object (accel_label->accel_widget, "accel_closures_changed", + G_CALLBACK (refetch_widget_accel_closure), + accel_label, G_CONNECT_SWAPPED); + refetch_widget_accel_closure (accel_label); + } + g_object_notify (G_OBJECT (accel_label), "accel_widget"); + } +} + +static void gtk_accel_label_queue_refetch (GtkAccelLabel *accel_label) { g_return_if_fail (GTK_IS_ACCEL_LABEL (accel_label)); @@ -347,45 +408,46 @@ gtk_accel_label_queue_refetch (GtkAccelLabel *accel_label) accel_label); } +static void +check_accel_changed (GtkAccelGroup *accel_group, + guint keyval, + GdkModifierType modifier, + GClosure *accel_closure, + GtkAccelLabel *accel_label) +{ + if (accel_closure == accel_label->accel_closure) + gtk_accel_label_queue_refetch (accel_label); +} + void -gtk_accel_label_set_accel_object (GtkAccelLabel *accel_label, - GObject *accel_object) +gtk_accel_label_set_accel_closure (GtkAccelLabel *accel_label, + GClosure *accel_closure) { g_return_if_fail (GTK_IS_ACCEL_LABEL (accel_label)); - g_return_if_fail (accel_object == NULL || G_IS_OBJECT (accel_object)); - - if (accel_object != accel_label->accel_object) + if (accel_closure) + g_return_if_fail (gtk_accel_group_from_accel_closure (accel_closure) != NULL); + + if (accel_closure != accel_label->accel_closure) { - if (accel_label->accel_object) + if (accel_label->accel_closure) { - g_signal_handlers_disconnect_by_func (accel_label->accel_object, - G_CALLBACK (gtk_accel_label_queue_refetch), - accel_object); - g_object_unref (accel_label->accel_object); + g_signal_handlers_disconnect_by_func (accel_label->accel_group, + G_CALLBACK (check_accel_changed), + accel_label); + accel_label->accel_group = NULL; + g_closure_unref (accel_label->accel_closure); } - if (accel_label->queue_id) + accel_label->accel_closure = accel_closure; + if (accel_label->accel_closure) { - gtk_idle_remove (accel_label->queue_id); - accel_label->queue_id = 0; + g_closure_ref (accel_label->accel_closure); + accel_label->accel_group = gtk_accel_group_from_accel_closure (accel_closure); + g_signal_connect_object (accel_label->accel_group, "accel_changed", + G_CALLBACK (check_accel_changed), + accel_label, 0); } - accel_label->accel_object = accel_object; - if (accel_label->accel_object) - { - g_object_ref (accel_label->accel_object); - g_signal_connect_object (accel_label->accel_object, - "add-accelerator", - G_CALLBACK (gtk_accel_label_queue_refetch), - accel_label, - G_CONNECT_AFTER | G_CONNECT_SWAPPED); - g_signal_connect_object (accel_label->accel_object, - "remove-accelerator", - G_CALLBACK (gtk_accel_label_queue_refetch), - accel_label, - G_CONNECT_AFTER | G_CONNECT_SWAPPED); - } - gtk_accel_label_refetch (accel_label); - - g_object_notify (G_OBJECT (accel_label), "accel_object"); + gtk_accel_label_queue_refetch (accel_label); + g_object_notify (G_OBJECT (accel_label), "accel_closure"); } } @@ -401,107 +463,106 @@ gtk_accel_label_refetch_idle (GtkAccelLabel *accel_label) return retval; } +static gboolean +find_accel (GtkAccelKey *key, + GClosure *closure, + gpointer data) +{ + return data == (gpointer) closure; +} + gboolean gtk_accel_label_refetch (GtkAccelLabel *accel_label) { GtkAccelLabelClass *class; + gchar *utf8; g_return_val_if_fail (GTK_IS_ACCEL_LABEL (accel_label), FALSE); class = GTK_ACCEL_LABEL_GET_CLASS (accel_label); - + g_free (accel_label->accel_string); accel_label->accel_string = NULL; - - if (accel_label->accel_object) + + if (accel_label->accel_closure) { - GtkAccelEntry *entry = NULL; - GSList *slist; - - slist = gtk_accel_group_entries_from_object (accel_label->accel_object); - for (; slist; slist = slist->next) + GtkAccelKey *key = gtk_accel_group_find (accel_label->accel_group, find_accel, accel_label->accel_closure); + + if (key && key->accel_flags & GTK_ACCEL_VISIBLE) { - entry = slist->data; - if (entry->accel_flags & GTK_ACCEL_VISIBLE) + GString *gstring; + gboolean seen_mod = FALSE; + + gstring = g_string_new (accel_label->accel_string); + g_string_append (gstring, gstring->len ? class->accel_seperator : " "); + + if (key->accel_mods & GDK_SHIFT_MASK) { - GString *gstring; - gboolean had_mod; - - gstring = g_string_new (accel_label->accel_string); - if (gstring->len) - g_string_append (gstring, class->accel_seperator); - else - g_string_append (gstring, " "); - - if (entry->accel_flags & GTK_ACCEL_SIGNAL_VISIBLE) - { - g_string_append (gstring, class->signal_quote1); - g_string_append (gstring, gtk_signal_name (entry->signal_id)); - g_string_append (gstring, class->signal_quote2); - } - - had_mod = FALSE; - if (entry->accelerator_mods & GDK_SHIFT_MASK) - { - g_string_append (gstring, class->mod_name_shift); - had_mod = TRUE; - } - if (entry->accelerator_mods & GDK_CONTROL_MASK) - { - if (had_mod) - g_string_append (gstring, class->mod_separator); - g_string_append (gstring, class->mod_name_control); - had_mod = TRUE; - } - if (entry->accelerator_mods & GDK_MOD1_MASK) - { - if (had_mod) - g_string_append (gstring, class->mod_separator); - g_string_append (gstring, class->mod_name_alt); - had_mod = TRUE; - } - - if (had_mod) + g_string_append (gstring, class->mod_name_shift); + seen_mod = TRUE; + } + if (key->accel_mods & GDK_CONTROL_MASK) + { + if (seen_mod) g_string_append (gstring, class->mod_separator); - if (entry->accelerator_key < 0x80 || - (entry->accelerator_key > 0x80 && - entry->accelerator_key <= 0xff && - class->latin1_to_char)) - { - switch (entry->accelerator_key) - { - case ' ': - g_string_append (gstring, "Space"); - break; - case '\\': - g_string_append (gstring, "Backslash"); - break; - default: - g_string_append_c (gstring, toupper (entry->accelerator_key)); - break; - } - } - else + g_string_append (gstring, class->mod_name_control); + seen_mod = TRUE; + } + if (key->accel_mods & GDK_MOD1_MASK) + { + if (seen_mod) + g_string_append (gstring, class->mod_separator); + g_string_append (gstring, class->mod_name_alt); + seen_mod = TRUE; + } + if (seen_mod) + g_string_append (gstring, class->mod_separator); + if (key->accel_key < 0x80 || + (key->accel_key > 0x80 && + key->accel_key <= 0xff && + class->latin1_to_char)) + { + switch (key->accel_key) { - gchar *tmp; - - tmp = gtk_accelerator_name (entry->accelerator_key, 0); - if (tmp[0] != 0 && tmp[1] == 0) - tmp[0] = toupper (tmp[0]); - g_string_append (gstring, tmp); - g_free (tmp); + case ' ': + g_string_append (gstring, "Space"); + break; + case '\\': + g_string_append (gstring, "Backslash"); + break; + default: + g_string_append_c (gstring, toupper (key->accel_key)); + break; } - - g_free (accel_label->accel_string); - accel_label->accel_string = gstring->str; - g_string_free (gstring, FALSE); } + else + { + gchar *tmp; + + tmp = gtk_accelerator_name (key->accel_key, 0); + if (tmp[0] != 0 && tmp[1] == 0) + tmp[0] = toupper (tmp[0]); + g_string_append (gstring, tmp); + g_free (tmp); + } + g_free (accel_label->accel_string); + accel_label->accel_string = gstring->str; + g_string_free (gstring, FALSE); } + if (!accel_label->accel_string) + accel_label->accel_string = g_strdup ("-/-"); } - + if (!accel_label->accel_string) accel_label->accel_string = g_strdup (""); + utf8 = g_locale_to_utf8 (accel_label->accel_string, -1, NULL, NULL, NULL); + if (utf8) + { + g_free (accel_label->accel_string); + accel_label->accel_string = utf8; + } + if (accel_label->queue_id) { gtk_idle_remove (accel_label->queue_id); diff --git a/gtk/gtkaccellabel.h b/gtk/gtkaccellabel.h index 5a9b779aa..89529e88d 100644 --- a/gtk/gtkaccellabel.h +++ b/gtk/gtkaccellabel.h @@ -54,11 +54,13 @@ struct _GtkAccelLabel { GtkLabel label; - guint queue_id; - guint accel_padding; - GObject *accel_object; - gchar *accel_string; - guint16 accel_string_width; + guint queue_id; + guint accel_padding; + GtkWidget *accel_widget; + GClosure *accel_closure; + GtkAccelGroup *accel_group; + gchar *accel_string; + guint16 accel_string_width; }; struct _GtkAccelLabelClass @@ -80,20 +82,15 @@ struct _GtkAccelLabelClass #endif /* GTK_DISABLE_DEPRECATED */ GtkType gtk_accel_label_get_type (void) G_GNUC_CONST; -GtkWidget *gtk_accel_label_new (const gchar *string); -GObject *gtk_accel_label_get_accel_object (GtkAccelLabel *accel_label); +GtkWidget* gtk_accel_label_new (const gchar *string); +GtkWidget* gtk_accel_label_get_accel_widget (GtkAccelLabel *accel_label); guint gtk_accel_label_get_accel_width (GtkAccelLabel *accel_label); -void gtk_accel_label_set_accel_object (GtkAccelLabel *accel_label, - GObject *accel_object); +void gtk_accel_label_set_accel_widget (GtkAccelLabel *accel_label, + GtkWidget *accel_widget); +void gtk_accel_label_set_accel_closure (GtkAccelLabel *accel_label, + GClosure *closure); gboolean gtk_accel_label_refetch (GtkAccelLabel *accel_label); -#ifndef GTK_DISABLE_DEPRECATED -#define gtk_accel_label_get_accel_widget(accel_label) \ - GTK_WIDGET(gtk_accel_label_get_accel_object(acel_label)) -#define gtk_accel_label_set_accel_widget(accel_label, accel_widget) \ - gtk_accel_label_set_accel_object((accel_label), G_OBJECT(accel_widget)) -#endif - #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/gtk/gtkaccelmap.c b/gtk/gtkaccelmap.c new file mode 100644 index 000000000..24dca7d5c --- /dev/null +++ b/gtk/gtkaccelmap.c @@ -0,0 +1,858 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1998, 2001 Tim Janik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser 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 "gtkaccelmap.h" + +#include "gtkwindow.h" /* in lack of GtkAcceleratable */ + +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> + + +/* --- structures --- */ +typedef struct { + const gchar *accel_path; + guint accel_key; + guint accel_mods; + guint std_accel_key; + guint std_accel_mods; + guint changed : 1; + GHookList *hooks; +} AccelEntry; + + +/* --- variables --- */ +static GHashTable *accel_entry_ht = NULL; /* accel_path -> AccelEntry */ +static GSList *accel_filters = NULL; + + +/* --- functions --- */ +static guint +accel_entry_hash (gconstpointer key) +{ + const AccelEntry *entry = key; + + return g_str_hash (entry->accel_path); +} + +static gboolean +accel_entry_equal (gconstpointer key1, + gconstpointer key2) +{ + const AccelEntry *entry1 = key1; + const AccelEntry *entry2 = key2; + + return g_str_equal (entry1->accel_path, entry2->accel_path); +} + +static inline AccelEntry* +accel_path_lookup (const gchar *accel_path) +{ + AccelEntry ekey; + + ekey.accel_path = accel_path; + + /* safety NULL check for return_if_fail()s */ + return accel_path ? g_hash_table_lookup (accel_entry_ht, &ekey) : NULL; +} + +void +_gtk_accel_map_init (void) +{ + g_assert (accel_entry_ht == NULL); + + accel_entry_ht = g_hash_table_new (accel_entry_hash, accel_entry_equal); +} + +static gboolean +gtk_accel_path_is_valid (const gchar *accel_path) +{ + gchar *p; + + if (!accel_path || accel_path[0] != '<' || + accel_path[1] == '<' || accel_path[1] == '>' || !accel_path[1]) + return FALSE; + p = strchr (accel_path, '>'); + if (!p || p[1] != '/') + return FALSE; + return TRUE; +} + +/** + * gtk_accel_map_add_entry + * @accel_path: valid accelerator path + * @accel_key: the accelerator key + * @accel_mods: the accelerator modifiers + * @returns: the GQuark for the @accel_path (to ease local storage) + * + * Register a new accelerator with the global accelerator map. + * This function should only be called once per @accel_path + * with the canonical @accel_key and @accel_mods for this path. + * To change the accelerator during runtime programatically, use + * gtk_accel_map_change_entry(). + * The accelerator path must consist of "<WINDOWTYPE>/Category1/Category2/.../Action", + * where WINDOWTYPE should be a unique application specifc identifier, that + * corresponds to the kind of window the accelerator is being used in, e.g. "Gimp-Image", + * "Abiword-Document" or "Gnumeric-Settings". + * The Category1/.../Action portion is most apropriately choosen by the action the + * accelerator triggers, i.e. for accelerators on menu items, choose the item's menu path, + * e.g. "File/Save As", "Image/View/Zoom" or "Edit/Select All". + * So a full valid accelerator path may look like: + * "<Gimp-Toolbox>/File/Dialogs/Tool Options...". + */ +GQuark +gtk_accel_map_add_entry (const gchar *accel_path, + guint accel_key, + guint accel_mods) +{ + AccelEntry *entry; + + g_return_val_if_fail (gtk_accel_path_is_valid (accel_path), 0); + + accel_mods &= gtk_accelerator_get_default_mod_mask (); + + entry = accel_path_lookup (accel_path); + if (entry) + { + if (!entry->std_accel_key && !entry->std_accel_mods && + (accel_key || accel_mods)) + { + entry->std_accel_key = accel_key; + entry->std_accel_mods = accel_mods; + if (!entry->changed) + gtk_accel_map_change_entry (entry->accel_path, accel_key, accel_mods, TRUE); + } + } + else + { + entry = g_new0 (AccelEntry, 1); + entry->accel_path = g_quark_to_string (g_quark_from_string (accel_path)); + entry->std_accel_key = accel_key; + entry->std_accel_mods = accel_mods; + entry->accel_key = accel_key; + entry->accel_mods = accel_mods; + entry->changed = FALSE; + g_hash_table_insert (accel_entry_ht, entry, entry); + } + return g_quark_try_string (entry->accel_path); +} + +typedef struct { + GHook hook; + GtkAccelGroup *accel_group; +} AccelHook; + +static void +accel_hook_finalize (GHookList *hook_list, + GHook *hook) +{ + GDestroyNotify destroy = hook->destroy; + AccelHook *ahook = (AccelHook*) hook; + + if (ahook->accel_group) + g_object_unref (ahook->accel_group); + + if (destroy) + { + hook->destroy = NULL; + destroy (hook->data); + } +} + +/** + * GtkAccelMapNotify + * @data: notifier user data + * @accel_path_quark: accelerator path (as #GQuark) which has just changed + * @accel_key: new accelerator key + * @accel_mods: new accelerator modifiers + * @accel_group: accelerator group of this notifier + * @old_accel_key: former accelerator key + * @old_accel_mods): former accelerator modifiers + * + * #GtkAccelMapNotify is the signature of user callbacks, installed via + * gtk_accel_map_add_notifier(). Once the accel path of the notifier changes, + * the notifier is invoked with this signature, where @accel_path_quark + * indicates the accel path that changed, and @data and @accel_group are + * the notifier's arguments as passed into gtk_accel_map_add_notifier(). + */ + +/** + * gtk_accel_map_add_notifer + * @accel_path: valid accelerator path + * @notify_data: data argument to the notifier + * @notify_func: the notifier function + * @accel_group: accelerator group used by the notifier function + * + * Install a notifier function to be called if an accelerator + * map entry changes. @accel_group has to be the accel group + * that is being affected (gets an accelerator removed or added, + * when the notifier function is executed). + */ +void +gtk_accel_map_add_notifer (const gchar *accel_path, + gpointer notify_data, + GtkAccelMapNotify notify_func, + GtkAccelGroup *accel_group) +{ + AccelEntry *entry; + AccelHook *ahook; + GHook *hook; + + g_return_if_fail (gtk_accel_path_is_valid (accel_path)); + g_return_if_fail (notify_func != NULL); + if (accel_group) + g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group)); + + entry = accel_path_lookup (accel_path); + if (!entry) + { + gtk_accel_map_add_entry (accel_path, 0, 0); + entry = accel_path_lookup (accel_path); + } + if (!entry->hooks) + { + entry->hooks = g_new (GHookList, 1); + g_hook_list_init (entry->hooks, sizeof (AccelHook)); + entry->hooks->finalize_hook = accel_hook_finalize; + } + hook = g_hook_alloc (entry->hooks); + hook->data = notify_data; + hook->func = notify_func; + hook->destroy = NULL; + ahook = (AccelHook*) hook; + ahook->accel_group = accel_group ? g_object_ref (accel_group) : NULL; + g_hook_append (entry->hooks, hook); +} + +/** + * gtk_accel_map_remove_notifer + * @accel_path: valid accelerator path + * @notify_data: data argument to the notifier + * @notify_func: the notifier function + * + * Remove a notifier function, previously installed through + * gtk_accel_map_add_notifer(). + */ +void +gtk_accel_map_remove_notifer (const gchar *accel_path, + gpointer notify_data, + GtkAccelMapNotify notify_func) +{ + AccelEntry *entry; + + g_return_if_fail (gtk_accel_path_is_valid (accel_path)); + g_return_if_fail (notify_func != NULL); + + entry = accel_path_lookup (accel_path); + if (entry && entry->hooks) + { + GHook *hook = g_hook_find_func_data (entry->hooks, TRUE, notify_func, notify_data); + + if (hook && g_hook_destroy (entry->hooks, hook->hook_id)) + return; /* successfully removed */ + } + g_warning (G_STRLOC ": no notifier %p(%p) installed for accel path \"%s\"", + notify_func, notify_data, accel_path); +} + +/** + * gtk_accel_map_lookup_entry + * @accel_path: valid accelerator path + * @key: accelerator key to be filled in (optional) + * @returns: #GQuark for @accel_path or (0) if @accel_path is not known + * + * Lookup the accelerator entry for @accel_path and fill in @key. + * If the lookup revealed no results, (0) is returned, the entry's + * #GQuark otherwise. + */ +GQuark +gtk_accel_map_lookup_entry (const gchar *accel_path, + GtkAccelKey *key) +{ + AccelEntry *entry; + + g_return_val_if_fail (gtk_accel_path_is_valid (accel_path), 0); + + entry = accel_path_lookup (accel_path); + if (entry && key) + { + key->accel_key = entry->accel_key; + key->accel_mods = entry->accel_mods; + key->accel_flags = 0; // FIXME: global lock? + } + + return entry ? g_quark_try_string (entry->accel_path) : 0; +} + +static void +hash2slist_foreach (gpointer key, + gpointer value, + gpointer user_data) +{ + GSList **slist_p = user_data; + + *slist_p = g_slist_prepend (*slist_p, value); +} + +static GSList* +g_hash_table_slist_values (GHashTable *hash_table) +{ + GSList *slist = NULL; + + g_return_val_if_fail (hash_table != NULL, NULL); + + g_hash_table_foreach (hash_table, hash2slist_foreach, &slist); + + return slist; +} + +static gboolean +internal_change_entry (const gchar *accel_path, + guint accel_key, + GdkModifierType accel_mods, + gboolean replace, + gboolean simulate) +{ + GSList *node, *slist, *win_list, *group_list, *replace_list = NULL; + GHashTable *group_hm, *win_hm; + gboolean change_accel, removable, can_change = TRUE, seen_accel = FALSE, hooks_may_recurse = TRUE; + GQuark entry_quark; + GHook *hook; + AccelEntry *entry = accel_path_lookup (accel_path); + + /* not much todo if there's no entry yet */ + if (!entry) + { + if (!simulate) + { + gtk_accel_map_add_entry (accel_path, 0, 0); + entry = accel_path_lookup (accel_path); + entry->accel_key = accel_key; + entry->accel_mods = accel_mods; + entry->changed = TRUE; + } + return TRUE; + } + + /* if there's nothing to change, not much todo either */ + if (entry->accel_key == accel_key && entry->accel_mods == accel_mods) + return FALSE; + + /* nobody's interested, easy going */ + if (!entry->hooks) + { + if (!simulate) + { + entry->accel_key = accel_key; + entry->accel_mods = accel_mods; + entry->changed = TRUE; + } + return TRUE; + } + + /* 1) fetch all accel groups affected by this entry */ + entry_quark = g_quark_try_string (entry->accel_path); + group_hm = g_hash_table_new (NULL, NULL); + win_hm = g_hash_table_new (NULL, NULL); + hook = g_hook_first_valid (entry->hooks, hooks_may_recurse); + while (hook) + { + AccelHook *ahook = (AccelHook*) hook; + + if (ahook->accel_group) + g_hash_table_insert (group_hm, ahook->accel_group, ahook->accel_group); + hook = g_hook_next_valid (entry->hooks, hook, hooks_may_recurse); + } + + /* 2) collect acceleratables affected */ + group_list = g_hash_table_slist_values (group_hm); + for (slist = group_list; slist; slist = slist->next) + { + GtkAccelGroup *group = slist->data; + + for (node = group->acceleratables; node; node = node->next) + g_hash_table_insert (win_hm, node->data, node->data); + } + g_slist_free (group_list); + + /* 3) include all accel groups used by acceleratables */ + win_list = g_hash_table_slist_values (win_hm); + g_hash_table_destroy (win_hm); + for (slist = win_list; slist; slist = slist->next) + for (node = gtk_accel_groups_from_acceleratable (slist->data); node; node = node->next) + g_hash_table_insert (group_hm, node->data, node->data); + group_list = g_hash_table_slist_values (group_hm); + g_hash_table_destroy (group_hm); + + /* 4) walk the acceleratables and figure whether they occupy accel_key&accel_mods */ + for (slist = accel_key ? win_list : NULL; slist; slist = slist->next) + if (GTK_IS_WINDOW (slist->data)) /* bad kludge in lack of a GtkAcceleratable */ + if (_gtk_window_query_nonaccels (slist->data, accel_key, accel_mods)) + { + seen_accel = TRUE; + break; + } + removable = !seen_accel; + + /* 5) walk all accel groups and search for locks */ + for (slist = removable ? group_list : NULL; slist; slist = slist->next) + { + GtkAccelGroup *group = slist->data; + GtkAccelGroupEntry *ag_entry; + guint i, n; + + n = 0; + ag_entry = entry->accel_key ? gtk_accel_group_query (group, entry->accel_key, entry->accel_mods, &n) : NULL; + for (i = 0; i < n; i++) + if (ag_entry[i].accel_path_quark == entry_quark) + { + can_change = !(ag_entry[i].key.accel_flags & GTK_ACCEL_LOCKED); + if (!can_change) + goto break_loop_step5; + } + + n = 0; + ag_entry = accel_key ? gtk_accel_group_query (group, accel_key, accel_mods, &n) : NULL; + for (i = 0; i < n; i++) + { + seen_accel = TRUE; + removable = !group->lock_count && !(ag_entry[i].key.accel_flags & GTK_ACCEL_LOCKED); + if (!removable) + goto break_loop_step5; + if (ag_entry[i].accel_path_quark) + replace_list = g_slist_prepend (replace_list, GUINT_TO_POINTER (ag_entry->accel_path_quark)); + } + } + break_loop_step5: + + /* 6) check whether we can remove existing accelerators */ + for (slist = removable ? replace_list : NULL; slist; slist = slist->next) + if (!internal_change_entry (g_quark_to_string (GPOINTER_TO_UINT (slist->data)), 0, 0, FALSE, TRUE)) + { + removable = FALSE; + break; + } + + /* 7) check conditions and proceed if possible */ + change_accel = can_change && (!seen_accel || (removable && replace)); + + if (change_accel && !simulate) + { + guint old_accel_key, old_accel_mods; + + /* 8) remove existing accelerators */ + for (slist = replace_list; slist; slist = slist->next) + internal_change_entry (g_quark_to_string (GPOINTER_TO_UINT (slist->data)), 0, 0, FALSE, FALSE); + + /* 9) install new accelerator */ + old_accel_key = entry->accel_key; + old_accel_mods = entry->accel_mods; + entry->accel_key = accel_key; + entry->accel_mods = accel_mods; + entry->changed = TRUE; + hook = g_hook_first_valid (entry->hooks, hooks_may_recurse); + while (hook) + { + gboolean was_in_call, need_destroy = FALSE; + GtkAccelMapNotify hook_func = hook->func; + AccelHook *ahook = (AccelHook*) hook; + + was_in_call = G_HOOK_IN_CALL (hook); + hook->flags |= G_HOOK_FLAG_IN_CALL; + /* need_destroy = */ hook_func (hook->data, g_quark_try_string (entry->accel_path), + entry->accel_key, entry->accel_mods, + ahook->accel_group, + old_accel_key, old_accel_mods); + if (!was_in_call) + hook->flags &= ~G_HOOK_FLAG_IN_CALL; + if (need_destroy) + g_hook_destroy_link (entry->hooks, hook); + hook = g_hook_next_valid (entry->hooks, hook, hooks_may_recurse); + } + } + g_slist_free (replace_list); + g_slist_free (group_list); + g_slist_free (win_list); + + return change_accel; +} + +/** + * gtk_accel_map_change_entry + * @accel_path: valid accelerator path + * @accel_key: new accelerator key + * @accel_mods: new accelerator modifiers + * @replace: %TRUE if other accelerators may be deleted upon conflicts + * @returns: %TRUE if the accelerator could be changed, %FALSE otherwise + * + * Change the @accel_key and @accel_mods currently associated with @accel_path. + * Due to conflicts with other accelerators, a change may not alwys be possible, + * @replace indicates whether other accelerators may be deleted to resolve such + * conflicts. A change will only occour if all conflicts could be resolved (which + * might not be the case if conflicting accelerators are locked). Succesfull + * changes are indicated by a %TRUE return value. + * Changes occouring are also indicated by invocation of notifiers attached to + * @accel_path (see gtk_accel_map_add_notifer() on this) and other accelerators + * that are being deleted. + */ +gboolean +gtk_accel_map_change_entry (const gchar *accel_path, + guint accel_key, + GdkModifierType accel_mods, + gboolean replace) +{ + g_return_val_if_fail (gtk_accel_path_is_valid (accel_path), FALSE); + + return internal_change_entry (accel_path, accel_key, accel_key ? accel_mods : 0, replace, FALSE); +} + +static guint +accel_map_parse_accel_path (GScanner *scanner) +{ + guint accel_key = 0, accel_mods = 0; + gchar *path, *accel; + + /* parse accel path */ + g_scanner_get_next_token (scanner); + if (scanner->token != G_TOKEN_STRING) + return G_TOKEN_STRING; + + /* test if the next token is an accelerator */ + g_scanner_peek_next_token (scanner); + if (scanner->next_token != G_TOKEN_STRING) + { + /* if not so, eat that token and error out */ + g_scanner_get_next_token (scanner); + return G_TOKEN_STRING; + } + + /* get the full accelerator specification */ + path = g_strdup (scanner->value.v_string); + g_scanner_get_next_token (scanner); + accel = g_strdup (scanner->value.v_string); + + /* ensure the entry is present */ + gtk_accel_map_add_entry (path, 0, 0); + + /* and propagate it */ + gtk_accelerator_parse (accel, &accel_key, &accel_mods); + gtk_accel_map_change_entry (path, accel_key, accel_mods, TRUE); + + g_free (accel); + g_free (path); + + /* check correct statement end */ + g_scanner_get_next_token (scanner); + if (scanner->token != ')') + return ')'; + else + return G_TOKEN_NONE; +} + +static void +accel_map_parse_statement (GScanner *scanner) +{ + guint expected_token; + + g_scanner_get_next_token (scanner); + + if (scanner->token == G_TOKEN_SYMBOL) + { + guint (*parser_func) (GScanner*); + + parser_func = scanner->value.v_symbol; + + expected_token = parser_func (scanner); + } + else + expected_token = G_TOKEN_SYMBOL; + + /* skip rest of statement on errrors + */ + if (expected_token != G_TOKEN_NONE) + { + register guint level; + + level = 1; + if (scanner->token == ')') + level--; + if (scanner->token == '(') + level++; + + while (!g_scanner_eof (scanner) && level > 0) + { + g_scanner_get_next_token (scanner); + + if (scanner->token == '(') + level++; + else if (scanner->token == ')') + level--; + } + } +} + +void +gtk_accel_map_load_scanner (GScanner *scanner) +{ + gboolean skip_comment_single; + gboolean symbol_2_token; + gchar *cpair_comment_single; + gpointer saved_symbol; + + g_return_if_fail (scanner != 0); + + /* configure scanner */ + skip_comment_single = scanner->config->skip_comment_single; + scanner->config->skip_comment_single = TRUE; + cpair_comment_single = scanner->config->cpair_comment_single; + scanner->config->cpair_comment_single = ";\n"; + symbol_2_token = scanner->config->symbol_2_token; + scanner->config->symbol_2_token = FALSE; + saved_symbol = g_scanner_lookup_symbol (scanner, "gtk_accel_path"); + g_scanner_scope_add_symbol (scanner, 0, "gtk_accel_path", accel_map_parse_accel_path); + + /* outer parsing loop + */ + g_scanner_peek_next_token (scanner); + while (scanner->next_token == '(') + { + g_scanner_get_next_token (scanner); + + accel_map_parse_statement (scanner); + + g_scanner_peek_next_token (scanner); + } + + /* restore config */ + scanner->config->skip_comment_single = skip_comment_single; + scanner->config->cpair_comment_single = cpair_comment_single; + scanner->config->symbol_2_token = symbol_2_token; + g_scanner_scope_remove_symbol (scanner, 0, "gtk_accel_path"); + if (saved_symbol) + g_scanner_scope_add_symbol (scanner, 0, "gtk_accel_path", saved_symbol); +} + +/** + * gtk_accel_map_load_fd + * @fd: valid readable file descriptor + * + * Filedescriptor variant of gtk_accel_map_load(). + * Note that the file descriptor will not be closed by this function. + */ +void +gtk_accel_map_load_fd (gint fd) +{ + GScanner *scanner; + + g_return_if_fail (fd >= 0); + + /* create and setup scanner */ + scanner = g_scanner_new (NULL); + g_scanner_input_file (scanner, fd); + + gtk_accel_map_load_scanner (scanner); + + g_scanner_destroy (scanner); +} + +/** + * gtk_accel_map_load + * @file_name: a file containing accelerator specifications + * + * Parses a file previously saved with gtk_accel_map_save() for + * accelerator specifications, and propagates them accordingly. + */ +void +gtk_accel_map_load (const gchar *file_name) +{ + gint fd; + + g_return_if_fail (file_name != NULL); + + if (!g_file_test (file_name, G_FILE_TEST_IS_REGULAR)) + return; + + fd = open (file_name, O_RDONLY); + if (fd < 0) + return; + + gtk_accel_map_load_fd (fd); + + close (fd); +} + +static void +accel_map_print (gpointer data, + const gchar *accel_path, + guint accel_key, + guint accel_mods, + gboolean changed) +{ + GString *gstring = g_string_new (changed ? NULL : "; "); + gint err, fd = GPOINTER_TO_INT (data); + gchar *tmp, *name; + + g_string_append (gstring, "(gtk_accel_path \""); + + tmp = g_strescape (accel_path, NULL); + g_string_append (gstring, tmp); + g_free (tmp); + + g_string_append (gstring, "\" \""); + + name = gtk_accelerator_name (accel_key, accel_mods); + tmp = g_strescape (name, NULL); + g_free (name); + g_string_append (gstring, tmp); + g_free (tmp); + + g_string_append (gstring, "\")\n"); + + do + err = write (fd, gstring->str, gstring->len); + while (err < 0 && errno == EINTR); + + g_string_free (gstring, TRUE); +} + +/** + * gtk_accel_map_save_fd + * @fd: valid writable file descriptor + * + * Filedescriptor variant of gtk_accel_map_save(). + * Note that the file descriptor will not be closed by this function. + */ +void +gtk_accel_map_save_fd (gint fd) +{ + GString *gstring; + gint err; + + g_return_if_fail (fd >= 0); + + gstring = g_string_new ("; "); + if (g_get_prgname ()) + g_string_append (gstring, g_get_prgname ()); + g_string_append (gstring, " GtkAccelMap rc-file -*- scheme -*-\n"); + g_string_append (gstring, "; this file is an automated accelerator map dump\n"); + g_string_append (gstring, ";\n"); + + do + err = write (fd, gstring->str, gstring->len); + while (err < 0 && errno == EINTR); + + gtk_accel_map_foreach (GINT_TO_POINTER (fd), accel_map_print); +} + +/** + * gtk_accel_map_save + * @file_name: the file to contain accelerator specifications + * + * Saves current accelerator specifications (accelerator path, key + * and modifiers) to @file_name. + * The file is written in a format suitable to be read back in by + * gtk_accel_map_load(). + */ +void +gtk_accel_map_save (const gchar *file_name) +{ + gint fd; + + g_return_if_fail (file_name != NULL); + + fd = open (file_name, O_CREAT | O_TRUNC | O_WRONLY, 0644); + if (fd < 0) + return; + + gtk_accel_map_save_fd (fd); + + close (fd); +} + +/** + * gtk_accel_map_foreach + * @data: data to be passed into @foreach_func + * @foreach_func: function to be executed for each accel map entry + * + * Loop over the entries in the accelerator map, and execute + * @foreach_func on each. The signature of @foreach_func is that of + * #GtkAccelMapForeach, the @changed parameter indicates whether + * this accelerator was changed during runtime (thus, would need + * saving during an accelerator map dump). + */ +void +gtk_accel_map_foreach (gpointer data, + GtkAccelMapForeach foreach_func) +{ + GSList *entries, *slist, *node; + + g_return_if_fail (foreach_func != NULL); + + entries = g_hash_table_slist_values (accel_entry_ht); + for (slist = entries; slist; slist = slist->next) + { + AccelEntry *entry = slist->data; + gboolean changed = entry->accel_key != entry->std_accel_key || entry->accel_mods != entry->std_accel_mods; + + for (node = accel_filters; node; node = node->next) + if (g_pattern_match_string (node->data, entry->accel_path)) + goto skip_accel; + foreach_func (data, entry->accel_path, entry->accel_key, entry->accel_mods, changed); + skip_accel: + } + g_slist_free (entries); +} + +void +gtk_accel_map_foreach_unfiltered (gpointer data, + GtkAccelMapForeach foreach_func) +{ + GSList *entries, *slist; + + g_return_if_fail (foreach_func != NULL); + + entries = g_hash_table_slist_values (accel_entry_ht); + for (slist = entries; slist; slist = slist->next) + { + AccelEntry *entry = slist->data; + gboolean changed = entry->accel_key != entry->std_accel_key || entry->accel_mods != entry->std_accel_mods; + + foreach_func (data, entry->accel_path, entry->accel_key, entry->accel_mods, changed); + } + g_slist_free (entries); +} + +void +gtk_accel_map_add_filter (const gchar *filter_pattern) +{ + GPatternSpec *pspec; + GSList *slist; + + g_return_if_fail (filter_pattern != NULL); + + pspec = g_pattern_spec_new (filter_pattern); + for (slist = accel_filters; slist; slist = slist->next) + if (g_pattern_spec_equal (pspec, slist->data)) + { + g_pattern_spec_free (pspec); + return; + } + accel_filters = g_slist_prepend (accel_filters, pspec); +} diff --git a/gtk/gtkaccelmap.h b/gtk/gtkaccelmap.h new file mode 100644 index 000000000..99d0887ff --- /dev/null +++ b/gtk/gtkaccelmap.h @@ -0,0 +1,81 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1998, 2001 Tim Janik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser 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_ACCEL_MAP_H__ +#define __GTK_ACCEL_MAP_H__ + + +#include <gtk/gtkaccelgroup.h> + +G_BEGIN_DECLS + + +/* --- notifier --- */ +typedef void (*GtkAccelMapNotify) (gpointer data, + GQuark accel_path_quark, + guint accel_key, + guint accel_mods, + GtkAccelGroup *accel_group, + guint old_accel_key, + guint old_accel_mods); +typedef void (*GtkAccelMapForeach) (gpointer data, + const gchar *accel_path, + guint accel_key, + guint accel_mods, + gboolean changed); + + +/* --- public API --- */ +GQuark gtk_accel_map_add_entry (const gchar *accel_path, + guint accel_key, + guint accel_mods); +void gtk_accel_map_add_notifer (const gchar *accel_path, + gpointer notify_data, + GtkAccelMapNotify notify_func, + GtkAccelGroup *accel_group); +void gtk_accel_map_remove_notifer (const gchar *accel_path, + gpointer notify_data, + GtkAccelMapNotify notify_func); +GQuark gtk_accel_map_lookup_entry (const gchar *accel_path, + GtkAccelKey *key); +gboolean gtk_accel_map_change_entry (const gchar *accel_path, + guint accel_key, + GdkModifierType accel_mods, + gboolean replace); +void gtk_accel_map_load (const gchar *file_name); +void gtk_accel_map_save (const gchar *file_name); +void gtk_accel_map_foreach (gpointer data, + GtkAccelMapForeach foreach_func); +void gtk_accel_map_load_fd (gint fd); +void gtk_accel_map_load_scanner (GScanner *scanner); +void gtk_accel_map_save_fd (gint fd); + + +/* --- filter functions --- */ +void gtk_accel_map_add_filter (const gchar *filter_pattern); +void gtk_accel_map_foreach_unfilterd (gpointer data, + GtkAccelMapForeach foreach_func); + + +/* --- internal API --- */ +void _gtk_accel_map_init (void); + + +G_END_DECLS + +#endif /* __GTK_ACCEL_MAP_H__ */ diff --git a/gtk/gtkitemfactory.c b/gtk/gtkitemfactory.c index 6ab691fba..02fa3df2e 100644 --- a/gtk/gtkitemfactory.c +++ b/gtk/gtkitemfactory.c @@ -39,6 +39,7 @@ #include "gtk/gtkcheckmenuitem.h" #include "gtk/gtkimagemenuitem.h" #include "gtk/gtktearoffmenuitem.h" +#include "gtk/gtkaccelmap.h" #include "gtk/gtkaccellabel.h" #include "gdk/gdkkeysyms.h" #include "gtk/gtkimage.h" @@ -75,13 +76,6 @@ struct _GtkIFCBData gpointer func_data; guint callback_action; }; -struct _GtkIFDumpData -{ - GtkPrintFunc print_func; - gpointer func_data; - guint modified_only : 1; - GPatternSpec *pspec; -}; /* --- prototypes --- */ @@ -114,47 +108,6 @@ static GQuark quark_type_tearoff_item = 0; static GQuark quark_type_separator_item = 0; static GQuark quark_type_branch = 0; static GQuark quark_type_last_branch = 0; -static GScannerConfig ifactory_scanner_config = -{ - ( - " \t\n" - ) /* cset_skip_characters */, - ( - G_CSET_a_2_z - "_" - G_CSET_A_2_Z - ) /* cset_identifier_first */, - ( - G_CSET_a_2_z - "-+_0123456789" - G_CSET_A_2_Z - G_CSET_LATINS - G_CSET_LATINC - ) /* cset_identifier_nth */, - ( ";\n" ) /* cpair_comment_single */, - - FALSE /* case_sensitive */, - - TRUE /* skip_comment_multi */, - TRUE /* skip_comment_single */, - FALSE /* scan_comment_multi */, - TRUE /* scan_identifier */, - FALSE /* scan_identifier_1char */, - FALSE /* scan_identifier_NULL */, - TRUE /* scan_symbols */, - TRUE /* scan_binary */, - TRUE /* scan_octal */, - TRUE /* scan_float */, - TRUE /* scan_hex */, - FALSE /* scan_hex_dollar */, - TRUE /* scan_string_sq */, - TRUE /* scan_string_dq */, - TRUE /* numbers_2_int */, - FALSE /* int_2_float */, - FALSE /* identifier_2_string */, - TRUE /* char_2_token */, - FALSE /* symbol_2_token */, -}; /* --- functions --- */ @@ -187,22 +140,16 @@ static void gtk_item_factory_class_init (GtkItemFactoryClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS (class); - GtkObjectClass *object_class; + GtkObjectClass *object_class = GTK_OBJECT_CLASS (class); gtk_item_factory_class = class; - - parent_class = gtk_type_class (GTK_TYPE_OBJECT); - - object_class = (GtkObjectClass*) class; + parent_class = g_type_class_peek_parent (class); gobject_class->finalize = gtk_item_factory_finalize; object_class->destroy = gtk_item_factory_destroy; - class->cpair_comment_single = g_strdup (";\n"); - class->item_ht = g_hash_table_new (g_str_hash, g_str_equal); - class->dummy = NULL; ifactory_item_chunks = g_mem_chunk_new ("GtkItemFactoryItem", sizeof (GtkItemFactoryItem), @@ -285,125 +232,6 @@ gtk_item_factory_callback_marshal (GtkWidget *widget, } static void -gtk_item_factory_propagate_accelerator (GtkItemFactoryItem *item, - GtkWidget *exclude) -{ - GSList *widget_list; - GSList *slist; - - if (item->in_propagation) - return; - - item->in_propagation = TRUE; - - widget_list = NULL; - for (slist = item->widgets; slist; slist = slist->next) - { - GtkWidget *widget; - - widget = slist->data; - - if (widget != exclude) - { - gtk_widget_ref (widget); - widget_list = g_slist_prepend (widget_list, widget); - } - } - - for (slist = widget_list; slist; slist = slist->next) - { - GtkWidget *widget; - GtkAccelGroup *accel_group; - guint signal_id; - - widget = slist->data; - - accel_group = gtk_object_get_data_by_id (GTK_OBJECT (widget), quark_accel_group); - - signal_id = gtk_signal_lookup ("activate", GTK_OBJECT_TYPE (widget)); - if (signal_id && accel_group) - { - if (item->accelerator_key) - gtk_widget_add_accelerator (widget, - "activate", - accel_group, - item->accelerator_key, - item->accelerator_mods, - GTK_ACCEL_VISIBLE); - else - { - GSList *work; - - work = gtk_accel_group_entries_from_object (G_OBJECT (widget)); - while (work) - { - GtkAccelEntry *ac_entry; - - ac_entry = work->data; - work = work->next; - if (ac_entry->accel_flags & GTK_ACCEL_VISIBLE && - ac_entry->accel_group == accel_group && - ac_entry->signal_id == signal_id) - gtk_widget_remove_accelerator (GTK_WIDGET (widget), - ac_entry->accel_group, - ac_entry->accelerator_key, - ac_entry->accelerator_mods); - } - } - } - - gtk_widget_unref (widget); - } - - g_slist_free (widget_list); - - item->in_propagation = FALSE; -} - -static gint -gtk_item_factory_item_add_accelerator (GtkWidget *widget, - guint accel_signal_id, - GtkAccelGroup *accel_group, - guint accel_key, - guint accel_mods, - GtkAccelFlags accel_flags, - GtkItemFactoryItem *item) -{ - if (!item->in_propagation && - g_slist_find (item->widgets, widget) && - accel_signal_id == gtk_signal_lookup ("activate", GTK_OBJECT_TYPE (widget))) - { - item->accelerator_key = accel_key; - item->accelerator_mods = accel_mods; - item->modified = TRUE; - - gtk_item_factory_propagate_accelerator (item, widget); - } - - return TRUE; -} - -static void -gtk_item_factory_item_remove_accelerator (GtkWidget *widget, - GtkAccelGroup *accel_group, - guint accel_key, - guint accel_mods, - GtkItemFactoryItem *item) -{ - if (!item->in_propagation && - g_slist_find (item->widgets, widget) && - item->accelerator_key == accel_key && - item->accelerator_mods == accel_mods) - { - item->accelerator_key = 0; - item->accelerator_mods = 0; - item->modified = TRUE; - - gtk_item_factory_propagate_accelerator (item, widget); - } -} - -static void gtk_item_factory_item_remove_widget (GtkWidget *widget, GtkItemFactoryItem *item) { @@ -416,8 +244,8 @@ void gtk_item_factory_add_foreign (GtkWidget *accel_widget, const gchar *full_path, GtkAccelGroup *accel_group, - guint keyval, - GdkModifierType modifiers) + guint accel_key, + GdkModifierType accel_mods) { GtkItemFactoryClass *class; GtkItemFactoryItem *item; @@ -427,7 +255,7 @@ gtk_item_factory_add_foreign (GtkWidget *accel_widget, class = gtk_type_class (GTK_TYPE_ITEM_FACTORY); - keyval = keyval != GDK_VoidSymbol ? keyval : 0; + accel_key = accel_key != GDK_VoidSymbol ? accel_key : 0; item = g_hash_table_lookup (class->item_ht, full_path); if (!item) @@ -435,11 +263,6 @@ gtk_item_factory_add_foreign (GtkWidget *accel_widget, item = g_chunk_new (GtkItemFactoryItem, ifactory_item_chunks); item->path = g_strdup (full_path); - item->accelerator_key = keyval; - item->accelerator_mods = modifiers; - item->modified = FALSE; - item->in_propagation = FALSE; - item->dummy = NULL; item->widgets = NULL; g_hash_table_insert (class->item_ht, item->path, item); @@ -470,29 +293,12 @@ gtk_item_factory_add_foreign (GtkWidget *accel_widget, */ if (gtk_signal_lookup ("activate", GTK_OBJECT_TYPE (accel_widget))) { - if (item->accelerator_key && accel_group) - gtk_widget_add_accelerator (accel_widget, - "activate", - accel_group, - item->accelerator_key, - item->accelerator_mods, - GTK_ACCEL_VISIBLE); - else - gtk_widget_remove_accelerators (accel_widget, - "activate", - TRUE); + if (accel_key && accel_group) + { + gtk_accel_map_add_entry (full_path, accel_key, accel_mods); + _gtk_widget_set_accel_path (accel_widget, full_path, accel_group); + } } - - /* keep track of accelerator changes - */ - gtk_signal_connect_after (GTK_OBJECT (accel_widget), - "add-accelerator", - GTK_SIGNAL_FUNC (gtk_item_factory_item_add_accelerator), - item); - gtk_signal_connect_after (GTK_OBJECT (accel_widget), - "remove-accelerator", - GTK_SIGNAL_FUNC (gtk_item_factory_item_remove_accelerator), - item); } static void @@ -725,136 +531,6 @@ gtk_item_factory_path_from_widget (GtkWidget *widget) return gtk_object_get_data_by_id (GTK_OBJECT (widget), quark_item_path); } -static gchar * -item_factory_escape_path (const gchar *path) -{ - GString *str = g_string_new (NULL); - - while (*path) - { - gchar c = *path; - - switch (c) - { - case '\n': - g_string_append (str, "\\n"); - break; - case '\r': - g_string_append (str, "\\r"); - break; - case '"': - case '\\': - g_string_append_c (str, '\\'); - /* Fall through */ - default: - g_string_append_c (str, c); - } - - path++; - } - - return g_string_free (str, FALSE); -} - -static void -gtk_item_factory_foreach (gpointer hash_key, - gpointer value, - gpointer user_data) -{ - GtkItemFactoryItem *item; - GtkIFDumpData *data; - gchar *string; - gchar *path; - gchar *name; - gchar comment_prefix[2] = "\000\000"; - - item = value; - data = user_data; - - if (data->pspec && !g_pattern_match_string (data->pspec, item->path)) - return; - - comment_prefix[0] = gtk_item_factory_class->cpair_comment_single[0]; - - path = item_factory_escape_path (hash_key); - name = gtk_accelerator_name (item->accelerator_key, item->accelerator_mods); - string = g_strconcat (item->modified ? "" : comment_prefix, - "(menu-path \"", - path, - "\" \"", - name, - "\")", - NULL); - g_free (path); - g_free (name); - - data->print_func (data->func_data, string); - - g_free (string); -} - -void -gtk_item_factory_dump_items (GPatternSpec *path_pspec, - gboolean modified_only, - GtkPrintFunc print_func, - gpointer func_data) -{ - GtkIFDumpData data; - - g_return_if_fail (print_func != NULL); - - if (!gtk_item_factory_class) - gtk_type_class (GTK_TYPE_ITEM_FACTORY); - - data.print_func = print_func; - data.func_data = func_data; - data.modified_only = (modified_only != FALSE); - data.pspec = path_pspec; - - g_hash_table_foreach (gtk_item_factory_class->item_ht, gtk_item_factory_foreach, &data); -} - -void -gtk_item_factory_print_func (gpointer FILE_pointer, - const gchar *string) -{ - FILE *f_out = FILE_pointer; - - g_return_if_fail (FILE_pointer != NULL); - g_return_if_fail (string != NULL); - - fputs (string, f_out); - fputc ('\n', f_out); -} - -void -gtk_item_factory_dump_rc (const gchar *file_name, - GPatternSpec *path_pspec, - gboolean modified_only) -{ - FILE *f_out; - - g_return_if_fail (file_name != NULL); - - f_out = fopen (file_name, "w"); - if (!f_out) - return; - - fputs ("; ", f_out); - if (g_get_prgname ()) - fputs (g_get_prgname (), f_out); - fputs (" GtkItemFactory rc-file -*- scheme -*-\n", f_out); - fputs ("; this file is an automated menu-path dump\n", f_out); - fputs (";\n", f_out); - - gtk_item_factory_dump_items (path_pspec, - modified_only, - gtk_item_factory_print_func, - f_out); - - fclose (f_out); -} - void gtk_item_factory_create_items (GtkItemFactory *ifactory, guint n_entries, @@ -1193,25 +869,32 @@ gtk_item_factory_create_item (GtkItemFactory *ifactory, parent = gtk_item_factory_get_widget (ifactory, parent_path); g_return_if_fail (parent != NULL); } - g_free (parent_path); if (GTK_IS_OPTION_MENU (parent)) { option_menu = GTK_OPTION_MENU (parent); if (!option_menu->menu) - gtk_option_menu_set_menu (option_menu, gtk_widget_new (GTK_TYPE_MENU, NULL)); + { + GtkWidget *menu = g_object_new (GTK_TYPE_MENU, NULL); + gchar *p = g_strconcat (ifactory->path, parent_path, NULL); + + gtk_menu_set_accel_path (GTK_MENU (menu), p); + g_free (p); + gtk_option_menu_set_menu (option_menu, menu); + } parent = option_menu->menu; } + g_free (parent_path); g_return_if_fail (GTK_IS_CONTAINER (parent)); accelerator = entry->accelerator; widget = gtk_widget_new (type, - "GtkWidget::visible", TRUE, - "GtkWidget::sensitive", (type_id != quark_type_separator_item && - type_id != quark_type_title), - "GtkWidget::parent", parent, + "visible", TRUE, + "sensitive", (type_id != quark_type_separator_item && + type_id != quark_type_title), + "parent", parent, NULL); if (option_menu && !option_menu->menu_item) gtk_option_menu_set_history (option_menu, 0); @@ -1223,32 +906,26 @@ gtk_item_factory_create_item (GtkItemFactory *ifactory, if (type_id == quark_type_image_item) { GdkPixbuf *pixbuf = NULL; - image = NULL; + image = NULL; pixbuf = gdk_pixbuf_new_from_inline (-1, entry->extra_data, FALSE, NULL); - if (pixbuf) image = gtk_image_new_from_pixbuf (pixbuf); - if (image) { gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (widget), image); - gtk_widget_show (image); } - if (pixbuf) g_object_unref (G_OBJECT (pixbuf)); } if (type_id == quark_type_stock_item) { image = gtk_image_new_from_stock (entry->extra_data, GTK_ICON_SIZE_MENU); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (widget), image); - gtk_widget_show (image); if (gtk_stock_lookup (entry->extra_data, &stock_item)) @@ -1257,8 +934,6 @@ gtk_item_factory_create_item (GtkItemFactory *ifactory, accelerator = gtk_accelerator_name (stock_item.keyval, stock_item.modifier); } } - - /* install underline accelerators for this item */ @@ -1269,12 +944,11 @@ gtk_item_factory_create_item (GtkItemFactory *ifactory, GtkWidget *label; label = gtk_widget_new (GTK_TYPE_ACCEL_LABEL, - "GtkWidget::visible", TRUE, - "GtkWidget::parent", widget, - "GtkAccelLabel::accel_object", widget, - "GtkMisc::xalign", 0.0, + "visible", TRUE, + "parent", widget, + "accel_widget", widget, + "xalign", 0.0, NULL); - gtk_label_set_text_with_mnemonic (GTK_LABEL (label), name); } @@ -1283,16 +957,19 @@ gtk_item_factory_create_item (GtkItemFactory *ifactory, if (type_id == quark_type_branch || type_id == quark_type_last_branch) { + gchar *p; + if (entry->callback) g_warning ("gtk_item_factory_create_item(): Can't specify a callback on a branch: \"%s\"", entry->path); - if (type_id == quark_type_last_branch) gtk_menu_item_set_right_justified (GTK_MENU_ITEM (widget), TRUE); parent = widget; - widget = gtk_widget_new (GTK_TYPE_MENU, - NULL); + widget = gtk_widget_new (GTK_TYPE_MENU, NULL); + p = g_strconcat (ifactory->path, path, NULL); + gtk_menu_set_accel_path (GTK_MENU (widget), p); + g_free (p); gtk_menu_item_set_submenu (GTK_MENU_ITEM (parent), widget); } @@ -1306,10 +983,8 @@ gtk_item_factory_create_item (GtkItemFactory *ifactory, callback_type, item_type_path, widget); - if (accelerator != entry->accelerator) g_free (accelerator); - g_free (path); } @@ -1595,192 +1270,6 @@ gtk_item_factory_popup_with_data (GtkItemFactory *ifactory, mouse_button, time); } -static guint -gtk_item_factory_parse_menu_path (GScanner *scanner, - GtkItemFactoryClass *class) -{ - GtkItemFactoryItem *item; - - g_scanner_get_next_token (scanner); - if (scanner->token != G_TOKEN_STRING) - return G_TOKEN_STRING; - - g_scanner_peek_next_token (scanner); - if (scanner->next_token != G_TOKEN_STRING) - { - g_scanner_get_next_token (scanner); - return G_TOKEN_STRING; - } - - item = g_hash_table_lookup (class->item_ht, scanner->value.v_string); - if (!item) - { - item = g_chunk_new (GtkItemFactoryItem, ifactory_item_chunks); - - item->path = g_strdup (scanner->value.v_string); - item->accelerator_key = 0; - item->accelerator_mods = 0; - item->modified = TRUE; - item->in_propagation = FALSE; - item->dummy = NULL; - item->widgets = NULL; - - g_hash_table_insert (class->item_ht, item->path, item); - } - g_scanner_get_next_token (scanner); - - if (!item->in_propagation) - { - guint old_keyval; - guint old_mods; - - old_keyval = item->accelerator_key; - old_mods = item->accelerator_mods; - gtk_accelerator_parse (scanner->value.v_string, - &item->accelerator_key, - &item->accelerator_mods); - if (old_keyval != item->accelerator_key || - old_mods != item->accelerator_mods) - { - item->modified = TRUE; - gtk_item_factory_propagate_accelerator (item, NULL); - } - } - - g_scanner_get_next_token (scanner); - if (scanner->token != ')') - return ')'; - else - return G_TOKEN_NONE; -} - -static void -gtk_item_factory_parse_statement (GScanner *scanner, - GtkItemFactoryClass *class) -{ - guint expected_token; - - g_scanner_get_next_token (scanner); - - if (scanner->token == G_TOKEN_SYMBOL) - { - guint (*parser_func) (GScanner*, GtkItemFactoryClass*); - - parser_func = scanner->value.v_symbol; - - /* check whether this is a GtkItemFactory symbol. - */ - if (parser_func == gtk_item_factory_parse_menu_path) - expected_token = parser_func (scanner, class); - else - expected_token = G_TOKEN_SYMBOL; - } - else - expected_token = G_TOKEN_SYMBOL; - - /* skip rest of statement on errrors - */ - if (expected_token != G_TOKEN_NONE) - { - register guint level; - - level = 1; - if (scanner->token == ')') - level--; - if (scanner->token == '(') - level++; - - while (!g_scanner_eof (scanner) && level > 0) - { - g_scanner_get_next_token (scanner); - - if (scanner->token == '(') - level++; - else if (scanner->token == ')') - level--; - } - } -} - -void -gtk_item_factory_parse_rc_string (const gchar *rc_string) -{ - GScanner *scanner; - - g_return_if_fail (rc_string != NULL); - - if (!gtk_item_factory_class) - gtk_type_class (GTK_TYPE_ITEM_FACTORY); - - ifactory_scanner_config.cpair_comment_single = gtk_item_factory_class->cpair_comment_single; - scanner = g_scanner_new (&ifactory_scanner_config); - - g_scanner_input_text (scanner, rc_string, strlen (rc_string)); - - gtk_item_factory_parse_rc_scanner (scanner); - - g_scanner_destroy (scanner); -} - -void -gtk_item_factory_parse_rc_scanner (GScanner *scanner) -{ - gpointer saved_symbol; - - g_return_if_fail (scanner != NULL); - - if (!gtk_item_factory_class) - gtk_type_class (GTK_TYPE_ITEM_FACTORY); - - saved_symbol = g_scanner_lookup_symbol (scanner, "menu-path"); - g_scanner_scope_remove_symbol (scanner, 0, "menu-path"); - g_scanner_scope_add_symbol (scanner, 0, "menu-path", gtk_item_factory_parse_menu_path); - - g_scanner_peek_next_token (scanner); - - while (scanner->next_token == '(') - { - g_scanner_get_next_token (scanner); - - gtk_item_factory_parse_statement (scanner, gtk_item_factory_class); - - g_scanner_peek_next_token (scanner); - } - - g_scanner_scope_remove_symbol (scanner, 0, "menu-path"); - g_scanner_scope_add_symbol (scanner, 0, "menu-path", saved_symbol); -} - -void -gtk_item_factory_parse_rc (const gchar *file_name) -{ - gint fd; - GScanner *scanner; - - g_return_if_fail (file_name != NULL); - - if (!g_file_test (file_name, G_FILE_TEST_IS_REGULAR)) - return; - - fd = open (file_name, O_RDONLY); - if (fd < 0) - return; - - if (!gtk_item_factory_class) - gtk_type_class (GTK_TYPE_ITEM_FACTORY); - - ifactory_scanner_config.cpair_comment_single = gtk_item_factory_class->cpair_comment_single; - scanner = g_scanner_new (&ifactory_scanner_config); - - g_scanner_input_file (scanner, fd); - - gtk_item_factory_parse_rc_scanner (scanner); - - g_scanner_destroy (scanner); - - close (fd); -} - void gtk_item_factory_set_translate_func (GtkItemFactory *ifactory, GtkTranslateFunc func, diff --git a/gtk/gtkitemfactory.h b/gtk/gtkitemfactory.h index 2fba37fd5..394ed0fe2 100644 --- a/gtk/gtkitemfactory.h +++ b/gtk/gtkitemfactory.h @@ -79,11 +79,7 @@ struct _GtkItemFactoryClass { GtkObjectClass object_class; - gchar *cpair_comment_single; - GHashTable *item_ht; - - gpointer dummy; }; struct _GtkItemFactoryEntry @@ -122,12 +118,6 @@ struct _GtkItemFactoryEntry struct _GtkItemFactoryItem { gchar *path; - guint accelerator_key; - guint accelerator_mods; - guint modified : 1; - guint in_propagation : 1; - gchar *dummy; - GSList *widgets; }; @@ -147,9 +137,6 @@ void gtk_item_factory_construct (GtkItemFactory *ifactory, /* These functions operate on GtkItemFactoryClass basis. */ -void gtk_item_factory_parse_rc (const gchar *file_name); -void gtk_item_factory_parse_rc_string (const gchar *rc_string); -void gtk_item_factory_parse_rc_scanner (GScanner *scanner); void gtk_item_factory_add_foreign (GtkWidget *accel_widget, const gchar *full_path, GtkAccelGroup *accel_group, @@ -168,19 +155,6 @@ GtkWidget* gtk_item_factory_get_widget_by_action (GtkItemFactory *ifactory, GtkWidget* gtk_item_factory_get_item_by_action (GtkItemFactory *ifactory, guint action); -/* If `path_pspec' is passed as `NULL', this function will iterate over - * all hash entries. otherwise only those entries will be dumped for which - * the pattern matches, e.g. "<Image>*...". - */ -void gtk_item_factory_dump_items (GPatternSpec *path_pspec, - gboolean modified_only, - GtkPrintFunc print_func, - gpointer func_data); -void gtk_item_factory_dump_rc (const gchar *file_name, - GPatternSpec *path_pspec, - gboolean modified_only); -void gtk_item_factory_print_func (gpointer FILE_pointer, - const gchar *string); void gtk_item_factory_create_item (GtkItemFactory *ifactory, GtkItemFactoryEntry *entry, gpointer callback_data, diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c index 6e6c9452c..1279df02d 100644 --- a/gtk/gtkmain.c +++ b/gtk/gtkmain.c @@ -47,6 +47,7 @@ #include <pango/pango-utils.h> /* For pango_split_file_list */ +#include "gtkaccelmap.h" #include "gtkdnd.h" #include "gtkversion.h" #include "gtkmain.h" @@ -625,9 +626,9 @@ gtk_init_check (int *argc, gtk_colormap = gdk_colormap_get_system (); gtk_type_init (0); + _gtk_accel_map_init (); _gtk_rc_init (); - /* Register an exit function to make sure we are able to cleanup. */ g_atexit (gtk_exit_func); diff --git a/gtk/gtkmarshal.list b/gtk/gtkmarshal.list index e49173255..0cd270728 100644 --- a/gtk/gtkmarshal.list +++ b/gtk/gtkmarshal.list @@ -24,6 +24,7 @@ BOOLEAN:BOXED BOOLEAN:BOXED,BOXED BOOLEAN:ENUM +BOOLEAN:OBJECT,UINT,UINT BOOLEAN:OBJECT,INT,INT,UINT BOOLEAN:OBJECT,STRING,STRING,BOXED BOOLEAN:OBJECT,BOXED,BOXED @@ -78,7 +79,9 @@ VOID:POINTER,UINT VOID:STRING VOID:STRING,STRING VOID:STRING,INT,POINTER +VOID:UINT,UINT +VOID:UINT,UINT,BOXED +VOID:UINT,STRING VOID:UINT,BOXED,UINT,FLAGS,FLAGS VOID:UINT,OBJECT,UINT,FLAGS,FLAGS -VOID:UINT,STRING VOID:VOID diff --git a/gtk/gtkmarshalers.list b/gtk/gtkmarshalers.list index e49173255..0cd270728 100644 --- a/gtk/gtkmarshalers.list +++ b/gtk/gtkmarshalers.list @@ -24,6 +24,7 @@ BOOLEAN:BOXED BOOLEAN:BOXED,BOXED BOOLEAN:ENUM +BOOLEAN:OBJECT,UINT,UINT BOOLEAN:OBJECT,INT,INT,UINT BOOLEAN:OBJECT,STRING,STRING,BOXED BOOLEAN:OBJECT,BOXED,BOXED @@ -78,7 +79,9 @@ VOID:POINTER,UINT VOID:STRING VOID:STRING,STRING VOID:STRING,INT,POINTER +VOID:UINT,UINT +VOID:UINT,UINT,BOXED +VOID:UINT,STRING VOID:UINT,BOXED,UINT,FLAGS,FLAGS VOID:UINT,OBJECT,UINT,FLAGS,FLAGS -VOID:UINT,STRING VOID:VOID diff --git a/gtk/gtkmenu.c b/gtk/gtkmenu.c index 34781391c..375b348c4 100644 --- a/gtk/gtkmenu.c +++ b/gtk/gtkmenu.c @@ -27,6 +27,7 @@ #include <ctype.h> #include <string.h> /* memset */ #include "gdk/gdkkeysyms.h" +#include "gtkaccelmap.h" #include "gtkbindings.h" #include "gtklabel.h" #include "gtkmain.h" @@ -76,6 +77,7 @@ static void gtk_menu_get_property (GObject *object, GValue *value, GParamSpec *pspec); static void gtk_menu_destroy (GtkObject *object); +static void gtk_menu_finalize (GObject *object); static void gtk_menu_realize (GtkWidget *widget); static void gtk_menu_unrealize (GtkWidget *widget); static void gtk_menu_size_request (GtkWidget *widget, @@ -83,6 +85,7 @@ static void gtk_menu_size_request (GtkWidget *widget, static void gtk_menu_size_allocate (GtkWidget *widget, GtkAllocation *allocation); static void gtk_menu_paint (GtkWidget *widget); +static void gtk_menu_show (GtkWidget *widget); static gboolean gtk_menu_expose (GtkWidget *widget, GdkEventExpose *event); static gboolean gtk_menu_key_press (GtkWidget *widget, @@ -161,21 +164,16 @@ gtk_menu_get_type (void) static void gtk_menu_class_init (GtkMenuClass *class) { - GObjectClass *gobject_class; - GtkObjectClass *object_class; - GtkWidgetClass *widget_class; - GtkContainerClass *container_class; - GtkMenuShellClass *menu_shell_class; - + GObjectClass *gobject_class = G_OBJECT_CLASS (class); + GtkObjectClass *object_class = GTK_OBJECT_CLASS (class); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); + GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class); + GtkMenuShellClass *menu_shell_class = GTK_MENU_SHELL_CLASS (class); GtkBindingSet *binding_set; - gobject_class = (GObjectClass*) class; - object_class = (GtkObjectClass*) class; - widget_class = (GtkWidgetClass*) class; - container_class = (GtkContainerClass*) class; - menu_shell_class = (GtkMenuShellClass*) class; - parent_class = gtk_type_class (gtk_menu_shell_get_type ()); + parent_class = g_type_class_peek_parent (class); + gobject_class->finalize = gtk_menu_finalize; gobject_class->set_property = gtk_menu_set_property; gobject_class->get_property = gtk_menu_get_property; @@ -192,6 +190,7 @@ gtk_menu_class_init (GtkMenuClass *class) widget_class->unrealize = gtk_menu_unrealize; widget_class->size_request = gtk_menu_size_request; widget_class->size_allocate = gtk_menu_size_allocate; + widget_class->show = gtk_menu_show; widget_class->expose_event = gtk_menu_expose; widget_class->key_press_event = gtk_menu_key_press; widget_class->motion_notify_event = gtk_menu_motion_notify; @@ -388,8 +387,6 @@ gtk_menu_destroy (GtkObject *object) gtk_menu_stop_navigating_submenu (menu); - gtk_menu_set_accel_group (menu, NULL); - if (menu->old_active_menu_item) { gtk_widget_unref (menu->old_active_menu_item); @@ -403,6 +400,12 @@ gtk_menu_destroy (GtkObject *object) gtk_object_ref (object); } + if (menu->accel_group) + { + g_object_unref (menu->accel_group); + menu->accel_group = NULL; + } + if (menu->toplevel) gtk_widget_destroy (menu->toplevel); if (menu->tearoff_window) @@ -411,6 +414,15 @@ gtk_menu_destroy (GtkObject *object) GTK_OBJECT_CLASS (parent_class)->destroy (object); } +static void +gtk_menu_finalize (GObject *object) +{ + GtkMenu *menu = GTK_MENU (object); + + g_free (menu->accel_path); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} void gtk_menu_attach_to_widget (GtkMenu *menu, @@ -828,6 +840,7 @@ gtk_menu_set_accel_group (GtkMenu *menu, menu->accel_group = accel_group; if (menu->accel_group) gtk_accel_group_ref (menu->accel_group); + _gtk_menu_refresh_accel_paths (menu, TRUE); } } @@ -839,6 +852,76 @@ gtk_menu_get_accel_group (GtkMenu *menu) return menu->accel_group; } +/** + * gtk_menu_set_accel_path + * @menu: a valid #GtkMenu + * @accel_path: a valid accelerator path + * + * Sets an accelerator path for this menu from which accelerator paths + * for its immediate children, its menu items, can be constructed. + * The main purpose of this function is to spare the programmer the + * inconvenience of having to call gtk_menu_item_set_accel_path() on + * each menu item that should support runtime user changable accelerators. + * Instead, by just calling gtk_menu_set_accel_path() on their parent, + * each menu item of this menu, that contains a label describing its purpose, + * automatically gets an accel path assigned. For example, a menu containing + * menu items "New" and "Exit", will, after gtk_menu_set_accel_path (menu, + * "<Gnumeric-Sheet>/File"); has been called, assign its items the accel paths: + * "<Gnumeric-Sheet>/File/New" and "<Gnumeric-Sheet>/File/Exit". + * Assigning accel paths to menu items then enables the user to change + * their accelerators at runtime. More details about accelerator paths + * and their default setups can be found at gtk_accel_map_add_entry(). + */ +void +gtk_menu_set_accel_path (GtkMenu *menu, + const gchar *accel_path) +{ + g_return_if_fail (GTK_IS_MENU (menu)); + if (accel_path) + g_return_if_fail (accel_path[0] == '<' && strchr (accel_path, '/')); /* simplistic check */ + + g_free (menu->accel_path); + menu->accel_path = g_strdup (accel_path); + if (menu->accel_path) + _gtk_menu_refresh_accel_paths (menu, FALSE); +} + +typedef struct { + GtkMenu *menu; + gboolean group_changed; +} AccelPropagation; + +static void +refresh_accel_paths_froeach (GtkWidget *widget, + gpointer data) +{ + AccelPropagation *prop = data; + + if (GTK_IS_MENU_ITEM (widget)) /* should always be true */ + _gtk_menu_item_refresh_accel_path (GTK_MENU_ITEM (widget), + prop->menu->accel_path, + prop->menu->accel_group, + prop->group_changed); +} + +void +_gtk_menu_refresh_accel_paths (GtkMenu *menu, + gboolean group_changed) +{ + g_return_if_fail (GTK_IS_MENU (menu)); + + if (menu->accel_path && menu->accel_group) + { + AccelPropagation prop; + + prop.menu = menu; + prop.group_changed = group_changed; + gtk_container_foreach (GTK_CONTAINER (menu), + refresh_accel_paths_froeach, + &prop); + } +} + void gtk_menu_reposition (GtkMenu *menu) { @@ -1480,20 +1563,33 @@ gtk_menu_expose (GtkWidget *widget, return FALSE; } +static void +gtk_menu_show (GtkWidget *widget) +{ + GtkMenu *menu = GTK_MENU (widget); + + _gtk_menu_refresh_accel_paths (menu, FALSE); + + GTK_WIDGET_CLASS (parent_class)->show (widget); +} + static gboolean gtk_menu_key_press (GtkWidget *widget, GdkEventKey *event) { GtkMenuShell *menu_shell; GtkMenu *menu; + GtkAccelGroup *accel_group; gboolean delete = FALSE; gchar *accel = NULL; + guint accel_key, accel_mods; g_return_val_if_fail (GTK_IS_MENU (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); menu_shell = GTK_MENU_SHELL (widget); menu = GTK_MENU (widget); + accel_group = gtk_menu_get_accel_group (menu); gtk_menu_stop_navigating_submenu (menu); @@ -1543,58 +1639,50 @@ gtk_menu_key_press (GtkWidget *widget, break; } + accel_key = event->keyval; + accel_mods = event->state & gtk_accelerator_get_default_mod_mask (); + /* Modify the accelerators */ if (menu_shell->active_menu_item && - GTK_BIN (menu_shell->active_menu_item)->child && - GTK_MENU_ITEM (menu_shell->active_menu_item)->submenu == NULL && - !gtk_widget_accelerators_locked (menu_shell->active_menu_item) && + GTK_BIN (menu_shell->active_menu_item)->child && /* no seperators */ + GTK_MENU_ITEM (menu_shell->active_menu_item)->submenu == NULL && /* no submenus */ (delete || (gtk_accelerator_valid (event->keyval, event->state) && - (event->state || - (event->keyval >= GDK_F1 && event->keyval <= GDK_F35))))) + (accel_mods || + (accel_key >= GDK_F1 && accel_key <= GDK_F35))))) { - GtkMenuItem *menu_item; - GtkAccelGroup *accel_group; - - menu_item = GTK_MENU_ITEM (menu_shell->active_menu_item); - - if (!GTK_MENU (widget)->accel_group) - accel_group = gtk_accel_group_get_default (); + GtkWidget *menu_item = menu_shell->active_menu_item; + gboolean replace_accels = TRUE; + const gchar *path; + + path = _gtk_widget_get_accel_path (menu_item); + if (!path) + { + /* can't change accelerators on menu_items without paths + * (basically, those items are accelerator-locked). + */ + /* g_print("item has no path, menu prefix: %s\n", menu->accel_path); */ + gdk_beep (); + } else - accel_group = GTK_MENU (widget)->accel_group; - - gtk_widget_remove_accelerators (GTK_WIDGET (menu_item), - gtk_signal_name (menu_item->accelerator_signal), - TRUE); - - if (!delete && - 0 == gtk_widget_accelerator_signal (GTK_WIDGET (menu_item), - accel_group, - event->keyval, - event->state)) { - GSList *slist; - - slist = gtk_accel_group_entries_from_object (G_OBJECT (menu_item)); - while (slist) + gboolean changed; + + if (delete) { - GtkAccelEntry *ac_entry; - - ac_entry = slist->data; - - if (ac_entry->signal_id == menu_item->accelerator_signal) - break; - - slist = slist->next; + accel_key = 0; + accel_mods = 0; + } + changed = gtk_accel_map_change_entry (path, accel_key, accel_mods, replace_accels); + + if (!changed) + { + /* we failed, probably because this key is in use and + * locked already + */ + /* g_print("failed to change\n"); */ + gdk_beep (); } - - if (!slist) - gtk_widget_add_accelerator (GTK_WIDGET (menu_item), - gtk_signal_name (menu_item->accelerator_signal), - accel_group, - event->keyval, - event->state, - GTK_ACCEL_VISIBLE); } } diff --git a/gtk/gtkmenu.h b/gtk/gtkmenu.h index 3948271d1..225c9a90b 100644 --- a/gtk/gtkmenu.h +++ b/gtk/gtkmenu.h @@ -64,6 +64,7 @@ struct _GtkMenu GtkWidget *old_active_menu_item; GtkAccelGroup *accel_group; + gchar *accel_path; GtkMenuPositionFunc position_func; gpointer position_func_data; @@ -146,7 +147,10 @@ void gtk_menu_set_active (GtkMenu *menu, void gtk_menu_set_accel_group (GtkMenu *menu, GtkAccelGroup *accel_group); GtkAccelGroup* gtk_menu_get_accel_group (GtkMenu *menu); - +void gtk_menu_set_accel_path (GtkMenu *menu, + const gchar *accel_path); +void _gtk_menu_refresh_accel_paths (GtkMenu *menu, + gboolean group_changed); /* A reference count is kept for a widget when it is attached to * a particular widget. This is typically a menu item; it may also diff --git a/gtk/gtkmenuitem.c b/gtk/gtkmenuitem.c index edc7f4f3f..e269a790f 100644 --- a/gtk/gtkmenuitem.c +++ b/gtk/gtkmenuitem.c @@ -51,6 +51,7 @@ enum { static void gtk_menu_item_class_init (GtkMenuItemClass *klass); static void gtk_menu_item_init (GtkMenuItem *menu_item); static void gtk_menu_item_destroy (GtkObject *object); +static void gtk_menu_item_finalize (GObject *object); static void gtk_menu_item_size_request (GtkWidget *widget, GtkRequisition *requisition); static void gtk_menu_item_size_allocate (GtkWidget *widget, @@ -60,6 +61,7 @@ static void gtk_menu_item_paint (GtkWidget *widget, 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); @@ -120,18 +122,15 @@ gtk_menu_item_get_type (void) static void gtk_menu_item_class_init (GtkMenuItemClass *klass) { - GtkObjectClass *object_class; - GtkWidgetClass *widget_class; - GtkContainerClass *container_class; - GtkItemClass *item_class; - - object_class = (GtkObjectClass*) klass; - widget_class = (GtkWidgetClass*) klass; - container_class = (GtkContainerClass*) klass; - item_class = (GtkItemClass*) klass; + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass); + GtkItemClass *item_class = GTK_ITEM_CLASS (klass); - parent_class = gtk_type_class (gtk_item_get_type ()); + parent_class = g_type_class_peek_parent (klass); + gobject_class->finalize = gtk_menu_item_finalize; object_class->destroy = gtk_menu_item_destroy; @@ -141,7 +140,7 @@ gtk_menu_item_class_init (GtkMenuItemClass *klass) widget_class->show_all = gtk_menu_item_show_all; widget_class->hide_all = gtk_menu_item_hide_all; widget_class->mnemonic_activate = gtk_menu_item_mnemonic_activate; - + container_class->forall = gtk_menu_item_forall; item_class->select = gtk_real_menu_item_select; @@ -194,7 +193,6 @@ static void gtk_menu_item_init (GtkMenuItem *menu_item) { menu_item->submenu = NULL; - menu_item->accelerator_signal = menu_item_signals[ACTIVATE]; menu_item->toggle_size = 0; menu_item->accelerator_width = 0; menu_item->show_submenu_indicator = FALSE; @@ -269,8 +267,17 @@ gtk_menu_item_destroy (GtkObject *object) if (menu_item->submenu) gtk_widget_destroy (menu_item->submenu); - if (GTK_OBJECT_CLASS (parent_class)->destroy) - (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); + GTK_OBJECT_CLASS (parent_class)->destroy (object); +} + +static void +gtk_menu_item_finalize (GObject *object) +{ + GtkMenuItem *menu_item = GTK_MENU_ITEM (object); + + g_free (menu_item->accel_path); + + G_OBJECT_CLASS (parent_class)->finalize (object); } static void @@ -898,6 +905,107 @@ gtk_menu_item_hide_all (GtkWidget *widget) } static void +gtk_menu_item_accel_name_foreach (GtkWidget *widget, + gpointer data) +{ + const gchar **path_p = data; + + if (!*path_p) + { + if (GTK_IS_LABEL (widget)) + { + *path_p = gtk_label_get_text (GTK_LABEL (widget)); + if (*path_p && (*path_p)[0] == 0) + *path_p = NULL; + } + else if (GTK_IS_CONTAINER (widget)) + gtk_container_foreach (GTK_CONTAINER (widget), + gtk_menu_item_accel_name_foreach, + data); + } +} + +void +_gtk_menu_item_refresh_accel_path (GtkMenuItem *menu_item, + const gchar *prefix, + GtkAccelGroup *accel_group, + gboolean group_changed) +{ + const gchar *path; + GtkWidget *widget; + + g_return_if_fail (GTK_IS_MENU_ITEM (menu_item)); + g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group)); + + widget = GTK_WIDGET (menu_item); + + path = _gtk_widget_get_accel_path (widget); + if (!path) /* no active accel_path yet */ + { + path = menu_item->accel_path; + if (!path && prefix) + { + gchar *postfix = NULL; + + /* try to construct one from label text */ + gtk_container_foreach (GTK_CONTAINER (menu_item), + gtk_menu_item_accel_name_foreach, + &postfix); + menu_item->accel_path = postfix ? g_strconcat (prefix, "/", postfix, NULL) : NULL; + path = menu_item->accel_path; + } + if (path) + _gtk_widget_set_accel_path (widget, path, accel_group); + } + else if (group_changed) /* reinstall accelerators */ + _gtk_widget_set_accel_path (widget, path, accel_group); +} + +/** + * gtk_menu_item_set_accel_path + * @menu_item: a valid #GtkMenuItem + * @accel_path: accelerator path, corresponding to this menu item's funcitonality + * + * Set the accelerator path on @menu_item, through which runtime changes of the + * menu item's accelerator caused by the user can be identified and saved to + * persistant storage (see gtk_accel_map_save() on this). + * To setup a default accelerator for this menu item, call + * gtk_accel_map_add_entry() with the same @accel_path. + * See also gtk_accel_map_add_entry() on the specifics of accelerator paths, + * and gtk_menu_set_accel_path() for a more convenient variant of this function. + */ +void +gtk_menu_item_set_accel_path (GtkMenuItem *menu_item, + const gchar *accel_path) +{ + GtkWidget *widget; + + g_return_if_fail (GTK_IS_MENU_ITEM (menu_item)); + g_return_if_fail (accel_path && accel_path[0] == '<' && strchr (accel_path, '/')); + + widget = GTK_WIDGET (menu_item); + + /* store new path */ + g_free (menu_item->accel_path); + menu_item->accel_path = g_strdup (accel_path); + + /* forget accelerators associated with old path */ + _gtk_widget_set_accel_path (widget, NULL, NULL); + + /* install accelerators associated with new path */ + if (widget->parent) + { + GtkMenu *menu = GTK_MENU (widget->parent); + + if (menu->accel_group) + _gtk_menu_item_refresh_accel_path (GTK_MENU_ITEM (widget), + NULL, + menu->accel_group, + FALSE); + } +} + +static void gtk_menu_item_forall (GtkContainer *container, gboolean include_internals, GtkCallback callback, @@ -913,5 +1021,5 @@ gtk_menu_item_forall (GtkContainer *container, menu_item = GTK_MENU_ITEM (container); if (bin->child) - (* callback) (bin->child, callback_data); + callback (bin->child, callback_data); } diff --git a/gtk/gtkmenuitem.h b/gtk/gtkmenuitem.h index 1f46eaa8f..2b53d95e0 100644 --- a/gtk/gtkmenuitem.h +++ b/gtk/gtkmenuitem.h @@ -54,9 +54,9 @@ struct _GtkMenuItem GtkWidget *submenu; - guint accelerator_signal; guint16 toggle_size; guint16 accelerator_width; + gchar *accel_path; guint show_submenu_indicator : 1; guint submenu_placement : 1; @@ -106,6 +106,13 @@ void gtk_menu_item_toggle_size_allocate (GtkMenuItem *menu_item, void gtk_menu_item_set_right_justified (GtkMenuItem *menu_item, gboolean right_justified); gboolean gtk_menu_item_get_right_justified (GtkMenuItem *menu_item); +void gtk_menu_item_set_accel_path (GtkMenuItem *menu_item, + const gchar *accel_path); + +void _gtk_menu_item_refresh_accel_path (GtkMenuItem *menu_item, + const gchar *prefix, + GtkAccelGroup *accel_group, + gboolean group_changed); #ifndef GTK_DISABLE_DEPRECATED #define gtk_menu_item_right_justify(menu_item) gtk_menu_item_set_right_justified ((menu_item), TRUE) diff --git a/gtk/gtknotebook.c b/gtk/gtknotebook.c index 4ed824919..f9b5a0828 100644 --- a/gtk/gtknotebook.c +++ b/gtk/gtknotebook.c @@ -3540,7 +3540,6 @@ gtk_notebook_menu_item_create (GtkNotebook *notebook, gtk_widget_show (page->menu_label); menu_item = gtk_menu_item_new (); - gtk_widget_lock_accelerators (menu_item); gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label); gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item, gtk_notebook_real_page_position (notebook, list)); diff --git a/gtk/gtksettings.c b/gtk/gtksettings.c index bd666813d..28f7ed8f1 100644 --- a/gtk/gtksettings.c +++ b/gtk/gtksettings.c @@ -399,8 +399,17 @@ _gtk_settings_parse_convert (GtkRcPropertyParser parser, if (free_gstring) g_string_free (gstring, TRUE); } - else if (!G_VALUE_HOLDS (src_value, G_TYPE_GSTRING) && - g_value_type_transformable (G_VALUE_TYPE (src_value), G_VALUE_TYPE (dest_value))) + else if (G_VALUE_HOLDS (src_value, G_TYPE_GSTRING)) + { + if (G_VALUE_HOLDS (dest_value, G_TYPE_STRING)) + { + GString *gstring = g_value_get_boxed (src_value); + + g_value_set_string (dest_value, gstring ? gstring->str : NULL); + success = !g_param_value_validate (pspec, dest_value); + } + } + else if (g_value_type_transformable (G_VALUE_TYPE (src_value), G_VALUE_TYPE (dest_value))) success = g_param_value_convert (pspec, src_value, dest_value, TRUE); return success; @@ -420,7 +429,7 @@ apply_queued_setting (GtkSettings *data, g_object_set_property (G_OBJECT (data), pspec->name, &tmp_value); else { - gchar *debug = g_strdup_value_contents (&tmp_value); + gchar *debug = g_strdup_value_contents (&qvalue->value); g_message ("%s: failed to retrieve property `%s' of type `%s' from rc file value \"%s\" of type `%s'", qvalue->origin, @@ -519,7 +528,7 @@ _gtk_rc_property_parser_from_type (GType type) void gtk_settings_install_property (GParamSpec *pspec) { - GtkRcPropertyParser parser = NULL; + GtkRcPropertyParser parser; g_return_if_fail (G_IS_PARAM_SPEC (pspec)); @@ -549,9 +558,9 @@ free_value (gpointer data) } void -gtk_settings_set_property_value (GtkSettings *settings, - const gchar *prop_name, - const GtkSettingsValue *new_value) +gtk_settings_set_property_value (GtkSettings *settings, + const gchar *prop_name, + const GtkSettingsValue *new_value) { GtkSettingsValue *qvalue; GParamSpec *pspec; @@ -909,7 +918,6 @@ gtk_rc_property_parse_border (const GParamSpec *pspec, return success; } - void _gtk_settings_handle_event (GdkEventSetting *event) { diff --git a/gtk/gtksignal.c b/gtk/gtksignal.c index b24741dd8..10f2328ef 100644 --- a/gtk/gtksignal.c +++ b/gtk/gtksignal.c @@ -43,7 +43,7 @@ gtk_signal_newv (const gchar *name, g_return_val_if_fail (n_params < SIGNAL_MAX_PARAMS, 0); - closure = g_signal_type_cclosure_new (object_type, function_offset); + closure = function_offset ? g_signal_type_cclosure_new (object_type, function_offset) : 0; return g_signal_newv (name, object_type, signal_flags, closure, NULL, NULL, marshaller, return_val, n_params, params); } diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 6ee796b39..646ac4907 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -28,6 +28,7 @@ #include <string.h> #include <locale.h> #include "gtkcontainer.h" +#include "gtkaccelmap.h" #include "gtkiconfactory.h" #include "gtkintl.h" #include "gtkmain.h" @@ -69,8 +70,6 @@ enum { DIRECTION_CHANGED, GRAB_NOTIFY, CHILD_NOTIFY, - ADD_ACCELERATOR, - REMOVE_ACCELERATOR, MNEMONIC_ACTIVATE, GRAB_FOCUS, FOCUS, @@ -114,6 +113,7 @@ enum { WINDOW_STATE_EVENT, POPUP_MENU, SHOW_HELP, + ACCEL_CLOSURES_CHANGED, LAST_SIGNAL }; @@ -230,6 +230,8 @@ static GParamSpecPool *style_property_spec_pool = NULL; static GQuark quark_property_parser = 0; static GQuark quark_aux_info = 0; +static GQuark quark_accel_path = 0; +static GQuark quark_accel_closures = 0; static GQuark quark_event_mask = 0; static GQuark quark_extension_event_mode = 0; static GQuark quark_parent_window = 0; @@ -299,6 +301,8 @@ gtk_widget_class_init (GtkWidgetClass *klass) quark_property_parser = g_quark_from_static_string ("gtk-rc-property-parser"); quark_aux_info = g_quark_from_static_string ("gtk-aux-info"); + quark_accel_path = g_quark_from_static_string ("gtk-accel-path"); + quark_accel_closures = g_quark_from_static_string ("gtk-accel-closures"); quark_event_mask = g_quark_from_static_string ("gtk-event-mask"); quark_extension_event_mode = g_quark_from_static_string ("gtk-extension-event-mode"); quark_parent_window = g_quark_from_static_string ("gtk-parent-window"); @@ -341,8 +345,6 @@ gtk_widget_class_init (GtkWidgetClass *klass) klass->direction_changed = gtk_widget_direction_changed; klass->grab_notify = NULL; klass->child_notify = NULL; - klass->add_accelerator = (void*) gtk_accel_group_handle_add; - klass->remove_accelerator = (void*) gtk_accel_group_handle_remove; klass->mnemonic_activate = gtk_widget_real_mnemonic_activate; klass->grab_focus = gtk_widget_real_grab_focus; klass->focus = gtk_widget_real_focus; @@ -620,12 +622,6 @@ gtk_widget_class_init (GtkWidgetClass *klass) g_cclosure_marshal_VOID__PARAM, G_TYPE_NONE, 1, G_TYPE_PARAM); - widget_signals[ADD_ACCELERATOR] = - gtk_accel_group_create_add (GTK_CLASS_TYPE (object_class), GTK_RUN_LAST, - GTK_SIGNAL_OFFSET (GtkWidgetClass, add_accelerator)); - widget_signals[REMOVE_ACCELERATOR] = - gtk_accel_group_create_remove (GTK_CLASS_TYPE (object_class), GTK_RUN_LAST, - GTK_SIGNAL_OFFSET (GtkWidgetClass, remove_accelerator)); widget_signals[MNEMONIC_ACTIVATE] = g_signal_new ("mnemonic_activate", GTK_CLASS_TYPE (object_class), @@ -1020,6 +1016,13 @@ gtk_widget_class_init (GtkWidgetClass *klass) GTK_SIGNAL_OFFSET (GtkWidgetClass, show_help), gtk_marshal_NONE__ENUM, GTK_TYPE_NONE, 1, GTK_TYPE_WIDGET_HELP_TYPE); + widget_signals[ACCEL_CLOSURES_CHANGED] = + gtk_signal_new ("accel_closures_changed", + 0, + GTK_CLASS_TYPE (object_class), + 0, + gtk_marshal_NONE__NONE, + GTK_TYPE_NONE, 0); binding_set = gtk_binding_set_by_class (klass); gtk_binding_entry_add_signal (binding_set, GDK_F10, GDK_SHIFT_MASK, @@ -1035,7 +1038,6 @@ gtk_widget_class_init (GtkWidgetClass *klass) "show_help", 1, GTK_TYPE_WIDGET_HELP_TYPE, GTK_WIDGET_HELP_TOOLTIP); - gtk_binding_entry_add_signal (binding_set, GDK_F1, GDK_SHIFT_MASK, "show_help", 1, GTK_TYPE_WIDGET_HELP_TYPE, @@ -2497,148 +2499,305 @@ gtk_widget_real_size_allocate (GtkWidget *widget, } } +typedef struct { + GClosure closure; + guint signal_id; +} AccelClosure; + static void -gtk_widget_stop_add_accelerator (GtkWidget *widget) +closure_accel_activate (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data) { - g_return_if_fail (GTK_IS_WIDGET (widget)); + AccelClosure *aclosure = (AccelClosure*) closure; - gtk_signal_emit_stop (GTK_OBJECT (widget), widget_signals[ADD_ACCELERATOR]); + if (GTK_WIDGET_IS_SENSITIVE (closure->data)) + g_signal_emit (closure->data, aclosure->signal_id, 0); + + /* we handled the accelerator */ + g_value_set_boolean (return_value, TRUE); } static void -gtk_widget_stop_remove_accelerator (GtkWidget *widget) +closures_destroy (gpointer data) { - g_return_if_fail (GTK_IS_WIDGET (widget)); + GSList *slist, *closures = data; - gtk_signal_emit_stop (GTK_OBJECT (widget), widget_signals[REMOVE_ACCELERATOR]); + for (slist = closures; slist; slist = slist->next) + { + g_closure_invalidate (slist->data); + g_closure_unref (slist->data); + } + g_slist_free (closures); } -void -gtk_widget_lock_accelerators (GtkWidget *widget) +static GClosure* +widget_new_accel_closure (GtkWidget *widget, + guint signal_id) { - g_return_if_fail (GTK_IS_WIDGET (widget)); - - if (!gtk_widget_accelerators_locked (widget)) + AccelClosure *aclosure; + GClosure *closure = NULL; + GSList *slist, *closures; + + closures = g_object_steal_qdata (G_OBJECT (widget), quark_accel_closures); + for (slist = closures; slist; slist = slist->next) + if (!gtk_accel_group_from_accel_closure (slist->data)) + { + /* reuse this closure */ + closure = slist->data; + break; + } + if (!closure) { - gtk_signal_connect (GTK_OBJECT (widget), - "add_accelerator", - GTK_SIGNAL_FUNC (gtk_widget_stop_add_accelerator), - NULL); - gtk_signal_connect (GTK_OBJECT (widget), - "remove_accelerator", - GTK_SIGNAL_FUNC (gtk_widget_stop_remove_accelerator), - NULL); + closure = g_closure_new_object (sizeof (AccelClosure), G_OBJECT (widget)); + closures = g_slist_prepend (closures, g_closure_ref (closure)); + g_closure_sink (closure); + g_closure_set_marshal (closure, closure_accel_activate); } + g_object_set_qdata_full (G_OBJECT (widget), quark_accel_closures, closures, closures_destroy); + + aclosure = (AccelClosure*) closure; + g_assert (closure->data == widget); + g_assert (closure->marshal == closure_accel_activate); + aclosure->signal_id = signal_id; + + return closure; } +/** + * gtk_widget_add_accelerator + * @widget: widget to install an accelerator on + * @accel_signal: widget signal to emit on accelerator actiavtion + * @accel_group: accel group for this widget, added to its toplevel + * @accel_key: GDK keyval of the accelerator + * @accel_mods: modifier key combination of the accelerator + * @accel_flags: flag accelerators, e.g. GTK_ACCEL_VISIBLE + * + * Install an accelerator for this @widget in @accel_group, that causes + * @accel_signal to be emitted if the accelerator is actiavted. + * The @accel_group needs to be added to the widget's toplevel via + * gtk_window_add_accel_group(), and the signal must be of type %G_RUN_ACTION. + * Accelerators added through this function are not user changable during + * runtime. If you want to support accelerators that can be changed by the + * user, use gtk_accel_map_add_entry() and gtk_menu_item_set_accel_path() + * instead. + */ void -gtk_widget_unlock_accelerators (GtkWidget *widget) +gtk_widget_add_accelerator (GtkWidget *widget, + const gchar *accel_signal, + GtkAccelGroup *accel_group, + guint accel_key, + guint accel_mods, + GtkAccelFlags accel_flags) { + GClosure *closure; + GSignalQuery query; + g_return_if_fail (GTK_IS_WIDGET (widget)); - - if (gtk_widget_accelerators_locked (widget)) + g_return_if_fail (accel_signal != NULL); + g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group)); + + g_signal_query (g_signal_lookup (accel_signal, G_OBJECT_TYPE (widget)), &query); + if (!query.signal_id || + !(query.signal_flags & G_SIGNAL_ACTION) || + query.return_type != G_TYPE_NONE || + query.n_params) { - gtk_signal_disconnect_by_func (GTK_OBJECT (widget), - GTK_SIGNAL_FUNC (gtk_widget_stop_add_accelerator), - NULL); - gtk_signal_disconnect_by_func (GTK_OBJECT (widget), - GTK_SIGNAL_FUNC (gtk_widget_stop_remove_accelerator), - NULL); + /* hmm, should be elaborate enough */ + g_warning (G_STRLOC ": widget `%s' has no activatable signal \"%s\" without arguments", + G_OBJECT_TYPE_NAME (widget), accel_signal); + return; } + + closure = widget_new_accel_closure (widget, query.signal_id); + + /* install the accelerator. since we don't map this onto an accel_path, + * the accelerator will automatically be locked. + */ + gtk_accel_group_connect (accel_group, + accel_key, + accel_mods, + accel_flags | GTK_ACCEL_LOCKED, + closure, + 0); + + g_signal_emit (widget, widget_signals[ACCEL_CLOSURES_CHANGED], 0); } +/** + * gtk_widget_remove_accelerator + * @widget: widget to install an accelerator on + * @accel_group: accel group for this widget + * @accel_key: GDK keyval of the accelerator + * @accel_mods: modifier key combination of the accelerator + * @returns: whether an accelerator was installed and could be removed + * + * Remove an accelerator from @widget, previously installed with + * gtk_widget_add_accelerator(). + */ gboolean -gtk_widget_accelerators_locked (GtkWidget *widget) +gtk_widget_remove_accelerator (GtkWidget *widget, + GtkAccelGroup *accel_group, + guint accel_key, + guint accel_mods) { - g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); + GtkAccelGroupEntry *ag_entry; + GSList *slist; + guint n, i; - return gtk_signal_handler_pending_by_func (GTK_OBJECT (widget), - widget_signals[ADD_ACCELERATOR], - TRUE, - GTK_SIGNAL_FUNC (gtk_widget_stop_add_accelerator), - NULL) > 0; + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); + g_return_val_if_fail (GTK_IS_ACCEL_GROUP (accel_group), FALSE); + + ag_entry = gtk_accel_group_query (accel_group, accel_key, accel_mods, &n); + for (slist = _gtk_widget_get_accel_closures (widget); slist; slist = slist->next) + { + /* paranoid sanity checking */ + for (i = 0; i < n; i++) + if (slist->data == (gpointer) ag_entry[i].closure) + { + gboolean is_removed = gtk_accel_groups_disconnect_closure (slist->data); + g_signal_emit (widget, widget_signals[ACCEL_CLOSURES_CHANGED], 0); + return is_removed; + } + } + + g_warning (G_STRLOC ": no accelerator (%u,%u) installed in accel group (%p) for %s (%p)", + accel_key, accel_mods, accel_group, + G_OBJECT_TYPE_NAME (widget), widget); + + return FALSE; } -void -gtk_widget_add_accelerator (GtkWidget *widget, - const gchar *accel_signal, - GtkAccelGroup *accel_group, - guint accel_key, - guint accel_mods, - GtkAccelFlags accel_flags) +GSList* +_gtk_widget_get_accel_closures (GtkWidget *widget) { - g_return_if_fail (GTK_IS_WIDGET (widget)); - g_return_if_fail (accel_group != NULL); + g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL); - gtk_accel_group_add (accel_group, - accel_key, - accel_mods, - accel_flags, - (GObject*) widget, - accel_signal); + return g_object_get_qdata (G_OBJECT (widget), quark_accel_closures); } -void -gtk_widget_remove_accelerator (GtkWidget *widget, - GtkAccelGroup *accel_group, - guint accel_key, - guint accel_mods) +typedef struct { + GtkWidget *widget; + GtkAccelGroup *accel_group; + const gchar *path; + GClosure *closure; +} AccelPath; + +static void +accel_path_changed (gpointer data, + GQuark accel_path_quark, + guint accel_key, + guint accel_mods, + GtkAccelGroup *accel_group, + guint old_accel_key, + guint old_accel_mods) +{ + AccelPath *apath = data; + gboolean notify = FALSE; + + if (apath->closure) + { + /* the closure might have been removed already (due to replacements) */ + gtk_accel_groups_disconnect_closure (apath->closure); + g_closure_unref (apath->closure); + apath->closure = NULL; + notify = TRUE; + } + if (accel_key) + { + apath->closure = widget_new_accel_closure (apath->widget, GTK_WIDGET_GET_CLASS (apath->widget)->activate_signal); + g_closure_ref (apath->closure); + /* need to specify path to get an unlocked accelerator */ + gtk_accel_group_connect (apath->accel_group, + accel_key, + accel_mods, + GTK_ACCEL_VISIBLE, + apath->closure, + accel_path_quark); + notify = TRUE; + } + if (notify) + g_signal_emit (apath->widget, widget_signals[ACCEL_CLOSURES_CHANGED], 0); +} + +static void +destroy_accel_path (gpointer data) { - g_return_if_fail (GTK_IS_WIDGET (widget)); - g_return_if_fail (accel_group != NULL); + AccelPath *apath = data; + + /* stop notification */ + gtk_accel_map_remove_notifer (apath->path, apath, accel_path_changed); - gtk_accel_group_remove (accel_group, - accel_key, - accel_mods, - (GObject*) widget); + /* if the closure is currently connected, get rid of that connection */ + if (apath->closure) + { + gtk_accel_groups_disconnect_closure (apath->closure); + g_closure_unref (apath->closure); + } + g_object_unref (apath->accel_group); + g_free (apath); } +/* accel_group: the accel group used to activate this widget + * accel_path: the accel path, associating the accelerator + * to activate this widget + * set accel path through which this widget can be actiavated. + */ void -gtk_widget_remove_accelerators (GtkWidget *widget, - const gchar *accel_signal, - gboolean visible_only) +_gtk_widget_set_accel_path (GtkWidget *widget, + const gchar *accel_path, + GtkAccelGroup *accel_group) { - GSList *slist; - guint signal_id; - + AccelPath *apath; + GtkAccelKey key; + g_return_if_fail (GTK_IS_WIDGET (widget)); - g_return_if_fail (accel_signal != NULL); - - signal_id = gtk_signal_lookup (accel_signal, GTK_OBJECT_TYPE (widget)); - g_return_if_fail (signal_id != 0); - - slist = gtk_accel_group_entries_from_object (G_OBJECT (widget)); - while (slist) + g_return_if_fail (GTK_WIDGET_GET_CLASS (widget)->activate_signal != 0); + if (accel_path) + g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group)); + + if (accel_path) { - GtkAccelEntry *ac_entry; - - ac_entry = slist->data; - slist = slist->next; - if (ac_entry->accel_flags & GTK_ACCEL_VISIBLE && - ac_entry->signal_id == signal_id) - gtk_widget_remove_accelerator (GTK_WIDGET (widget), - ac_entry->accel_group, - ac_entry->accelerator_key, - ac_entry->accelerator_mods); + GQuark quark_path = gtk_accel_map_add_entry (accel_path, 0, 0); + + if (!quark_path) + return; /* pathologic anyway */ + + apath = g_new (AccelPath, 1); + apath->widget = widget; + apath->accel_group = g_object_ref (accel_group); + apath->path = g_quark_to_string (quark_path); + apath->closure = NULL; + } + else + apath = NULL; + + /* also removes possible old settings */ + g_object_set_qdata_full (G_OBJECT (widget), quark_accel_path, apath, destroy_accel_path); + + if (apath) + { + /* setup accel path hooks to react to changes */ + gtk_accel_map_add_notifer (apath->path, apath, accel_path_changed, apath->accel_group); + + /* install accelerators for this path */ + if (gtk_accel_map_lookup_entry (apath->path, &key)) + accel_path_changed (apath, g_quark_try_string (apath->path), key.accel_key, key.accel_mods, NULL, 0, 0); } } -guint -gtk_widget_accelerator_signal (GtkWidget *widget, - GtkAccelGroup *accel_group, - guint accel_key, - guint accel_mods) +const gchar* +_gtk_widget_get_accel_path (GtkWidget *widget) { - GtkAccelEntry *ac_entry; + AccelPath *apath; - g_return_val_if_fail (GTK_IS_WIDGET (widget), 0); - g_return_val_if_fail (accel_group != NULL, 0); - - ac_entry = gtk_accel_group_get_entry (accel_group, accel_key, accel_mods); + g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL); - if (ac_entry && ac_entry->object == (GObject*) widget) - return ac_entry->signal_id; - return 0; + apath = g_object_get_qdata (G_OBJECT (widget), quark_accel_path); + return apath ? apath->path : NULL; } gboolean @@ -5361,6 +5520,10 @@ gtk_widget_real_destroy (GtkObject *object) */ widget = GTK_WIDGET (object); + /* wipe accelerator closures (keep order) */ + g_object_set_qdata (G_OBJECT (widget), quark_accel_path, NULL); + g_object_set_qdata (G_OBJECT (widget), quark_accel_closures, NULL); + gtk_grab_remove (widget); gtk_selection_remove_all (widget); diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h index 3d9969a24..ee464fa43 100644 --- a/gtk/gtkwidget.h +++ b/gtk/gtkwidget.h @@ -277,18 +277,6 @@ struct _GtkWidgetClass void (* child_notify) (GtkWidget *widget, GParamSpec *pspec); - /* accelerators */ - void (* add_accelerator) (GtkWidget *widget, - guint accel_signal_id, - GtkAccelGroup *accel_group, - guint accel_key, - GdkModifierType accel_mods, - GtkAccelFlags accel_flags); - void (* remove_accelerator) (GtkWidget *widget, - GtkAccelGroup *accel_group, - guint accel_key, - GdkModifierType accel_mods); - /* Mnemonics */ gboolean (* mnemonic_activate) (GtkWidget *widget, gboolean group_cycling); @@ -496,20 +484,15 @@ void gtk_widget_add_accelerator (GtkWidget *widget, guint accel_key, guint accel_mods, GtkAccelFlags accel_flags); -void gtk_widget_remove_accelerator (GtkWidget *widget, - GtkAccelGroup *accel_group, - guint accel_key, - guint accel_mods); -void gtk_widget_remove_accelerators (GtkWidget *widget, - const gchar *accel_signal, - gboolean visible_only); -guint gtk_widget_accelerator_signal (GtkWidget *widget, +gboolean gtk_widget_remove_accelerator (GtkWidget *widget, GtkAccelGroup *accel_group, guint accel_key, guint accel_mods); -void gtk_widget_lock_accelerators (GtkWidget *widget); -void gtk_widget_unlock_accelerators (GtkWidget *widget); -gboolean gtk_widget_accelerators_locked (GtkWidget *widget); +void _gtk_widget_set_accel_path (GtkWidget *widget, + const gchar *accel_path, + GtkAccelGroup *accel_group); +const gchar* _gtk_widget_get_accel_path (GtkWidget *widget); +GSList* _gtk_widget_get_accel_closures (GtkWidget *widget); gboolean gtk_widget_mnemonic_activate (GtkWidget *widget, gboolean group_cycling); gboolean gtk_widget_event (GtkWidget *widget, diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 5641caaea..d5b68cb0f 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -45,6 +45,7 @@ enum { ACTIVATE_FOCUS, ACTIVATE_DEFAULT, MOVE_FOCUS, + ACCELS_CHANGED, LAST_SIGNAL }; @@ -220,6 +221,7 @@ static void gtk_window_set_default_size_internal (GtkWindow *window, static void gtk_window_realize_icon (GtkWindow *window); static void gtk_window_unrealize_icon (GtkWindow *window); +static void gtk_window_notify_accels_changed (GtkWindow *window); static GSList *toplevel_list = NULL; static GHashTable *mnemonic_hash_table = NULL; @@ -309,6 +311,8 @@ gtk_window_class_init (GtkWindowClass *klass) parent_class = gtk_type_class (gtk_bin_get_type ()); + mnemonic_hash_table = g_hash_table_new (mnemonic_hash, mnemonic_equal); + gobject_class->dispose = gtk_window_dispose; gobject_class->finalize = gtk_window_finalize; @@ -345,6 +349,7 @@ gtk_window_class_init (GtkWindowClass *klass) klass->activate_default = gtk_window_real_activate_default; klass->activate_focus = gtk_window_real_activate_focus; klass->move_focus = gtk_window_move_focus; + klass->accels_changed = NULL; /* Construct */ g_object_class_install_property (gobject_class, @@ -493,10 +498,16 @@ gtk_window_class_init (GtkWindowClass *klass) G_TYPE_NONE, 1, GTK_TYPE_DIRECTION_TYPE); - - if (!mnemonic_hash_table) - mnemonic_hash_table = g_hash_table_new (mnemonic_hash, - mnemonic_equal); + + window_signals[ACCELS_CHANGED] = + g_signal_new ("accels_changed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + GTK_SIGNAL_OFFSET (GtkWindowClass, accels_changed), + NULL, NULL, + gtk_marshal_VOID__VOID, + G_TYPE_NONE, + 0); /* * Key bindings @@ -1001,6 +1012,38 @@ gtk_window_set_policy (GtkWindow *window, gtk_widget_queue_resize (GTK_WIDGET (window)); } +static gboolean +handle_accels_changed (gpointer data) +{ + GtkWindow *window = GTK_WINDOW (data); + + if (window->accels_changed_handler) + { + gtk_idle_remove (window->accels_changed_handler); + window->accels_changed_handler = 0; + } + + g_signal_emit (window, window_signals[ACCELS_CHANGED], 0); + + return FALSE; +} + +static void +gtk_window_notify_accels_changed (GtkWindow *window) +{ + if (!window->accels_changed_handler) + window->accels_changed_handler = gtk_idle_add (handle_accels_changed, window); +} + +/** + * gtk_window_add_accel_group: + * @window: window to attach accelerator group to + * @accel_group: a #GtkAccelGroup + * + * Associate @accel_group with @window, such that calling + * gtk_accel_groups_activate() on @window will activate accelerators + * in @accel_group. + **/ void gtk_window_add_accel_group (GtkWindow *window, GtkAccelGroup *accel_group) @@ -1008,9 +1051,19 @@ gtk_window_add_accel_group (GtkWindow *window, g_return_if_fail (GTK_IS_WINDOW (window)); g_return_if_fail (accel_group != NULL); - gtk_accel_group_attach (accel_group, G_OBJECT (window)); + _gtk_accel_group_attach (accel_group, G_OBJECT (window)); + g_signal_connect_object (accel_group, "accel_changed", + G_CALLBACK (gtk_window_notify_accels_changed), + window, G_CONNECT_SWAPPED); } +/** + * gtk_accel_group_detach: + * @accel_group: a #GtkAccelGroup + * @object: a #GObject + * + * Reverses the effects of gtk_window_add_accel_group(). + **/ void gtk_window_remove_accel_group (GtkWindow *window, GtkAccelGroup *accel_group) @@ -1018,7 +1071,10 @@ gtk_window_remove_accel_group (GtkWindow *window, g_return_if_fail (GTK_IS_WINDOW (window)); g_return_if_fail (accel_group != NULL); - gtk_accel_group_detach (accel_group, G_OBJECT (window)); + g_signal_handlers_disconnect_by_func (accel_group, + G_CALLBACK (gtk_window_notify_accels_changed), + window); + _gtk_accel_group_detach (accel_group, G_OBJECT (window)); } void @@ -1048,6 +1104,7 @@ gtk_window_add_mnemonic (GtkWindow *window, mnemonic->targets = g_slist_prepend (NULL, target); g_hash_table_insert (mnemonic_hash_table, mnemonic, mnemonic); } + gtk_window_notify_accels_changed (window); } void @@ -1073,6 +1130,7 @@ gtk_window_remove_mnemonic (GtkWindow *window, g_hash_table_remove (mnemonic_hash_table, mnemonic); g_free (mnemonic); } + gtk_window_notify_accels_changed (window); } gboolean @@ -1140,6 +1198,7 @@ gtk_window_set_mnemonic_modifier (GtkWindow *window, g_return_if_fail ((modifier & ~GDK_MODIFIER_MASK) == 0); window->mnemonic_modifier = modifier; + gtk_window_notify_accels_changed (window); } /** @@ -2836,7 +2895,13 @@ gtk_window_finalize (GObject *object) &window->geometry_info->widget); g_free (window->geometry_info); } - + + if (window->accels_changed_handler) + { + gtk_idle_remove (window->accels_changed_handler); + window->accels_changed_handler = 0; + } + G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -3371,6 +3436,46 @@ gtk_window_configure_event (GtkWidget *widget, return TRUE; } +/* the accel_key and accel_mods fields of the key have to be setup + * upon calling this function. it'll then return whether that key + * is at all used as accelerator, and if so will OR in the + * accel_flags member of the key. + */ +gboolean +_gtk_window_query_nonaccels (GtkWindow *window, + guint accel_key, + GdkModifierType accel_mods) +{ + g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE); + + /* movement keys are considered locked accels */ + if (!accel_mods) + { + static const guint bindings[] = { + GDK_space, GDK_KP_Space, GDK_Return, GDK_KP_Enter, GDK_Up, GDK_KP_Up, GDK_Down, GDK_KP_Down, + GDK_Left, GDK_KP_Left, GDK_Right, GDK_KP_Right, GDK_Tab, GDK_KP_Tab, GDK_ISO_Left_Tab, + }; + guint i; + + for (i = 0; i < G_N_ELEMENTS (bindings); i++) + if (bindings[i] == accel_key) + return TRUE; + } + + /* mnemonics are considered locked accels */ + if (accel_mods == window->mnemonic_modifier) + { + GtkWindowMnemonic mkey; + + mkey.window = window; + mkey.keyval = accel_key; + if (g_hash_table_lookup (mnemonic_hash_table, &mkey)) + return TRUE; + } + + return FALSE; +} + static gint gtk_window_key_press_event (GtkWidget *widget, GdkEventKey *event) @@ -3404,29 +3509,6 @@ gtk_window_key_press_event (GtkWidget *widget, return handled; } - -static void -gtk_window_real_activate_default (GtkWindow *window) -{ - gtk_window_activate_default (window); -} - -static void -gtk_window_real_activate_focus (GtkWindow *window) -{ - gtk_window_activate_focus (window); -} - -static void -gtk_window_move_focus (GtkWindow *window, - GtkDirectionType dir) -{ - gtk_widget_child_focus (GTK_WIDGET (window), dir); - - if (!GTK_CONTAINER (window)->focus_child) - gtk_window_set_focus (window, NULL); -} - static gint gtk_window_key_release_event (GtkWidget *widget, GdkEventKey *event) @@ -3452,6 +3534,28 @@ gtk_window_key_release_event (GtkWidget *widget, return handled; } +static void +gtk_window_real_activate_default (GtkWindow *window) +{ + gtk_window_activate_default (window); +} + +static void +gtk_window_real_activate_focus (GtkWindow *window) +{ + gtk_window_activate_focus (window); +} + +static void +gtk_window_move_focus (GtkWindow *window, + GtkDirectionType dir) +{ + gtk_widget_child_focus (GTK_WIDGET (window), dir); + + if (!GTK_CONTAINER (window)->focus_child) + gtk_window_set_focus (window, NULL); +} + static gint gtk_window_enter_notify_event (GtkWidget *widget, GdkEventCrossing *event) diff --git a/gtk/gtkwindow.h b/gtk/gtkwindow.h index 57a880181..8e62e60d0 100644 --- a/gtk/gtkwindow.h +++ b/gtk/gtkwindow.h @@ -104,6 +104,8 @@ struct _GtkWindow guint frame_top; guint frame_right; guint frame_bottom; + + guint accels_changed_handler; GdkModifierType mnemonic_modifier; gpointer gtk_reserved1; /* For future GdkScreen * */ @@ -124,6 +126,7 @@ struct _GtkWindowClass void (* activate_default) (GtkWindow *window); void (* move_focus) (GtkWindow *window, GtkDirectionType direction); + void (*accels_changed) (GtkWindow *window); }; #define GTK_TYPE_WINDOW_GROUP (gtk_window_group_get_type ()) @@ -320,6 +323,11 @@ void _gtk_window_constrain_size (GtkWindow *window, gint *new_height); GtkWindowGroup *_gtk_window_get_group (GtkWindow *window); +/* --- internal (GtkAcceleratable) --- */ +gboolean _gtk_window_query_nonaccels (GtkWindow *window, + guint accel_key, + GdkModifierType accel_mods); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/gtk/maketypes.awk b/gtk/maketypes.awk index 2a88f4549..d0ab8b9f7 100644 --- a/gtk/maketypes.awk +++ b/gtk/maketypes.awk @@ -32,7 +32,11 @@ BEGIN { printf ("# define GTKTYPEBUILTINS_VAR extern __declspec(dllimport)\n"); printf ("# endif\n"); printf ("#else\n"); - printf ("# define GTKTYPEBUILTINS_VAR extern\n"); + printf ("# ifdef GTK_COMPILATION\n"); + printf ("# define GTKTYPEBUILTINS_VAR\n"); + printf ("# else\n"); + printf ("# define GTKTYPEBUILTINS_VAR extern\n"); + printf ("# endif\n"); printf ("#endif\n"); printf ("\n"); } diff --git a/tests/testgtk.c b/tests/testgtk.c index 5cbdad12d..dd8134bd4 100644 --- a/tests/testgtk.c +++ b/tests/testgtk.c @@ -3047,7 +3047,7 @@ create_menus (void) NULL); accel_group = gtk_accel_group_new (); - gtk_accel_group_attach (accel_group, G_OBJECT (window)); + gtk_window_add_accel_group (window, accel_group); gtk_window_set_title (GTK_WINDOW (window), "menus"); gtk_container_set_border_width (GTK_CONTAINER (window), 0); @@ -3103,7 +3103,7 @@ create_menus (void) accel_group, GDK_F1, 0, - GTK_ACCEL_VISIBLE | GTK_ACCEL_SIGNAL_VISIBLE); + GTK_ACCEL_VISIBLE); menuitem = gtk_check_menu_item_new_with_label ("Accelerator Locked"); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); gtk_widget_show (menuitem); @@ -3128,7 +3128,6 @@ create_menus (void) GDK_F3, 0, GTK_ACCEL_VISIBLE); - gtk_widget_lock_accelerators (menuitem); optionmenu = gtk_option_menu_new (); gtk_option_menu_set_menu (GTK_OPTION_MENU (optionmenu), menu); @@ -3287,7 +3286,7 @@ dump_accels (gpointer callback_data, guint callback_action, GtkWidget *widget) { - gtk_item_factory_dump_items (NULL, FALSE, gtk_item_factory_print_func, stdout); + gtk_accel_map_save_fd (1 /* stdout */); } static GtkItemFactoryEntry menu_items[] = @@ -3360,7 +3359,7 @@ create_item_factory (void) "<main>", item_factory, (GtkDestroyNotify) gtk_object_unref); - gtk_accel_group_attach (accel_group, G_OBJECT (window)); + gtk_window_add_accel_group (window, accel_group); gtk_window_set_title (GTK_WINDOW (window), "Item Factory"); gtk_container_set_border_width (GTK_CONTAINER (window), 0); gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL); diff --git a/tests/testgtkrc b/tests/testgtkrc index 34bf05497..4b4cc5741 100644 --- a/tests/testgtkrc +++ b/tests/testgtkrc @@ -26,6 +26,9 @@ double-click_timeout = 42 bell-duration = 39 bell_duration = 40 +gtk-cursor-blink-time = 200 +# gtk-menu-bar-accel = F10 + style "global-style-properties" { # xthickness = 20 |