1 /* gdkapplaunchcontext.c - Gtk+ implementation for GAppLaunchContext
2 
3    Copyright (C) 2007 Red Hat, Inc.
4 
5    The Gnome Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9 
10    The Gnome Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14 
15    You should have received a copy of the GNU Library General Public
16    License along with this library. If not, see <http://www.gnu.org/licenses/>.
17 
18    Author: Alexander Larsson <alexl@redhat.com>
19 */
20 
21 #include "config.h"
22 
23 #include "gdkapplaunchcontextprivate.h"
24 #include "gdkdisplay.h"
25 #include "gdkintl.h"
26 
27 
28 /**
29  * GdkAppLaunchContext:
30  *
31  * `GdkAppLaunchContext` handles launching an application in a graphical context.
32  *
33  * It is an implementation of `GAppLaunchContext` that provides startup
34  * notification and allows to launch applications on a specific screen
35  * or workspace.
36  *
37  * ## Launching an application
38  *
39  * ```c
40  * GdkAppLaunchContext *context;
41  *
42  * context = gdk_display_get_app_launch_context (display);
43  *
44  * gdk_app_launch_context_set_display (display);
45  * gdk_app_launch_context_set_timestamp (gdk_event_get_time (event));
46  *
47  * if (!g_app_info_launch_default_for_uri ("http://www.gtk.org", context, &error))
48  *   g_warning ("Launching failed: %s\n", error->message);
49  *
50  * g_object_unref (context);
51  * ```
52  */
53 
54 static void    gdk_app_launch_context_finalize    (GObject           *object);
55 static char * gdk_app_launch_context_get_display_name (GAppLaunchContext *context,
56                                                         GAppInfo          *info,
57                                                         GList             *files);
58 static char * gdk_app_launch_context_get_startup_notify_id (GAppLaunchContext *context,
59                                                              GAppInfo          *info,
60                                                              GList             *files);
61 static void    gdk_app_launch_context_launch_failed (GAppLaunchContext *context,
62                                                      const char        *startup_notify_id);
63 
64 
65 enum
66 {
67   PROP_0,
68   PROP_DISPLAY
69 };
70 
G_DEFINE_TYPE(GdkAppLaunchContext,gdk_app_launch_context,G_TYPE_APP_LAUNCH_CONTEXT)71 G_DEFINE_TYPE (GdkAppLaunchContext, gdk_app_launch_context, G_TYPE_APP_LAUNCH_CONTEXT)
72 
73 static void
74 gdk_app_launch_context_get_property (GObject    *object,
75                                      guint       prop_id,
76                                      GValue     *value,
77                                      GParamSpec *pspec)
78 {
79   GdkAppLaunchContext *context = GDK_APP_LAUNCH_CONTEXT (object);
80 
81   switch (prop_id)
82     {
83     case PROP_DISPLAY:
84       g_value_set_object (value, context->display);
85       break;
86     default:
87       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
88     }
89 }
90 
91 static void
gdk_app_launch_context_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)92 gdk_app_launch_context_set_property (GObject      *object,
93                                      guint         prop_id,
94                                      const GValue *value,
95                                      GParamSpec   *pspec)
96 {
97   GdkAppLaunchContext *context = GDK_APP_LAUNCH_CONTEXT (object);
98 
99   switch (prop_id)
100     {
101     case PROP_DISPLAY:
102       context->display = g_value_dup_object (value);
103       break;
104     default:
105       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
106     }
107 }
108 
109 static void
gdk_app_launch_context_class_init(GdkAppLaunchContextClass * klass)110 gdk_app_launch_context_class_init (GdkAppLaunchContextClass *klass)
111 {
112   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
113   GAppLaunchContextClass *context_class = G_APP_LAUNCH_CONTEXT_CLASS (klass);
114 
115   gobject_class->set_property = gdk_app_launch_context_set_property,
116   gobject_class->get_property = gdk_app_launch_context_get_property;
117 
118   gobject_class->finalize = gdk_app_launch_context_finalize;
119 
120   context_class->get_display = gdk_app_launch_context_get_display_name;
121   context_class->get_startup_notify_id = gdk_app_launch_context_get_startup_notify_id;
122   context_class->launch_failed = gdk_app_launch_context_launch_failed;
123 
124   /**
125    * GdkAppLaunchContext:display: (attributes org.gtk.Property.get=gdk_app_launch_context_get_display)
126    *
127    * The display that the `GdkAppLaunchContext` is on.
128    */
129   g_object_class_install_property (gobject_class, PROP_DISPLAY,
130     g_param_spec_object ("display", P_("Display"), P_("Display"),
131                          GDK_TYPE_DISPLAY,
132                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
133 }
134 
135 static void
gdk_app_launch_context_init(GdkAppLaunchContext * context)136 gdk_app_launch_context_init (GdkAppLaunchContext *context)
137 {
138   context->workspace = -1;
139 }
140 
141 static void
gdk_app_launch_context_finalize(GObject * object)142 gdk_app_launch_context_finalize (GObject *object)
143 {
144   GdkAppLaunchContext *context = GDK_APP_LAUNCH_CONTEXT (object);
145 
146   if (context->display)
147     g_object_unref (context->display);
148 
149   if (context->icon)
150     g_object_unref (context->icon);
151 
152   g_free (context->icon_name);
153 
154   G_OBJECT_CLASS (gdk_app_launch_context_parent_class)->finalize (object);
155 }
156 
157 static char *
gdk_app_launch_context_get_display_name(GAppLaunchContext * context,GAppInfo * info,GList * files)158 gdk_app_launch_context_get_display_name (GAppLaunchContext *context,
159                                          GAppInfo          *info,
160                                          GList             *files)
161 {
162   GdkAppLaunchContext *ctx = GDK_APP_LAUNCH_CONTEXT (context);
163   GdkDisplay *display;
164 
165   if (ctx->display)
166     display = ctx->display;
167   else
168     display = gdk_display_get_default ();
169 
170   return g_strdup (gdk_display_get_name (display));
171 }
172 
173 /**
174  * gdk_app_launch_context_get_display: (attributes org.gtk.Method.get_property=display)
175  * @context: a `GdkAppLaunchContext`
176  *
177  * Gets the `GdkDisplay` that @context is for.
178  *
179  * Returns: (transfer none): the display of @context
180  */
181 GdkDisplay *
gdk_app_launch_context_get_display(GdkAppLaunchContext * context)182 gdk_app_launch_context_get_display (GdkAppLaunchContext *context)
183 {
184   g_return_val_if_fail (GDK_IS_APP_LAUNCH_CONTEXT (context), NULL);
185 
186   return context->display;
187 }
188 
189 /**
190  * gdk_app_launch_context_set_desktop:
191  * @context: a `GdkAppLaunchContext`
192  * @desktop: the number of a workspace, or -1
193  *
194  * Sets the workspace on which applications will be launched.
195  *
196  * This only works when running under a window manager that
197  * supports multiple workspaces, as described in the
198  * [Extended Window Manager Hints](http://www.freedesktop.org/Standards/wm-spec).
199  *
200  * When the workspace is not specified or @desktop is set to -1,
201  * it is up to the window manager to pick one, typically it will
202  * be the current workspace.
203  */
204 void
gdk_app_launch_context_set_desktop(GdkAppLaunchContext * context,int desktop)205 gdk_app_launch_context_set_desktop (GdkAppLaunchContext *context,
206                                     int                  desktop)
207 {
208   g_return_if_fail (GDK_IS_APP_LAUNCH_CONTEXT (context));
209 
210   context->workspace = desktop;
211 }
212 
213 /**
214  * gdk_app_launch_context_set_timestamp:
215  * @context: a `GdkAppLaunchContext`
216  * @timestamp: a timestamp
217  *
218  * Sets the timestamp of @context.
219  *
220  * The timestamp should ideally be taken from the event that
221  * triggered the launch.
222  *
223  * Window managers can use this information to avoid moving the
224  * focus to the newly launched application when the user is busy
225  * typing in another window. This is also known as 'focus stealing
226  * prevention'.
227  */
228 void
gdk_app_launch_context_set_timestamp(GdkAppLaunchContext * context,guint32 timestamp)229 gdk_app_launch_context_set_timestamp (GdkAppLaunchContext *context,
230                                       guint32              timestamp)
231 {
232   g_return_if_fail (GDK_IS_APP_LAUNCH_CONTEXT (context));
233 
234   context->timestamp = timestamp;
235 }
236 
237 /**
238  * gdk_app_launch_context_set_icon:
239  * @context: a `GdkAppLaunchContext`
240  * @icon: (nullable): a `GIcon`
241  *
242  * Sets the icon for applications that are launched with this
243  * context.
244  *
245  * Window Managers can use this information when displaying startup
246  * notification.
247  *
248  * See also [method@Gdk.AppLaunchContext.set_icon_name].
249  */
250 void
gdk_app_launch_context_set_icon(GdkAppLaunchContext * context,GIcon * icon)251 gdk_app_launch_context_set_icon (GdkAppLaunchContext *context,
252                                  GIcon               *icon)
253 {
254   g_return_if_fail (GDK_IS_APP_LAUNCH_CONTEXT (context));
255   g_return_if_fail (icon == NULL || G_IS_ICON (icon));
256 
257   if (context->icon)
258     {
259       g_object_unref (context->icon);
260       context->icon = NULL;
261     }
262 
263   if (icon)
264     context->icon = g_object_ref (icon);
265 }
266 
267 /**
268  * gdk_app_launch_context_set_icon_name:
269  * @context: a `GdkAppLaunchContext`
270  * @icon_name: (nullable): an icon name
271  *
272  * Sets the icon for applications that are launched with this context.
273  *
274  * The @icon_name will be interpreted in the same way as the Icon field
275  * in desktop files. See also [method@Gdk.AppLaunchContext.set_icon].
276  *
277  * If both @icon and @icon_name are set, the @icon_name takes priority.
278  * If neither @icon or @icon_name is set, the icon is taken from either
279  * the file that is passed to launched application or from the `GAppInfo`
280  * for the launched application itself.
281  */
282 void
gdk_app_launch_context_set_icon_name(GdkAppLaunchContext * context,const char * icon_name)283 gdk_app_launch_context_set_icon_name (GdkAppLaunchContext *context,
284                                       const char          *icon_name)
285 {
286   g_return_if_fail (GDK_IS_APP_LAUNCH_CONTEXT (context));
287 
288   g_free (context->icon_name);
289   context->icon_name = g_strdup (icon_name);
290 }
291 
292 static char *
gdk_app_launch_context_get_startup_notify_id(GAppLaunchContext * context,GAppInfo * info,GList * files)293 gdk_app_launch_context_get_startup_notify_id (GAppLaunchContext *context,
294                                               GAppInfo          *info,
295                                               GList             *files)
296 {
297  return NULL;
298 }
299 
300 static void
gdk_app_launch_context_launch_failed(GAppLaunchContext * context,const char * startup_notify_id)301 gdk_app_launch_context_launch_failed (GAppLaunchContext *context,
302                                       const char        *startup_notify_id)
303 {
304 }
305