diff options
author | William Hua <william@attente.ca> | 2012-08-17 23:19:57 -0400 |
---|---|---|
committer | Ryan Lortie <desrt@desrt.ca> | 2012-08-20 13:13:49 -0400 |
commit | fe48e077bdab8821ba08e5135cfa6816d5e623af (patch) | |
tree | bf7388f37359ab0f458d9c6628dd5c858be22d91 /gtk | |
parent | dd45862a066474d0ebf9330f6c090f99a3422a63 (diff) | |
download | gtk+-fe48e077bdab8821ba08e5135cfa6816d5e623af.tar.gz |
Action helper support in Mac OS menus.
Diffstat (limited to 'gtk')
-rw-r--r-- | gtk/gtkapplication.c | 27 | ||||
-rw-r--r-- | gtk/gtkmodelmenu-quartz.c | 255 | ||||
-rw-r--r-- | gtk/gtkmodelmenu-quartz.h | 8 |
3 files changed, 76 insertions, 214 deletions
diff --git a/gtk/gtkapplication.c b/gtk/gtkapplication.c index 0a233d993c..8124df1a49 100644 --- a/gtk/gtkapplication.c +++ b/gtk/gtkapplication.c @@ -167,7 +167,6 @@ struct _GtkApplicationPrivate #endif #ifdef GDK_WINDOWING_QUARTZ - GActionMuxer *muxer; GMenu *combined; GSList *inhibitors; @@ -346,7 +345,9 @@ gtk_application_menu_changed_quartz (GObject *object, g_menu_append_submenu (combined, "Application", gtk_application_get_app_menu (application)); g_menu_append_section (combined, NULL, gtk_application_get_menubar (application)); - gtk_quartz_set_main_menu (G_MENU_MODEL (combined), G_ACTION_OBSERVABLE (application->priv->muxer)); + gtk_quartz_set_main_menu (G_MENU_MODEL (combined), application); + + g_object_unref (combined); } static void gtk_application_startup_session_quartz (GtkApplication *app); @@ -356,9 +357,6 @@ gtk_application_startup_quartz (GtkApplication *application) { [NSApp finishLaunching]; - application->priv->muxer = g_action_muxer_new (); - g_action_muxer_insert (application->priv->muxer, "app", G_ACTION_GROUP (application)); - g_signal_connect (application, "notify::app-menu", G_CALLBACK (gtk_application_menu_changed_quartz), NULL); g_signal_connect (application, "notify::menubar", G_CALLBACK (gtk_application_menu_changed_quartz), NULL); gtk_application_menu_changed_quartz (G_OBJECT (application), NULL, NULL); @@ -369,25 +367,14 @@ gtk_application_startup_quartz (GtkApplication *application) static void gtk_application_shutdown_quartz (GtkApplication *application) { - g_signal_handlers_disconnect_by_func (application, gtk_application_menu_changed_quartz, NULL); + gtk_quartz_clear_main_menu (); - g_object_unref (application->priv->muxer); - application->priv->muxer = NULL; + g_signal_handlers_disconnect_by_func (application, gtk_application_menu_changed_quartz, NULL); g_slist_free_full (application->priv->inhibitors, (GDestroyNotify) gtk_application_quartz_inhibitor_free); application->priv->inhibitors = NULL; } - -static void -gtk_application_focus_changed (GtkApplication *application, - GtkWindow *window) -{ - if (G_IS_ACTION_GROUP (window)) - g_action_muxer_insert (application->priv->muxer, "win", G_ACTION_GROUP (window)); - else - g_action_muxer_remove (application->priv->muxer, "win"); -} #endif static gboolean @@ -408,10 +395,6 @@ gtk_application_focus_in_event_cb (GtkWindow *window, g_object_notify (G_OBJECT (application), "active-window"); -#ifdef GDK_WINDOWING_QUARTZ - gtk_application_focus_changed (application, window); -#endif - return FALSE; } diff --git a/gtk/gtkmodelmenu-quartz.c b/gtk/gtkmodelmenu-quartz.c index c85cbb8ee7..a5a73ecdcc 100644 --- a/gtk/gtkmodelmenu-quartz.c +++ b/gtk/gtkmodelmenu-quartz.c @@ -22,6 +22,7 @@ #include <gdk/gdkkeysyms.h> #include "gtkaccelmapprivate.h" +#include "gtkactionhelper.h" #import <Cocoa/Cocoa.h> @@ -174,20 +175,16 @@ gtk_quartz_model_menu_get_unichar (gint key) -typedef struct _GtkQuartzActionObserver GtkQuartzActionObserver; - - - @interface GNSMenu : NSMenu { - GActionObservable *actions; - GMenuModel *model; - guint update_idle; - GSList *connected; - gboolean with_separators; + GtkApplication *application; + GMenuModel *model; + guint update_idle; + GSList *connected; + gboolean with_separators; } -- (id)initWithTitle:(NSString *)title model:(GMenuModel *)aModel actions:(GActionObservable *)someActions hasSeparators:(BOOL)hasSeparators; +- (id)initWithTitle:(NSString *)title model:(GMenuModel *)aModel application:(GtkApplication *)application hasSeparators:(BOOL)hasSeparators; - (void)model:(GMenuModel *)model didChangeAtPosition:(NSInteger)position removed:(NSInteger)removed added:(NSInteger)added; @@ -199,115 +196,18 @@ typedef struct _GtkQuartzActionObserver GtkQuartzActionObserver; @interface GNSMenuItem : NSMenuItem { - gchar *action; - GVariant *target; - BOOL canActivate; - GActionGroup *actions; - GtkQuartzActionObserver *observer; + GtkActionHelper *helper; } -- (id)initWithModel:(GMenuModel *)model index:(NSInteger)index observable:(GActionObservable *)observable; - -- (void)observableActionAddedWithParameterType:(const GVariantType *)parameterType enabled:(BOOL)enabled state:(GVariant *)state; -- (void)observableActionEnabledChangedTo:(BOOL)enabled; -- (void)observableActionStateChangedTo:(GVariant *)state; -- (void)observableActionRemoved; +- (id)initWithModel:(GMenuModel *)model index:(NSInteger)index application:(GtkApplication *)application; - (void)didSelectItem:(id)sender; -@end - - - -struct _GtkQuartzActionObserver -{ - GObject parent_instance; - - GNSMenuItem *item; -}; - - - -typedef GObjectClass GtkQuartzActionObserverClass; - -static void gtk_quartz_action_observer_observer_iface_init (GActionObserverInterface *iface); -G_DEFINE_TYPE_WITH_CODE (GtkQuartzActionObserver, gtk_quartz_action_observer, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_OBSERVER, gtk_quartz_action_observer_observer_iface_init)) - -static void -gtk_quartz_action_observer_action_added (GActionObserver *observer, - GActionObservable *observable, - const gchar *action_name, - const GVariantType *parameter_type, - gboolean enabled, - GVariant *state) -{ - GtkQuartzActionObserver *qao = (GtkQuartzActionObserver *) observer; - - [qao->item observableActionAddedWithParameterType:parameter_type enabled:enabled state:state]; -} - -static void -gtk_quartz_action_observer_action_enabled_changed (GActionObserver *observer, - GActionObservable *observable, - const gchar *action_name, - gboolean enabled) -{ - GtkQuartzActionObserver *qao = (GtkQuartzActionObserver *) observer; - - [qao->item observableActionEnabledChangedTo:enabled]; -} - -static void -gtk_quartz_action_observer_action_state_changed (GActionObserver *observer, - GActionObservable *observable, - const gchar *action_name, - GVariant *state) -{ - GtkQuartzActionObserver *qao = (GtkQuartzActionObserver *) observer; - - [qao->item observableActionStateChangedTo:state]; -} - -static void -gtk_quartz_action_observer_action_removed (GActionObserver *observer, - GActionObservable *observable, - const gchar *action_name) -{ - GtkQuartzActionObserver *qao = (GtkQuartzActionObserver *) observer; - - [qao->item observableActionRemoved]; -} - -static void -gtk_quartz_action_observer_init (GtkQuartzActionObserver *item) -{ -} - -static void -gtk_quartz_action_observer_observer_iface_init (GActionObserverInterface *iface) -{ - iface->action_added = gtk_quartz_action_observer_action_added; - iface->action_enabled_changed = gtk_quartz_action_observer_action_enabled_changed; - iface->action_state_changed = gtk_quartz_action_observer_action_state_changed; - iface->action_removed = gtk_quartz_action_observer_action_removed; -} - -static void -gtk_quartz_action_observer_class_init (GtkQuartzActionObserverClass *class) -{ -} +- (void)helperChanged; -static GtkQuartzActionObserver * -gtk_quartz_action_observer_new (GNSMenuItem *item) -{ - GtkQuartzActionObserver *observer; +@end - observer = g_object_new (gtk_quartz_action_observer_get_type (), NULL); - observer->item = item; - return observer; -} static gboolean gtk_quartz_model_menu_handle_changes (gpointer user_data) @@ -330,10 +230,17 @@ gtk_quartz_model_menu_items_changed (GMenuModel *model, } void -gtk_quartz_set_main_menu (GMenuModel *model, - GActionObservable *observable) +gtk_quartz_set_main_menu (GMenuModel *model, + GtkApplication *application) { - [NSApp setMainMenu:[[[GNSMenu alloc] initWithTitle:@"Main Menu" model:model actions:observable hasSeparators:NO] autorelease]]; + [NSApp setMainMenu:[[[GNSMenu alloc] initWithTitle:@"Main Menu" model:model application:application hasSeparators:NO] autorelease]]; +} + +void +gtk_quartz_clear_main_menu (void) +{ + // ensure that we drop all GNSMenuItem (to ensure 'application' has no extra references) + [NSApp setMainMenu:[[[NSMenu alloc] init] autorelease]]; } @interface GNSMenu () @@ -363,7 +270,7 @@ gtk_quartz_set_main_menu (GMenuModel *model, g_object_unref (section); } else - [self addItem:[[[GNSMenuItem alloc] initWithModel:aModel index:index observable:actions] autorelease]]; + [self addItem:[[[GNSMenuItem alloc] initWithModel:aModel index:index application:application] autorelease]]; } - (void)appendFromModel:(GMenuModel *)aModel withSeparators:(BOOL)withSeparators @@ -427,14 +334,14 @@ gtk_quartz_set_main_menu (GMenuModel *model, return G_SOURCE_REMOVE; } -- (id)initWithTitle:(NSString *)title model:(GMenuModel *)aModel actions:(GActionObservable *)someActions hasSeparators:(BOOL)hasSeparators +- (id)initWithTitle:(NSString *)title model:(GMenuModel *)aModel application:(GtkApplication *)anApplication hasSeparators:(BOOL)hasSeparators { if((self = [super initWithTitle:title]) != nil) { [self setAutoenablesItems:NO]; model = g_object_ref (aModel); - actions = g_object_ref (someActions); + application = g_object_ref (anApplication); with_separators = hasSeparators; [self populate]; @@ -453,7 +360,7 @@ gtk_quartz_set_main_menu (GMenuModel *model, connected = g_slist_delete_link (connected, connected); } - g_object_unref (actions); + g_object_unref (application); g_object_unref (model); [super dealloc]; @@ -463,9 +370,19 @@ gtk_quartz_set_main_menu (GMenuModel *model, +static void +gtk_quartz_action_helper_changed (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + GNSMenuItem *item = user_data; + + [item helperChanged]; +} + @implementation GNSMenuItem -- (id)initWithModel:(GMenuModel *)model index:(NSInteger)index observable:(GActionObservable *)observable +- (id)initWithModel:(GMenuModel *)model index:(NSInteger)index application:(GtkApplication *)application { gchar *title = NULL; @@ -489,15 +406,16 @@ gtk_quartz_set_main_menu (GMenuModel *model, if ((self = [super initWithTitle:[NSString stringWithUTF8String:title ? : ""] action:@selector(didSelectItem:) keyEquivalent:@""]) != nil) { GMenuModel *submenu; + gchar *action; + GVariant *target; + action = NULL; g_menu_model_get_item_attribute (model, index, G_MENU_ATTRIBUTE_ACTION, "s", &action); target = g_menu_model_get_item_attribute_value (model, index, G_MENU_ATTRIBUTE_TARGET, NULL); - actions = g_object_ref (observable); - observer = gtk_quartz_action_observer_new (self); if ((submenu = g_menu_model_get_item_link (model, index, G_MENU_LINK_SUBMENU))) { - [self setSubmenu:[[[GNSMenu alloc] initWithTitle:[NSString stringWithUTF8String:title] model:submenu actions:observable hasSeparators:YES] autorelease]]; + [self setSubmenu:[[[GNSMenu alloc] initWithTitle:[NSString stringWithUTF8String:title] model:submenu application:application hasSeparators:YES] autorelease]]; g_object_unref (submenu); } @@ -506,7 +424,13 @@ gtk_quartz_set_main_menu (GMenuModel *model, GtkAccelKey key; gchar *path; - g_action_observable_register_observer (observable, action, G_ACTION_OBSERVER (observer)); + helper = gtk_action_helper_new_with_application (application); + gtk_action_helper_set_action_name (helper, action); + gtk_action_helper_set_action_target_value (helper, target); + + g_signal_connect (helper, "notify", G_CALLBACK (gtk_quartz_action_helper_changed), self); + + [self helperChanged]; path = _gtk_accel_path_for_action (action, target); if (gtk_accel_map_lookup_entry (path, &key)) @@ -537,15 +461,6 @@ gtk_quartz_set_main_menu (GMenuModel *model, g_free (path); [self setTarget:self]; - - gboolean enabled; - const GVariantType *parameterType; - GVariant *state; - - if (g_action_group_query_action (actions, action, &enabled, ¶meterType, NULL, NULL, &state)) - [self observableActionAddedWithParameterType:parameterType enabled:enabled state:state]; - else - [self setEnabled:NO]; } } @@ -556,74 +471,36 @@ gtk_quartz_set_main_menu (GMenuModel *model, - (void)dealloc { - if (observer != NULL) - g_object_unref (observer); - - if (actions != NULL) - g_object_unref (actions); - - if (target != NULL) - g_variant_unref (target); - - g_free (action); + if (helper != NULL) + g_object_unref (helper); [super dealloc]; } -- (void)observableActionAddedWithParameterType:(const GVariantType *)parameterType enabled:(BOOL)enabled state:(GVariant *)state +- (void)didSelectItem:(id)sender { - canActivate = (target == NULL && parameterType == NULL) || - (target != NULL && parameterType != NULL && - g_variant_is_of_type (target, parameterType)); - - if (canActivate) - { - if (target != NULL && state != NULL) - { - [self setOnStateImage:[NSImage imageNamed:@"NSMenuRadio"]]; - [self setState:g_variant_equal (state, target) ? NSOnState : NSOffState]; - } - else if (state != NULL && g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN)) - { - [self setOnStateImage:[NSImage imageNamed:@"NSMenuCheckmark"]]; - [self setState:g_variant_get_boolean (state) ? NSOnState : NSOffState]; - } - else - [self setState:NSOffState]; - - [self setEnabled:enabled]; - } - else - [self setEnabled:NO]; + gtk_action_helper_activate (helper); } -- (void)observableActionEnabledChangedTo:(BOOL)enabled +- (void)helperChanged { - if (canActivate) - [self setEnabled:enabled]; -} + [self setEnabled:gtk_action_helper_get_enabled (helper)]; + [self setState:gtk_action_helper_get_active (helper)]; -- (void)observableActionStateChangedTo:(GVariant *)state -{ - if (canActivate) + switch (gtk_action_helper_get_role (helper)) { - if (target != NULL) - [self setState:g_variant_equal (state, target) ? NSOnState : NSOffState]; - else if (g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN)) - [self setState:g_variant_get_boolean (state) ? NSOnState : NSOffState]; + case GTK_ACTION_HELPER_ROLE_NORMAL: + [self setOnStateImage:nil]; + break; + case GTK_ACTION_HELPER_ROLE_TOGGLE: + [self setOnStateImage:[NSImage imageNamed:@"NSMenuCheckmark"]]; + break; + case GTK_ACTION_HELPER_ROLE_RADIO: + [self setOnStateImage:[NSImage imageNamed:@"NSMenuRadio"]]; + break; + default: + g_assert_not_reached (); } } -- (void)observableActionRemoved -{ - if (canActivate) - [self setEnabled:NO]; -} - -- (void)didSelectItem:(id)sender -{ - if (canActivate) - g_action_group_activate_action (actions, action, target); -} - @end diff --git a/gtk/gtkmodelmenu-quartz.h b/gtk/gtkmodelmenu-quartz.h index 93d83e5cd2..1be9220363 100644 --- a/gtk/gtkmodelmenu-quartz.h +++ b/gtk/gtkmodelmenu-quartz.h @@ -20,9 +20,11 @@ #ifndef __GTK_MODELMENU_QUARTZ_H__ #define __GTK_MODELMENU_QUARTZ_H__ -#include "gactionobservable.h" +#include "gtkapplication.h" -void gtk_quartz_set_main_menu (GMenuModel *model, - GActionObservable *observable); +void gtk_quartz_set_main_menu (GMenuModel *model, + GtkApplication *application); + +void gtk_quartz_clear_main_menu (void); #endif /* __GTK_MODELMENU_QUARTZ_H__ */ |