Bug Summary

File:core/screen.c
Warning:line 1779, column 11
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/sysprof-6 -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-08-05-233600-31145-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
29
Assuming 'i' is < field 'n_xinerama_infos'
30
Loop condition is true. Entering loop body
1778 {
1779 if (visited[i] == FALSE(0))
19
Assuming the condition is false
20
Taking false branch
23
Assuming the condition is false
24
Taking false branch
27
Assuming the condition is false
28
Taking false branch
31
Out of bound memory access (access exceeds upper limit of memory block)
1780 {
1781 (*xineramas_list)[cur++] = i;
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 */