1 /* Unique - Single Instance Backendlication library
2 * uniquebackend.c: Base class for IPC transports
3 *
4 * Copyright (C) 2007 Emmanuele Bassi <ebassi@o-hand.com>
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.1 of the License, 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, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * 02110-1301 USA
20 */
21
22 /**
23 * SECTION:unique-backend
24 * @short_description: Backend abstraction
25 *
26 * #UniqueBackend is the base, abstract class implemented by the different
27 * IPC mechanisms used by Unique. Each #UniqueApp instance creates a
28 * #UniqueBackend to request the name or to send messages.
29 */
30
31 #include <config.h>
32
33 #include <stdlib.h>
34 #include <string.h>
35 #include <errno.h>
36 #include <time.h>
37
38 #include <glib/gi18n.h>
39
40 #include <gdk/gdk.h>
41 #ifdef GDK_WINDOWING_X11
42 #include <gdk/gdkx.h>
43 #include <X11/Xatom.h>
44 #endif
45
46 #include "uniquebackend.h"
47 #include "uniqueinternals.h"
48
49 G_DEFINE_ABSTRACT_TYPE (UniqueBackend, unique_backend, G_TYPE_OBJECT);
50
51 static void
unique_backend_finalize(GObject * gobject)52 unique_backend_finalize (GObject *gobject)
53 {
54 UniqueBackend *backend = UNIQUE_BACKEND (gobject);
55
56 g_free (backend->name);
57 g_free (backend->startup_id);
58
59 G_OBJECT_CLASS (unique_backend_parent_class)->finalize (gobject);
60 }
61
62 static void
unique_backend_class_init(UniqueBackendClass * klass)63 unique_backend_class_init (UniqueBackendClass *klass)
64 {
65 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
66
67 gobject_class->finalize = unique_backend_finalize;
68 }
69
70 static void
unique_backend_init(UniqueBackend * backend)71 unique_backend_init (UniqueBackend *backend)
72 {
73 backend->name = NULL;
74 backend->startup_id = NULL;
75 backend->screen = gdk_screen_get_default ();
76 backend->workspace = -1;
77 }
78
79 /**
80 * unique_backend_set_name:
81 * @backend: FIXME
82 * @name: FIXME
83 *
84 * FIXME
85 */
86 void
unique_backend_set_name(UniqueBackend * backend,const gchar * name)87 unique_backend_set_name (UniqueBackend *backend,
88 const gchar *name)
89 {
90 g_return_if_fail (UNIQUE_IS_BACKEND (backend));
91 g_return_if_fail (name != NULL);
92
93 if (!backend->name)
94 {
95 backend->name = g_strdup (name);
96 return;
97 }
98
99 if (strcmp (backend->name, name) != 0)
100 {
101 g_free (backend->name);
102 backend->name = g_strdup (name);
103 }
104 }
105
106 /**
107 * unique_backend_get_name:
108 * @backend: FIXME
109 *
110 * FIXME
111 *
112 * Return value: FIXME
113 */
114 const gchar *
unique_backend_get_name(UniqueBackend * backend)115 unique_backend_get_name (UniqueBackend *backend)
116 {
117 g_return_val_if_fail (UNIQUE_IS_BACKEND (backend), NULL);
118
119 return backend->name;
120 }
121
122 /**
123 * unique_backend_set_startup_id:
124 * @backend: FIXME
125 * @startup_id: FIXME
126 *
127 * FIXME
128 */
129 void
unique_backend_set_startup_id(UniqueBackend * backend,const gchar * startup_id)130 unique_backend_set_startup_id (UniqueBackend *backend,
131 const gchar *startup_id)
132 {
133 g_return_if_fail (UNIQUE_IS_BACKEND (backend));
134 g_return_if_fail (startup_id != NULL);
135
136 if (!backend->startup_id)
137 {
138 backend->startup_id = g_strdup (startup_id);
139 return;
140 }
141
142 if (strcmp (backend->startup_id, startup_id) != 0)
143 {
144 g_free (backend->startup_id);
145 backend->startup_id = g_strdup (startup_id);
146 }
147 }
148
149 /**
150 * unique_backend_get_startup_id:
151 * @backend: FIXME
152 *
153 * FIXME
154 *
155 * Return value: FIXME
156 */
157 const gchar *
unique_backend_get_startup_id(UniqueBackend * backend)158 unique_backend_get_startup_id (UniqueBackend *backend)
159 {
160 g_return_val_if_fail (UNIQUE_IS_BACKEND (backend), NULL);
161
162 return backend->startup_id;
163 }
164
165 /**
166 * unique_backend_set_screen:
167 * @backend: FIXME
168 * @screen: FIXME
169 *
170 * FIXME
171 */
172 void
unique_backend_set_screen(UniqueBackend * backend,GdkScreen * screen)173 unique_backend_set_screen (UniqueBackend *backend,
174 GdkScreen *screen)
175 {
176 g_return_if_fail (UNIQUE_IS_BACKEND (backend));
177 g_return_if_fail (screen == NULL || GDK_IS_SCREEN (screen));
178
179 if (!screen)
180 screen = gdk_screen_get_default ();
181
182 backend->screen = screen;
183 }
184
185 /**
186 * unique_backend_get_screen:
187 * @backend: FIXME
188 *
189 * FIXME
190 *
191 * Return value: FIXME
192 */
193 GdkScreen *
unique_backend_get_screen(UniqueBackend * backend)194 unique_backend_get_screen (UniqueBackend *backend)
195 {
196 g_return_val_if_fail (UNIQUE_IS_BACKEND (backend), NULL);
197
198 return backend->screen;
199 }
200
201 /**
202 * unique_backend_get_workspace:
203 * @backend: a #UniqueBackend
204 *
205 * Retrieves the current workspace.
206 *
207 * Return value: a workspace number
208 */
209 guint
unique_backend_get_workspace(UniqueBackend * backend)210 unique_backend_get_workspace (UniqueBackend *backend)
211 {
212 GdkDisplay *display;
213 GdkWindow *root_win;
214 #ifdef GDK_WINDOWING_X11
215 Atom _net_current_desktop, type;
216 int format;
217 unsigned long n_items, bytes_after;
218 unsigned char *data_return = 0;
219 #endif
220
221 g_return_val_if_fail (UNIQUE_IS_BACKEND (backend), 0);
222
223 if (backend->workspace != -1)
224 return backend->workspace;
225
226 display = gdk_screen_get_display (backend->screen);
227 root_win = gdk_screen_get_root_window (backend->screen);
228
229 #ifdef GDK_WINDOWING_X11
230 _net_current_desktop =
231 gdk_x11_get_xatom_by_name_for_display (display, "_NET_CURRENT_DESKTOP");
232
233 XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
234 GDK_WINDOW_XID (root_win),
235 _net_current_desktop,
236 0, G_MAXLONG,
237 False, XA_CARDINAL,
238 &type, &format, &n_items, &bytes_after,
239 &data_return);
240
241 if (type == XA_CARDINAL && format == 32 && n_items > 0)
242 {
243 backend->workspace = (guint) data_return[0];
244 XFree (data_return);
245 }
246 #endif
247
248 return backend->workspace;
249 }
250
251 /**
252 * unique_backend_request_name:
253 * @backend: a #UniqueBackend
254 *
255 * Requests the name set using unique_backend_set_name() using @backend.
256 *
257 * Return value: %TRUE if the name was assigned to us, %FALSE if there
258 * already is a registered name
259 */
260 gboolean
unique_backend_request_name(UniqueBackend * backend)261 unique_backend_request_name (UniqueBackend *backend)
262 {
263 g_return_val_if_fail (UNIQUE_IS_BACKEND (backend), FALSE);
264
265 return UNIQUE_BACKEND_GET_CLASS (backend)->request_name (backend);
266 }
267
268 /**
269 * unique_backend_send_message:
270 * @backend: a #UniqueBackend
271 * @command_id: command to send
272 * @message_data: message to send, or %NULL
273 * @time_: time of the command emission, or 0 for the current time
274 *
275 * Sends @command_id, and optionally @message_data, to a running instance
276 * using @backend.
277 *
278 * Return value: a #UniqueResponse value sent by the running instance
279 */
280 UniqueResponse
unique_backend_send_message(UniqueBackend * backend,gint command_id,UniqueMessageData * message_data,guint time_)281 unique_backend_send_message (UniqueBackend *backend,
282 gint command_id,
283 UniqueMessageData *message_data,
284 guint time_)
285 {
286 g_return_val_if_fail (UNIQUE_IS_BACKEND (backend), UNIQUE_RESPONSE_INVALID);
287 g_return_val_if_fail (command_id != 0, UNIQUE_RESPONSE_INVALID);
288
289 if (time_ == 0)
290 time_ = (guint) time (NULL);
291
292 return UNIQUE_BACKEND_GET_CLASS (backend)->send_message (backend, command_id,
293 message_data,
294 time_);
295 }
296
297 #include "bacon/uniquebackend-bacon.h"
298 #ifdef HAVE_DBUS
299 #include "dbus/uniquebackend-dbus.h"
300 #endif
301
302 /**
303 * unique_backend_create:
304 *
305 * Creates a #UniqueBackend using the default backend defined at
306 * compile time. You can override the default backend by setting the
307 * <literal>UNIQUE_BACKEND</literal> environment variable with the
308 * name of the desired backend.
309 *
310 * Return value: the newly created #UniqueBackend instance
311 */
312 UniqueBackend *
unique_backend_create(void)313 unique_backend_create (void)
314 {
315 const gchar *backend_name;
316 GType backend_gtype = G_TYPE_INVALID;
317
318 backend_name = g_getenv ("UNIQUE_BACKEND");
319 if (!backend_name)
320 backend_name = UNIQUE_DEFAULT_BACKEND_S;
321
322 if (backend_name && backend_name[0] != '\0')
323 {
324 #ifdef HAVE_BACON
325 if (strcmp (backend_name, "bacon") == 0)
326 backend_gtype = unique_backend_bacon_get_type ();
327 #endif
328 #ifdef HAVE_DBUS
329 if (strcmp (backend_name, "dbus") == 0)
330 backend_gtype = unique_backend_dbus_get_type ();
331 #endif /* HAVE_DBUS */
332 #if !defined(HAVE_BACON) && !defined(HAVE_DBUS)
333 #error Need either bacon or dbus
334 #endif
335 }
336
337 return g_object_new (backend_gtype, NULL);
338 }
339