1 | /* |
2 | * Copyright © 2010 Codethink Limited |
3 | * Copyright © 2013 Canonical Limited |
4 | * Copyright © 2020 Emmanuel Gil Peyrot |
5 | * |
6 | * This library is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU Lesser General Public |
8 | * License as published by the Free Software Foundation; either |
9 | * version 2 of the licence, or (at your option) any later version. |
10 | * |
11 | * This library 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 GNU |
14 | * Lesser General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU Lesser General Public |
17 | * License along with this library. If not, see <http://www.gnu.org/licenses/>. |
18 | * |
19 | * Author: Ryan Lortie <desrt@desrt.ca> |
20 | */ |
21 | |
22 | #include "config.h" |
23 | |
24 | #include "gtkapplicationprivate.h" |
25 | #include "gtknative.h" |
26 | |
27 | #include <gdk/wayland/gdkwayland.h> |
28 | #include <gdk/wayland/gdkdisplay-wayland.h> |
29 | #include <gdk/wayland/gdksurface-wayland.h> |
30 | #include <gdk/wayland/idle-inhibit-unstable-v1-client-protocol.h> |
31 | |
32 | typedef struct |
33 | { |
34 | GtkApplicationImplDBusClass parent_class; |
35 | |
36 | /* stores the dbus version of the overridden methods */ |
37 | guint (*dbus_inhibit) (GtkApplicationImpl *impl, |
38 | GtkWindow *window, |
39 | GtkApplicationInhibitFlags flags, |
40 | const char *reason); |
41 | void (*dbus_uninhibit) (GtkApplicationImpl *impl, |
42 | guint cookie); |
43 | } GtkApplicationImplWaylandClass; |
44 | |
45 | typedef struct |
46 | { |
47 | guint cookie; |
48 | guint dbus_cookie; |
49 | GtkApplicationInhibitFlags flags; |
50 | GdkSurface *surface; |
51 | |
52 | } GtkApplicationWaylandInhibitor; |
53 | |
54 | static void |
55 | gtk_application_wayland_inhibitor_free (GtkApplicationWaylandInhibitor *inhibitor) |
56 | { |
57 | g_slice_free (GtkApplicationWaylandInhibitor, inhibitor); |
58 | } |
59 | |
60 | typedef struct |
61 | { |
62 | GtkApplicationImplDBus dbus; |
63 | GSList *inhibitors; |
64 | guint next_cookie; |
65 | |
66 | } GtkApplicationImplWayland; |
67 | |
68 | G_DEFINE_TYPE (GtkApplicationImplWayland, gtk_application_impl_wayland, GTK_TYPE_APPLICATION_IMPL_DBUS) |
69 | |
70 | static void |
71 | gtk_application_impl_wayland_handle_window_realize (GtkApplicationImpl *impl, |
72 | GtkWindow *window) |
73 | { |
74 | GtkApplicationImplClass *impl_class = |
75 | GTK_APPLICATION_IMPL_CLASS (gtk_application_impl_wayland_parent_class); |
76 | GtkApplicationImplDBus *dbus = (GtkApplicationImplDBus *) impl; |
77 | GdkSurface *gdk_surface; |
78 | char *window_path; |
79 | |
80 | gdk_surface = gtk_native_get_surface (self: GTK_NATIVE (ptr: window)); |
81 | |
82 | if (!GDK_IS_WAYLAND_TOPLEVEL (gdk_surface)) |
83 | return; |
84 | |
85 | window_path = gtk_application_impl_dbus_get_window_path (dbus, window); |
86 | |
87 | gdk_wayland_toplevel_set_dbus_properties (toplevel: GDK_TOPLEVEL (ptr: gdk_surface), |
88 | application_id: dbus->application_id, |
89 | app_menu_path: dbus->app_menu_path, |
90 | menubar_path: dbus->menubar_path, |
91 | window_object_path: window_path, |
92 | application_object_path: dbus->object_path, |
93 | unique_bus_name: dbus->unique_name); |
94 | |
95 | g_free (mem: window_path); |
96 | |
97 | impl_class->handle_window_realize (impl, window); |
98 | } |
99 | |
100 | static void |
101 | gtk_application_impl_wayland_before_emit (GtkApplicationImpl *impl, |
102 | GVariant *platform_data) |
103 | { |
104 | const char *startup_notification_id = NULL; |
105 | |
106 | g_variant_lookup (dictionary: platform_data, key: "desktop-startup-id" , format_string: "&s" , &startup_notification_id); |
107 | |
108 | gdk_wayland_display_set_startup_notification_id (display: gdk_display_get_default (), startup_id: startup_notification_id); |
109 | } |
110 | |
111 | static guint |
112 | gtk_application_impl_wayland_inhibit (GtkApplicationImpl *impl, |
113 | GtkWindow *window, |
114 | GtkApplicationInhibitFlags flags, |
115 | const char *reason) |
116 | { |
117 | GtkApplicationImplWayland *wayland = (GtkApplicationImplWayland *) impl; |
118 | GdkSurface *surface; |
119 | GtkApplicationWaylandInhibitor *inhibitor; |
120 | gboolean success; |
121 | |
122 | if (!flags) |
123 | return 0; |
124 | |
125 | inhibitor = g_slice_new0 (GtkApplicationWaylandInhibitor); |
126 | inhibitor->cookie = ++wayland->next_cookie; |
127 | inhibitor->flags = flags; |
128 | wayland->inhibitors = g_slist_prepend (list: wayland->inhibitors, data: inhibitor); |
129 | |
130 | if (flags & GTK_APPLICATION_INHIBIT_IDLE) |
131 | { |
132 | surface = gtk_native_get_surface (self: GTK_NATIVE (ptr: window)); |
133 | if (GDK_IS_WAYLAND_TOPLEVEL (surface)) |
134 | { |
135 | success = gdk_wayland_toplevel_inhibit_idle (toplevel: GDK_TOPLEVEL (ptr: surface)); |
136 | if (success) |
137 | { |
138 | flags &= ~GTK_APPLICATION_INHIBIT_IDLE; |
139 | inhibitor->surface = surface; |
140 | } |
141 | } |
142 | } |
143 | |
144 | inhibitor->dbus_cookie = ((GtkApplicationImplWaylandClass *) G_OBJECT_GET_CLASS (wayland))->dbus_inhibit (impl, window, flags, reason); |
145 | |
146 | return inhibitor->cookie; |
147 | } |
148 | |
149 | static void |
150 | gtk_application_impl_wayland_uninhibit (GtkApplicationImpl *impl, |
151 | guint cookie) |
152 | { |
153 | GtkApplicationImplWayland *wayland = (GtkApplicationImplWayland *) impl; |
154 | GSList *iter; |
155 | |
156 | for (iter = wayland->inhibitors; iter; iter = iter->next) |
157 | { |
158 | GtkApplicationWaylandInhibitor *inhibitor = iter->data; |
159 | |
160 | if (inhibitor->cookie == cookie) |
161 | { |
162 | if (inhibitor->dbus_cookie) |
163 | ((GtkApplicationImplWaylandClass *) G_OBJECT_GET_CLASS (wayland))->dbus_uninhibit (impl, inhibitor->dbus_cookie); |
164 | if (inhibitor->surface) |
165 | gdk_wayland_toplevel_uninhibit_idle (toplevel: GDK_TOPLEVEL (ptr: inhibitor->surface)); |
166 | gtk_application_wayland_inhibitor_free (inhibitor); |
167 | wayland->inhibitors = g_slist_delete_link (list: wayland->inhibitors, link_: iter); |
168 | return; |
169 | } |
170 | } |
171 | |
172 | g_warning ("Invalid inhibitor cookie" ); |
173 | } |
174 | |
175 | static void |
176 | gtk_application_impl_wayland_init (GtkApplicationImplWayland *wayland) |
177 | { |
178 | } |
179 | |
180 | static void |
181 | gtk_application_impl_wayland_class_init (GtkApplicationImplWaylandClass *class) |
182 | { |
183 | GtkApplicationImplClass *impl_class = GTK_APPLICATION_IMPL_CLASS (class); |
184 | |
185 | class->dbus_inhibit = impl_class->inhibit; |
186 | class->dbus_uninhibit = impl_class->uninhibit; |
187 | |
188 | impl_class->handle_window_realize = |
189 | gtk_application_impl_wayland_handle_window_realize; |
190 | impl_class->before_emit = |
191 | gtk_application_impl_wayland_before_emit; |
192 | impl_class->inhibit = |
193 | gtk_application_impl_wayland_inhibit; |
194 | impl_class->uninhibit = |
195 | gtk_application_impl_wayland_uninhibit; |
196 | } |
197 | |