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 "platform.h"
26 #include "consts.h"
27 #include "datastructs-private.h"
28 #include "datastructs.h"
29
30 #ifdef GDK_WINDOWING_X11
gtk_widget_get_x11_property_string(GtkWidget * widget,const char * name)31 G_GNUC_INTERNAL char *gtk_widget_get_x11_property_string(GtkWidget *widget, const char *name)
32 {
33 GdkWindow *window;
34 GdkDisplay *display;
35 Display *xdisplay;
36 Window xwindow;
37 Atom property;
38 Atom actual_type;
39 int actual_format;
40 unsigned long nitems;
41 unsigned long bytes_after;
42 unsigned char *prop;
43
44 g_return_val_if_fail(GTK_IS_WIDGET(widget), NULL);
45
46 window = gtk_widget_get_window(widget);
47 display = gdk_window_get_display(window);
48 xdisplay = GDK_DISPLAY_XDISPLAY(display);
49 xwindow = GDK_WINDOW_XID(window);
50
51 property = None;
52
53 if (display != NULL)
54 property = gdk_x11_get_xatom_by_name_for_display(display, name);
55
56 if (property == None)
57 property = gdk_x11_get_xatom_by_name(name);
58
59 g_return_val_if_fail(property != None, NULL);
60
61 if (XGetWindowProperty(xdisplay,
62 xwindow,
63 property,
64 0,
65 G_MAXLONG,
66 False,
67 AnyPropertyType,
68 &actual_type,
69 &actual_format,
70 &nitems,
71 &bytes_after,
72 &prop) == Success)
73 {
74 if (actual_format)
75 {
76 char *string = g_strdup((const char *)prop);
77
78 if (prop != NULL)
79 XFree(prop);
80
81 return string;
82 }
83 else
84 return NULL;
85 }
86
87 return NULL;
88 }
89
gtk_widget_set_x11_property_string(GtkWidget * widget,const char * name,const char * value)90 G_GNUC_INTERNAL void gtk_widget_set_x11_property_string(GtkWidget *widget, const char *name,
91 const char *value)
92 {
93 GdkWindow *window;
94 GdkDisplay *display;
95 Display *xdisplay;
96 Window xwindow;
97 Atom property;
98 Atom type;
99
100 g_return_if_fail(GTK_IS_WIDGET(widget));
101
102 window = gtk_widget_get_window(widget);
103 display = gdk_window_get_display(window);
104 xdisplay = GDK_DISPLAY_XDISPLAY(display);
105 xwindow = GDK_WINDOW_XID(window);
106
107 property = None;
108
109 if (display != NULL)
110 property = gdk_x11_get_xatom_by_name_for_display(display, name);
111
112 if (property == None)
113 property = gdk_x11_get_xatom_by_name(name);
114
115 g_return_if_fail(property != None);
116
117 type = None;
118
119 if (display != NULL)
120 type = gdk_x11_get_xatom_by_name_for_display(display, "UTF8_STRING");
121
122 if (type == None)
123 type = gdk_x11_get_xatom_by_name("UTF8_STRING");
124
125 g_return_if_fail(type != None);
126
127 if (value != NULL)
128 XChangeProperty(xdisplay,
129 xwindow,
130 property,
131 type,
132 8,
133 PropModeReplace,
134 (unsigned char *)value,
135 g_utf8_strlen(value, -1));
136 else
137 XDeleteProperty(xdisplay, xwindow, property);
138 }
139
gtk_x11_window_get_window_data(GtkWindow * window)140 G_GNUC_INTERNAL WindowData *gtk_x11_window_get_window_data(GtkWindow *window)
141 {
142 WindowData *window_data;
143
144 g_return_val_if_fail(GTK_IS_WINDOW(window), NULL);
145
146 window_data = g_object_get_qdata(G_OBJECT(window), window_data_quark());
147
148 if (window_data == NULL)
149 {
150 static guint window_id;
151
152 GDBusConnection *session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
153 char *object_path = g_strdup_printf(OBJECT_PATH "/%d", window_id);
154 char *old_unique_bus_name =
155 gtk_widget_get_x11_property_string(GTK_WIDGET(window), _GTK_UNIQUE_BUS_NAME);
156 char *old_unity_object_path =
157 gtk_widget_get_x11_property_string(GTK_WIDGET(window), _UNITY_OBJECT_PATH);
158 char *old_menubar_object_path =
159 gtk_widget_get_x11_property_string(GTK_WIDGET(window),
160 _GTK_MENUBAR_OBJECT_PATH);
161 GDBusActionGroup *old_action_group = NULL;
162 GDBusMenuModel *old_menu_model = NULL;
163
164 if (old_unique_bus_name != NULL)
165 {
166 if (old_unity_object_path != NULL)
167 old_action_group = g_dbus_action_group_get(session,
168 old_unique_bus_name,
169 old_unity_object_path);
170
171 if (old_menubar_object_path != NULL)
172 old_menu_model = g_dbus_menu_model_get(session,
173 old_unique_bus_name,
174 old_menubar_object_path);
175 }
176
177 window_data = window_data_new();
178 window_data->window_id = window_id++;
179 window_data->menu_model = g_menu_new();
180 window_data->action_group =
181 unity_gtk_action_group_new(G_ACTION_GROUP(old_action_group));
182
183 if (old_menu_model != NULL)
184 {
185 window_data->old_model = G_MENU_MODEL(g_object_ref(old_menu_model));
186 g_menu_append_section(window_data->menu_model,
187 NULL,
188 G_MENU_MODEL(old_menu_model));
189 }
190
191 window_data->menu_model_export_id =
192 g_dbus_connection_export_menu_model(session,
193 old_menubar_object_path != NULL
194 ? old_menubar_object_path
195 : object_path,
196 G_MENU_MODEL(window_data->menu_model),
197 NULL);
198 window_data->action_group_export_id =
199 g_dbus_connection_export_action_group(session,
200 old_unity_object_path != NULL
201 ? old_unity_object_path
202 : object_path,
203 G_ACTION_GROUP(window_data->action_group),
204 NULL);
205
206 if (old_unique_bus_name == NULL)
207 gtk_widget_set_x11_property_string(GTK_WIDGET(window),
208 _GTK_UNIQUE_BUS_NAME,
209 g_dbus_connection_get_unique_name(
210 session));
211
212 if (old_unity_object_path == NULL)
213 gtk_widget_set_x11_property_string(GTK_WIDGET(window),
214 _UNITY_OBJECT_PATH,
215 object_path);
216
217 if (old_menubar_object_path == NULL)
218 gtk_widget_set_x11_property_string(GTK_WIDGET(window),
219 _GTK_MENUBAR_OBJECT_PATH,
220 object_path);
221
222 g_object_set_qdata_full(G_OBJECT(window),
223 window_data_quark(),
224 window_data,
225 window_data_free);
226
227 g_free(old_menubar_object_path);
228 g_free(old_unity_object_path);
229 g_free(old_unique_bus_name);
230 g_free(object_path);
231 }
232
233 return window_data;
234 }
235 #endif
236 #ifdef GDK_WINDOWING_WAYLAND
237
238 #include <wayland-client.h>
239
240 void gdk_wayland_window_set_dbus_properties_libgtk_only(
241 GdkWindow *window, const char *application_id, const char *app_menu_path,
242 const char *menubar_path, const char *window_object_path, const char *application_object_path,
243 const char *unique_bus_name);
244
gtk_wayland_window_get_window_data(GtkWindow * window)245 G_GNUC_INTERNAL WindowData *gtk_wayland_window_get_window_data(GtkWindow *window)
246 {
247 WindowData *window_data;
248
249 g_return_val_if_fail(GTK_IS_WINDOW(window), NULL);
250
251 window_data = g_object_get_qdata(G_OBJECT(window), window_data_quark());
252 if (window_data == NULL)
253 {
254 static guint window_id;
255 GMenuModel *old_menu_model = NULL;
256 GDBusActionGroup *old_action_group = NULL;
257 GtkApplication *application;
258 GApplication *gApp;
259 GDBusConnection *connection;
260
261 char *unique_bus_name;
262 char *object_path;
263 char *menubar_object_path;
264 char *application_id;
265 char *application_object_path;
266
267 window_data = window_data_new();
268 window_data->menu_model = g_menu_new();
269
270 if (GTK_IS_APPLICATION_WINDOW(window))
271 {
272 char *unity_object_path;
273
274 application = gtk_window_get_application(window);
275 g_return_val_if_fail(GTK_IS_APPLICATION(application), NULL);
276
277 window_data->action_group = NULL;
278
279 gApp = G_APPLICATION(application);
280 g_return_val_if_fail(g_application_get_is_registered(gApp), NULL);
281 g_return_val_if_fail(!g_application_get_is_remote(gApp), NULL);
282 g_return_val_if_fail(window_data->menu_model == NULL ||
283 G_IS_MENU_MODEL(window_data->menu_model),
284 NULL);
285
286 application_id =
287 g_strdup_printf("%s", g_application_get_application_id(gApp));
288 application_object_path =
289 g_strdup_printf("%s", g_application_get_dbus_object_path(gApp));
290
291 window_data->window_id = window_id++; // IN THE GNOME IMPLEMENTATION THIS IS
292 // STARTED IN ONE NOT CERO (So, we
293 // make is similar)
294
295 connection = g_application_get_dbus_connection(gApp);
296 object_path = g_strdup_printf(OBJECT_PATH "/%d", window_id);
297
298 unique_bus_name =
299 g_strdup_printf("%s", g_dbus_connection_get_unique_name(connection));
300 unity_object_path =
301 g_strdup_printf("%s%s",
302 g_application_get_dbus_object_path(gApp) != NULL
303 ? g_application_get_dbus_object_path(gApp)
304 : object_path,
305 g_application_get_dbus_object_path(gApp) != NULL
306 ? "/menus/menubar"
307 : "");
308 menubar_object_path = g_strdup_printf("%s", unity_object_path);
309
310 old_menu_model = G_MENU_MODEL(gtk_application_get_menubar(application));
311 if (old_menu_model != NULL)
312 {
313 old_action_group = g_dbus_action_group_get(connection,
314 unique_bus_name,
315 unity_object_path);
316 window_data->old_model = g_object_ref(old_menu_model);
317 g_menu_append_section(window_data->menu_model,
318 NULL,
319 old_menu_model);
320 }
321
322 // Set the actions
323 window_data->action_group =
324 unity_gtk_action_group_new(G_ACTION_GROUP(old_action_group));
325 window_data->action_group_export_id =
326 g_dbus_connection_export_action_group(connection,
327 unity_object_path,
328 G_ACTION_GROUP(
329 window_data->action_group),
330 NULL);
331
332 // Set the menubar
333 gtk_application_set_menubar(GTK_APPLICATION(application),
334 G_MENU_MODEL(window_data->menu_model));
335
336 g_free(unity_object_path);
337 }
338 else
339 {
340 GdkWindow *gdk_win;
341 const char *app_menu_path = NULL;
342
343 window_data->window_id = window_id++;
344
345 connection = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
346 unique_bus_name =
347 g_strdup_printf("%s", g_dbus_connection_get_unique_name(connection));
348 gdk_win = gtk_widget_get_window(GTK_WIDGET(window));
349 application = gtk_window_get_application(window);
350
351 old_menu_model = G_MENU_MODEL(window_data->menu_model);
352
353 window_data->action_group =
354 unity_gtk_action_group_new(G_ACTION_GROUP(old_action_group));
355
356 if (GTK_IS_APPLICATION(application))
357 {
358 gApp = G_APPLICATION(application);
359 application_id =
360 g_strdup_printf("%s", g_application_get_application_id(gApp));
361 object_path =
362 g_strdup_printf("%s/menus/menubar/%d",
363 g_application_get_dbus_object_path(gApp),
364 window_data->window_id);
365 application_object_path =
366 g_strdup_printf("%s", g_application_get_dbus_object_path(gApp));
367 menubar_object_path = g_strdup_printf("%s/window/%d",
368 object_path,
369 window_data->window_id);
370 }
371 else
372 {
373 application_id = g_strdup_printf("%s",
374 g_get_prgname() != NULL
375 ? g_get_prgname()
376 : gdk_get_program_class());
377 object_path = g_strdup_printf("%s/menus/menubar/%d",
378 OBJECT_PATH,
379 window_data->window_id);
380 application_object_path = g_strdup_printf("%s", OBJECT_PATH);
381 menubar_object_path = g_strdup_printf("%s/window/%d",
382 object_path,
383 window_data->window_id);
384 }
385
386 window_data->menu_model_export_id =
387 g_dbus_connection_export_menu_model(connection,
388 object_path,
389 G_MENU_MODEL(
390 window_data->menu_model),
391 NULL);
392 window_data->action_group_export_id =
393 g_dbus_connection_export_action_group(connection,
394 object_path,
395 G_ACTION_GROUP(
396 window_data->action_group),
397 NULL);
398
399 gdk_wayland_window_set_dbus_properties_libgtk_only(gdk_win,
400 application_id,
401 app_menu_path,
402 object_path,
403 menubar_object_path,
404 application_object_path,
405 unique_bus_name);
406 }
407 g_free(unique_bus_name);
408 g_free(object_path);
409 g_free(menubar_object_path);
410 g_free(application_id);
411 g_free(application_object_path);
412 g_object_set_qdata_full(G_OBJECT(window),
413 window_data_quark(),
414 window_data,
415 window_data_free);
416 }
417 return window_data;
418 }
419 #endif
420