1 | /* GDK - The GIMP Drawing Kit |
2 | * Copyright (C) 2000 Red Hat, Inc. |
3 | * |
4 | * This library is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Lesser General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2 of the License, or (at your option) any later version. |
8 | * |
9 | * This library is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * Lesser General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU Lesser General Public |
15 | * License along with this library. If not, see <http://www.gnu.org/licenses/>. |
16 | */ |
17 | |
18 | /* |
19 | * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS |
20 | * file for a list of people on the GTK+ Team. See the ChangeLog |
21 | * files for a list of changes. These files are distributed with |
22 | * GTK+ at ftp://ftp.gtk.org/pub/gtk/. |
23 | */ |
24 | |
25 | #include "config.h" |
26 | |
27 | #include "gdkconfig.h" |
28 | #include "gdkdisplaymanagerprivate.h" |
29 | #include "gdkdisplayprivate.h" |
30 | #include "gdkinternals.h" |
31 | #include "gdkkeysprivate.h" |
32 | #include "gdkmarshalers.h" |
33 | #include "gdkintl.h" |
34 | |
35 | #ifdef GDK_WINDOWING_X11 |
36 | #include "x11/gdkx.h" |
37 | #include "x11/gdkprivate-x11.h" |
38 | #endif |
39 | |
40 | #ifdef GDK_WINDOWING_QUARTZ |
41 | /* When the gdk_quartz_display_open function is removed We can |
42 | * immediately include gdkquartzdisplaymanager.h here instead of |
43 | * gdkprivate-quartz.h so that we won’t have to enable -xobjective-c |
44 | * for the “generic” GDK source code. |
45 | * #include "quartz/gdkquartzdisplaymanager.h" |
46 | */ |
47 | #include "quartz/gdkprivate-quartz.h" |
48 | #endif |
49 | |
50 | #ifdef GDK_WINDOWING_BROADWAY |
51 | #include "broadway/gdkprivate-broadway.h" |
52 | #endif |
53 | |
54 | #ifdef GDK_WINDOWING_WIN32 |
55 | #include "win32/gdkwin32.h" |
56 | #include "win32/gdkprivate-win32.h" |
57 | #endif |
58 | |
59 | #ifdef GDK_WINDOWING_WAYLAND |
60 | #include "wayland/gdkprivate-wayland.h" |
61 | #endif |
62 | |
63 | #ifdef GDK_WINDOWING_MIR |
64 | #include "mir/gdkmir-private.h" |
65 | #endif |
66 | |
67 | /** |
68 | * SECTION:gdkdisplaymanager |
69 | * @Short_description: Maintains a list of all open GdkDisplays |
70 | * @Title: GdkDisplayManager |
71 | * |
72 | * The purpose of the #GdkDisplayManager singleton object is to offer |
73 | * notification when displays appear or disappear or the default display |
74 | * changes. |
75 | * |
76 | * You can use gdk_display_manager_get() to obtain the #GdkDisplayManager |
77 | * singleton, but that should be rarely necessary. Typically, initializing |
78 | * GTK+ opens a display that you can work with without ever accessing the |
79 | * #GdkDisplayManager. |
80 | * |
81 | * The GDK library can be built with support for multiple backends. |
82 | * The #GdkDisplayManager object determines which backend is used |
83 | * at runtime. |
84 | * |
85 | * When writing backend-specific code that is supposed to work with |
86 | * multiple GDK backends, you have to consider both compile time and |
87 | * runtime. At compile time, use the #GDK_WINDOWING_X11, #GDK_WINDOWING_WIN32 |
88 | * macros, etc. to find out which backends are present in the GDK library |
89 | * you are building your application against. At runtime, use type-check |
90 | * macros like GDK_IS_X11_DISPLAY() to find out which backend is in use: |
91 | * |
92 | * ## Backend-specific code ## {#backend-specific} |
93 | * |
94 | * |[<!-- language="C" --> |
95 | * #ifdef GDK_WINDOWING_X11 |
96 | * if (GDK_IS_X11_DISPLAY (display)) |
97 | * { |
98 | * // make X11-specific calls here |
99 | * } |
100 | * else |
101 | * #endif |
102 | * #ifdef GDK_WINDOWING_QUARTZ |
103 | * if (GDK_IS_QUARTZ_DISPLAY (display)) |
104 | * { |
105 | * // make Quartz-specific calls here |
106 | * } |
107 | * else |
108 | * #endif |
109 | * g_error ("Unsupported GDK backend"); |
110 | * ]| |
111 | */ |
112 | |
113 | |
114 | enum { |
115 | PROP_0, |
116 | PROP_DEFAULT_DISPLAY |
117 | }; |
118 | |
119 | enum { |
120 | DISPLAY_OPENED, |
121 | LAST_SIGNAL |
122 | }; |
123 | |
124 | static void gdk_display_manager_class_init (GdkDisplayManagerClass *klass); |
125 | static void gdk_display_manager_set_property (GObject *object, |
126 | guint prop_id, |
127 | const GValue *value, |
128 | GParamSpec *pspec); |
129 | static void gdk_display_manager_get_property (GObject *object, |
130 | guint prop_id, |
131 | GValue *value, |
132 | GParamSpec *pspec); |
133 | |
134 | static guint signals[LAST_SIGNAL] = { 0 }; |
135 | |
136 | G_DEFINE_TYPE (GdkDisplayManager, gdk_display_manager, G_TYPE_OBJECT) |
137 | |
138 | static void |
139 | gdk_display_manager_class_init (GdkDisplayManagerClass *klass) |
140 | { |
141 | GObjectClass *object_class = G_OBJECT_CLASS (klass); |
142 | |
143 | object_class->set_property = gdk_display_manager_set_property; |
144 | object_class->get_property = gdk_display_manager_get_property; |
145 | |
146 | /** |
147 | * GdkDisplayManager::display-opened: |
148 | * @manager: the object on which the signal is emitted |
149 | * @display: the opened display |
150 | * |
151 | * The ::display-opened signal is emitted when a display is opened. |
152 | * |
153 | * Since: 2.2 |
154 | */ |
155 | signals[DISPLAY_OPENED] = |
156 | g_signal_new (g_intern_static_string ("display-opened" ), |
157 | G_OBJECT_CLASS_TYPE (object_class), |
158 | G_SIGNAL_RUN_LAST, |
159 | G_STRUCT_OFFSET (GdkDisplayManagerClass, display_opened), |
160 | NULL, NULL, |
161 | _gdk_marshal_VOID__OBJECT, |
162 | G_TYPE_NONE, |
163 | 1, |
164 | GDK_TYPE_DISPLAY); |
165 | |
166 | g_object_class_install_property (object_class, |
167 | PROP_DEFAULT_DISPLAY, |
168 | g_param_spec_object ("default-display" , |
169 | P_("Default Display" ), |
170 | P_("The default display for GDK" ), |
171 | GDK_TYPE_DISPLAY, |
172 | G_PARAM_READWRITE|G_PARAM_STATIC_NAME| |
173 | G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB)); |
174 | } |
175 | |
176 | static void |
177 | gdk_display_manager_init (GdkDisplayManager *manager) |
178 | { |
179 | } |
180 | |
181 | static void |
182 | gdk_display_manager_set_property (GObject *object, |
183 | guint prop_id, |
184 | const GValue *value, |
185 | GParamSpec *pspec) |
186 | { |
187 | switch (prop_id) |
188 | { |
189 | case PROP_DEFAULT_DISPLAY: |
190 | gdk_display_manager_set_default_display (GDK_DISPLAY_MANAGER (object), |
191 | g_value_get_object (value)); |
192 | break; |
193 | default: |
194 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
195 | break; |
196 | } |
197 | } |
198 | |
199 | static void |
200 | gdk_display_manager_get_property (GObject *object, |
201 | guint prop_id, |
202 | GValue *value, |
203 | GParamSpec *pspec) |
204 | { |
205 | switch (prop_id) |
206 | { |
207 | case PROP_DEFAULT_DISPLAY: |
208 | g_value_set_object (value, |
209 | gdk_display_manager_get_default_display (GDK_DISPLAY_MANAGER (object))); |
210 | break; |
211 | default: |
212 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
213 | break; |
214 | } |
215 | } |
216 | |
217 | static const gchar *allowed_backends; |
218 | |
219 | /** |
220 | * gdk_set_allowed_backends: |
221 | * @backends: a comma-separated list of backends |
222 | * |
223 | * Sets a list of backends that GDK should try to use. |
224 | * |
225 | * This can be be useful if your application does not |
226 | * work with certain GDK backends. |
227 | * |
228 | * By default, GDK tries all included backends. |
229 | * |
230 | * For example, |
231 | * |[<!-- language="C" --> |
232 | * gdk_set_allowed_backends ("wayland,quartz,*"); |
233 | * ]| |
234 | * instructs GDK to try the Wayland backend first, |
235 | * followed by the Quartz backend, and then all |
236 | * others. |
237 | * |
238 | * If the `GDK_BACKEND` environment variable |
239 | * is set, it determines what backends are tried in what |
240 | * order, while still respecting the set of allowed backends |
241 | * that are specified by this function. |
242 | * |
243 | * The possible backend names are x11, win32, quartz, |
244 | * broadway, wayland. You can also include a * in the |
245 | * list to try all remaining backends. |
246 | * |
247 | * This call must happen prior to gdk_display_open(), |
248 | * gtk_init(), gtk_init_with_args() or gtk_init_check() |
249 | * in order to take effect. |
250 | * |
251 | * Since: 3.10 |
252 | */ |
253 | void |
254 | gdk_set_allowed_backends (const gchar *backends) |
255 | { |
256 | allowed_backends = g_strdup (backends); |
257 | } |
258 | |
259 | typedef struct _GdkBackend GdkBackend; |
260 | |
261 | struct _GdkBackend { |
262 | const char *name; |
263 | GdkDisplay * (* open_display) (const char *name); |
264 | }; |
265 | |
266 | static GdkBackend gdk_backends[] = { |
267 | #ifdef GDK_WINDOWING_QUARTZ |
268 | { "quartz" , _gdk_quartz_display_open }, |
269 | #endif |
270 | #ifdef GDK_WINDOWING_WIN32 |
271 | { "win32" , _gdk_win32_display_open }, |
272 | #endif |
273 | #ifdef GDK_WINDOWING_WAYLAND |
274 | { "wayland" , _gdk_wayland_display_open }, |
275 | #endif |
276 | #ifdef GDK_WINDOWING_X11 |
277 | { "x11" , _gdk_x11_display_open }, |
278 | #endif |
279 | #ifdef GDK_WINDOWING_MIR |
280 | { "mir" , _gdk_mir_display_open }, |
281 | #endif |
282 | #ifdef GDK_WINDOWING_BROADWAY |
283 | { "broadway" , _gdk_broadway_display_open }, |
284 | #endif |
285 | /* NULL-terminating this array so we can use commas above */ |
286 | { NULL, NULL } |
287 | }; |
288 | |
289 | /** |
290 | * gdk_display_manager_get: |
291 | * |
292 | * Gets the singleton #GdkDisplayManager object. |
293 | * |
294 | * When called for the first time, this function consults the |
295 | * `GDK_BACKEND` environment variable to find out which |
296 | * of the supported GDK backends to use (in case GDK has been compiled |
297 | * with multiple backends). Applications can use gdk_set_allowed_backends() |
298 | * to limit what backends can be used. |
299 | * |
300 | * Returns: (transfer none): The global #GdkDisplayManager singleton; |
301 | * gdk_parse_args(), gdk_init(), or gdk_init_check() must have |
302 | * been called first. |
303 | * |
304 | * Since: 2.2 |
305 | **/ |
306 | GdkDisplayManager* |
307 | gdk_display_manager_get (void) |
308 | { |
309 | static GdkDisplayManager *manager = NULL; |
310 | |
311 | if (manager == NULL) |
312 | manager = g_object_new (GDK_TYPE_DISPLAY_MANAGER, NULL); |
313 | |
314 | return manager; |
315 | } |
316 | |
317 | /** |
318 | * gdk_display_manager_get_default_display: |
319 | * @manager: a #GdkDisplayManager |
320 | * |
321 | * Gets the default #GdkDisplay. |
322 | * |
323 | * Returns: (nullable) (transfer none): a #GdkDisplay, or %NULL if |
324 | * there is no default display. |
325 | * |
326 | * Since: 2.2 |
327 | */ |
328 | GdkDisplay * |
329 | gdk_display_manager_get_default_display (GdkDisplayManager *manager) |
330 | { |
331 | return manager->default_display; |
332 | } |
333 | |
334 | /** |
335 | * gdk_display_get_default: |
336 | * |
337 | * Gets the default #GdkDisplay. This is a convenience |
338 | * function for: |
339 | * `gdk_display_manager_get_default_display (gdk_display_manager_get ())`. |
340 | * |
341 | * Returns: (nullable) (transfer none): a #GdkDisplay, or %NULL if |
342 | * there is no default display. |
343 | * |
344 | * Since: 2.2 |
345 | */ |
346 | GdkDisplay * |
347 | gdk_display_get_default (void) |
348 | { |
349 | return gdk_display_manager_get_default_display (gdk_display_manager_get ()); |
350 | } |
351 | |
352 | /** |
353 | * gdk_screen_get_default: |
354 | * |
355 | * Gets the default screen for the default display. (See |
356 | * gdk_display_get_default ()). |
357 | * |
358 | * Returns: (nullable) (transfer none): a #GdkScreen, or %NULL if |
359 | * there is no default display. |
360 | * |
361 | * Since: 2.2 |
362 | */ |
363 | GdkScreen * |
364 | gdk_screen_get_default (void) |
365 | { |
366 | GdkDisplay *display; |
367 | |
368 | display = gdk_display_get_default (); |
369 | |
370 | if (display) |
371 | return GDK_DISPLAY_GET_CLASS (display)->get_default_screen (display); |
372 | else |
373 | return NULL; |
374 | } |
375 | |
376 | /** |
377 | * gdk_display_manager_set_default_display: |
378 | * @manager: a #GdkDisplayManager |
379 | * @display: a #GdkDisplay |
380 | * |
381 | * Sets @display as the default display. |
382 | * |
383 | * Since: 2.2 |
384 | **/ |
385 | void |
386 | gdk_display_manager_set_default_display (GdkDisplayManager *manager, |
387 | GdkDisplay *display) |
388 | { |
389 | manager->default_display = display; |
390 | |
391 | if (display) |
392 | GDK_DISPLAY_GET_CLASS (display)->make_default (display); |
393 | |
394 | g_object_notify (G_OBJECT (manager), "default-display" ); |
395 | } |
396 | |
397 | /** |
398 | * gdk_display_manager_list_displays: |
399 | * @manager: a #GdkDisplayManager |
400 | * |
401 | * List all currently open displays. |
402 | * |
403 | * Returns: (transfer container) (element-type GdkDisplay): a newly |
404 | * allocated #GSList of #GdkDisplay objects. Free with g_slist_free() |
405 | * when you are done with it. |
406 | * |
407 | * Since: 2.2 |
408 | **/ |
409 | GSList * |
410 | gdk_display_manager_list_displays (GdkDisplayManager *manager) |
411 | { |
412 | return g_slist_copy (manager->displays); |
413 | } |
414 | |
415 | /** |
416 | * gdk_display_manager_open_display: |
417 | * @manager: a #GdkDisplayManager |
418 | * @name: the name of the display to open |
419 | * |
420 | * Opens a display. |
421 | * |
422 | * Returns: (nullable) (transfer none): a #GdkDisplay, or %NULL if the |
423 | * display could not be opened |
424 | * |
425 | * Since: 3.0 |
426 | */ |
427 | GdkDisplay * |
428 | gdk_display_manager_open_display (GdkDisplayManager *manager, |
429 | const gchar *name) |
430 | { |
431 | const gchar *backend_list; |
432 | GdkDisplay *display; |
433 | gchar **backends; |
434 | gint i, j; |
435 | gboolean allow_any; |
436 | |
437 | if (allowed_backends == NULL) |
438 | allowed_backends = "*" ; |
439 | allow_any = strstr (allowed_backends, "*" ) != NULL; |
440 | |
441 | backend_list = g_getenv ("GDK_BACKEND" ); |
442 | if (backend_list == NULL) |
443 | backend_list = allowed_backends; |
444 | else if (g_strcmp0 (backend_list, "help" ) == 0) |
445 | { |
446 | fprintf (stderr, "Supported GDK backends:" ); |
447 | for (i = 0; gdk_backends[i].name != NULL; i++) |
448 | fprintf (stderr, " %s" , gdk_backends[i].name); |
449 | fprintf (stderr, "\n" ); |
450 | |
451 | backend_list = allowed_backends; |
452 | } |
453 | backends = g_strsplit (backend_list, "," , 0); |
454 | |
455 | display = NULL; |
456 | |
457 | for (i = 0; display == NULL && backends[i] != NULL; i++) |
458 | { |
459 | const gchar *backend = backends[i]; |
460 | gboolean any = g_str_equal (backend, "*" ); |
461 | |
462 | if (!allow_any && !any && !strstr (allowed_backends, backend)) |
463 | continue; |
464 | |
465 | for (j = 0; gdk_backends[j].name != NULL; j++) |
466 | { |
467 | if ((any && allow_any) || |
468 | (any && strstr (allowed_backends, gdk_backends[j].name)) || |
469 | g_str_equal (backend, gdk_backends[j].name)) |
470 | { |
471 | GDK_NOTE (MISC, g_message ("Trying %s backend" , gdk_backends[j].name)); |
472 | display = gdk_backends[j].open_display (name); |
473 | if (display) |
474 | break; |
475 | } |
476 | } |
477 | } |
478 | |
479 | g_strfreev (backends); |
480 | |
481 | return display; |
482 | } |
483 | |
484 | void |
485 | _gdk_display_manager_add_display (GdkDisplayManager *manager, |
486 | GdkDisplay *display) |
487 | { |
488 | if (manager->displays == NULL) |
489 | gdk_display_manager_set_default_display (manager, display); |
490 | |
491 | manager->displays = g_slist_prepend (manager->displays, display); |
492 | |
493 | g_signal_emit (manager, signals[DISPLAY_OPENED], 0, display); |
494 | } |
495 | |
496 | /* NB: This function can be called multiple times per display. */ |
497 | void |
498 | _gdk_display_manager_remove_display (GdkDisplayManager *manager, |
499 | GdkDisplay *display) |
500 | { |
501 | manager->displays = g_slist_remove (manager->displays, display); |
502 | |
503 | if (manager->default_display == display) |
504 | { |
505 | if (manager->displays) |
506 | gdk_display_manager_set_default_display (manager, manager->displays->data); |
507 | else |
508 | gdk_display_manager_set_default_display (manager, NULL); |
509 | } |
510 | } |
511 | |