Bug Summary

File:core/screen.c
Warning:line 1781, column 36
Out of bound memory access (access exceeds upper limit of memory block)

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name screen.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I .. -I ./include -D CROMA_LIBEXECDIR="/usr/libexec" -D HOST_ALIAS="" -D CROMA_LOCALEDIR="/usr/share/locale" -D CROMA_PKGDATADIR="/usr/share/croma" -D CROMA_DATADIR="/usr/share" -D G_LOG_DOMAIN="croma" -D SN_API_NOT_YET_FROZEN=1 -I /usr/include/ctk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -D _REENTRANT -D _REENTRANT -I /usr/include/startup-notification-1.0 -I /usr/include/libgtop-2.0 -D PIC -internal-isystem /usr/lib/llvm-16/lib/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/13/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/src -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-02-14-231308-31150-1 -x c core/screen.c
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3/* Croma X screen handler */
4
5/*
6 * Copyright (C) 2001, 2002 Havoc Pennington
7 * Copyright (C) 2002, 2003 Red Hat Inc.
8 * Some ICCCM manager selection code derived from fvwm2,
9 * Copyright (C) 2001 Dominik Vogt, Matthias Clasen, and fvwm2 team
10 * Copyright (C) 2003 Rob Adams
11 * Copyright (C) 2004-2006 Elijah Newren
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License as
15 * published by the Free Software Foundation; either version 2 of the
16 * License, or (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
26 * 02110-1301, USA.
27 */
28
29#include <config.h>
30#include "screen-private.h"
31#include "util.h"
32#include "errors.h"
33#include "window-private.h"
34#include "frame-private.h"
35#include "prefs.h"
36#include "workspace.h"
37#include "keybindings.h"
38#include "prefs.h"
39#include "stack.h"
40#include "xprops.h"
41#include "compositor.h"
42
43#ifdef HAVE_SOLARIS_XINERAMA
44#include <X11/extensions/xinerama.h>
45#endif
46#ifdef HAVE_XFREE_XINERAMA
47#include <X11/extensions/Xinerama.h>
48#endif
49
50#include <X11/Xatom.h>
51#include <cairo/cairo-xlib.h>
52#include <locale.h>
53#include <string.h>
54#include <stdio.h>
55
56static char* get_screen_name (MetaDisplay *display,
57 int number);
58
59static void update_num_workspaces (MetaScreen *screen,
60 guint32 timestamp);
61static void update_focus_mode (MetaScreen *screen);
62static void set_workspace_names (MetaScreen *screen);
63static void prefs_changed_callback (MetaPreference pref,
64 gpointer data);
65
66static void set_desktop_geometry_hint (MetaScreen *screen);
67static void set_desktop_viewport_hint (MetaScreen *screen);
68
69#ifdef HAVE_STARTUP_NOTIFICATION
70static void meta_screen_sn_event (SnMonitorEvent *event,
71 void *user_data);
72#endif
73
74static int
75set_wm_check_hint (MetaScreen *screen)
76{
77 unsigned long data[1];
78
79 g_return_val_if_fail (screen->display->leader_window != None, 0)do { if ((screen->display->leader_window != 0L)) { } else
{ g_return_if_fail_warning ("croma", ((const char*) (__func__
)), "screen->display->leader_window != None"); return (
0); } } while (0)
;
80
81 data[0] = screen->display->leader_window;
82
83 XChangeProperty (screen->display->xdisplay, screen->xroot,
84 screen->display->atom__NET_SUPPORTING_WM_CHECK,
85 XA_WINDOW((Atom) 33),
86 32, PropModeReplace0, (guchar*) data, 1);
87
88 return Success0;
89}
90
91static void
92unset_wm_check_hint (MetaScreen *screen)
93{
94 XDeleteProperty (screen->display->xdisplay, screen->xroot,
95 screen->display->atom__NET_SUPPORTING_WM_CHECK);
96}
97
98static int
99set_supported_hint (MetaScreen *screen)
100{
101 Atom atoms[] = {
102#define EWMH_ATOMS_ONLY
103#define item(x) screen->display->atom_##x,
104#include "atomnames.h"
105#undef item
106#undef EWMH_ATOMS_ONLY
107 screen->display->atom__CTK_FRAME_EXTENTS,
108 screen->display->atom__CTK_SHOW_WINDOW_MENU,
109 };
110
111 XChangeProperty (screen->display->xdisplay, screen->xroot,
112 screen->display->atom__NET_SUPPORTED,
113 XA_ATOM((Atom) 4),
114 32, PropModeReplace0,
115 (guchar*) atoms, G_N_ELEMENTS(atoms)(sizeof (atoms) / sizeof ((atoms)[0])));
116
117 return Success0;
118}
119
120static int
121set_wm_icon_size_hint (MetaScreen *screen)
122{
123 int icon_size = meta_prefs_get_icon_size();
124#define N_VALS 6
125 gulong vals[N_VALS];
126
127 /* min width, min height, max w, max h, width inc, height inc */
128 vals[0] = icon_size; /* width */
129 vals[1] = icon_size; /* height */
130 vals[2] = icon_size; /* width */
131 vals[3] = icon_size; /* height */
132 vals[4] = 0;
133 vals[5] = 0;
134
135 XChangeProperty (screen->display->xdisplay, screen->xroot,
136 screen->display->atom_WM_ICON_SIZE,
137 XA_CARDINAL((Atom) 6),
138 32, PropModeReplace0, (guchar*) vals, N_VALS);
139
140 return Success0;
141#undef N_VALS
142}
143
144static void
145reload_xinerama_infos (MetaScreen *screen)
146{
147 MetaDisplay *display;
148
149 {
150 GList *tmp;
151
152 tmp = screen->workspaces;
153 while (tmp != NULL((void*)0))
154 {
155 MetaWorkspace *space = tmp->data;
156
157 meta_workspace_invalidate_work_area (space);
158
159 tmp = tmp->next;
160 }
161 }
162
163 display = screen->display;
164
165 if (screen->xinerama_infos)
166 g_free (screen->xinerama_infos);
167
168 screen->xinerama_infos = NULL((void*)0);
169 screen->n_xinerama_infos = 0;
170 screen->last_xinerama_index = 0;
171
172 screen->display->xinerama_cache_invalidated = TRUE(!(0));
173
174#ifdef HAVE_XFREE_XINERAMA
175 if (XineramaIsActive (display->xdisplay))
176 {
177 XineramaScreenInfo *infos;
178 int n_infos;
179
180 n_infos = 0;
181 infos = XineramaQueryScreens (display->xdisplay, &n_infos);
182
183 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
184 "Found %d Xinerama screens on display %s\n",
185 n_infos, display->name);
186
187 if (n_infos > 0)
188 {
189 int i;
190
191 screen->xinerama_infos = g_new (MetaXineramaScreenInfo, n_infos)((MetaXineramaScreenInfo *) g_malloc_n ((n_infos), sizeof (MetaXineramaScreenInfo
)))
;
192 screen->n_xinerama_infos = n_infos;
193
194 i = 0;
195 while (i < n_infos)
196 {
197 screen->xinerama_infos[i].number = infos[i].screen_number;
198 screen->xinerama_infos[i].rect.x = infos[i].x_org;
199 screen->xinerama_infos[i].rect.y = infos[i].y_org;
200 screen->xinerama_infos[i].rect.width = infos[i].width;
201 screen->xinerama_infos[i].rect.height = infos[i].height;
202
203 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
204 "Xinerama %d is %d,%d %d x %d\n",
205 screen->xinerama_infos[i].number,
206 screen->xinerama_infos[i].rect.x,
207 screen->xinerama_infos[i].rect.y,
208 screen->xinerama_infos[i].rect.width,
209 screen->xinerama_infos[i].rect.height);
210
211 ++i;
212 }
213 }
214
215 meta_XFree (infos)do { if ((infos)) XFree ((infos)); } while (0);
216 }
217 else
218 {
219 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
220 "No XFree86 Xinerama extension or XFree86 Xinerama inactive on display %s\n",
221 display->name);
222 }
223#else
224 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
225 "Croma compiled without XFree86 Xinerama support\n");
226#endif /* HAVE_XFREE_XINERAMA */
227
228#ifdef HAVE_SOLARIS_XINERAMA
229 /* This code from CDK, Copyright (C) 2002 Sun Microsystems */
230 if (screen->n_xinerama_infos == 0 &&
231 XineramaGetState (screen->display->xdisplay,
232 screen->number))
233 {
234 XRectangle monitors[MAXFRAMEBUFFERS];
235 unsigned char hints[16];
236 int result;
237 int n_monitors;
238
239 n_monitors = 0;
240 result = XineramaGetInfo (screen->display->xdisplay,
241 screen->number,
242 monitors, hints,
243 &n_monitors);
244 /* Yes I know it should be Success but the current implementation
245 * returns the num of monitor
246 */
247 if (result > 0)
248 {
249 int i;
250
251 g_assert (n_monitors > 0)do { if (n_monitors > 0) ; else g_assertion_message_expr (
"croma", "core/screen.c", 251, ((const char*) (__func__)), "n_monitors > 0"
); } while (0)
;
252
253 screen->xinerama_infos = g_new (MetaXineramaScreenInfo, n_monitors)((MetaXineramaScreenInfo *) g_malloc_n ((n_monitors), sizeof (
MetaXineramaScreenInfo)))
;
254 screen->n_xinerama_infos = n_monitors;
255
256 i = 0;
257 while (i < n_monitors)
258 {
259 screen->xinerama_infos[i].number = i;
260 screen->xinerama_infos[i].rect.x = monitors[i].x;
261 screen->xinerama_infos[i].rect.y = monitors[i].y;
262 screen->xinerama_infos[i].rect.width = monitors[i].width;
263 screen->xinerama_infos[i].rect.height = monitors[i].height;
264
265 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
266 "Xinerama %d is %d,%d %d x %d\n",
267 screen->xinerama_infos[i].number,
268 screen->xinerama_infos[i].rect.x,
269 screen->xinerama_infos[i].rect.y,
270 screen->xinerama_infos[i].rect.width,
271 screen->xinerama_infos[i].rect.height);
272
273 ++i;
274 }
275 }
276 }
277 else if (screen->n_xinerama_infos == 0)
278 {
279 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
280 "No Solaris Xinerama extension or Solaris Xinerama inactive on display %s\n",
281 display->name);
282 }
283#else
284 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
285 "Croma compiled without Solaris Xinerama support\n");
286#endif /* HAVE_SOLARIS_XINERAMA */
287
288
289 /* If no Xinerama, fill in the single screen info so
290 * we can use the field unconditionally
291 */
292 if (screen->n_xinerama_infos == 0)
293 {
294 if (g_getenv ("CROMA_DEBUG_XINERAMA"))
295 {
296 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
297 "Pretending a single monitor has two Xinerama screens\n");
298
299 screen->xinerama_infos = g_new (MetaXineramaScreenInfo, 2)((MetaXineramaScreenInfo *) g_malloc_n ((2), sizeof (MetaXineramaScreenInfo
)))
;
300 screen->n_xinerama_infos = 2;
301
302 screen->xinerama_infos[0].number = 0;
303 screen->xinerama_infos[0].rect = screen->rect;
304 screen->xinerama_infos[0].rect.width = screen->rect.width / 2;
305
306 screen->xinerama_infos[1].number = 1;
307 screen->xinerama_infos[1].rect = screen->rect;
308 screen->xinerama_infos[1].rect.x = screen->rect.width / 2;
309 screen->xinerama_infos[1].rect.width = screen->rect.width / 2;
310 }
311 else
312 {
313 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
314 "No Xinerama screens, using default screen info\n");
315
316 screen->xinerama_infos = g_new (MetaXineramaScreenInfo, 1)((MetaXineramaScreenInfo *) g_malloc_n ((1), sizeof (MetaXineramaScreenInfo
)))
;
317 screen->n_xinerama_infos = 1;
318
319 screen->xinerama_infos[0].number = 0;
320 screen->xinerama_infos[0].rect = screen->rect;
321 }
322 }
323
324 g_assert (screen->n_xinerama_infos > 0)do { if (screen->n_xinerama_infos > 0) ; else g_assertion_message_expr
("croma", "core/screen.c", 324, ((const char*) (__func__)), "screen->n_xinerama_infos > 0"
); } while (0)
;
325 g_assert (screen->xinerama_infos != NULL)do { if (screen->xinerama_infos != ((void*)0)) ; else g_assertion_message_expr
("croma", "core/screen.c", 325, ((const char*) (__func__)), "screen->xinerama_infos != NULL"
); } while (0)
;
326}
327
328MetaScreen*
329meta_screen_new (MetaDisplay *display,
330 int number,
331 guint32 timestamp)
332{
333 MetaScreen *screen;
334 Window xroot;
335 Display *xdisplay;
336 XWindowAttributes attr;
337 Window new_wm_sn_owner;
338 Window current_wm_sn_owner;
339 gboolean replace_current_wm;
340 Atom wm_sn_atom;
341 char buf[128];
342 guint32 manager_timestamp;
343 gulong current_workspace;
344
345 replace_current_wm = meta_get_replace_current_wm ();
346
347 /* Only display->name, display->xdisplay, and display->error_traps
348 * can really be used in this function, since normally screens are
349 * created from the MetaDisplay constructor
350 */
351
352 xdisplay = display->xdisplay;
353
354 meta_verbosemeta_verbose_real ("Trying screen %d on display '%s'\n",
355 number, display->name);
356
357 xroot = RootWindow (xdisplay, number)((&((_XPrivDisplay)(xdisplay))->screens[number])->root
)
;
358
359 /* FVWM checks for None here, I don't know if this
360 * ever actually happens
361 */
362 if (xroot == None0L)
363 {
364 meta_warning (_("Screen %d on display '%s' is invalid\n")dgettext ("croma", "Screen %d on display '%s' is invalid\n"),
365 number, display->name);
366 return NULL((void*)0);
367 }
368
369 sprintf (buf, "WM_S%d", number);
370 wm_sn_atom = XInternAtom (xdisplay, buf, False0);
371
372 current_wm_sn_owner = XGetSelectionOwner (xdisplay, wm_sn_atom);
373
374 if (current_wm_sn_owner != None0L)
375 {
376 XSetWindowAttributes attrs;
377
378 if (!replace_current_wm)
379 {
380 meta_warning (_("Screen %d on display \"%s\" already has a window manager; try using the --replace option to replace the current window manager.\n")dgettext ("croma", "Screen %d on display \"%s\" already has a window manager; try using the --replace option to replace the current window manager.\n"
)
,
381 number, display->name);
382
383 return NULL((void*)0);
384 }
385
386 /* We want to find out when the current selection owner dies */
387 meta_error_trap_push (display);
388 attrs.event_mask = StructureNotifyMask(1L<<17);
389 XChangeWindowAttributes (xdisplay,
390 current_wm_sn_owner, CWEventMask(1L<<11), &attrs);
391 if (meta_error_trap_pop_with_return (display, FALSE(0)) != Success0)
392 current_wm_sn_owner = None0L; /* don't wait for it to die later on */
393 }
394
395 /* We need SelectionClear and SelectionRequest events on the new_wm_sn_owner,
396 * but those cannot be masked, so we only need NoEventMask.
397 */
398 new_wm_sn_owner = meta_create_offscreen_window (xdisplay, xroot, NoEventMask0L);
399
400 manager_timestamp = timestamp;
401
402 XSetSelectionOwner (xdisplay, wm_sn_atom, new_wm_sn_owner,
403 manager_timestamp);
404
405 if (XGetSelectionOwner (xdisplay, wm_sn_atom) != new_wm_sn_owner)
406 {
407 meta_warning (_("Could not acquire window manager selection on screen %d display \"%s\"\n")dgettext ("croma", "Could not acquire window manager selection on screen %d display \"%s\"\n"
)
,
408 number, display->name);
409
410 XDestroyWindow (xdisplay, new_wm_sn_owner);
411
412 return NULL((void*)0);
413 }
414
415 {
416 /* Send client message indicating that we are now the WM */
417 XClientMessageEvent ev;
418
419 ev.type = ClientMessage33;
420 ev.window = xroot;
421 ev.message_type = display->atom_MANAGER;
422 ev.format = 32;
423 ev.data.l[0] = manager_timestamp;
424 ev.data.l[1] = wm_sn_atom;
425
426 XSendEvent (xdisplay, xroot, False0, StructureNotifyMask(1L<<17), (XEvent*)&ev);
427 }
428
429 /* Wait for old window manager to go away */
430 if (current_wm_sn_owner != None0L)
431 {
432 XEvent event;
433
434 /* We sort of block infinitely here which is probably lame. */
435
436 meta_verbosemeta_verbose_real ("Waiting for old window manager to exit\n");
437 do
438 {
439 XWindowEvent (xdisplay, current_wm_sn_owner,
440 StructureNotifyMask(1L<<17), &event);
441 }
442 while (event.type != DestroyNotify17);
443 }
444
445 /* select our root window events */
446 meta_error_trap_push (display);
447
448 /* We need to or with the existing event mask since
449 * ctk+ may be interested in other events.
450 */
451 XGetWindowAttributes (xdisplay, xroot, &attr);
452 XSelectInput (xdisplay,
453 xroot,
454 SubstructureRedirectMask(1L<<20) | SubstructureNotifyMask(1L<<19) |
455 ColormapChangeMask(1L<<23) | PropertyChangeMask(1L<<22) |
456 LeaveWindowMask(1L<<5) | EnterWindowMask(1L<<4) |
457 KeyPressMask(1L<<0) | KeyReleaseMask(1L<<1) |
458 FocusChangeMask(1L<<21) | StructureNotifyMask(1L<<17) |
459#ifdef HAVE_COMPOSITE_EXTENSIONS1
460 ExposureMask(1L<<15) |
461#endif
462 attr.your_event_mask);
463 if (meta_error_trap_pop_with_return (display, FALSE(0)) != Success0)
464 {
465 meta_warning (_("Screen %d on display \"%s\" already has a window manager\n")dgettext ("croma", "Screen %d on display \"%s\" already has a window manager\n"
)
,
466 number, display->name);
467
468 XDestroyWindow (xdisplay, new_wm_sn_owner);
469
470 return NULL((void*)0);
471 }
472
473 screen = g_new (MetaScreen, 1)((MetaScreen *) g_malloc_n ((1), sizeof (MetaScreen)));
474 screen->closing = 0;
475
476 screen->display = display;
477 screen->number = number;
478 screen->screen_name = get_screen_name (display, number);
479 screen->xscreen = ScreenOfDisplay (xdisplay, number)(&((_XPrivDisplay)(xdisplay))->screens[number]);
480 screen->xroot = xroot;
481 screen->rect.x = screen->rect.y = 0;
482 screen->rect.width = WidthOfScreen (screen->xscreen)((screen->xscreen)->width);
483 screen->rect.height = HeightOfScreen (screen->xscreen)((screen->xscreen)->height);
484 screen->current_cursor = -1; /* invalid/unset */
485 screen->default_xvisual = DefaultVisualOfScreen (screen->xscreen)((screen->xscreen)->root_visual);
486 screen->default_depth = DefaultDepthOfScreen (screen->xscreen)((screen->xscreen)->root_depth);
487 screen->flash_window = None0L;
488
489 screen->wm_sn_selection_window = new_wm_sn_owner;
490 screen->wm_sn_atom = wm_sn_atom;
491 screen->wm_sn_timestamp = manager_timestamp;
492
493#ifdef HAVE_COMPOSITE_EXTENSIONS1
494 g_snprintf (buf, sizeof(buf), "_NET_WM_CM_S%d", screen->number);
495 screen->wm_cm_atom = XInternAtom (screen->display->xdisplay, buf, FALSE(0));
496 screen->wm_cm_selection_window = meta_create_offscreen_window (xdisplay,
497 xroot,
498 NoEventMask0L);
499#endif
500 screen->work_area_idle = 0;
501
502 screen->active_workspace = NULL((void*)0);
503 screen->workspaces = NULL((void*)0);
504 screen->rows_of_workspaces = 1;
505 screen->columns_of_workspaces = -1;
506 screen->vertical_workspaces = FALSE(0);
507 screen->starting_corner = META_SCREEN_TOPLEFT;
508 screen->compositor_data = NULL((void*)0);
509
510 {
511 XFontStruct *font_info;
512 XGCValues gc_values;
513 gulong value_mask = 0;
514
515 gc_values.subwindow_mode = IncludeInferiors1;
516 value_mask |= GCSubwindowMode(1L<<15);
517 gc_values.function = GXinvert0xa;
518 value_mask |= GCFunction(1L<<0);
519 gc_values.line_width = META_WIREFRAME_XOR_LINE_WIDTH2;
520 value_mask |= GCLineWidth(1L<<4);
521
522 font_info = XLoadQueryFont (screen->display->xdisplay, "fixed");
523
524 if (font_info != NULL((void*)0))
525 {
526 gc_values.font = font_info->fid;
527 value_mask |= GCFont(1L<<14);
528 XFreeFontInfo (NULL((void*)0), font_info, 1);
529 }
530 else
531 meta_warning ("xserver doesn't have 'fixed' font.\n");
532
533 screen->root_xor_gc = XCreateGC (screen->display->xdisplay,
534 screen->xroot,
535 value_mask,
536 &gc_values);
537 }
538
539 screen->xinerama_infos = NULL((void*)0);
540 screen->n_xinerama_infos = 0;
541 screen->last_xinerama_index = 0;
542
543 reload_xinerama_infos (screen);
544
545 meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
546
547 /* Handle creating a no_focus_window for this screen */
548 screen->no_focus_window =
549 meta_create_offscreen_window (display->xdisplay,
550 screen->xroot,
551 FocusChangeMask(1L<<21)|KeyPressMask(1L<<0)|KeyReleaseMask(1L<<1));
552 XMapWindow (display->xdisplay, screen->no_focus_window);
553 /* Done with no_focus_window stuff */
554
555 set_wm_icon_size_hint (screen);
556
557 set_supported_hint (screen);
558
559 set_wm_check_hint (screen);
560
561 set_desktop_viewport_hint (screen);
562
563 set_desktop_geometry_hint (screen);
564
565 meta_screen_update_workspace_layout (screen);
566
567 /* Get current workspace */
568 current_workspace = 0;
569 if (meta_prop_get_cardinal (screen->display,
570 screen->xroot,
571 screen->display->atom__NET_CURRENT_DESKTOP,
572 &current_workspace))
573 meta_verbosemeta_verbose_real ("Read existing _NET_CURRENT_DESKTOP = %d\n",
574 (int) current_workspace);
575 else
576 meta_verbosemeta_verbose_real ("No _NET_CURRENT_DESKTOP present\n");
577
578 /* Screens must have at least one workspace at all times,
579 * so create that required workspace.
580 */
581 meta_workspace_activate (meta_workspace_new (screen), timestamp);
582 update_num_workspaces (screen, timestamp);
583
584 set_workspace_names (screen);
585
586 screen->all_keys_grabbed = FALSE(0);
587 screen->keys_grabbed = FALSE(0);
588 meta_screen_grab_keys (screen);
589
590 screen->ui = meta_ui_new (screen->display->xdisplay,
591 screen->xscreen);
592
593 screen->tab_popup = NULL((void*)0);
594 screen->tile_preview = NULL((void*)0);
595
596 screen->tile_preview_timeout_id = 0;
597
598 screen->stack = meta_stack_new (screen);
599
600 meta_prefs_add_listener (prefs_changed_callback, screen);
601
602#ifdef HAVE_STARTUP_NOTIFICATION
603 screen->sn_context =
604 sn_monitor_context_new (screen->display->sn_display,
605 screen->number,
606 meta_screen_sn_event,
607 screen,
608 NULL((void*)0));
609 screen->startup_sequences = NULL((void*)0);
610 screen->startup_sequence_timeout = 0;
611#endif
612
613 /* Switch to the _NET_CURRENT_DESKTOP workspace */
614 {
615 MetaWorkspace *space;
616
617 space = meta_screen_get_workspace_by_index (screen,
618 current_workspace);
619
620 if (space != NULL((void*)0))
621 meta_workspace_activate (space, timestamp);
622 }
623
624 meta_verbosemeta_verbose_real ("Added screen %d ('%s') root 0x%lx\n",
625 screen->number, screen->screen_name, screen->xroot);
626
627 return screen;
628}
629
630void
631meta_screen_free (MetaScreen *screen,
632 guint32 timestamp)
633{
634 MetaDisplay *display;
635 XGCValues gc_values = { 0 };
636
637 display = screen->display;
638
639 screen->closing += 1;
640
641 meta_display_grab (display);
642
643 if (screen->display->compositor)
644 {
645 meta_compositor_unmanage_screen (screen->display->compositor,
646 screen);
647 }
648
649 meta_display_unmanage_windows_for_screen (display, screen, timestamp);
650
651 meta_prefs_remove_listener (prefs_changed_callback, screen);
652
653 meta_screen_ungrab_keys (screen);
654
655#ifdef HAVE_STARTUP_NOTIFICATION
656 g_slist_free_full (screen->startup_sequences,
657 (GDestroyNotify) sn_startup_sequence_unref);
658 screen->startup_sequences = NULL((void*)0);
659
660 if (screen->startup_sequence_timeout != 0)
661 {
662 g_source_remove (screen->startup_sequence_timeout);
663 screen->startup_sequence_timeout = 0;
664 }
665 if (screen->sn_context)
666 {
667 sn_monitor_context_unref (screen->sn_context);
668 screen->sn_context = NULL((void*)0);
669 }
670#endif
671
672 meta_ui_free (screen->ui);
673
674 meta_stack_free (screen->stack);
675
676 meta_error_trap_push (screen->display);
677 XSelectInput (screen->display->xdisplay, screen->xroot, 0);
678 if (meta_error_trap_pop_with_return (screen->display, FALSE(0)) != Success0)
679 meta_warning (_("Could not release screen %d on display \"%s\"\n")dgettext ("croma", "Could not release screen %d on display \"%s\"\n"
)
,
680 screen->number, screen->display->name);
681
682 unset_wm_check_hint (screen);
683
684 XDestroyWindow (screen->display->xdisplay,
685 screen->wm_sn_selection_window);
686
687 if (screen->work_area_idle != 0)
688 g_source_remove (screen->work_area_idle);
689
690
691 if (XGetGCValues (screen->display->xdisplay,
692 screen->root_xor_gc,
693 GCFont(1L<<14),
694 &gc_values))
695 {
696 XUnloadFont (screen->display->xdisplay,
697 gc_values.font);
698 }
699
700 XFreeGC (screen->display->xdisplay,
701 screen->root_xor_gc);
702
703 if (screen->xinerama_infos)
704 g_free (screen->xinerama_infos);
705
706 if (screen->tile_preview_timeout_id)
707 g_source_remove (screen->tile_preview_timeout_id);
708
709 if (screen->tile_preview)
710 meta_tile_preview_free (screen->tile_preview);
711
712 g_free (screen->screen_name);
713 g_free (screen);
714
715 XFlush (display->xdisplay);
716 meta_display_ungrab (display);
717}
718
719typedef struct
720{
721 Window xwindow;
722 XWindowAttributes attrs;
723} WindowInfo;
724
725static GList *
726list_windows (MetaScreen *screen)
727{
728 Window ignored1, ignored2;
729 Window *children;
730 guint n_children, i;
731 GList *result;
732
733 XQueryTree (screen->display->xdisplay,
734 screen->xroot,
735 &ignored1, &ignored2, &children, &n_children);
736
737 result = NULL((void*)0);
738 for (i = 0; i < n_children; ++i)
739 {
740 WindowInfo *info = g_new0 (WindowInfo, 1)((WindowInfo *) g_malloc0_n ((1), sizeof (WindowInfo)));
741
742 meta_error_trap_push (screen->display);
743
744 XGetWindowAttributes (screen->display->xdisplay,
745 children[i], &info->attrs);
746
747 if (meta_error_trap_pop_with_return (screen->display, TRUE(!(0))))
748 {
749 meta_verbosemeta_verbose_real ("Failed to get attributes for window 0x%lx\n",
750 children[i]);
751 g_free (info);
752 }
753 else
754 {
755 info->xwindow = children[i];
756 result = g_list_prepend (result, info);
757 }
758 }
759
760 if (children)
761 XFree (children);
762
763 return g_list_reverse (result);
764}
765
766void
767meta_screen_manage_all_windows (MetaScreen *screen)
768{
769 GList *windows;
770 GList *list;
771
772 meta_display_grab (screen->display);
773
774 windows = list_windows (screen);
775
776 meta_stack_freeze (screen->stack);
777 for (list = windows; list != NULL((void*)0); list = list->next)
778 {
779 WindowInfo *info = list->data;
780 MetaWindow *window;
781 gboolean test_window_owner;
782
783 window = meta_window_new_with_attrs (screen->display, info->xwindow, TRUE(!(0)),
784 &info->attrs);
785 test_window_owner = info->xwindow == screen->no_focus_window ||
786 info->xwindow == screen->flash_window ||
787 info->xwindow == screen->wm_sn_selection_window;
788
789#ifdef HAVE_COMPOSITE_EXTENSIONS1
790 test_window_owner = test_window_owner || info->xwindow == screen->wm_cm_selection_window;
791#endif
792 if (test_window_owner)
793 {
794 meta_verbosemeta_verbose_real ("Not managing our own windows\n");
795 continue;
796 }
797
798 if (screen->display->compositor)
799 meta_compositor_add_window (screen->display->compositor, window,
800 info->xwindow, &info->attrs);
801 }
802 meta_stack_thaw (screen->stack);
803
804 g_list_free_full (windows, g_free);
805
806 meta_display_ungrab (screen->display);
807}
808
809void
810meta_screen_composite_all_windows (MetaScreen *screen)
811{
812#ifdef HAVE_COMPOSITE_EXTENSIONS1
813 MetaDisplay *display;
814 GList *windows, *list;
815
816 display = screen->display;
817 if (!display->compositor)
818 return;
819
820 windows = list_windows (screen);
821
822 meta_stack_freeze (screen->stack);
823
824 for (list = windows; list != NULL((void*)0); list = list->next)
825 {
826 WindowInfo *info = list->data;
827
828 if (info->xwindow == screen->no_focus_window ||
829 info->xwindow == screen->flash_window ||
830 info->xwindow == screen->wm_sn_selection_window ||
831 info->xwindow == screen->wm_cm_selection_window) {
832 meta_verbosemeta_verbose_real ("Not managing our own windows\n");
833 continue;
834 }
835
836 meta_compositor_add_window (display->compositor,
837 meta_display_lookup_x_window (display,
838 info->xwindow),
839 info->xwindow, &info->attrs);
840 }
841
842 meta_stack_thaw (screen->stack);
843
844 g_list_free_full (windows, g_free);
845#endif
846}
847
848MetaScreen*
849meta_screen_for_x_screen (Screen *xscreen)
850{
851 MetaDisplay *display;
852
853 display = meta_display_for_x_display (DisplayOfScreen (xscreen)((xscreen)->display));
854
855 if (display == NULL((void*)0))
856 return NULL((void*)0);
857
858 return meta_display_screen_for_x_screen (display, xscreen);
859}
860
861static void
862prefs_changed_callback (MetaPreference pref,
863 gpointer data)
864{
865 MetaScreen *screen = data;
866
867 if (pref == META_PREF_NUM_WORKSPACES)
868 {
869 /* GSettings doesn't provide timestamps, but luckily update_num_workspaces
870 * often doesn't need it...
871 */
872 guint32 timestamp =
873 meta_display_get_current_time_roundtrip (screen->display);
874 update_num_workspaces (screen, timestamp);
875 }
876 else if (pref == META_PREF_FOCUS_MODE)
877 {
878 update_focus_mode (screen);
879 }
880 else if (pref == META_PREF_WORKSPACE_NAMES)
881 {
882 set_workspace_names (screen);
883 }
884}
885
886
887static char*
888get_screen_name (MetaDisplay *display,
889 int number)
890{
891 char *p;
892 char *dname;
893 char *scr;
894
895 /* DisplayString gives us a sort of canonical display,
896 * vs. the user-entered name from XDisplayName()
897 */
898 dname = g_strdup (DisplayString (display->xdisplay))g_strdup_inline ((((_XPrivDisplay)(display->xdisplay))->
display_name))
;
899
900 /* Change display name to specify this screen.
901 */
902 p = strrchr (dname, ':');
903 if (p)
904 {
905 p = strchr (p, '.');
906 if (p)
907 *p = '\0';
908 }
909
910 scr = g_strdup_printf ("%s.%d", dname, number);
911
912 g_free (dname);
913
914 return scr;
915}
916
917static gint
918ptrcmp (gconstpointer a, gconstpointer b)
919{
920 if (a < b)
921 return -1;
922 else if (a > b)
923 return 1;
924 else
925 return 0;
926}
927
928static void
929listify_func (gpointer key, gpointer value, gpointer data)
930{
931 GSList **listp;
932
933 listp = data;
934
935 *listp = g_slist_prepend (*listp, value);
936}
937
938void
939meta_screen_foreach_window (MetaScreen *screen,
940 MetaScreenWindowFunc func,
941 gpointer data)
942{
943 GSList *winlist;
944 GSList *tmp;
945
946 /* If we end up doing this often, just keeping a list
947 * of windows might be sensible.
948 */
949
950 winlist = NULL((void*)0);
951 g_hash_table_foreach (screen->display->window_ids,
952 listify_func,
953 &winlist);
954
955 winlist = g_slist_sort (winlist, ptrcmp);
956
957 tmp = winlist;
958 while (tmp != NULL((void*)0))
959 {
960 /* If the next node doesn't contain this window
961 * a second time, delete the window.
962 */
963 if (tmp->next == NULL((void*)0) ||
964 (tmp->next && tmp->next->data != tmp->data))
965 {
966 MetaWindow *window = tmp->data;
967
968 if (window->screen == screen)
969 (* func) (screen, window, data);
970 }
971
972 tmp = tmp->next;
973 }
974 g_slist_free (winlist);
975}
976
977static void
978queue_draw (MetaScreen *screen, MetaWindow *window, gpointer data)
979{
980 if (window->frame)
981 meta_frame_queue_draw (window->frame);
982}
983
984void
985meta_screen_queue_frame_redraws (MetaScreen *screen)
986{
987 meta_screen_foreach_window (screen, queue_draw, NULL((void*)0));
988}
989
990static void
991queue_resize (MetaScreen *screen, MetaWindow *window, gpointer data)
992{
993 meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
994}
995
996void
997meta_screen_queue_window_resizes (MetaScreen *screen)
998{
999 meta_screen_foreach_window (screen, queue_resize, NULL((void*)0));
1000}
1001
1002int
1003meta_screen_get_n_workspaces (MetaScreen *screen)
1004{
1005 return g_list_length (screen->workspaces);
1006}
1007
1008MetaWorkspace*
1009meta_screen_get_workspace_by_index (MetaScreen *screen,
1010 int idx)
1011{
1012 GList *tmp;
1013 int i;
1014
1015 /* should be robust, idx is maybe from an app */
1016 if (idx < 0)
1017 return NULL((void*)0);
1018
1019 i = 0;
1020 tmp = screen->workspaces;
1021 while (tmp != NULL((void*)0))
1022 {
1023 MetaWorkspace *w = tmp->data;
1024
1025 if (i == idx)
1026 return w;
1027
1028 ++i;
1029 tmp = tmp->next;
1030 }
1031
1032 return NULL((void*)0);
1033}
1034
1035static void
1036set_number_of_spaces_hint (MetaScreen *screen,
1037 int n_spaces)
1038{
1039 unsigned long data[1];
1040
1041 if (screen->closing > 0)
1042 return;
1043
1044 data[0] = n_spaces;
1045
1046 meta_verbosemeta_verbose_real ("Setting _NET_NUMBER_OF_DESKTOPS to %lu\n", data[0]);
1047
1048 meta_error_trap_push (screen->display);
1049 XChangeProperty (screen->display->xdisplay, screen->xroot,
1050 screen->display->atom__NET_NUMBER_OF_DESKTOPS,
1051 XA_CARDINAL((Atom) 6),
1052 32, PropModeReplace0, (guchar*) data, 1);
1053 meta_error_trap_pop (screen->display, FALSE(0));
1054}
1055
1056static void
1057set_desktop_geometry_hint (MetaScreen *screen)
1058{
1059 unsigned long data[2];
1060
1061 if (screen->closing > 0)
1062 return;
1063
1064 data[0] = screen->rect.width;
1065 data[1] = screen->rect.height;
1066
1067 meta_verbosemeta_verbose_real ("Setting _NET_DESKTOP_GEOMETRY to %lu, %lu\n", data[0], data[1]);
1068
1069 meta_error_trap_push (screen->display);
1070 XChangeProperty (screen->display->xdisplay, screen->xroot,
1071 screen->display->atom__NET_DESKTOP_GEOMETRY,
1072 XA_CARDINAL((Atom) 6),
1073 32, PropModeReplace0, (guchar*) data, 2);
1074 meta_error_trap_pop (screen->display, FALSE(0));
1075}
1076
1077static void
1078set_desktop_viewport_hint (MetaScreen *screen)
1079{
1080 unsigned long data[2];
1081
1082 if (screen->closing > 0)
1083 return;
1084
1085 /*
1086 * Croma does not implement viewports, so this is a fixed 0,0
1087 */
1088 data[0] = 0;
1089 data[1] = 0;
1090
1091 meta_verbosemeta_verbose_real ("Setting _NET_DESKTOP_VIEWPORT to 0, 0\n");
1092
1093 meta_error_trap_push (screen->display);
1094 XChangeProperty (screen->display->xdisplay, screen->xroot,
1095 screen->display->atom__NET_DESKTOP_VIEWPORT,
1096 XA_CARDINAL((Atom) 6),
1097 32, PropModeReplace0, (guchar*) data, 2);
1098 meta_error_trap_pop (screen->display, FALSE(0));
1099}
1100
1101static void
1102update_num_workspaces (MetaScreen *screen,
1103 guint32 timestamp)
1104{
1105 int new_num;
1106 GList *tmp;
1107 int i;
1108 GList *extras;
1109 MetaWorkspace *last_remaining;
1110 gboolean need_change_space;
1111
1112 new_num = meta_prefs_get_num_workspaces ();
1113
1114 g_assert (new_num > 0)do { if (new_num > 0) ; else g_assertion_message_expr ("croma"
, "core/screen.c", 1114, ((const char*) (__func__)), "new_num > 0"
); } while (0)
;
1115
1116 last_remaining = NULL((void*)0);
1117 extras = NULL((void*)0);
1118 i = 0;
1119 tmp = screen->workspaces;
1120 while (tmp != NULL((void*)0))
1121 {
1122 MetaWorkspace *w = tmp->data;
1123
1124 if (i >= new_num)
1125 extras = g_list_prepend (extras, w);
1126 else
1127 last_remaining = w;
1128
1129 ++i;
1130 tmp = tmp->next;
1131 }
1132
1133 g_assert (last_remaining)do { if (last_remaining) ; else g_assertion_message_expr ("croma"
, "core/screen.c", 1133, ((const char*) (__func__)), "last_remaining"
); } while (0)
;
1134
1135 /* Get rid of the extra workspaces by moving all their windows
1136 * to last_remaining, then activating last_remaining if
1137 * one of the removed workspaces was active. This will be a bit
1138 * wacky if the config tool for changing number of workspaces
1139 * is on a removed workspace ;-)
1140 */
1141 need_change_space = FALSE(0);
1142 tmp = extras;
1143 while (tmp != NULL((void*)0))
1144 {
1145 MetaWorkspace *w = tmp->data;
1146
1147 meta_workspace_relocate_windows (w, last_remaining);
1148
1149 if (w == screen->active_workspace)
1150 need_change_space = TRUE(!(0));
1151
1152 tmp = tmp->next;
1153 }
1154
1155 if (need_change_space)
1156 meta_workspace_activate (last_remaining, timestamp);
1157
1158 /* Should now be safe to free the workspaces */
1159 tmp = extras;
1160 while (tmp != NULL((void*)0))
1161 {
1162 MetaWorkspace *w = tmp->data;
1163
1164 g_assert (w->windows == NULL)do { if (w->windows == ((void*)0)) ; else g_assertion_message_expr
("croma", "core/screen.c", 1164, ((const char*) (__func__)),
"w->windows == NULL"); } while (0)
;
1165 meta_workspace_free (w);
1166
1167 tmp = tmp->next;
1168 }
1169
1170 g_list_free (extras);
1171
1172 while (i < new_num)
1173 {
1174 meta_workspace_new (screen);
1175 ++i;
1176 }
1177
1178 set_number_of_spaces_hint (screen, new_num);
1179
1180 meta_screen_queue_workarea_recalc (screen);
1181}
1182
1183static void
1184update_focus_mode (MetaScreen *screen)
1185{
1186 /* nothing to do anymore */ ;
1187}
1188
1189void
1190meta_screen_set_cursor (MetaScreen *screen,
1191 MetaCursor cursor)
1192{
1193 Cursor xcursor;
1194
1195 if (cursor == screen->current_cursor)
1196 return;
1197
1198 screen->current_cursor = cursor;
1199
1200 xcursor = meta_display_create_x_cursor (screen->display, cursor);
1201 XDefineCursor (screen->display->xdisplay, screen->xroot, xcursor);
1202 XFlush (screen->display->xdisplay);
1203 XFreeCursor (screen->display->xdisplay, xcursor);
1204}
1205
1206void
1207meta_screen_update_cursor (MetaScreen *screen)
1208{
1209 Cursor xcursor;
1210
1211 xcursor = meta_display_create_x_cursor (screen->display,
1212 screen->current_cursor);
1213 XDefineCursor (screen->display->xdisplay, screen->xroot, xcursor);
1214 XFlush (screen->display->xdisplay);
1215 XFreeCursor (screen->display->xdisplay, xcursor);
1216}
1217
1218#define MAX_PREVIEW_SCREEN_FRACTION0.33 0.33
1219#define MAX_PREVIEW_SIZE300 300
1220
1221static cairo_surface_t *
1222get_window_surface (MetaWindow *window)
1223{
1224 cairo_surface_t *surface, *scaled;
1225 cairo_t *cr;
1226 const MetaXineramaScreenInfo *current;
1227 int width, height, max_columns, max_size;
1228 double ratio;
1229
1230 surface = meta_compositor_get_window_surface (window->display->compositor, window);
1231
1232 if (surface == NULL((void*)0))
1233 return NULL((void*)0);
1234
1235 width = cairo_xlib_surface_get_width (surface);
1236 height = cairo_xlib_surface_get_height (surface);
1237
1238 current = meta_screen_get_current_xinerama (window->screen);
1239 max_columns = meta_prefs_get_alt_tab_max_columns ();
1240
1241 /* Scale surface to fit current screen */
1242 if (width > height)
1243 {
1244 max_size = MIN (MAX_PREVIEW_SIZE, current->rect.width / max_columns * MAX_PREVIEW_SCREEN_FRACTION)(((300) < (current->rect.width / max_columns * 0.33)) ?
(300) : (current->rect.width / max_columns * 0.33))
;
1245 ratio = ((double) width) / max_size;
1246 width = (int) max_size;
1247 height = (int) (((double) height) / ratio);
1248 }
1249 else
1250 {
1251 max_size = MIN (MAX_PREVIEW_SIZE, current->rect.height / max_columns * MAX_PREVIEW_SCREEN_FRACTION)(((300) < (current->rect.height / max_columns * 0.33)) ?
(300) : (current->rect.height / max_columns * 0.33))
;
1252 ratio = ((double) height) / max_size;
1253 height = (int) max_size;
1254 width = (int) (((double) width) / ratio);
1255 }
1256
1257 meta_error_trap_push (window->display);
1258 scaled = cairo_surface_create_similar (surface,
1259 cairo_surface_get_content (surface),
1260 width, height);
1261 if (meta_error_trap_pop_with_return (window->display, FALSE(0)) != Success0)
1262 return NULL((void*)0);
1263
1264 cr = cairo_create (scaled);
1265 cairo_scale (cr, 1/ratio, 1/ratio);
1266 cairo_set_source_surface (cr, surface, 0, 0);
1267 cairo_paint (cr);
1268
1269 cairo_destroy (cr);
1270 cairo_surface_destroy (surface);
1271
1272 return scaled;
1273}
1274
1275void
1276meta_screen_ensure_tab_popup (MetaScreen *screen,
1277 MetaTabList list_type,
1278 MetaTabShowType show_type)
1279{
1280 MetaTabEntry *entries;
1281 GList *tab_list;
1282 GList *tmp;
1283 int len;
1284 int i;
1285 gint border;
1286 int scale;
1287
1288 if (screen->tab_popup)
1289 return;
1290
1291 tab_list = meta_display_get_tab_list (screen->display,
1292 list_type,
1293 screen,
1294 screen->active_workspace);
1295
1296 len = g_list_length (tab_list);
1297 scale = cdk_window_get_scale_factor (cdk_get_default_root_window ());
1298
1299 entries = g_new (MetaTabEntry, len + 1)((MetaTabEntry *) g_malloc_n ((len + 1), sizeof (MetaTabEntry
)))
;
1300 entries[len].key = NULL((void*)0);
1301 entries[len].title = NULL((void*)0);
1302 entries[len].icon = NULL((void*)0);
1303 entries[len].win_surface = NULL((void*)0);
1304
1305 border = meta_prefs_show_tab_border() ? BORDER_OUTLINE_TAB |
1306 BORDER_OUTLINE_WINDOW : BORDER_OUTLINE_TAB;
1307 i = 0;
1308 tmp = tab_list;
1309 while (i < len)
1310 {
1311 MetaWindow *window;
1312 MetaRectangle r;
1313
1314 window = tmp->data;
1315
1316 entries[i].key = (MetaTabEntryKey) window->xwindow;
1317 entries[i].title = window->title;
1318 entries[i].win_surface = NULL((void*)0);
1319
1320 entries[i].icon = g_object_ref (window->icon)((__typeof__ (window->icon)) (g_object_ref) (window->icon
))
;
1321
1322 /* Only get the window thumbnail surface if the user has a compositor
1323 * enabled and does NOT have compositing-fast-alt-tab-set to true in
1324 * GSettings. There is an obvious lag when the surface is retrieved. */
1325 if (meta_prefs_get_compositing_manager() && !meta_prefs_get_compositing_fast_alt_tab())
1326 {
1327 cairo_surface_t *win_surface;
1328
1329 /* Get window thumbnail */
1330 win_surface = get_window_surface (window);
1331
1332 if (win_surface != NULL((void*)0))
1333 {
1334 cairo_surface_t *surface, *icon;
1335 cairo_t *cr;
1336 int width, height, icon_width, icon_height;
1337
1338#define ICON_OFFSET6 6
1339
1340 width = cairo_xlib_surface_get_width (win_surface);
1341 height = cairo_xlib_surface_get_height (win_surface);
1342
1343 /* Create a new surface to overlap the window icon into */
1344 surface = cairo_surface_create_similar (win_surface,
1345 cairo_surface_get_content (win_surface),
1346 width, height);
1347
1348 cr = cairo_create (surface);
1349 cairo_set_source_surface (cr, win_surface, 0, 0);
1350 cairo_paint (cr);
1351
1352 /* Get the window icon as a surface */
1353 icon = cdk_cairo_surface_create_from_pixbuf (window->icon, scale, NULL((void*)0));
1354
1355 icon_width = cairo_image_surface_get_width (icon) / scale;
1356 icon_height = cairo_image_surface_get_height (icon) / scale;
1357
1358 /* Overlap the window icon surface over the window thumbnail */
1359 cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
1360 cairo_set_source_surface (cr, icon,
1361 width - icon_width - ICON_OFFSET6,
1362 height - icon_height - ICON_OFFSET6);
1363 cairo_paint (cr);
1364
1365 entries[i].win_surface = surface;
1366
1367 cairo_destroy (cr);
1368 cairo_surface_destroy (icon);
1369 cairo_surface_destroy (win_surface);
1370 }
1371 }
1372
1373 entries[i].blank = FALSE(0);
1374 entries[i].hidden = !meta_window_showing_on_its_workspace (window);
1375 entries[i].demands_attention = window->wm_state_demands_attention;
1376
1377 if (show_type == META_TAB_SHOW_INSTANTLY ||
1378 !entries[i].hidden ||
1379 !meta_window_get_icon_geometry (window, &r))
1380 meta_window_get_outer_rect (window, &r);
1381
1382 entries[i].rect = r;
1383
1384 /* Find inside of highlight rectangle to be used when window is
1385 * outlined for tabbing. This should be the size of the
1386 * east/west frame, and the size of the south frame, on those
1387 * sides. On the top it should be the size of the south frame
1388 * edge.
1389 */
1390 if (border & BORDER_OUTLINE_WINDOW)
1391 {
1392#define OUTLINE_WIDTH5 5
1393 /* Top side */
1394 entries[i].inner_rect.y = OUTLINE_WIDTH5;
1395
1396 /* Bottom side */
1397 entries[i].inner_rect.height = r.height - entries[i].inner_rect.y - OUTLINE_WIDTH5;
1398
1399 /* Left side */
1400 entries[i].inner_rect.x = OUTLINE_WIDTH5;
1401
1402 /* Right side */
1403 entries[i].inner_rect.width = r.width - entries[i].inner_rect.x - OUTLINE_WIDTH5;
1404 }
1405
1406 ++i;
1407 tmp = tmp->next;
1408 }
1409
1410 screen->tab_popup = meta_ui_tab_popup_new (entries,
1411 len,
1412 meta_prefs_get_alt_tab_max_columns(),
1413 meta_prefs_get_alt_tab_expand_to_fit_title(),
1414 border);
1415
1416 for (i = 0; i < len; i++)
1417 {
1418 g_object_unref (entries[i].icon);
1419 if (entries[i].win_surface)
1420 cairo_surface_destroy (entries[i].win_surface);
1421 }
1422
1423 g_free (entries);
1424
1425 g_list_free (tab_list);
1426
1427 /* don't show tab popup, since proper window isn't selected yet */
1428}
1429
1430void
1431meta_screen_ensure_workspace_popup (MetaScreen *screen)
1432{
1433 MetaTabEntry *entries;
1434 int len;
1435 int i;
1436 MetaWorkspaceLayout layout;
1437 int n_workspaces;
1438 int current_workspace;
1439
1440 if (screen->tab_popup)
1441 return;
1442
1443 current_workspace = meta_workspace_index (screen->active_workspace);
1444 n_workspaces = meta_screen_get_n_workspaces (screen);
1445
1446 meta_screen_calc_workspace_layout (screen, n_workspaces,
1447 current_workspace, &layout);
1448
1449 len = layout.grid_area;
1450
1451 entries = g_new (MetaTabEntry, len + 1)((MetaTabEntry *) g_malloc_n ((len + 1), sizeof (MetaTabEntry
)))
;
1452 entries[len].key = NULL((void*)0);
1453 entries[len].title = NULL((void*)0);
1454 entries[len].icon = NULL((void*)0);
1455 entries[len].win_surface = NULL((void*)0);
1456
1457 i = 0;
1458 while (i < len)
1459 {
1460 if (layout.grid[i] >= 0)
1461 {
1462 MetaWorkspace *workspace;
1463
1464 workspace = meta_screen_get_workspace_by_index (screen,
1465 layout.grid[i]);
1466
1467 entries[i].key = (MetaTabEntryKey) workspace;
1468 entries[i].title = meta_workspace_get_name (workspace);
1469 entries[i].icon = NULL((void*)0);
1470 entries[i].win_surface = NULL((void*)0);
1471 entries[i].blank = FALSE(0);
1472
1473 g_assert (entries[i].title != NULL)do { if (entries[i].title != ((void*)0)) ; else g_assertion_message_expr
("croma", "core/screen.c", 1473, ((const char*) (__func__)),
"entries[i].title != NULL"); } while (0)
;
1474 }
1475 else
1476 {
1477 entries[i].key = NULL((void*)0);
1478 entries[i].title = NULL((void*)0);
1479 entries[i].icon = NULL((void*)0);
1480 entries[i].win_surface = NULL((void*)0);
1481 entries[i].blank = TRUE(!(0));
1482 }
1483 entries[i].hidden = FALSE(0);
1484 entries[i].demands_attention = FALSE(0);
1485
1486 ++i;
1487 }
1488
1489 screen->tab_popup = meta_ui_tab_popup_new (entries,
1490 len,
1491 layout.cols,
1492 FALSE(0), /* expand_for_titles */
1493 BORDER_OUTLINE_WORKSPACE);
1494
1495 g_free (entries);
1496 meta_screen_free_workspace_layout (&layout);
1497
1498 /* don't show tab popup, since proper space isn't selected yet */
1499}
1500
1501static gboolean
1502meta_screen_tile_preview_update_timeout (gpointer data)
1503{
1504 MetaScreen *screen = data;
1505 MetaWindow *window = screen->display->grab_window;
1506 gboolean needs_preview = FALSE(0);
1507
1508 screen->tile_preview_timeout_id = 0;
1509
1510 if (!screen->tile_preview)
1511 screen->tile_preview = meta_tile_preview_new ();
1512
1513 if (window)
1514 {
1515 switch (window->tile_mode)
1516 {
1517 case META_TILE_MAXIMIZED:
1518 if (!META_WINDOW_MAXIMIZED (window)((window)->maximized_horizontally && (window)->
maximized_vertically)
)
1519 needs_preview = TRUE(!(0));
1520 break;
1521
1522 case META_TILE_NONE:
1523 needs_preview = FALSE(0);
1524 break;
1525
1526 default:
1527 if (!META_WINDOW_SIDE_TILED (window)((window)->tiled && ((window)->tile_mode == META_TILE_LEFT
|| (window)->tile_mode == META_TILE_RIGHT))
)
1528 needs_preview = TRUE(!(0));
1529 break;
1530
1531 }
1532 }
1533
1534 if (needs_preview)
1535 {
1536 MetaRectangle tile_rect;
1537
1538 meta_window_get_current_tile_area (window, &tile_rect);
1539 meta_tile_preview_show (screen->tile_preview, &tile_rect, screen);
1540 }
1541 else
1542 meta_tile_preview_hide (screen->tile_preview);
1543
1544 return FALSE(0);
1545}
1546
1547#define TILE_PREVIEW_TIMEOUT_MS200 200
1548
1549void
1550meta_screen_tile_preview_update (MetaScreen *screen,
1551 gboolean delay)
1552{
1553 if (delay)
1554 {
1555 if (screen->tile_preview_timeout_id > 0)
1556 return;
1557
1558 screen->tile_preview_timeout_id =
1559 g_timeout_add (TILE_PREVIEW_TIMEOUT_MS200,
1560 meta_screen_tile_preview_update_timeout,
1561 screen);
1562 }
1563 else
1564 {
1565 if (screen->tile_preview_timeout_id > 0)
1566 g_source_remove (screen->tile_preview_timeout_id);
1567
1568 meta_screen_tile_preview_update_timeout ((gpointer)screen);
1569 }
1570}
1571
1572void
1573meta_screen_tile_preview_hide (MetaScreen *screen)
1574{
1575 if (screen->tile_preview_timeout_id > 0)
1576 g_source_remove (screen->tile_preview_timeout_id);
1577
1578 if (screen->tile_preview)
1579 meta_tile_preview_hide (screen->tile_preview);
1580}
1581
1582MetaWindow*
1583meta_screen_get_mouse_window (MetaScreen *screen,
1584 MetaWindow *not_this_one)
1585{
1586 MetaWindow *window;
1587 Window root_return, child_return;
1588 int root_x_return, root_y_return;
1589 int win_x_return, win_y_return;
1590 unsigned int mask_return;
1591
1592 if (not_this_one)
1593 meta_topicmeta_topic_real (META_DEBUG_FOCUS,
1594 "Focusing mouse window excluding %s\n", not_this_one->desc);
1595
1596 meta_error_trap_push (screen->display);
1597 XQueryPointer (screen->display->xdisplay,
1598 screen->xroot,
1599 &root_return,
1600 &child_return,
1601 &root_x_return,
1602 &root_y_return,
1603 &win_x_return,
1604 &win_y_return,
1605 &mask_return);
1606 meta_error_trap_pop (screen->display, TRUE(!(0)));
1607
1608 window = meta_stack_get_default_focus_window_at_point (screen->stack,
1609 screen->active_workspace,
1610 not_this_one,
1611 root_x_return,
1612 root_y_return);
1613
1614 return window;
1615}
1616
1617const MetaXineramaScreenInfo*
1618meta_screen_get_xinerama_for_rect (MetaScreen *screen,
1619 MetaRectangle *rect)
1620{
1621 int i;
1622 int best_xinerama, xinerama_score;
1623
1624 if (screen->n_xinerama_infos == 1)
1625 return &screen->xinerama_infos[0];
1626
1627 best_xinerama = 0;
1628 xinerama_score = 0;
1629
1630 for (i = 0; i < screen->n_xinerama_infos; i++)
1631 {
1632 MetaRectangle dest;
1633 if (meta_rectangle_intersect (&screen->xinerama_infos[i].rect,
1634 rect,
1635 &dest))
1636 {
1637 int cur = meta_rectangle_area (&dest);
1638 if (cur > xinerama_score)
1639 {
1640 xinerama_score = cur;
1641 best_xinerama = i;
1642 }
1643 }
1644 }
1645
1646 return &screen->xinerama_infos[best_xinerama];
1647}
1648
1649const MetaXineramaScreenInfo*
1650meta_screen_get_xinerama_for_window (MetaScreen *screen,
1651 MetaWindow *window)
1652{
1653 MetaRectangle window_rect;
1654
1655 meta_window_get_outer_rect (window, &window_rect);
1656
1657 return meta_screen_get_xinerama_for_rect (screen, &window_rect);
1658}
1659
1660const MetaXineramaScreenInfo*
1661meta_screen_get_xinerama_neighbor (MetaScreen *screen,
1662 int which_xinerama,
1663 MetaScreenDirection direction)
1664{
1665 MetaXineramaScreenInfo* input = screen->xinerama_infos + which_xinerama;
1666 MetaXineramaScreenInfo* current;
1667 int i;
1668
1669 for (i = 0; i < screen->n_xinerama_infos; i++)
1670 {
1671 current = screen->xinerama_infos + i;
1672
1673 if ((direction == META_SCREEN_RIGHT &&
1674 current->rect.x == input->rect.x + input->rect.width &&
1675 meta_rectangle_vert_overlap(&current->rect, &input->rect)) ||
1676 (direction == META_SCREEN_LEFT &&
1677 input->rect.x == current->rect.x + current->rect.width &&
1678 meta_rectangle_vert_overlap(&current->rect, &input->rect)) ||
1679 (direction == META_SCREEN_UP &&
1680 input->rect.y == current->rect.y + current->rect.height &&
1681 meta_rectangle_horiz_overlap(&current->rect, &input->rect)) ||
1682 (direction == META_SCREEN_DOWN &&
1683 current->rect.y == input->rect.y + input->rect.height &&
1684 meta_rectangle_horiz_overlap(&current->rect, &input->rect)))
1685 {
1686 return current;
1687 }
1688 }
1689
1690 return NULL((void*)0);
1691}
1692
1693void
1694meta_screen_get_natural_xinerama_list (MetaScreen *screen,
1695 int** xineramas_list,
1696 int* n_xineramas)
1697{
1698 const MetaXineramaScreenInfo* current;
1699 GQueue* xinerama_queue;
1700 int* visited;
1701 int cur = 0;
1702 int i;
1703
1704 *n_xineramas = screen->n_xinerama_infos;
1705 *xineramas_list = g_new (int, screen->n_xinerama_infos)((int *) g_malloc_n ((screen->n_xinerama_infos), sizeof (int
)))
;
1706
1707 /* we calculate a natural ordering by which to choose xineramas for
1708 * window placement. We start at the current xinerama, and perform
1709 * a breadth-first search of the xineramas starting from that
1710 * xinerama. We choose preferentially left, then right, then down,
1711 * then up. The visitation order produced by this traversal is the
1712 * natural xinerama ordering.
1713 */
1714
1715 visited = g_new (int, screen->n_xinerama_infos)((int *) g_malloc_n ((screen->n_xinerama_infos), sizeof (int
)))
;
1716 for (i = 0; i < screen->n_xinerama_infos; i++)
1
Assuming 'i' is < field 'n_xinerama_infos'
2
Loop condition is true. Entering loop body
3
Assuming 'i' is < field 'n_xinerama_infos'
4
Loop condition is true. Entering loop body
5
Assuming 'i' is < field 'n_xinerama_infos'
6
Loop condition is true. Entering loop body
7
Assuming 'i' is >= field 'n_xinerama_infos'
8
Loop condition is false. Execution continues on line 1721
1717 {
1718 visited[i] = FALSE(0);
1719 }
1720
1721 current = meta_screen_get_current_xinerama (screen);
1722 xinerama_queue = g_queue_new ();
1723 g_queue_push_tail (xinerama_queue, (gpointer) current);
1724 visited[current->number] = TRUE(!(0));
1725
1726 while (!g_queue_is_empty (xinerama_queue))
9
Assuming the condition is true
10
Loop condition is true. Entering loop body
15
Assuming the condition is false
16
Loop condition is false. Execution continues on line 1777
1727 {
1728 const MetaXineramaScreenInfo* tmp;
1729
1730 current = (const MetaXineramaScreenInfo*)
1731 g_queue_pop_head (xinerama_queue);
1732
1733 (*xineramas_list)[cur++] = current->number;
1734
1735 /* enqueue each of the directions */
1736 tmp = meta_screen_get_xinerama_neighbor (screen,
1737 current->number,
1738 META_SCREEN_LEFT);
1739 if (tmp && !visited[tmp->number])
11
Assuming 'tmp' is null
1740 {
1741 g_queue_push_tail (xinerama_queue,
1742 (MetaXineramaScreenInfo*) tmp);
1743 visited[tmp->number] = TRUE(!(0));
1744 }
1745 tmp = meta_screen_get_xinerama_neighbor (screen,
1746 current->number,
1747 META_SCREEN_RIGHT);
1748 if (tmp && !visited[tmp->number])
12
Assuming 'tmp' is null
1749 {
1750 g_queue_push_tail (xinerama_queue,
1751 (MetaXineramaScreenInfo*) tmp);
1752 visited[tmp->number] = TRUE(!(0));
1753 }
1754 tmp = meta_screen_get_xinerama_neighbor (screen,
1755 current->number,
1756 META_SCREEN_UP);
1757 if (tmp && !visited[tmp->number])
13
Assuming 'tmp' is null
1758 {
1759 g_queue_push_tail (xinerama_queue,
1760 (MetaXineramaScreenInfo*) tmp);
1761 visited[tmp->number] = TRUE(!(0));
1762 }
1763 tmp = meta_screen_get_xinerama_neighbor (screen,
1764 current->number,
1765 META_SCREEN_DOWN);
1766 if (tmp && !visited[tmp->number])
14
Assuming 'tmp' is null
1767 {
1768 g_queue_push_tail (xinerama_queue,
1769 (MetaXineramaScreenInfo*) tmp);
1770 visited[tmp->number] = TRUE(!(0));
1771 }
1772 }
1773
1774 /* in case we somehow missed some set of xineramas, go through the
1775 * visited list and add in any xineramas that were missed
1776 */
1777 for (i = 0; i < screen->n_xinerama_infos; i++)
17
Assuming 'i' is < field 'n_xinerama_infos'
18
Loop condition is true. Entering loop body
21
Assuming 'i' is < field 'n_xinerama_infos'
22
Loop condition is true. Entering loop body
25
Assuming 'i' is < field 'n_xinerama_infos'
26
Loop condition is true. Entering loop body
1778 {
1779 if (visited[i] == FALSE(0))
19
Assuming the condition is true
20
Taking true branch
23
Assuming the condition is true
24
Taking true branch
27
Assuming the condition is true
28
Taking true branch
1780 {
1781 (*xineramas_list)[cur++] = i;
29
Out of bound memory access (access exceeds upper limit of memory block)
1782 }
1783 }
1784
1785 g_free (visited);
1786 g_queue_free (xinerama_queue);
1787}
1788
1789const MetaXineramaScreenInfo*
1790meta_screen_get_current_xinerama (MetaScreen *screen)
1791{
1792 if (screen->n_xinerama_infos == 1)
1793 return &screen->xinerama_infos[0];
1794
1795 /* Sadly, we have to do it this way. Yuck.
1796 */
1797
1798 if (screen->display->xinerama_cache_invalidated)
1799 {
1800 Window root_return, child_return;
1801 int win_x_return, win_y_return;
1802 unsigned int mask_return;
1803 int i;
1804 MetaRectangle pointer_position;
1805
1806 screen->display->xinerama_cache_invalidated = FALSE(0);
1807
1808 pointer_position.width = pointer_position.height = 1;
1809 XQueryPointer (screen->display->xdisplay,
1810 screen->xroot,
1811 &root_return,
1812 &child_return,
1813 &pointer_position.x,
1814 &pointer_position.y,
1815 &win_x_return,
1816 &win_y_return,
1817 &mask_return);
1818
1819 screen->last_xinerama_index = 0;
1820 for (i = 0; i < screen->n_xinerama_infos; i++)
1821 {
1822 if (meta_rectangle_contains_rect (&screen->xinerama_infos[i].rect,
1823 &pointer_position))
1824 {
1825 screen->last_xinerama_index = i;
1826 break;
1827 }
1828 }
1829
1830 meta_topicmeta_topic_real (META_DEBUG_XINERAMA,
1831 "Rechecked current Xinerama, now %d\n",
1832 screen->last_xinerama_index);
1833 }
1834
1835 return &screen->xinerama_infos[screen->last_xinerama_index];
1836}
1837
1838#define _NET_WM_ORIENTATION_HORZ0 0
1839#define _NET_WM_ORIENTATION_VERT1 1
1840
1841#define _NET_WM_TOPLEFT0 0
1842#define _NET_WM_TOPRIGHT1 1
1843#define _NET_WM_BOTTOMRIGHT2 2
1844#define _NET_WM_BOTTOMLEFT3 3
1845
1846void
1847meta_screen_update_workspace_layout (MetaScreen *screen)
1848{
1849 gulong *list;
1850 int n_items;
1851
1852 list = NULL((void*)0);
1853 n_items = 0;
1854
1855 if (meta_prop_get_cardinal_list (screen->display,
1856 screen->xroot,
1857 screen->display->atom__NET_DESKTOP_LAYOUT,
1858 &list, &n_items))
1859 {
1860 if (n_items == 3 || n_items == 4)
1861 {
1862 int cols, rows;
1863
1864 switch (list[0])
1865 {
1866 case _NET_WM_ORIENTATION_HORZ0:
1867 screen->vertical_workspaces = FALSE(0);
1868 break;
1869 case _NET_WM_ORIENTATION_VERT1:
1870 screen->vertical_workspaces = TRUE(!(0));
1871 break;
1872 default:
1873 meta_warning ("Someone set a weird orientation in _NET_DESKTOP_LAYOUT\n");
1874 break;
1875 }
1876
1877 cols = list[1];
1878 rows = list[2];
1879
1880 if (rows <= 0 && cols <= 0)
1881 {
1882 meta_warning ("Columns = %d rows = %d in _NET_DESKTOP_LAYOUT makes no sense\n", rows, cols);
1883 }
1884 else
1885 {
1886 if (rows > 0)
1887 screen->rows_of_workspaces = rows;
1888 else
1889 screen->rows_of_workspaces = -1;
1890
1891 if (cols > 0)
1892 screen->columns_of_workspaces = cols;
1893 else
1894 screen->columns_of_workspaces = -1;
1895 }
1896
1897 if (n_items == 4)
1898 {
1899 switch (list[3])
1900 {
1901 case _NET_WM_TOPLEFT0:
1902 screen->starting_corner = META_SCREEN_TOPLEFT;
1903 break;
1904 case _NET_WM_TOPRIGHT1:
1905 screen->starting_corner = META_SCREEN_TOPRIGHT;
1906 break;
1907 case _NET_WM_BOTTOMRIGHT2:
1908 screen->starting_corner = META_SCREEN_BOTTOMRIGHT;
1909 break;
1910 case _NET_WM_BOTTOMLEFT3:
1911 screen->starting_corner = META_SCREEN_BOTTOMLEFT;
1912 break;
1913 default:
1914 meta_warning ("Someone set a weird starting corner in _NET_DESKTOP_LAYOUT\n");
1915 break;
1916 }
1917 }
1918 else
1919 screen->starting_corner = META_SCREEN_TOPLEFT;
1920 }
1921 else
1922 {
1923 meta_warning ("Someone set _NET_DESKTOP_LAYOUT to %d integers instead of 4 "
1924 "(3 is accepted for backwards compat)\n", n_items);
1925 }
1926
1927 meta_XFree (list)do { if ((list)) XFree ((list)); } while (0);
1928 }
1929
1930 meta_verbosemeta_verbose_real ("Workspace layout rows = %d cols = %d orientation = %d starting corner = %u\n",
1931 screen->rows_of_workspaces,
1932 screen->columns_of_workspaces,
1933 screen->vertical_workspaces,
1934 screen->starting_corner);
1935}
1936
1937static void
1938set_workspace_names (MetaScreen *screen)
1939{
1940 /* This updates names on root window when the pref changes,
1941 * note we only get prefs change notify if things have
1942 * really changed.
1943 */
1944 GString *flattened;
1945 int i;
1946 int n_spaces;
1947
1948 /* flatten to nul-separated list */
1949 n_spaces = meta_screen_get_n_workspaces (screen);
1950 flattened = g_string_new ("");
1951 i = 0;
1952 while (i < n_spaces)
1953 {
1954 const char *name;
1955
1956 name = meta_prefs_get_workspace_name (i);
1957
1958 if (name)
1959 g_string_append_len (flattened, name,g_string_append_len_inline (flattened, name, strlen (name) + 1
)
1960 strlen (name) + 1)g_string_append_len_inline (flattened, name, strlen (name) + 1
)
;
1961 else
1962 g_string_append_len (flattened, "", 1)g_string_append_len_inline (flattened, "", 1);
1963
1964 ++i;
1965 }
1966
1967 meta_error_trap_push (screen->display);
1968 XChangeProperty (screen->display->xdisplay,
1969 screen->xroot,
1970 screen->display->atom__NET_DESKTOP_NAMES,
1971 screen->display->atom_UTF8_STRING,
1972 8, PropModeReplace0,
1973 (unsigned char *)flattened->str, flattened->len);
1974 meta_error_trap_pop (screen->display, FALSE(0));
1975
1976 g_string_free (flattened, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(flattened), ((!(0)))) : g_string_free_and_steal (flattened))
: (g_string_free) ((flattened), ((!(0)))))
;
1977}
1978
1979void
1980meta_screen_update_workspace_names (MetaScreen *screen)
1981{
1982 char **names;
1983 int n_names;
1984 int i;
1985
1986 /* this updates names in prefs when the root window property changes,
1987 * iff the new property contents don't match what's already in prefs
1988 */
1989
1990 names = NULL((void*)0);
1991 n_names = 0;
1992 if (!meta_prop_get_utf8_list (screen->display,
1993 screen->xroot,
1994 screen->display->atom__NET_DESKTOP_NAMES,
1995 &names, &n_names))
1996 {
1997 meta_verbosemeta_verbose_real ("Failed to get workspace names from root window %d\n",
1998 screen->number);
1999 return;
2000 }
2001
2002 i = 0;
2003 while (i < n_names)
2004 {
2005 meta_topicmeta_topic_real (META_DEBUG_PREFS,
2006 "Setting workspace %d name to \"%s\" due to _NET_DESKTOP_NAMES change\n",
2007 i, names[i] ? names[i] : "null");
2008 meta_prefs_change_workspace_name (i, names[i]);
2009
2010 ++i;
2011 }
2012
2013 g_strfreev (names);
2014}
2015
2016Window
2017meta_create_offscreen_window (Display *xdisplay,
2018 Window parent,
2019 long valuemask)
2020{
2021 XSetWindowAttributes attrs;
2022
2023 /* we want to be override redirect because sometimes we
2024 * create a window on a screen we aren't managing.
2025 * (but on a display we are managing at least one screen for)
2026 */
2027 attrs.override_redirect = True1;
2028 attrs.event_mask = valuemask;
2029
2030 return XCreateWindow (xdisplay,
2031 parent,
2032 -100, -100, 1, 1,
2033 0,
2034 CopyFromParent0L,
2035 CopyFromParent0L,
2036 (Visual *)CopyFromParent0L,
2037 CWOverrideRedirect(1L<<9) | CWEventMask(1L<<11),
2038 &attrs);
2039}
2040
2041static void
2042set_work_area_hint (MetaScreen *screen)
2043{
2044 int num_workspaces;
2045 GList *tmp_list;
2046 unsigned long *data, *tmp;
2047 MetaRectangle area;
2048
2049 num_workspaces = meta_screen_get_n_workspaces (screen);
2050 data = g_new (unsigned long, num_workspaces * 4)((unsigned long *) g_malloc_n ((num_workspaces * 4), sizeof (
unsigned long)))
;
2051 tmp_list = screen->workspaces;
2052 tmp = data;
2053
2054 while (tmp_list != NULL((void*)0))
2055 {
2056 MetaWorkspace *workspace = tmp_list->data;
2057
2058 if (workspace->screen == screen)
2059 {
2060 meta_workspace_get_work_area_all_xineramas (workspace, &area);
2061 tmp[0] = area.x;
2062 tmp[1] = area.y;
2063 tmp[2] = area.width;
2064 tmp[3] = area.height;
2065
2066 tmp += 4;
2067 }
2068
2069 tmp_list = tmp_list->next;
2070 }
2071
2072 meta_error_trap_push (screen->display);
2073 XChangeProperty (screen->display->xdisplay, screen->xroot,
2074 screen->display->atom__NET_WORKAREA,
2075 XA_CARDINAL((Atom) 6), 32, PropModeReplace0,
2076 (guchar*) data, num_workspaces*4);
2077 g_free (data);
2078 meta_error_trap_pop (screen->display, FALSE(0));
2079}
2080
2081static gboolean
2082set_work_area_idle_func (MetaScreen *screen)
2083{
2084 meta_topicmeta_topic_real (META_DEBUG_WORKAREA,
2085 "Running work area idle function\n");
2086
2087 screen->work_area_idle = 0;
2088
2089 set_work_area_hint (screen);
2090
2091 return FALSE(0);
2092}
2093
2094void
2095meta_screen_queue_workarea_recalc (MetaScreen *screen)
2096{
2097 /* Recompute work area in an idle */
2098 if (screen->work_area_idle == 0)
2099 {
2100 meta_topicmeta_topic_real (META_DEBUG_WORKAREA,
2101 "Adding work area hint idle function\n");
2102 screen->work_area_idle =
2103 g_idle_add_full (META_PRIORITY_WORK_AREA_HINT(200 + 15),
2104 (GSourceFunc) set_work_area_idle_func,
2105 screen,
2106 NULL((void*)0));
2107 }
2108}
2109
2110
2111#ifdef WITH_VERBOSE_MODE1
2112static char *
2113meta_screen_corner_to_string (MetaScreenCorner corner)
2114{
2115 switch (corner)
2116 {
2117 case META_SCREEN_TOPLEFT:
2118 return "TopLeft";
2119 case META_SCREEN_TOPRIGHT:
2120 return "TopRight";
2121 case META_SCREEN_BOTTOMLEFT:
2122 return "BottomLeft";
2123 case META_SCREEN_BOTTOMRIGHT:
2124 return "BottomRight";
2125 }
2126
2127 return "Unknown";
2128}
2129#endif /* WITH_VERBOSE_MODE */
2130
2131void
2132meta_screen_calc_workspace_layout (MetaScreen *screen,
2133 int num_workspaces,
2134 int current_space,
2135 MetaWorkspaceLayout *layout)
2136{
2137 int rows, cols;
2138 int grid_area;
2139 int *grid;
2140 int i, r, c;
2141 int current_row, current_col;
2142
2143 rows = screen->rows_of_workspaces;
2144 cols = screen->columns_of_workspaces;
2145 if (rows <= 0 && cols <= 0)
2146 cols = num_workspaces;
2147
2148 if (rows <= 0)
2149 rows = num_workspaces / cols + ((num_workspaces % cols) > 0 ? 1 : 0);
2150 if (cols <= 0)
2151 cols = num_workspaces / rows + ((num_workspaces % rows) > 0 ? 1 : 0);
2152
2153 /* paranoia */
2154 if (rows < 1)
2155 rows = 1;
2156 if (cols < 1)
2157 cols = 1;
2158
2159 g_assert (rows != 0 && cols != 0)do { if (rows != 0 && cols != 0) ; else g_assertion_message_expr
("croma", "core/screen.c", 2159, ((const char*) (__func__)),
"rows != 0 && cols != 0"); } while (0)
;
2160
2161 grid_area = rows * cols;
2162
2163 meta_verbosemeta_verbose_real ("Getting layout rows = %d cols = %d current = %d "
2164 "num_spaces = %d vertical = %s corner = %s\n",
2165 rows, cols, current_space, num_workspaces,
2166 screen->vertical_workspaces ? "(true)" : "(false)",
2167 meta_screen_corner_to_string (screen->starting_corner));
2168
2169 /* ok, we want to setup the distances in the workspace array to go
2170 * in each direction. Remember, there are many ways that a workspace
2171 * array can be setup.
2172 * see http://www.freedesktop.org/standards/wm-spec/1.2/html/x109.html
2173 * and look at the _NET_DESKTOP_LAYOUT section for details.
2174 * For instance:
2175 */
2176 /* starting_corner = META_SCREEN_TOPLEFT
2177 * vertical_workspaces = 0 vertical_workspaces=1
2178 * 1234 1357
2179 * 5678 2468
2180 *
2181 * starting_corner = META_SCREEN_TOPRIGHT
2182 * vertical_workspaces = 0 vertical_workspaces=1
2183 * 4321 7531
2184 * 8765 8642
2185 *
2186 * starting_corner = META_SCREEN_BOTTOMLEFT
2187 * vertical_workspaces = 0 vertical_workspaces=1
2188 * 5678 2468
2189 * 1234 1357
2190 *
2191 * starting_corner = META_SCREEN_BOTTOMRIGHT
2192 * vertical_workspaces = 0 vertical_workspaces=1
2193 * 8765 8642
2194 * 4321 7531
2195 *
2196 */
2197 /* keep in mind that we could have a ragged layout, e.g. the "8"
2198 * in the above grids could be missing
2199 */
2200
2201
2202 grid = g_new (int, grid_area)((int *) g_malloc_n ((grid_area), sizeof (int)));
2203
2204 i = 0;
2205 switch (screen->starting_corner)
2206 {
2207 case META_SCREEN_TOPLEFT:
2208 if (screen->vertical_workspaces)
2209 {
2210 c = 0;
2211 while (c < cols)
2212 {
2213 r = 0;
2214 while (r < rows)
2215 {
2216 grid[r*cols+c] = i;
2217 ++i;
2218 ++r;
2219 }
2220 ++c;
2221 }
2222 }
2223 else
2224 {
2225 r = 0;
2226 while (r < rows)
2227 {
2228 c = 0;
2229 while (c < cols)
2230 {
2231 grid[r*cols+c] = i;
2232 ++i;
2233 ++c;
2234 }
2235 ++r;
2236 }
2237 }
2238 break;
2239 case META_SCREEN_TOPRIGHT:
2240 if (screen->vertical_workspaces)
2241 {
2242 c = cols - 1;
2243 while (c >= 0)
2244 {
2245 r = 0;
2246 while (r < rows)
2247 {
2248 grid[r*cols+c] = i;
2249 ++i;
2250 ++r;
2251 }
2252 --c;
2253 }
2254 }
2255 else
2256 {
2257 r = 0;
2258 while (r < rows)
2259 {
2260 c = cols - 1;
2261 while (c >= 0)
2262 {
2263 grid[r*cols+c] = i;
2264 ++i;
2265 --c;
2266 }
2267 ++r;
2268 }
2269 }
2270 break;
2271 case META_SCREEN_BOTTOMLEFT:
2272 if (screen->vertical_workspaces)
2273 {
2274 c = 0;
2275 while (c < cols)
2276 {
2277 r = rows - 1;
2278 while (r >= 0)
2279 {
2280 grid[r*cols+c] = i;
2281 ++i;
2282 --r;
2283 }
2284 ++c;
2285 }
2286 }
2287 else
2288 {
2289 r = rows - 1;
2290 while (r >= 0)
2291 {
2292 c = 0;
2293 while (c < cols)
2294 {
2295 grid[r*cols+c] = i;
2296 ++i;
2297 ++c;
2298 }
2299 --r;
2300 }
2301 }
2302 break;
2303 case META_SCREEN_BOTTOMRIGHT:
2304 if (screen->vertical_workspaces)
2305 {
2306 c = cols - 1;
2307 while (c >= 0)
2308 {
2309 r = rows - 1;
2310 while (r >= 0)
2311 {
2312 grid[r*cols+c] = i;
2313 ++i;
2314 --r;
2315 }
2316 --c;
2317 }
2318 }
2319 else
2320 {
2321 r = rows - 1;
2322 while (r >= 0)
2323 {
2324 c = cols - 1;
2325 while (c >= 0)
2326 {
2327 grid[r*cols+c] = i;
2328 ++i;
2329 --c;
2330 }
2331 --r;
2332 }
2333 }
2334 break;
2335 }
2336
2337 if (i != grid_area)
2338 meta_bug ("did not fill in the whole workspace grid in %s (%d filled)\n",
2339 G_STRFUNC((const char*) (__func__)), i);
2340
2341 current_row = 0;
2342 current_col = 0;
2343 r = 0;
2344 while (r < rows)
2345 {
2346 c = 0;
2347 while (c < cols)
2348 {
2349 if (grid[r*cols+c] == current_space)
2350 {
2351 current_row = r;
2352 current_col = c;
2353 }
2354 else if (grid[r*cols+c] >= num_workspaces)
2355 {
2356 /* flag nonexistent spaces with -1 */
2357 grid[r*cols+c] = -1;
2358 }
2359 ++c;
2360 }
2361 ++r;
2362 }
2363
2364 layout->rows = rows;
2365 layout->cols = cols;
2366 layout->grid = grid;
2367 layout->grid_area = grid_area;
2368 layout->current_row = current_row;
2369 layout->current_col = current_col;
2370
2371#ifdef WITH_VERBOSE_MODE1
2372 if (meta_is_verbose ())
2373 {
2374 r = 0;
2375 while (r < layout->rows)
2376 {
2377 meta_verbosemeta_verbose_real (" ");
2378 meta_push_no_msg_prefix ();
2379 c = 0;
2380 while (c < layout->cols)
2381 {
2382 if (r == layout->current_row &&
2383 c == layout->current_col)
2384 meta_verbosemeta_verbose_real ("*%2d ", layout->grid[r*layout->cols+c]);
2385 else
2386 meta_verbosemeta_verbose_real ("%3d ", layout->grid[r*layout->cols+c]);
2387 ++c;
2388 }
2389 meta_verbosemeta_verbose_real ("\n");
2390 meta_pop_no_msg_prefix ();
2391 ++r;
2392 }
2393 }
2394#endif /* WITH_VERBOSE_MODE */
2395}
2396
2397void
2398meta_screen_free_workspace_layout (MetaWorkspaceLayout *layout)
2399{
2400 g_free (layout->grid);
2401}
2402
2403static void
2404meta_screen_resize_func (MetaScreen *screen,
2405 MetaWindow *window,
2406 void *user_data)
2407{
2408 if (window->struts)
2409 {
2410 meta_window_update_struts (window);
2411 }
2412 meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
2413
2414 meta_window_recalc_features (window);
2415}
2416
2417void
2418meta_screen_resize (MetaScreen *screen,
2419 int width,
2420 int height)
2421{
2422 screen->rect.width = width;
2423 screen->rect.height = height;
2424
2425 reload_xinerama_infos (screen);
2426 set_desktop_geometry_hint (screen);
2427
2428 /* Queue a resize on all the windows */
2429 meta_screen_foreach_window (screen, meta_screen_resize_func, 0);
2430}
2431
2432void
2433meta_screen_update_showing_desktop_hint (MetaScreen *screen)
2434{
2435 unsigned long data[1];
2436
2437 data[0] = screen->active_workspace->showing_desktop ? 1 : 0;
2438
2439 meta_error_trap_push (screen->display);
2440 XChangeProperty (screen->display->xdisplay, screen->xroot,
2441 screen->display->atom__NET_SHOWING_DESKTOP,
2442 XA_CARDINAL((Atom) 6),
2443 32, PropModeReplace0, (guchar*) data, 1);
2444 meta_error_trap_pop (screen->display, FALSE(0));
2445}
2446
2447static void
2448queue_windows_showing (MetaScreen *screen)
2449{
2450 GSList *windows;
2451 GSList *tmp;
2452
2453 /* Must operate on all windows on display instead of just on the
2454 * active_workspace's window list, because the active_workspace's
2455 * window list may not contain the on_all_workspace windows.
2456 */
2457 windows = meta_display_list_windows (screen->display);
2458
2459 tmp = windows;
2460 while (tmp != NULL((void*)0))
2461 {
2462 MetaWindow *w = tmp->data;
2463
2464 if (w->screen == screen && !meta_prefs_is_in_skip_list (w->res_class))
2465 meta_window_queue (w, META_QUEUE_CALC_SHOWING);
2466
2467 tmp = tmp->next;
2468 }
2469
2470 g_slist_free (windows);
2471}
2472
2473void
2474meta_screen_minimize_all_on_active_workspace_except (MetaScreen *screen,
2475 MetaWindow *keep)
2476{
2477 GList *windows;
2478 GList *tmp;
2479
2480 windows = screen->active_workspace->windows;
2481
2482 tmp = windows;
2483 while (tmp != NULL((void*)0))
2484 {
2485 MetaWindow *w = tmp->data;
2486
2487 if (w->screen == screen &&
2488 w->has_minimize_func &&
2489 w != keep)
2490 meta_window_minimize (w);
2491
2492 tmp = tmp->next;
2493 }
2494}
2495
2496void
2497meta_screen_show_desktop (MetaScreen *screen,
2498 guint32 timestamp)
2499{
2500 GList *windows;
2501
2502 if (screen->active_workspace->showing_desktop)
2503 return;
2504
2505 screen->active_workspace->showing_desktop = TRUE(!(0));
2506
2507 queue_windows_showing (screen);
2508
2509 /* Focus the most recently used META_WINDOW_DESKTOP window, if there is one;
2510 * see bug 159257.
2511 */
2512 windows = screen->active_workspace->mru_list;
2513 while (windows != NULL((void*)0))
2514 {
2515 MetaWindow *w = windows->data;
2516
2517 if (w->screen == screen &&
2518 w->type == META_WINDOW_DESKTOP &&
2519 !meta_prefs_is_in_skip_list (w->res_class))
2520 {
2521 meta_window_focus (w, timestamp);
2522 break;
2523 }
2524
2525 windows = windows->next;
2526 }
2527
2528
2529 meta_screen_update_showing_desktop_hint (screen);
2530}
2531
2532void
2533meta_screen_unshow_desktop (MetaScreen *screen)
2534{
2535 if (!screen->active_workspace->showing_desktop)
2536 return;
2537
2538 screen->active_workspace->showing_desktop = FALSE(0);
2539
2540 queue_windows_showing (screen);
2541
2542 meta_screen_update_showing_desktop_hint (screen);
2543}
2544
2545
2546#ifdef HAVE_STARTUP_NOTIFICATION
2547static gboolean startup_sequence_timeout (void *data);
2548
2549static void
2550update_startup_feedback (MetaScreen *screen)
2551{
2552 if (screen->startup_sequences != NULL((void*)0))
2553 {
2554 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2555 "Setting busy cursor\n");
2556 meta_screen_set_cursor (screen, META_CURSOR_BUSY);
2557 }
2558 else
2559 {
2560 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2561 "Setting default cursor\n");
2562 meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
2563 }
2564}
2565
2566static void
2567add_sequence (MetaScreen *screen,
2568 SnStartupSequence *sequence)
2569{
2570 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2571 "Adding sequence %s\n",
2572 sn_startup_sequence_get_id (sequence));
2573 sn_startup_sequence_ref (sequence);
2574 screen->startup_sequences = g_slist_prepend (screen->startup_sequences,
2575 sequence);
2576
2577 /* our timeout just polls every second, instead of bothering
2578 * to compute exactly when we may next time out
2579 */
2580 if (screen->startup_sequence_timeout == 0)
2581 screen->startup_sequence_timeout = g_timeout_add (1000,
2582 startup_sequence_timeout,
2583 screen);
2584
2585 update_startup_feedback (screen);
2586}
2587
2588static void
2589remove_sequence (MetaScreen *screen,
2590 SnStartupSequence *sequence)
2591{
2592 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2593 "Removing sequence %s\n",
2594 sn_startup_sequence_get_id (sequence));
2595
2596 screen->startup_sequences = g_slist_remove (screen->startup_sequences,
2597 sequence);
2598 sn_startup_sequence_unref (sequence);
2599
2600 if (screen->startup_sequences == NULL((void*)0) &&
2601 screen->startup_sequence_timeout != 0)
2602 {
2603 g_source_remove (screen->startup_sequence_timeout);
2604 screen->startup_sequence_timeout = 0;
2605 }
2606
2607 update_startup_feedback (screen);
2608}
2609
2610typedef struct
2611{
2612 GSList *list;
2613 gint64 now;
2614} CollectTimedOutData;
2615
2616/* This should be fairly long, as it should never be required unless
2617 * apps or .desktop files are buggy, and it's confusing if
2618 * OpenOffice or whatever seems to stop launching - people
2619 * might decide they need to launch it again.
2620 */
2621#define STARTUP_TIMEOUT15000 15000
2622
2623static void
2624collect_timed_out_foreach (void *element,
2625 void *data)
2626{
2627 CollectTimedOutData *ctod = data;
2628 SnStartupSequence *sequence = element;
2629 double elapsed;
2630
2631 time_t tv_sec;
2632 suseconds_t tv_usec;
2633 gint64 tv;
2634
2635 sn_startup_sequence_get_last_active_time (sequence, &tv_sec, &tv_usec);
2636 tv = (tv_sec * G_USEC_PER_SEC1000000) + tv_usec;
2637 elapsed = (ctod->now - tv) / 1000.0;
2638
2639 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2640 "Sequence used %g seconds vs. %g max: %s\n",
2641 elapsed, (double) STARTUP_TIMEOUT15000,
2642 sn_startup_sequence_get_id (sequence));
2643
2644 if (elapsed > STARTUP_TIMEOUT15000)
2645 ctod->list = g_slist_prepend (ctod->list, sequence);
2646}
2647
2648static gboolean
2649startup_sequence_timeout (void *data)
2650{
2651 MetaScreen *screen = data;
2652 CollectTimedOutData ctod;
2653 GSList *tmp;
2654
2655 ctod.list = NULL((void*)0);
2656
2657 ctod.now = g_get_real_time ();
2658 g_slist_foreach (screen->startup_sequences,
2659 collect_timed_out_foreach,
2660 &ctod);
2661
2662 tmp = ctod.list;
2663 while (tmp != NULL((void*)0))
2664 {
2665 SnStartupSequence *sequence = tmp->data;
2666
2667 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2668 "Timed out sequence %s\n",
2669 sn_startup_sequence_get_id (sequence));
2670
2671 sn_startup_sequence_complete (sequence);
2672
2673 tmp = tmp->next;
2674 }
2675
2676 g_slist_free (ctod.list);
2677
2678 if (screen->startup_sequences != NULL((void*)0))
2679 {
2680 return TRUE(!(0));
2681 }
2682 else
2683 {
2684 /* remove */
2685 screen->startup_sequence_timeout = 0;
2686 return FALSE(0);
2687 }
2688}
2689
2690static void
2691meta_screen_sn_event (SnMonitorEvent *event,
2692 void *user_data)
2693{
2694 MetaScreen *screen;
2695 SnStartupSequence *sequence;
2696
2697 screen = user_data;
2698
2699 sequence = sn_monitor_event_get_startup_sequence (event);
2700
2701 switch (sn_monitor_event_get_type (event))
2702 {
2703 case SN_MONITOR_EVENT_INITIATED:
2704 {
2705 const char *wmclass;
2706
2707 wmclass = sn_startup_sequence_get_wmclass (sequence);
2708
2709 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2710 "Received startup initiated for %s wmclass %s\n",
2711 sn_startup_sequence_get_id (sequence),
2712 wmclass ? wmclass : "(unset)");
2713 add_sequence (screen, sequence);
2714 }
2715 break;
2716
2717 case SN_MONITOR_EVENT_COMPLETED:
2718 {
2719 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2720 "Received startup completed for %s\n",
2721 sn_startup_sequence_get_id (sequence));
2722 remove_sequence (screen,
2723 sn_monitor_event_get_startup_sequence (event));
2724 }
2725 break;
2726
2727 case SN_MONITOR_EVENT_CHANGED:
2728 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2729 "Received startup changed for %s\n",
2730 sn_startup_sequence_get_id (sequence));
2731 break;
2732
2733 case SN_MONITOR_EVENT_CANCELED:
2734 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2735 "Received startup canceled for %s\n",
2736 sn_startup_sequence_get_id (sequence));
2737 break;
2738 }
2739}
2740#endif
2741
2742/* Sets the initial_timestamp and initial_workspace properties
2743 * of a window according to information given us by the
2744 * startup-notification library.
2745 *
2746 * Returns TRUE if startup properties have been applied, and
2747 * FALSE if they have not (for example, if they had already
2748 * been applied.)
2749 */
2750gboolean
2751meta_screen_apply_startup_properties (MetaScreen *screen,
2752 MetaWindow *window)
2753{
2754#ifdef HAVE_STARTUP_NOTIFICATION
2755 const char *startup_id;
2756 GSList *tmp;
2757 SnStartupSequence *sequence;
2758
2759 /* Does the window have a startup ID stored? */
2760 startup_id = meta_window_get_startup_id (window);
2761
2762 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2763 "Applying startup props to %s id \"%s\"\n",
2764 window->desc,
2765 startup_id ? startup_id : "(none)");
2766
2767 sequence = NULL((void*)0);
2768 if (startup_id == NULL((void*)0))
2769 {
2770 /* No startup ID stored for the window. Let's ask the
2771 * startup-notification library whether there's anything
2772 * stored for the resource name or resource class hints.
2773 */
2774 tmp = screen->startup_sequences;
2775 while (tmp != NULL((void*)0))
2776 {
2777 const char *wmclass;
2778
2779 wmclass = sn_startup_sequence_get_wmclass (tmp->data);
2780
2781 if (wmclass != NULL((void*)0) &&
2782 ((window->res_class &&
2783 strcmp (wmclass, window->res_class) == 0) ||
2784 (window->res_name &&
2785 strcmp (wmclass, window->res_name) == 0)))
2786 {
2787 sequence = tmp->data;
2788
2789 g_assert (window->startup_id == NULL)do { if (window->startup_id == ((void*)0)) ; else g_assertion_message_expr
("croma", "core/screen.c", 2789, ((const char*) (__func__)),
"window->startup_id == NULL"); } while (0)
;
2790 window->startup_id = g_strdup (sn_startup_sequence_get_id (sequence))g_strdup_inline (sn_startup_sequence_get_id (sequence));
2791 startup_id = window->startup_id;
2792
2793 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2794 "Ending legacy sequence %s due to window %s\n",
2795 sn_startup_sequence_get_id (sequence),
2796 window->desc);
2797
2798 sn_startup_sequence_complete (sequence);
2799 break;
2800 }
2801
2802 tmp = tmp->next;
2803 }
2804 }
2805
2806 /* Still no startup ID? Bail. */
2807 if (startup_id == NULL((void*)0))
2808 return FALSE(0);
2809
2810 /* We might get this far and not know the sequence ID (if the window
2811 * already had a startup ID stored), so let's look for one if we don't
2812 * already know it.
2813 */
2814 if (sequence == NULL((void*)0))
2815 {
2816 tmp = screen->startup_sequences;
2817 while (tmp != NULL((void*)0))
2818 {
2819 const char *id;
2820
2821 id = sn_startup_sequence_get_id (tmp->data);
2822
2823 if (strcmp (id, startup_id) == 0)
2824 {
2825 sequence = tmp->data;
2826 break;
2827 }
2828
2829 tmp = tmp->next;
2830 }
2831 }
2832
2833 if (sequence != NULL((void*)0))
2834 {
2835 gboolean changed_something = FALSE(0);
2836
2837 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2838 "Found startup sequence for window %s ID \"%s\"\n",
2839 window->desc, startup_id);
2840
2841 if (!window->initial_workspace_set)
2842 {
2843 int space = sn_startup_sequence_get_workspace (sequence);
2844 if (space >= 0)
2845 {
2846 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2847 "Setting initial window workspace to %d based on startup info\n",
2848 space);
2849
2850 window->initial_workspace_set = TRUE(!(0));
2851 window->initial_workspace = space;
2852 changed_something = TRUE(!(0));
2853 }
2854 }
2855
2856 if (!window->initial_timestamp_set)
2857 {
2858 guint32 timestamp = sn_startup_sequence_get_timestamp (sequence);
2859 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2860 "Setting initial window timestamp to %u based on startup info\n",
2861 timestamp);
2862
2863 window->initial_timestamp_set = TRUE(!(0));
2864 window->initial_timestamp = timestamp;
2865 changed_something = TRUE(!(0));
2866 }
2867
2868 return changed_something;
2869 }
2870 else
2871 {
2872 meta_topicmeta_topic_real (META_DEBUG_STARTUP,
2873 "Did not find startup sequence for window %s ID \"%s\"\n",
2874 window->desc, startup_id);
2875 }
2876
2877#endif /* HAVE_STARTUP_NOTIFICATION */
2878
2879 return FALSE(0);
2880}
2881
2882int
2883meta_screen_get_screen_number (MetaScreen *screen)
2884{
2885 return screen->number;
2886}
2887
2888MetaDisplay *
2889meta_screen_get_display (MetaScreen *screen)
2890{
2891 return screen->display;
2892}
2893
2894Window
2895meta_screen_get_xroot (MetaScreen *screen)
2896{
2897 return screen->xroot;
2898}
2899
2900void
2901meta_screen_get_size (MetaScreen *screen,
2902 int *width,
2903 int *height)
2904{
2905 *width = screen->rect.width;
2906 *height = screen->rect.height;
2907}
2908
2909gpointer
2910meta_screen_get_compositor_data (MetaScreen *screen)
2911{
2912 return screen->compositor_data;
2913}
2914
2915void
2916meta_screen_set_compositor_data (MetaScreen *screen,
2917 gpointer compositor)
2918{
2919 screen->compositor_data = compositor;
2920}
2921
2922#ifdef HAVE_COMPOSITE_EXTENSIONS1
2923void
2924meta_screen_set_cm_selection (MetaScreen *screen)
2925{
2926 screen->wm_cm_timestamp = meta_display_get_current_time_roundtrip (
2927 screen->display);
2928
2929 meta_verbosemeta_verbose_real ("Setting selection for screen: %d\n", screen->number);
2930 XSetSelectionOwner (screen->display->xdisplay, screen->wm_cm_atom,
2931 screen->wm_cm_selection_window, screen->wm_cm_timestamp);
2932}
2933
2934void
2935meta_screen_unset_cm_selection (MetaScreen *screen)
2936{
2937 XSetSelectionOwner (screen->display->xdisplay, screen->wm_cm_atom,
2938 None0L, screen->wm_cm_timestamp);
2939}
2940
2941gboolean
2942meta_screen_is_cm_selected (MetaScreen *screen)
2943{
2944 Window owner = XGetSelectionOwner (screen->display->xdisplay, screen->wm_cm_atom);
2945 return owner != None0L;
2946}
2947#endif /* HAVE_COMPOSITE_EXTENSIONS */