]> Pileus Git - ~andy/gtk/blob - gtk/gtkapplication.c
application: use the same variable names in definitions and declarations
[~andy/gtk] / gtk / gtkapplication.c
1 /*
2  * Copyright © 2010 Codethink Limited
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the licence, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  *
19  * Author: Ryan Lortie <desrt@desrt.ca>
20  */
21
22 #include "config.h"
23
24 #include "gtkapplication.h"
25
26 #include <stdlib.h>
27 #ifdef HAVE_UNISTD_H
28 #include <unistd.h>
29 #endif
30 #include <string.h>
31
32 #include "gtkapplicationprivate.h"
33 #include "gtkmarshalers.h"
34 #include "gtkmain.h"
35 #include "gtkaccelmapprivate.h"
36 #include "gactionmuxer.h"
37
38 #ifdef GDK_WINDOWING_QUARTZ
39 #include "gtkquartz-menu.h"
40 #import <Cocoa/Cocoa.h>
41 #endif
42
43 #include <gdk/gdk.h>
44 #ifdef GDK_WINDOWING_X11
45 #include <gdk/x11/gdkx.h>
46 #endif
47
48 /**
49  * SECTION:gtkapplication
50  * @title: GtkApplication
51  * @short_description: Application class
52  *
53  * #GtkApplication is a class that handles many important aspects
54  * of a GTK+ application in a convenient fashion, without enforcing
55  * a one-size-fits-all application model.
56  *
57  * Currently, GtkApplication handles GTK+ initialization, application
58  * uniqueness, provides some basic scriptability and desktop shell integration
59  * by exporting actions and menus and manages a list of toplevel windows whose
60  * life-cycle is automatically tied to the life-cycle of your application.
61  *
62  * While GtkApplication works fine with plain #GtkWindows, it is recommended
63  * to use it together with #GtkApplicationWindow.
64  *
65  * When GDK threads are enabled, GtkApplication will acquire the GDK
66  * lock when invoking actions that arrive from other processes.  The GDK
67  * lock is not touched for local action invocations.  In order to have
68  * actions invoked in a predictable context it is therefore recommended
69  * that the GDK lock be held while invoking actions locally with
70  * g_action_group_activate_action().  The same applies to actions
71  * associated with #GtkApplicationWindow and to the 'activate' and
72  * 'open' #GApplication methods.
73  *
74  * To set an application menu on a GtkApplication, use
75  * g_application_set_app_menu(). The #GMenuModel that this function
76  * expects is usually constructed using #GtkBuilder, as seen in the
77  * following example. To set a menubar that will be automatically picked
78  * up by #GApplicationWindows, use g_application_set_menubar(). GTK+
79  * makes these menus appear as expected, depending on the platform
80  * the application is running on.
81  *
82  * <figure label="Menu integration in OS X">
83  * <graphic fileref="bloatpad-osx.png" format="PNG"/>
84  * </figure>
85  *
86  * <figure label="Menu integration in GNOME">
87  * <graphic fileref="bloatpad-gnome.png" format="PNG"/>
88  * </figure>
89  *
90  * <figure label="Menu integration in Xfce">
91  * <graphic fileref="bloatpad-xfce.png" format="PNG"/>
92  * </figure>
93  *
94  * <example id="gtkapplication"><title>A simple application</title>
95  * <programlisting>
96  * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../examples/bloatpad.c">
97  *  <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
98  * </xi:include>
99  * </programlisting>
100  * </example>
101  */
102
103 enum {
104   WINDOW_ADDED,
105   WINDOW_REMOVED,
106   LAST_SIGNAL
107 };
108
109 static guint gtk_application_signals[LAST_SIGNAL];
110
111 G_DEFINE_TYPE (GtkApplication, gtk_application, G_TYPE_APPLICATION)
112
113 struct _GtkApplicationPrivate
114 {
115   GList *windows;
116
117 #ifdef GDK_WINDOWING_X11
118   GDBusConnection *session;
119   gchar *window_prefix;
120   guint next_id;
121 #endif
122
123 #ifdef GDK_WINDOWING_QUARTZ
124   GActionMuxer *muxer;
125   GMenu *combined;
126 #endif
127 };
128
129 #ifdef GDK_WINDOWING_X11
130 static void
131 gtk_application_window_added_x11 (GtkApplication *application,
132                                   GtkWindow      *window)
133 {
134   if (application->priv->session == NULL)
135     return;
136
137   if (GTK_IS_APPLICATION_WINDOW (window))
138     {
139       GtkApplicationWindow *app_window = GTK_APPLICATION_WINDOW (window);
140       gboolean success;
141
142       /* GtkApplicationWindow associates with us when it is first created,
143        * so surely it's not realized yet...
144        */
145       g_assert (!gtk_widget_get_realized (GTK_WIDGET (window)));
146
147       do
148         {
149           gchar *window_path;
150           guint window_id;
151
152           window_id = application->priv->next_id++;
153           window_path = g_strdup_printf ("%s%d", application->priv->window_prefix, window_id);
154           success = gtk_application_window_publish (app_window, application->priv->session, window_path);
155           g_free (window_path);
156         }
157       while (!success);
158     }
159 }
160
161 static void
162 gtk_application_window_removed_x11 (GtkApplication *application,
163                                     GtkWindow      *window)
164 {
165   if (application->priv->session == NULL)
166     return;
167
168   if (GTK_IS_APPLICATION_WINDOW (window))
169     gtk_application_window_unpublish (GTK_APPLICATION_WINDOW (window));
170 }
171
172 static gchar *
173 window_prefix_from_appid (const gchar *appid)
174 {
175   gchar *appid_path, *iter;
176
177   appid_path = g_strconcat ("/", appid, "/windows/", NULL);
178   for (iter = appid_path; *iter; iter++)
179     {
180       if (*iter == '.')
181         *iter = '/';
182
183       if (*iter == '-')
184         *iter = '_';
185     }
186
187   return appid_path;
188 }
189
190 static void
191 gtk_application_startup_x11 (GtkApplication *application)
192 {
193   const gchar *application_id;
194
195   application_id = g_application_get_application_id (G_APPLICATION (application));
196   application->priv->session = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
197   application->priv->window_prefix = window_prefix_from_appid (application_id);
198 }
199
200 static void
201 gtk_application_shutdown_x11 (GtkApplication *application)
202 {
203   g_free (application->priv->window_prefix);
204   application->priv->window_prefix = NULL;
205   if (application->priv->session)
206     {
207       g_object_unref (application->priv->session);
208       application->priv->session = NULL;
209     }
210 }
211 #endif
212
213 #ifdef GDK_WINDOWING_QUARTZ
214 static void
215 gtk_application_menu_changed_quartz (GObject    *object,
216                                      GParamSpec *pspec,
217                                      gpointer    user_data)
218 {
219   GtkApplication *application = GTK_APPLICATION (object);
220   GMenu *combined;
221
222   combined = g_menu_new ();
223   g_menu_append_submenu (combined, "Application", g_application_get_app_menu (application));
224   g_menu_append_section (combined, NULL, gtk_application_get_menubar (application));
225
226   gtk_quartz_set_main_menu (G_MENU_MODEL (combined), G_ACTION_OBSERVABLE (application->priv->muxer));
227 }
228
229 static void
230 gtk_application_startup_quartz (GtkApplication *application)
231 {
232   [NSApp finishLaunching];
233
234   application->priv->muxer = g_action_muxer_new ();
235   g_action_muxer_insert (application->priv->muxer, "app", G_ACTION_GROUP (application));
236
237   g_signal_connect (application, "notify::app-menu", G_CALLBACK (gtk_application_menu_changed_quartz), NULL);
238   g_signal_connect (application, "notify::menubar", G_CALLBACK (gtk_application_menu_changed_quartz), NULL);
239   gtk_application_menu_changed_quartz (G_OBJECT (application), NULL, NULL);
240 }
241
242 static void
243 gtk_application_shutdown_quartz (GtkApplication *application)
244 {
245   g_signal_handlers_disconnect_by_func (application, gtk_application_menu_changed_quartz, NULL);
246
247   g_object_unref (application->priv->muxer);
248   application->priv->muxer = NULL;
249 }
250
251 static void
252 gtk_application_focus_changed (GtkApplication *application,
253                                GtkWindow      *window)
254 {
255   if (G_IS_ACTION_GROUP (window))
256     g_action_muxer_insert (application->priv->muxer, "win", G_ACTION_GROUP (window));
257   else
258     g_action_muxer_remove (application->priv->muxer, "win");
259 }
260 #endif
261
262 static gboolean
263 gtk_application_focus_in_event_cb (GtkWindow      *window,
264                                    GdkEventFocus  *event,
265                                    GtkApplication *application)
266 {
267   GtkApplicationPrivate *priv = application->priv;
268   GList *link;
269
270   /* Keep the window list sorted by most-recently-focused. */
271   link = g_list_find (priv->windows, window);
272   if (link != NULL && link != priv->windows)
273     {
274       priv->windows = g_list_remove_link (priv->windows, link);
275       priv->windows = g_list_concat (link, priv->windows);
276     }
277
278 #ifdef GDK_WINDOWING_QUARTZ
279   gtk_application_focus_changed (application, window);
280 #endif
281
282   return FALSE;
283 }
284
285 static void
286 gtk_application_startup (GApplication *application)
287 {
288   G_APPLICATION_CLASS (gtk_application_parent_class)
289     ->startup (application);
290
291   gtk_init (0, 0);
292
293 #ifdef GDK_WINDOWING_X11
294   gtk_application_startup_x11 (GTK_APPLICATION (application));
295 #endif
296
297 #ifdef GDK_WINDOWING_QUARTZ
298   gtk_application_startup_quartz (GTK_APPLICATION (application));
299 #endif
300 }
301
302 static void
303 gtk_application_shutdown (GApplication *application)
304 {
305 #ifdef GDK_WINDOWING_X11
306   gtk_application_shutdown_x11 (GTK_APPLICATION (application));
307 #endif
308
309 #ifdef GDK_WINDOWING_QUARTZ
310   gtk_application_shutdown_quartz (GTK_APPLICATION (application));
311 #endif
312
313   G_APPLICATION_CLASS (gtk_application_parent_class)
314     ->shutdown (application);
315 }
316
317 static void
318 gtk_application_add_platform_data (GApplication    *application,
319                                    GVariantBuilder *builder)
320 {
321   const gchar *startup_id;
322
323   startup_id = getenv ("DESKTOP_STARTUP_ID");
324   
325   if (startup_id && g_utf8_validate (startup_id, -1, NULL))
326     g_variant_builder_add (builder, "{sv}", "desktop-startup-id",
327                            g_variant_new_string (startup_id));
328 }
329
330 static void
331 gtk_application_before_emit (GApplication *application,
332                              GVariant     *platform_data)
333 {
334   GVariantIter iter;
335   const gchar *key;
336   GVariant *value;
337
338   gdk_threads_enter ();
339
340   g_variant_iter_init (&iter, platform_data);
341   while (g_variant_iter_loop (&iter, "{&sv}", &key, &value))
342     {
343 #ifdef GDK_WINDOWING_X11
344       if (strcmp (key, "desktop-startup-id") == 0)
345         {
346           GdkDisplay *display;
347           const gchar *id;
348
349           display = gdk_display_get_default ();
350           id = g_variant_get_string (value, NULL);
351           if (GDK_IS_X11_DISPLAY (display))
352             gdk_x11_display_set_startup_notification_id (display, id);
353        }
354 #endif
355     }
356 }
357
358 static void
359 gtk_application_after_emit (GApplication *application,
360                             GVariant     *platform_data)
361 {
362   gdk_notify_startup_complete ();
363
364   gdk_threads_leave ();
365 }
366
367 static void
368 gtk_application_init (GtkApplication *application)
369 {
370   application->priv = G_TYPE_INSTANCE_GET_PRIVATE (application,
371                                                    GTK_TYPE_APPLICATION,
372                                                    GtkApplicationPrivate);
373 }
374
375 static void
376 gtk_application_window_added (GtkApplication *application,
377                               GtkWindow      *window)
378 {
379   GtkApplicationPrivate *priv = application->priv;
380
381   priv->windows = g_list_prepend (priv->windows, window);
382   gtk_window_set_application (window, application);
383   g_application_hold (G_APPLICATION (application));
384
385   g_signal_connect (window, "focus-in-event",
386                     G_CALLBACK (gtk_application_focus_in_event_cb),
387                     application);
388
389 #ifdef GDK_WINDOWING_X11
390   gtk_application_window_added_x11 (application, window);
391 #endif
392 }
393
394 static void
395 gtk_application_window_removed (GtkApplication *application,
396                                 GtkWindow      *window)
397 {
398   GtkApplicationPrivate *priv = application->priv;
399
400 #ifdef GDK_WINDOWING_X11
401   gtk_application_window_removed_x11 (application, window);
402 #endif
403
404   g_signal_handlers_disconnect_by_func (window,
405                                         gtk_application_focus_in_event_cb,
406                                         application);
407
408   g_application_release (G_APPLICATION (application));
409   priv->windows = g_list_remove (priv->windows, window);
410   gtk_window_set_application (window, NULL);
411 }
412
413 static void
414 extract_accel_from_menu_item (GMenuModel     *model,
415                               gint            item,
416                               GtkApplication *app)
417 {
418   GMenuAttributeIter *iter;
419   const gchar *key;
420   GVariant *value;
421   const gchar *accel = NULL;
422   const gchar *action = NULL;
423   GVariant *target = NULL;
424
425   iter = g_menu_model_iterate_item_attributes (model, item);
426   while (g_menu_attribute_iter_get_next (iter, &key, &value))
427     {
428       if (g_str_equal (key, "action") && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
429         action = g_variant_get_string (value, NULL);
430       else if (g_str_equal (key, "accel") && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
431         accel = g_variant_get_string (value, NULL);
432       else if (g_str_equal (key, "target"))
433         target = g_variant_ref (value);
434       g_variant_unref (value);
435     }
436   g_object_unref (iter);
437
438   if (accel && action)
439     gtk_application_add_accelerator (app, accel, action, target);
440
441   if (target)
442     g_variant_unref (target);
443 }
444
445 static void
446 extract_accels_from_menu (GMenuModel     *model,
447                           GtkApplication *app)
448 {
449   gint i;
450   GMenuLinkIter *iter;
451   const gchar *key;
452   GMenuModel *m;
453
454   for (i = 0; i < g_menu_model_get_n_items (model); i++)
455     {
456       extract_accel_from_menu_item (model, i, app);
457
458       iter = g_menu_model_iterate_item_links (model, i);
459       while (g_menu_link_iter_get_next (iter, &key, &m))
460         {
461           extract_accels_from_menu (m, app);
462           g_object_unref (m);
463         }
464       g_object_unref (iter);
465     }
466 }
467
468 static void
469 gtk_application_notify (GObject    *object,
470                         GParamSpec *pspec)
471 {
472   if (strcmp (pspec->name, "app-menu") == 0 ||
473       strcmp (pspec->name, "menubar") == 0)
474     {
475       GMenuModel *model;
476       g_object_get (object, pspec->name, &model, NULL);
477       if (model)
478         {
479           extract_accels_from_menu (model, GTK_APPLICATION (object));
480           g_object_unref (model);
481         }
482     }
483
484   if (G_OBJECT_CLASS (gtk_application_parent_class)->notify)
485     G_OBJECT_CLASS (gtk_application_parent_class)->notify (object, pspec);
486 }
487
488 static void
489 gtk_application_class_init (GtkApplicationClass *class)
490 {
491   GObjectClass *object_class = G_OBJECT_CLASS (class);
492   GApplicationClass *application_class = G_APPLICATION_CLASS (class);
493
494   object_class->notify = gtk_application_notify;
495
496   application_class->add_platform_data = gtk_application_add_platform_data;
497   application_class->before_emit = gtk_application_before_emit;
498   application_class->after_emit = gtk_application_after_emit;
499   application_class->startup = gtk_application_startup;
500   application_class->shutdown = gtk_application_shutdown;
501
502   class->window_added = gtk_application_window_added;
503   class->window_removed = gtk_application_window_removed;
504
505   g_type_class_add_private (class, sizeof (GtkApplicationPrivate));
506
507   /**
508    * GtkApplication::window-added:
509    * @application: the #GtkApplication which emitted the signal
510    * @window: the newly-added #GtkWindow
511    *
512    * Emitted when a #GtkWindow is added to @application through
513    * gtk_application_add_window().
514    *
515    * Since: 3.2
516    */
517   gtk_application_signals[WINDOW_ADDED] =
518     g_signal_new ("window-added", GTK_TYPE_APPLICATION, G_SIGNAL_RUN_FIRST,
519                   G_STRUCT_OFFSET (GtkApplicationClass, window_added),
520                   NULL, NULL,
521                   g_cclosure_marshal_VOID__OBJECT,
522                   G_TYPE_NONE, 1, GTK_TYPE_WINDOW);
523
524   /**
525    * GtkApplication::window-removed:
526    * @application: the #GtkApplication which emitted the signal
527    * @window: the #GtkWindow that is being removed
528    *
529    * Emitted when a #GtkWindow is removed from @application,
530    * either as a side-effect of being destroyed or explicitly
531    * through gtk_application_remove_window().
532    *
533    * Since: 3.2
534    */
535   gtk_application_signals[WINDOW_REMOVED] =
536     g_signal_new ("window-removed", GTK_TYPE_APPLICATION, G_SIGNAL_RUN_FIRST,
537                   G_STRUCT_OFFSET (GtkApplicationClass, window_removed),
538                   NULL, NULL,
539                   g_cclosure_marshal_VOID__OBJECT,
540                   G_TYPE_NONE, 1, GTK_TYPE_WINDOW);
541 }
542
543 /**
544  * gtk_application_new:
545  * @application_id: the application id
546  * @flags: the application flags
547  *
548  * Creates a new #GtkApplication instance.
549  *
550  * This function calls g_type_init() for you. gtk_init() is called
551  * as soon as the application gets registered as the primary instance.
552  *
553  * Note that commandline arguments are not passed to gtk_init().
554  * All GTK+ functionality that is available via commandline arguments
555  * can also be achieved by setting suitable environment variables
556  * such as <envvar>G_DEBUG</envvar>, so this should not be a big
557  * problem. If you absolutely must support GTK+ commandline arguments,
558  * you can explicitly call gtk_init() before creating the application
559  * instance.
560  *
561  * The application id must be valid. See g_application_id_is_valid().
562  *
563  * Returns: a new #GtkApplication instance
564  */
565 GtkApplication *
566 gtk_application_new (const gchar       *application_id,
567                      GApplicationFlags  flags)
568 {
569   g_return_val_if_fail (g_application_id_is_valid (application_id), NULL);
570
571   g_type_init ();
572
573   return g_object_new (GTK_TYPE_APPLICATION,
574                        "application-id", application_id,
575                        "flags", flags,
576                        NULL);
577 }
578
579 /**
580  * gtk_application_add_window:
581  * @application: a #GtkApplication
582  * @window: a #GtkWindow
583  *
584  * Adds a window from @application.
585  *
586  * This call is equivalent to setting the #GtkWindow:application
587  * property of @window to @application.
588  *
589  * Normally, the connection between the application and the window
590  * will remain until the window is destroyed, but you can explicitly
591  * remove it with gtk_application_remove_window().
592  *
593  * GTK+ will keep the application running as long as it has
594  * any windows.
595  *
596  * Since: 3.0
597  **/
598 void
599 gtk_application_add_window (GtkApplication *application,
600                             GtkWindow      *window)
601 {
602   g_return_if_fail (GTK_IS_APPLICATION (application));
603
604   if (!g_list_find (application->priv->windows, window))
605     g_signal_emit (application,
606                    gtk_application_signals[WINDOW_ADDED], 0, window);
607 }
608
609 /**
610  * gtk_application_remove_window:
611  * @application: a #GtkApplication
612  * @window: a #GtkWindow
613  *
614  * Remove a window from @application.
615  *
616  * If @window belongs to @application then this call is equivalent to
617  * setting the #GtkWindow:application property of @window to
618  * %NULL.
619  *
620  * The application may stop running as a result of a call to this
621  * function.
622  *
623  * Since: 3.0
624  **/
625 void
626 gtk_application_remove_window (GtkApplication *application,
627                                GtkWindow      *window)
628 {
629   g_return_if_fail (GTK_IS_APPLICATION (application));
630
631   if (g_list_find (application->priv->windows, window))
632     g_signal_emit (application,
633                    gtk_application_signals[WINDOW_REMOVED], 0, window);
634 }
635
636 /**
637  * gtk_application_get_windows:
638  * @application: a #GtkApplication
639  *
640  * Gets a list of the #GtkWindows associated with @application.
641  *
642  * The list is sorted by most recently focused window, such that the first
643  * element is the currently focused window. (Useful for choosing a parent
644  * for a transient window.)
645  *
646  * The list that is returned should not be modified in any way. It will
647  * only remain valid until the next focus change or window creation or
648  * deletion.
649  *
650  * Returns: (element-type GtkWindow) (transfer none): a #GList of #GtkWindow
651  *
652  * Since: 3.0
653  **/
654 GList *
655 gtk_application_get_windows (GtkApplication *application)
656 {
657   g_return_val_if_fail (GTK_IS_APPLICATION (application), NULL);
658
659   return application->priv->windows;
660 }
661
662 /**
663  * gtk_application_add_accelerator:
664  * @application: a #GtkApplication
665  * @accelerator: accelerator string
666  * @action_name: the name of the action to activate
667  * @parameter: (allow-none): parameter to pass when activating the action,
668  *   or %NULL if the action does not accept an activation parameter
669  *
670  * Installs an accelerator that will cause the named action
671  * to be activated when the key combination specificed by @accelerator
672  * is pressed.
673  *
674  * @accelerator must be a string that can be parsed by
675  * gtk_accelerator_parse(), e.g. "<Primary>q" or "<Control><Alt>p".
676  *
677  * @action_name must be the name of an action as it would be used
678  * in the app menu, i.e. actions that have been added to the application
679  * are referred to with an "app." prefix, and window-specific actions
680  * with a "win." prefix.
681  *
682  * GtkApplication also extracts accelerators out of 'accel' attributes
683  * in the #GMenuModels passed to g_application_set_app_menu() and
684  * g_application_set_menubar(), which is usually more convenient
685  * than calling this function for each accelerator.
686  *
687  * Since: 3.4
688  */
689 void
690 gtk_application_add_accelerator (GtkApplication *application,
691                                  const gchar    *accelerator,
692                                  const gchar    *action_name,
693                                  GVariant       *parameter)
694 {
695   gchar *accel_path;
696   guint accel_key;
697   GdkModifierType accel_mods;
698
699   g_return_if_fail (GTK_IS_APPLICATION (application));
700
701   /* Call this here, since gtk_init() is only getting called in startup() */
702   _gtk_accel_map_init ();
703
704   gtk_accelerator_parse (accelerator, &accel_key, &accel_mods);
705
706   if (accel_key == 0)
707     {
708       g_warning ("Failed to parse accelerator: '%s'\n", accelerator);
709       return;
710     }
711
712   accel_path = _gtk_accel_path_for_action (action_name, parameter);
713
714   if (gtk_accel_map_lookup_entry (accel_path, NULL))
715     gtk_accel_map_change_entry (accel_path, accel_key, accel_mods, TRUE);
716   else
717     gtk_accel_map_add_entry (accel_path, accel_key, accel_mods);
718
719   g_free (accel_path);
720 }
721
722 /**
723  * gtk_application_remove_accelerator:
724  * @application: a #GtkApplication
725  * @action_name: the name of the action to activate
726  * @parameter: (allow-none): parameter to pass when activating the action,
727  *   or %NULL if the action does not accept an activation parameter
728  *
729  * Removes an accelerator that has been previously added
730  * with gtk_application_add_accelerator().
731  *
732  * Since: 3.4
733  */
734 void
735 gtk_application_remove_accelerator (GtkApplication *application,
736                                     const gchar    *action_name,
737                                     GVariant       *parameter)
738 {
739   gchar *accel_path;
740
741   g_return_if_fail (GTK_IS_APPLICATION (application));
742
743   accel_path = _gtk_accel_path_for_action (action_name, parameter);
744
745   if (!gtk_accel_map_lookup_entry (accel_path, NULL))
746     {
747       g_warning ("No accelerator found for '%s'\n", accel_path);
748       g_free (accel_path);
749       return;
750     }
751
752   gtk_accel_map_change_entry (accel_path, 0, 0, FALSE);
753   g_free (accel_path);
754 }
755
756 /**
757  * gtk_application_set_app_menu:
758  * @application: a #GtkApplication
759  * @model: (allow-none): a #GMenuModel, or %NULL
760  *
761  * Sets or unsets the application menu for @application.
762  *
763  * The application menu is a single menu containing items that typically
764  * impact the application as a whole, rather than acting on a specific
765  * window or document.  For example, you would expect to see
766  * "Preferences" or "Quit" in an application menu, but not "Save" or
767  * "Print".
768  *
769  * If supported, the application menu will be rendered by the desktop
770  * environment.
771  *
772  * Since: 3.4
773  */
774 void
775 gtk_application_set_app_menu (GtkApplication *application,
776                               GMenuModel     *model)
777 {
778   g_object_set (application, "app-menu", model, NULL);
779 }
780
781 /**
782  * gtk_application_get_app_menu:
783  * @application: a #GtkApplication
784  *
785  * Returns the menu model that has been set with
786  * g_application_set_app_menu().
787  *
788  * Returns: the application menu of @application
789  *
790  * Since: 3.4
791  */
792 GMenuModel *
793 gtk_application_get_app_menu (GtkApplication *application)
794 {
795   GMenuModel *app_menu;
796
797   g_object_get (application, "app-menu", &app_menu, NULL);
798   g_object_unref (app_menu);
799
800   return app_menu;
801 }
802
803 /**
804  * gtk_application_set_menubar:
805  * @application: a #GtkApplication
806  * @model: (allow-none): a #GMenuModel, or %NULL
807  *
808  * Sets or unsets the menubar for windows of @application.
809  *
810  * This is a menubar in the traditional sense.
811  *
812  * Depending on the desktop environment, this may appear at the top of
813  * each window, or at the top of the screen.  In some environments, if
814  * both the application menu and the menubar are set, the application
815  * menu will be presented as if it were the first item of the menubar.
816  * Other environments treat the two as completely separate -- for
817  * example, the application menu may be rendered by the desktop shell
818  * while the menubar (if set) remains in each individual window.
819  *
820  * Since: 3.4
821  */
822 void
823 gtk_application_set_menubar (GtkApplication *application,
824                              GMenuModel     *model)
825 {
826   g_object_set (application, "menubar", model, NULL);
827 }
828
829 /**
830  * gtk_application_get_menubar:
831  * @application: a #GtkApplication
832  *
833  * Returns the menu model that has been set with
834  * g_application_set_menubar().
835  *
836  * Returns: the menubar for windows of @application
837  *
838  * Since: 3.4
839  */
840 GMenuModel *
841 gtk_application_get_menubar (GtkApplication *application)
842 {
843   GMenuModel *menubar;
844
845   g_object_get (application, "menubar", &menubar, NULL);
846   g_object_unref (menubar);
847
848   return menubar;
849 }