1 /*
2 * appmenu-gtk-module
3 * Copyright 2012 Canonical Ltd.
4 * Copyright (C) 2015-2017 Konstantin Pugin <ria.freelander@gmail.com>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * Authors: Ryan Lortie <desrt@desrt.ca>
20 * William Hua <william.hua@canonical.com>
21 * Konstantin Pugin <ria.freelander@gmail.com>
22 * Lester Carballo Perez <lestcape@gmail.com>
23 */
24
25 #include "datastructs.h"
26 #include "datastructs-private.h"
27 #include "platform.h"
28
29 #include <appmenu-gtk-menu-shell.h>
30
31 G_GNUC_INTERNAL G_DEFINE_QUARK(window_data, window_data);
32 G_DEFINE_BOXED_TYPE(WindowData, window_data, (GBoxedCopyFunc)window_data_copy,
33 (GBoxedFreeFunc)window_data_free);
34 G_GNUC_INTERNAL G_DEFINE_QUARK(menu_shell_data, menu_shell_data);
35 G_DEFINE_BOXED_TYPE(MenuShellData, menu_shell_data, (GBoxedCopyFunc)menu_shell_data_copy,
36 (GBoxedFreeFunc)menu_shell_data_free);
37
window_data_new(void)38 G_GNUC_INTERNAL WindowData *window_data_new(void)
39 {
40 return g_slice_new0(WindowData);
41 }
42
window_data_free(gpointer data)43 G_GNUC_INTERNAL void window_data_free(gpointer data)
44 {
45 WindowData *window_data = data;
46
47 if (window_data != NULL)
48 {
49 GDBusConnection *session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
50
51 if (window_data->action_group_export_id)
52 g_dbus_connection_unexport_action_group(session,
53 window_data
54 ->action_group_export_id);
55
56 if (window_data->menu_model_export_id)
57 g_dbus_connection_unexport_menu_model(session,
58 window_data->menu_model_export_id);
59
60 if (window_data->action_group != NULL)
61 g_object_unref(window_data->action_group);
62
63 if (window_data->menu_model != NULL)
64 g_object_unref(window_data->menu_model);
65
66 if (window_data->old_model != NULL)
67 g_object_unref(window_data->old_model);
68
69 if (window_data->menus != NULL)
70 g_slist_free_full(window_data->menus, g_object_unref);
71
72 g_slice_free(WindowData, window_data);
73 }
74 }
75
window_data_copy(WindowData * source)76 G_GNUC_INTERNAL WindowData *window_data_copy(WindowData *source)
77 {
78 WindowData *ret = window_data_new();
79 ret->action_group_export_id = source->action_group_export_id;
80 ret->menu_model_export_id = source->menu_model_export_id;
81 if (source->action_group != NULL)
82 ret->action_group = g_object_ref(source->action_group);
83
84 if (source->menu_model != NULL)
85 ret->menu_model = g_object_ref(source->menu_model);
86
87 if (source->old_model != NULL)
88 ret->old_model = g_object_ref(source->old_model);
89
90 if (source->menus != NULL)
91 ret->menus = g_slist_copy_deep(source->menus, (GCopyFunc)g_object_ref, NULL);
92
93 return ret;
94 }
95
menu_shell_data_new(void)96 G_GNUC_INTERNAL MenuShellData *menu_shell_data_new(void)
97 {
98 return g_slice_new0(MenuShellData);
99 }
100
menu_shell_data_free(gpointer data)101 G_GNUC_INTERNAL void menu_shell_data_free(gpointer data)
102 {
103 if (data != NULL)
104 g_slice_free(MenuShellData, data);
105 }
106
menu_shell_data_copy(MenuShellData * source)107 G_GNUC_INTERNAL MenuShellData *menu_shell_data_copy(MenuShellData *source)
108 {
109 MenuShellData *ret = menu_shell_data_new();
110 ret->window = source->window;
111 return ret;
112 }
113
menu_shell_data_has_window(MenuShellData * source)114 G_GNUC_INTERNAL bool menu_shell_data_has_window(MenuShellData *source)
115 {
116 return source->window != NULL;
117 }
118
menu_shell_data_get_window(MenuShellData * source)119 G_GNUC_INTERNAL GtkWindow *menu_shell_data_get_window(MenuShellData *source)
120 {
121 return source->window;
122 }
123
gtk_menu_shell_get_menu_shell_data(GtkMenuShell * menu_shell)124 G_GNUC_INTERNAL MenuShellData *gtk_menu_shell_get_menu_shell_data(GtkMenuShell *menu_shell)
125 {
126 MenuShellData *menu_shell_data;
127
128 g_return_val_if_fail(GTK_IS_MENU_SHELL(menu_shell), NULL);
129
130 menu_shell_data = g_object_get_qdata(G_OBJECT(menu_shell), menu_shell_data_quark());
131
132 if (menu_shell_data == NULL)
133 {
134 menu_shell_data = menu_shell_data_new();
135
136 g_object_set_qdata_full(G_OBJECT(menu_shell),
137 menu_shell_data_quark(),
138 menu_shell_data,
139 menu_shell_data_free);
140 }
141
142 return menu_shell_data;
143 }
144
gtk_window_get_window_data(GtkWindow * window)145 G_GNUC_INTERNAL WindowData *gtk_window_get_window_data(GtkWindow *window)
146 {
147 WindowData *window_data = NULL;
148
149 g_return_val_if_fail(GTK_IS_WINDOW(window), NULL);
150
151 #if (defined(GDK_WINDOWING_WAYLAND))
152 if (GDK_IS_WAYLAND_DISPLAY(gdk_display_get_default()))
153 window_data = gtk_wayland_window_get_window_data(window);
154 #endif
155 #if (defined(GDK_WINDOWING_X11))
156 #if GTK_MAJOR_VERSION == 3
157 if (GDK_IS_X11_DISPLAY(gdk_display_get_default()))
158 #endif
159 window_data = gtk_x11_window_get_window_data(window);
160 #endif
161 return window_data;
162 }
163
gtk_window_disconnect_menu_shell(GtkWindow * window,GtkMenuShell * menu_shell)164 G_GNUC_INTERNAL void gtk_window_disconnect_menu_shell(GtkWindow *window, GtkMenuShell *menu_shell)
165 {
166 WindowData *window_data;
167 MenuShellData *menu_shell_data;
168
169 g_return_if_fail(GTK_IS_WINDOW(window));
170 g_return_if_fail(GTK_IS_MENU_SHELL(menu_shell));
171
172 menu_shell_data = gtk_menu_shell_get_menu_shell_data(menu_shell);
173
174 g_warn_if_fail(window == menu_shell_data->window);
175
176 window_data = gtk_window_get_window_data(menu_shell_data->window);
177
178 if (window_data != NULL)
179 {
180 GSList *iter;
181 guint i = 0;
182
183 if (window_data->old_model != NULL)
184 i++;
185
186 for (iter = window_data->menus; iter != NULL; iter = g_slist_next(iter), i++)
187 if (UNITY_GTK_MENU_SHELL(iter->data)->menu_shell == menu_shell)
188 break;
189
190 if (iter != NULL)
191 {
192 g_menu_remove(window_data->menu_model, i);
193
194 unity_gtk_action_group_disconnect_shell(window_data->action_group,
195 iter->data);
196
197 g_object_unref(iter->data);
198
199 window_data->menus = g_slist_delete_link(window_data->menus, iter);
200 }
201
202 menu_shell_data->window = NULL;
203 }
204 }
205
gtk_window_connect_menu_shell(GtkWindow * window,GtkMenuShell * menu_shell)206 G_GNUC_INTERNAL void gtk_window_connect_menu_shell(GtkWindow *window, GtkMenuShell *menu_shell)
207 {
208 MenuShellData *menu_shell_data;
209
210 g_return_if_fail(GTK_IS_WINDOW(window));
211 g_return_if_fail(GTK_IS_MENU_SHELL(menu_shell));
212
213 menu_shell_data = gtk_menu_shell_get_menu_shell_data(menu_shell);
214
215 if (window != menu_shell_data->window)
216 {
217 WindowData *window_data;
218
219 if (menu_shell_data->window != NULL)
220 gtk_window_disconnect_menu_shell(menu_shell_data->window, menu_shell);
221
222 window_data = gtk_window_get_window_data(window);
223
224 if (window_data != NULL)
225 {
226 GSList *iter;
227
228 for (iter = window_data->menus; iter != NULL; iter = g_slist_next(iter))
229 if (UNITY_GTK_MENU_SHELL(iter->data)->menu_shell == menu_shell)
230 break;
231
232 if (iter == NULL)
233 {
234 UnityGtkMenuShell *shell = unity_gtk_menu_shell_new(menu_shell);
235
236 unity_gtk_action_group_connect_shell(window_data->action_group,
237 shell);
238
239 g_menu_append_section(window_data->menu_model,
240 NULL,
241 G_MENU_MODEL(shell));
242
243 window_data->menus = g_slist_append(window_data->menus, shell);
244 }
245 }
246
247 menu_shell_data->window = window;
248 }
249 }
250