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
gtk_application_wayland_inhibitor_free(GtkApplicationWaylandInhibitor * inhibitor)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 
G_DEFINE_TYPE(GtkApplicationImplWayland,gtk_application_impl_wayland,GTK_TYPE_APPLICATION_IMPL_DBUS)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 (GTK_NATIVE (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 (GDK_TOPLEVEL (gdk_surface),
88                                             dbus->application_id,
89                                             dbus->app_menu_path,
90                                             dbus->menubar_path,
91                                             window_path,
92                                             dbus->object_path,
93                                             dbus->unique_name);
94 
95   g_free (window_path);
96 
97   impl_class->handle_window_realize (impl, window);
98 }
99 
100 static void
gtk_application_impl_wayland_before_emit(GtkApplicationImpl * impl,GVariant * platform_data)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 (platform_data, "desktop-startup-id", "&s", &startup_notification_id);
107 
108   gdk_wayland_display_set_startup_notification_id (gdk_display_get_default (), startup_notification_id);
109 }
110 
111 static guint
gtk_application_impl_wayland_inhibit(GtkApplicationImpl * impl,GtkWindow * window,GtkApplicationInhibitFlags flags,const char * reason)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 (wayland->inhibitors, inhibitor);
129 
130   if (flags & GTK_APPLICATION_INHIBIT_IDLE)
131     {
132       surface = gtk_native_get_surface (GTK_NATIVE (window));
133       if (GDK_IS_WAYLAND_TOPLEVEL (surface))
134         {
135           success = gdk_wayland_toplevel_inhibit_idle (GDK_TOPLEVEL (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
gtk_application_impl_wayland_uninhibit(GtkApplicationImpl * impl,guint cookie)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 (GDK_TOPLEVEL (inhibitor->surface));
166           gtk_application_wayland_inhibitor_free (inhibitor);
167           wayland->inhibitors = g_slist_delete_link (wayland->inhibitors, iter);
168           return;
169         }
170     }
171 
172   g_warning ("Invalid inhibitor cookie");
173 }
174 
175 static void
gtk_application_impl_wayland_init(GtkApplicationImplWayland * wayland)176 gtk_application_impl_wayland_init (GtkApplicationImplWayland *wayland)
177 {
178 }
179 
180 static void
gtk_application_impl_wayland_class_init(GtkApplicationImplWaylandClass * class)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