1 /* $Id$
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., Inc., 51 Franklin Street, Fifth Floor, Boston,
16 MA 02110-1301, USA.
17
18
19 xfwm4 - (c) 2002-2011 Olivier Fourdan
20
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <X11/Xlib.h>
28 #include <X11/Xutil.h>
29 #include <X11/extensions/shape.h>
30 #include <X11/extensions/Xinerama.h>
31 #include <glib.h>
32 #include <gdk/gdk.h>
33 #include <gdk/gdkx.h>
34 #include <gtk/gtk.h>
35 #include <pango/pango.h>
36 #include <libxfce4util/libxfce4util.h>
37
38 #ifdef HAVE_RENDER
39 #include <X11/extensions/Xrender.h>
40 #endif
41
42 #ifdef HAVE_LIBSTARTUP_NOTIFICATION
43 #define SN_API_NOT_YET_FROZEN
44 #include <libsn/sn.h>
45 #endif
46
47 #include <common/xfwm-common.h>
48
49 #include "display.h"
50 #include "screen.h"
51 #include "misc.h"
52 #include "mywindow.h"
53 #include "compositor.h"
54 #include "ui_style.h"
55
56 #ifndef WM_EXITING_TIMEOUT
57 #define WM_EXITING_TIMEOUT 15 /*seconds */
58 #endif
59
60 gboolean
myScreenCheckWMAtom(ScreenInfo * screen_info,Atom atom)61 myScreenCheckWMAtom (ScreenInfo *screen_info, Atom atom)
62 {
63 gchar selection[32];
64 Atom wm_sn_atom;
65
66 TRACE ("atom %lu", atom);
67
68 g_snprintf (selection, sizeof (selection), "WM_S%d", screen_info->screen);
69 wm_sn_atom = XInternAtom (myScreenGetXDisplay (screen_info), selection, FALSE);
70
71 return (atom == wm_sn_atom);
72 }
73
74 static gboolean
myScreenSetWMAtom(ScreenInfo * screen_info,gboolean replace_wm)75 myScreenSetWMAtom (ScreenInfo *screen_info, gboolean replace_wm)
76 {
77 const char *wm_name;
78 gchar selection[32];
79 gchar *display_name;
80 gulong wait, timeout;
81 DisplayInfo *display_info;
82 XSetWindowAttributes attrs;
83 Window current_wm;
84 XEvent event;
85 Atom wm_sn_atom;
86
87
88 g_return_val_if_fail (screen_info, FALSE);
89 g_return_val_if_fail (screen_info->display_info, FALSE);
90
91 TRACE ("replace %i", replace_wm);
92
93 display_info = screen_info->display_info;
94 g_snprintf (selection, sizeof (selection), "WM_S%d", screen_info->screen);
95 wm_sn_atom = XInternAtom (display_info->dpy, selection, FALSE);
96 display_name = xfwm_make_display_name (screen_info->gscr);
97 wm_name = gdk_x11_screen_get_window_manager_name (screen_info->gscr);
98
99 XSync (display_info->dpy, FALSE);
100 current_wm = XGetSelectionOwner (display_info->dpy, wm_sn_atom);
101 if (current_wm)
102 {
103 if (!replace_wm)
104 {
105 g_print ("Another Window Manager (%s) is already running on screen %s\n", wm_name, display_name);
106 g_print ("To replace the current window manager, try \"--replace\"\n");
107 g_free (display_name);
108
109 return FALSE;
110 }
111 myDisplayErrorTrapPush (display_info);
112 attrs.event_mask = StructureNotifyMask;
113 XChangeWindowAttributes (display_info->dpy, current_wm, CWEventMask, &attrs);
114 if (myDisplayErrorTrapPop (display_info))
115 {
116 current_wm = None;
117 }
118 }
119
120 if (!setXAtomManagerOwner (display_info, wm_sn_atom, screen_info->xroot, screen_info->xfwm4_win))
121 {
122 g_warning ("Cannot acquire window manager selection on screen %s", display_name);
123 g_free (display_name);
124
125 return FALSE;
126 }
127
128 /* Waiting for previous window manager to exit */
129 if (current_wm)
130 {
131 g_print ("Waiting for current window manager (%s) on screen %s to exit:", wm_name, display_name);
132 wait = 0;
133 timeout = WM_EXITING_TIMEOUT * G_USEC_PER_SEC;
134 while (wait < timeout)
135 {
136 if (XCheckWindowEvent (display_info->dpy, current_wm, StructureNotifyMask, &event) && (event.type == DestroyNotify))
137 {
138 break;
139 }
140 g_usleep(G_USEC_PER_SEC / 10);
141 wait += G_USEC_PER_SEC / 10;
142 if (wait % G_USEC_PER_SEC == 0)
143 {
144 g_print (".");
145 }
146 }
147
148 if (wait >= timeout)
149 {
150 g_print(" Failed\n");
151 g_warning("Previous window manager (%s) on screen %s is not exiting", wm_name, display_name);
152 g_free (display_name);
153
154 return FALSE;
155 }
156 g_print(" Done\n");
157 }
158 g_free (display_name);
159
160 return TRUE;
161 }
162
163 ScreenInfo *
myScreenInit(DisplayInfo * display_info,GdkScreen * gscr,unsigned long event_mask,gboolean replace_wm)164 myScreenInit (DisplayInfo *display_info, GdkScreen *gscr, unsigned long event_mask, gboolean replace_wm)
165 {
166 #ifdef ENABLE_KDE_SYSTRAY_PROXY
167 gchar selection[32];
168 #endif
169 ScreenInfo *screen_info;
170 GdkWindow *event_win;
171 PangoLayout *layout;
172 long desktop_visible;
173 int i, j;
174
175 g_return_val_if_fail (display_info, NULL);
176 g_return_val_if_fail (GDK_IS_SCREEN (gscr), NULL);
177 TRACE ("entering");
178
179 screen_info = g_new0 (ScreenInfo, 1);
180 screen_info->params = g_new0 (XfwmParams, 1);
181
182 screen_info->display_info = display_info;
183 screen_info->gscr = gscr;
184 desktop_visible = 0;
185 layout = NULL;
186
187 /* Create a GTK window so that we are just like any other GTK application */
188 screen_info->gtk_win = gtk_window_new (GTK_WINDOW_POPUP);
189 gtk_window_set_screen (GTK_WINDOW (screen_info->gtk_win), gscr);
190 gtk_window_resize (GTK_WINDOW (screen_info->gtk_win), 5, 5);
191 gtk_window_move (GTK_WINDOW (screen_info->gtk_win), -1000, -1000);
192 gtk_widget_set_name (screen_info->gtk_win, "xfwm");
193 gtk_widget_show_now (screen_info->gtk_win);
194
195 /*
196 * The first time the first Gtk application on a display uses pango,
197 * pango grabs the XServer while it creates the font cache window.
198 * Therefore, force the cache window to be created now instead of
199 * trying to do it while we have another grab and deadlocking the server.
200 */
201 layout = gtk_widget_create_pango_layout (screen_info->gtk_win, "-");
202 pango_layout_get_pixel_extents (layout, NULL, NULL);
203 g_object_unref (G_OBJECT (layout));
204
205 screen_info->xscreen = gdk_x11_screen_get_xscreen (gscr);
206 screen_info->xroot = gdk_x11_window_get_xid (gdk_screen_get_root_window (gscr));
207 screen_info->screen = gdk_x11_screen_get_screen_number (gscr);
208 screen_info->cmap = DefaultColormapOfScreen (screen_info->xscreen);
209 screen_info->depth = DefaultDepth (display_info->dpy, screen_info->screen);
210 screen_info->visual = DefaultVisual (display_info->dpy, screen_info->screen);
211 screen_info->shape_win = (Window) None;
212 myScreenComputeSize (screen_info);
213
214 screen_info->xfwm4_win = gdk_x11_window_get_xid (gtk_widget_get_window (screen_info->gtk_win));
215 if (!myScreenSetWMAtom (screen_info, replace_wm))
216 {
217 gtk_widget_destroy (screen_info->gtk_win);
218 g_free (screen_info);
219 return NULL;
220 }
221
222 event_win = eventFilterAddWin (gscr, display_info->devices, event_mask);
223 if (!event_win)
224 {
225 gtk_widget_destroy (screen_info->gtk_win);
226 g_free (screen_info);
227 return NULL;
228 }
229 gdk_window_set_user_data (event_win, screen_info->gtk_win);
230
231 screen_info->current_ws = 0;
232 screen_info->previous_ws = 0;
233 screen_info->current_ws = 0;
234 screen_info->previous_ws = 0;
235
236 screen_info->margins[STRUTS_TOP] = screen_info->gnome_margins[STRUTS_TOP] = 0;
237 screen_info->margins[STRUTS_LEFT] = screen_info->gnome_margins[STRUTS_LEFT] = 0;
238 screen_info->margins[STRUTS_RIGHT] = screen_info->gnome_margins[STRUTS_RIGHT] = 0;
239 screen_info->margins[STRUTS_BOTTOM] = screen_info->gnome_margins[STRUTS_BOTTOM] = 0;
240
241 screen_info->workspace_count = 0;
242 screen_info->workspace_names = NULL;
243 screen_info->workspace_names_items = 0;
244
245 screen_info->windows_stack = NULL;
246 screen_info->last_raise = NULL;
247 screen_info->windows = NULL;
248 screen_info->clients = NULL;
249 screen_info->client_count = 0;
250 screen_info->client_serial = 0L;
251 screen_info->button_handler_id = 0L;
252
253 screen_info->key_grabs = 0;
254 screen_info->pointer_grabs = 0;
255
256 getHint (display_info, screen_info->xroot, NET_SHOWING_DESKTOP, &desktop_visible);
257 screen_info->show_desktop = (desktop_visible != 0);
258
259 /* Create the side windows to detect edge movement */
260
261 /*left*/
262 xfwmWindowTemp (screen_info,
263 NULL, 0,
264 screen_info->xroot,
265 &screen_info->sidewalk[0],
266 0, 0,
267 1, screen_info->height,
268 EnterWindowMask,
269 TRUE);
270
271 /*right*/
272 xfwmWindowTemp (screen_info,
273 NULL, 0,
274 screen_info->xroot,
275 &screen_info->sidewalk[1],
276 screen_info->width - 1, 0,
277 1, screen_info->height,
278 EnterWindowMask,
279 TRUE);
280
281 /*top*/
282 xfwmWindowTemp (screen_info,
283 NULL, 0,
284 screen_info->xroot,
285 &screen_info->sidewalk[2],
286 0, 0,
287 screen_info->width, 1,
288 EnterWindowMask,
289 TRUE);
290
291 /*bottom*/
292 xfwmWindowTemp (screen_info,
293 NULL, 0,
294 screen_info->xroot,
295 &screen_info->sidewalk[3],
296 0, screen_info->height - 1,
297 screen_info->width, 1,
298 EnterWindowMask,
299 TRUE);
300
301 #ifdef ENABLE_KDE_SYSTRAY_PROXY
302 g_snprintf (selection, sizeof (selection), "_NET_SYSTEM_TRAY_S%d", screen_info->screen);
303 screen_info->net_system_tray_selection = XInternAtom (display_info->dpy, selection, FALSE);
304 screen_info->systray = getSystrayWindow (display_info, screen_info->net_system_tray_selection);
305 #endif
306
307 screen_info->font_desc = NULL;
308 screen_info->pango_attr_list = NULL;
309 screen_info->box_gc = None;
310
311 for (i = 0; i < SIDE_COUNT; i++)
312 {
313 xfwmPixmapInit (screen_info, &screen_info->sides[i][ACTIVE]);
314 xfwmPixmapInit (screen_info, &screen_info->sides[i][INACTIVE]);
315 }
316 for (i = 0; i < CORNER_COUNT; i++)
317 {
318 xfwmPixmapInit (screen_info, &screen_info->corners[i][ACTIVE]);
319 xfwmPixmapInit (screen_info, &screen_info->corners[i][INACTIVE]);
320 }
321 for (i = 0; i < BUTTON_COUNT; i++)
322 {
323 for (j = 0; j < STATE_COUNT; j++)
324 {
325 xfwmPixmapInit (screen_info, &screen_info->buttons[i][j]);
326 }
327 }
328 for (i = 0; i < TITLE_COUNT; i++)
329 {
330 xfwmPixmapInit (screen_info, &screen_info->title[i][ACTIVE]);
331 xfwmPixmapInit (screen_info, &screen_info->title[i][INACTIVE]);
332 xfwmPixmapInit (screen_info, &screen_info->top[i][ACTIVE]);
333 xfwmPixmapInit (screen_info, &screen_info->top[i][INACTIVE]);
334 }
335
336 screen_info->monitors_index = NULL;
337 myScreenInvalidateMonitorCache (screen_info);
338 myScreenRebuildMonitorIndex (screen_info);
339
340 return (screen_info);
341 }
342
343 ScreenInfo *
myScreenClose(ScreenInfo * screen_info)344 myScreenClose (ScreenInfo *screen_info)
345 {
346 DisplayInfo *display_info;
347
348 g_return_val_if_fail (screen_info, NULL);
349 TRACE ("entering");
350
351 display_info = screen_info->display_info;
352
353 clientUnframeAll (screen_info);
354 compositorUnmanageScreen (screen_info);
355 closeSettings (screen_info);
356
357 if (screen_info->workspace_names)
358 {
359 g_strfreev (screen_info->workspace_names);
360 }
361 screen_info->workspace_names = NULL;
362 screen_info->workspace_names_items = 0;
363
364 if (screen_info->shape_win != None)
365 {
366 XDestroyWindow (display_info->dpy, screen_info->shape_win);
367 screen_info->shape_win = (Window) None;
368 }
369
370 xfwmWindowDelete (&screen_info->sidewalk[0]);
371 xfwmWindowDelete (&screen_info->sidewalk[1]);
372 xfwmWindowDelete (&screen_info->sidewalk[2]);
373 xfwmWindowDelete (&screen_info->sidewalk[3]);
374 XSetInputFocus (display_info->dpy, screen_info->xroot, RevertToPointerRoot, CurrentTime);
375
376 g_free (screen_info->params);
377 screen_info->params = NULL;
378
379 gtk_widget_destroy (screen_info->gtk_win);
380 screen_info->gtk_win = NULL;
381
382 g_list_free (screen_info->windows_stack);
383 screen_info->windows_stack = NULL;
384
385 g_list_free (screen_info->windows);
386 screen_info->windows = NULL;
387
388 if (screen_info->monitors_index)
389 {
390 g_array_free (screen_info->monitors_index, TRUE);
391 screen_info->monitors_index = NULL;
392 }
393
394 if (screen_info->pango_attr_list)
395 {
396 pango_attr_list_unref (screen_info->pango_attr_list);
397 }
398
399 return (screen_info);
400 }
401
402 Display *
myScreenGetXDisplay(ScreenInfo * screen_info)403 myScreenGetXDisplay (ScreenInfo *screen_info)
404 {
405 DisplayInfo *display_info;
406
407 g_return_val_if_fail (screen_info, NULL);
408 g_return_val_if_fail (screen_info->display_info, NULL);
409
410 display_info = screen_info->display_info;
411 return display_info->dpy;
412 }
413
414 GtkWidget *
myScreenGetGtkWidget(ScreenInfo * screen_info)415 myScreenGetGtkWidget (ScreenInfo *screen_info)
416 {
417 g_return_val_if_fail (screen_info, NULL);
418
419 return screen_info->gtk_win;
420 }
421
422 GdkWindow *
myScreenGetGdkWindow(ScreenInfo * screen_info)423 myScreenGetGdkWindow (ScreenInfo *screen_info)
424 {
425 g_return_val_if_fail (screen_info, NULL);
426
427 return gtk_widget_get_window (screen_info->gtk_win);
428 }
429
430 gboolean
myScreenGrabKeyboard(ScreenInfo * screen_info,guint event_mask,guint32 timestamp)431 myScreenGrabKeyboard (ScreenInfo *screen_info, guint event_mask, guint32 timestamp)
432 {
433 gboolean grab;
434
435 g_return_val_if_fail (screen_info, FALSE);
436
437 TRACE ("timestamp %u", (unsigned int) timestamp);
438
439 grab = TRUE;
440 if (screen_info->key_grabs == 0)
441 {
442 myDisplayErrorTrapPush (screen_info->display_info);
443 grab = xfwm_device_grab (screen_info->display_info->devices,
444 &screen_info->display_info->devices->keyboard,
445 myScreenGetXDisplay (screen_info), screen_info->xroot,
446 TRUE, event_mask, GrabModeAsync, screen_info->xroot,
447 None, (Time) timestamp);
448 myDisplayErrorTrapPopIgnored (screen_info->display_info);
449 }
450 screen_info->key_grabs++;
451 TRACE ("global key grabs %i", screen_info->key_grabs);
452
453 return grab;
454 }
455
456 gboolean
myScreenGrabPointer(ScreenInfo * screen_info,gboolean owner_events,guint event_mask,Cursor cursor,guint32 timestamp)457 myScreenGrabPointer (ScreenInfo *screen_info, gboolean owner_events,
458 guint event_mask, Cursor cursor, guint32 timestamp)
459 {
460 gboolean grab;
461
462 g_return_val_if_fail (screen_info, FALSE);
463 TRACE ("timestamp %u", (unsigned int) timestamp);
464
465 grab = TRUE;
466 if (screen_info->pointer_grabs == 0)
467 {
468 myDisplayErrorTrapPush (screen_info->display_info);
469 grab = xfwm_device_grab (screen_info->display_info->devices,
470 &screen_info->display_info->devices->pointer,
471 myScreenGetXDisplay (screen_info), screen_info->xroot,
472 owner_events, event_mask, GrabModeAsync, screen_info->xroot,
473 cursor, (Time) timestamp);
474 myDisplayErrorTrapPopIgnored (screen_info->display_info);
475 }
476 screen_info->pointer_grabs++;
477 TRACE ("global pointer grabs %i", screen_info->pointer_grabs);
478
479 return grab;
480 }
481
482 gboolean
myScreenChangeGrabPointer(ScreenInfo * screen_info,gboolean owner_events,guint event_mask,Cursor cursor,guint32 timestamp)483 myScreenChangeGrabPointer (ScreenInfo *screen_info, gboolean owner_events,
484 guint event_mask, Cursor cursor, guint32 timestamp)
485 {
486 gboolean grab;
487
488 g_return_val_if_fail (screen_info, FALSE);
489 TRACE ("timestamp %u", (unsigned int) timestamp);
490
491 grab = FALSE;
492 if (screen_info->pointer_grabs > 0)
493 {
494 myDisplayErrorTrapPush (screen_info->display_info);
495 if (screen_info->display_info->devices->pointer.xi2_device == None)
496 {
497 grab = (XChangeActivePointerGrab (myScreenGetXDisplay (screen_info),
498 event_mask, cursor, (Time) timestamp) == GrabSuccess);
499 }
500 else
501 {
502 grab = xfwm_device_grab (screen_info->display_info->devices,
503 &screen_info->display_info->devices->pointer,
504 myScreenGetXDisplay (screen_info), screen_info->xroot,
505 owner_events, event_mask, GrabModeAsync, screen_info->xroot,
506 cursor, (Time) timestamp);
507 }
508 myDisplayErrorTrapPopIgnored (screen_info->display_info);
509 }
510
511 return grab;
512 }
513
514 unsigned int
myScreenUngrabKeyboard(ScreenInfo * screen_info,guint32 timestamp)515 myScreenUngrabKeyboard (ScreenInfo *screen_info, guint32 timestamp)
516 {
517 g_return_val_if_fail (screen_info, 0);
518 TRACE ("timestamp %u", (unsigned int) timestamp);
519
520 screen_info->key_grabs--;
521 if (screen_info->key_grabs < 0)
522 {
523 screen_info->key_grabs = 0;
524 }
525 if (screen_info->key_grabs == 0)
526 {
527 myDisplayErrorTrapPush (screen_info->display_info);
528 xfwm_device_ungrab (screen_info->display_info->devices,
529 &screen_info->display_info->devices->keyboard,
530 myScreenGetXDisplay (screen_info), (Time) timestamp);
531 myDisplayErrorTrapPopIgnored (screen_info->display_info);
532 }
533 TRACE ("global key grabs %i", screen_info->key_grabs);
534
535 return screen_info->key_grabs;
536 }
537
538 unsigned int
myScreenUngrabPointer(ScreenInfo * screen_info,guint32 timestamp)539 myScreenUngrabPointer (ScreenInfo *screen_info, guint32 timestamp)
540 {
541 g_return_val_if_fail (screen_info, 0);
542 TRACE ("timestamp %u", (unsigned int) timestamp);
543
544 screen_info->pointer_grabs--;
545 if (screen_info->pointer_grabs < 0)
546 {
547 screen_info->pointer_grabs = 0;
548 }
549 if (screen_info->pointer_grabs == 0)
550 {
551 myDisplayErrorTrapPush (screen_info->display_info);
552 xfwm_device_ungrab (screen_info->display_info->devices,
553 &screen_info->display_info->devices->pointer,
554 myScreenGetXDisplay (screen_info), (Time) timestamp);
555 myDisplayErrorTrapPopIgnored (screen_info->display_info);
556 }
557 TRACE ("global pointer grabs %i", screen_info->pointer_grabs);
558
559 return screen_info->pointer_grabs;
560 }
561
562 void
myScreenGrabKeys(ScreenInfo * screen_info)563 myScreenGrabKeys (ScreenInfo *screen_info)
564 {
565 Display *dpy;
566 int i;
567
568 g_return_if_fail (screen_info != NULL);
569
570 dpy = myScreenGetXDisplay (screen_info);
571
572 for (i = FIRST_KEY; i < KEY_COUNT; i++)
573 {
574 grabKey (screen_info->display_info->devices, dpy,
575 &screen_info->params->keys[i], screen_info->xroot);
576 }
577 }
578
579 void
myScreenUngrabKeys(ScreenInfo * screen_info)580 myScreenUngrabKeys (ScreenInfo *screen_info)
581 {
582 Display *dpy;
583
584 g_return_if_fail (screen_info != NULL);
585
586 dpy = myScreenGetXDisplay (screen_info);
587 ungrabKeys (screen_info->display_info->devices, dpy, screen_info->xroot);
588 }
589
590 gint
myScreenGetKeyPressed(ScreenInfo * screen_info,XfwmEventKey * event)591 myScreenGetKeyPressed (ScreenInfo *screen_info, XfwmEventKey *event)
592 {
593 gint key;
594 guint state;
595
596 state = event->state & MODIFIER_MASK;
597 for (key = 0; key < KEY_COUNT; key++)
598 {
599 if ((screen_info->params->keys[key].keycode == event->keycode)
600 && (screen_info->params->keys[key].modifier == state))
601 {
602 break;
603 }
604 }
605
606 return key;
607 }
608
609 int
myScreenGetModifierPressed(ScreenInfo * screen_info)610 myScreenGetModifierPressed (ScreenInfo *screen_info)
611 {
612 int rx, ry;
613
614 return (int) getMouseXY (screen_info, &rx, &ry);
615 }
616
617 Client *
myScreenGetClientFromWindow(ScreenInfo * screen_info,Window w,unsigned short mode)618 myScreenGetClientFromWindow (ScreenInfo *screen_info, Window w, unsigned short mode)
619 {
620 Client *c;
621 guint i;
622
623 g_return_val_if_fail (w != None, NULL);
624 TRACE ("looking for (0x%lx)", w);
625
626 for (c = screen_info->clients, i = 0; i < screen_info->client_count; c = c->next, i++)
627 {
628 if (clientGetFromWindow (c, w, mode))
629 {
630 return (c);
631 }
632 }
633 TRACE ("no client found");
634
635 return NULL;
636 }
637
638 gboolean
myScreenComputeSize(ScreenInfo * screen_info)639 myScreenComputeSize (ScreenInfo *screen_info)
640 {
641 gint num_monitors, i;
642 gint width, height;
643 GdkRectangle monitor;
644 gboolean changed;
645
646 g_return_val_if_fail (screen_info != NULL, FALSE);
647 g_return_val_if_fail (GDK_IS_SCREEN (screen_info->gscr), FALSE);
648
649 width = 0;
650 height = 0;
651 num_monitors = xfwm_get_n_monitors (screen_info->gscr);
652
653 if (num_monitors == 0)
654 {
655 return FALSE;
656 }
657
658 for (i = 0; i < num_monitors; i++)
659 {
660 xfwm_get_monitor_geometry (screen_info->gscr, i, &monitor, TRUE);
661 width = MAX (monitor.x + monitor.width, width);
662 height = MAX (monitor.y + monitor.height, height);
663 }
664
665 /* If we failed to compute the size, use whatever xlib reports */
666 if (width == 0 || height == 0)
667 {
668 width = WidthOfScreen (screen_info->xscreen);
669 height = HeightOfScreen (screen_info->xscreen);
670 }
671
672 changed = ((screen_info->width != width) | (screen_info->height != height));
673 screen_info->width = width;
674 screen_info->height = height;
675 TRACE ("width=%i, height=%i", width, height);
676
677 return changed;
678 }
679
680 gboolean
myScreenHasPrimaryMonitor(ScreenInfo * screen_info,Window w)681 myScreenHasPrimaryMonitor (ScreenInfo *screen_info, Window w)
682 {
683 #ifdef HAVE_RANDR
684 Display *display;
685 RROutput primary;
686
687 primary = None;
688 display = myScreenGetXDisplay (screen_info);
689
690 g_return_val_if_fail (display, FALSE);
691
692 if (screen_info->display_info->have_xrandr)
693 primary = XRRGetOutputPrimary (display, w);
694
695 if (primary != None)
696 return TRUE;
697 #endif /* HAVE_RANDR */
698 return FALSE;
699 }
700
701 gint
myScreenGetNumMonitors(ScreenInfo * screen_info)702 myScreenGetNumMonitors (ScreenInfo *screen_info)
703 {
704 g_return_val_if_fail (screen_info != NULL, 0);
705 g_return_val_if_fail (screen_info->monitors_index != NULL, 0);
706
707 return (screen_info->monitors_index->len);
708 }
709
710 gint
myScreenGetMonitorIndex(ScreenInfo * screen_info,gint idx)711 myScreenGetMonitorIndex (ScreenInfo *screen_info, gint idx)
712 {
713 g_return_val_if_fail (screen_info != NULL, 0);
714 g_return_val_if_fail (screen_info->monitors_index != NULL, 0);
715
716 return (g_array_index (screen_info->monitors_index, gint, idx));
717 }
718
719 gboolean
myScreenRebuildMonitorIndex(ScreenInfo * screen_info)720 myScreenRebuildMonitorIndex (ScreenInfo *screen_info)
721 {
722 gint i, j, num_monitors, previous_num_monitors;
723 GdkRectangle monitor, previous;
724 gboolean cloned;
725
726 g_return_val_if_fail (screen_info != NULL, FALSE);
727
728 previous_num_monitors = screen_info->num_monitors;
729 screen_info->num_monitors = 0;
730
731 if (screen_info->monitors_index)
732 {
733 g_array_free (screen_info->monitors_index, TRUE);
734 }
735 screen_info->monitors_index = g_array_new (FALSE, TRUE, sizeof (guint));
736
737 /* GDK already sorts monitors for us, for "cloned" monitors, sort
738 * the bigger ones first (giving preference to taller monitors
739 * over wider monitors)
740 */
741 num_monitors = xfwm_get_n_monitors (screen_info->gscr);
742 for (i = 0; i < num_monitors; i++)
743 {
744 xfwm_get_monitor_geometry (screen_info->gscr, i, &monitor, TRUE);
745 cloned = FALSE;
746 for (j = 0; j < (gint) screen_info->monitors_index->len; j++)
747 {
748 xfwm_get_monitor_geometry (screen_info->gscr, j, &previous, TRUE);
749 if ((previous.x == monitor.x) && (previous.y == monitor.y))
750 {
751 cloned = TRUE;
752 }
753 }
754 if (!cloned)
755 {
756 screen_info->num_monitors++;
757 g_array_append_val (screen_info->monitors_index , i);
758 }
759 }
760
761 TRACE ("physical monitor reported.: %i", num_monitors);
762 TRACE ("logical views found.......: %i", screen_info->num_monitors);
763
764 return (screen_info->num_monitors != previous_num_monitors);
765 }
766
767 void
myScreenInvalidateMonitorCache(ScreenInfo * screen_info)768 myScreenInvalidateMonitorCache (ScreenInfo *screen_info)
769 {
770 g_return_if_fail (screen_info != NULL);
771 TRACE ("entering");
772
773 screen_info->cache_monitor.x = -1;
774 screen_info->cache_monitor.y = -1;
775 screen_info->cache_monitor.width = 0;
776 screen_info->cache_monitor.height = 0;
777 }
778
779 /*
780 gdk_screen_get_monitor_at_point () doesn't give accurate results
781 when the point is off screen, use my own implementation from xfce 3
782 */
783 void
myScreenFindMonitorAtPoint(ScreenInfo * screen_info,gint x,gint y,GdkRectangle * rect)784 myScreenFindMonitorAtPoint (ScreenInfo *screen_info, gint x, gint y, GdkRectangle *rect)
785 {
786 gint dx, dy, center_x, center_y, num_monitors, i;
787 guint32 distsquare, min_distsquare;
788 GdkRectangle monitor, nearest_monitor = { G_MAXINT, G_MAXINT, 0, 0 };
789
790 g_return_if_fail (screen_info != NULL);
791 g_return_if_fail (rect != NULL);
792 g_return_if_fail (GDK_IS_SCREEN (screen_info->gscr));
793 TRACE ("(%i,%i)", x, y);
794
795 /* Cache system */
796 if ((x >= screen_info->cache_monitor.x) && (x < screen_info->cache_monitor.x + screen_info->cache_monitor.width) &&
797 (y >= screen_info->cache_monitor.y) && (y < screen_info->cache_monitor.y + screen_info->cache_monitor.height))
798 {
799 *rect = screen_info->cache_monitor;
800 return;
801 }
802
803 min_distsquare = G_MAXUINT32;
804 num_monitors = myScreenGetNumMonitors (screen_info);
805
806 for (i = 0; i < num_monitors; i++)
807 {
808 gint monitor_index;
809
810 monitor_index = myScreenGetMonitorIndex (screen_info, i);
811 xfwm_get_monitor_geometry (screen_info->gscr, monitor_index, &monitor, TRUE);
812
813 if ((x >= monitor.x) && (x < (monitor.x + monitor.width)) &&
814 (y >= monitor.y) && (y < (monitor.y + monitor.height)))
815 {
816 screen_info->cache_monitor = monitor;
817 *rect = screen_info->cache_monitor;
818 return;
819 }
820
821 center_x = monitor.x + (monitor.width / 2);
822 center_y = monitor.y + (monitor.height / 2);
823
824 dx = x - center_x;
825 dy = y - center_y;
826
827 distsquare = (dx * dx) + (dy * dy);
828
829 if (distsquare < min_distsquare)
830 {
831 min_distsquare = distsquare;
832 nearest_monitor = monitor;
833 }
834 }
835
836 screen_info->cache_monitor = nearest_monitor;
837 *rect = screen_info->cache_monitor;
838 }
839
840 void
myScreenGetXineramaMonitorGeometry(ScreenInfo * screen_info,gint monitor_num,GdkRectangle * rect)841 myScreenGetXineramaMonitorGeometry (ScreenInfo *screen_info, gint monitor_num, GdkRectangle *rect)
842 {
843 XineramaScreenInfo *infos;
844 int n;
845
846 g_return_if_fail (screen_info != NULL);
847 g_return_if_fail (rect != NULL);
848 g_return_if_fail (XineramaIsActive (myScreenGetXDisplay (screen_info)));
849
850 infos = XineramaQueryScreens (myScreenGetXDisplay (screen_info), &n);
851 if (infos == NULL || n <= 0 || monitor_num > n)
852 {
853 g_warning ("Cannot query Xinerama!");
854 XFree (infos);
855
856 /* Using screen size as fallback, safer than some random values */
857 rect->x = 0;
858 rect->y = 0;
859 rect->width = screen_info->width;
860 rect->height = screen_info->height;
861
862 return;
863 }
864
865 rect->x = infos[monitor_num].x_org;
866 rect->y = infos[monitor_num].y_org;
867 rect->width = infos[monitor_num].width;
868 rect->height = infos[monitor_num].height;
869
870 XFree (infos);
871 }
872
873 PangoFontDescription *
myScreenGetFontDescription(ScreenInfo * screen_info)874 myScreenGetFontDescription (ScreenInfo *screen_info)
875 {
876 GtkWidget *widget;
877
878 g_return_val_if_fail (screen_info != NULL, FALSE);
879
880 if (screen_info->font_desc != NULL)
881 {
882 return screen_info->font_desc;
883 }
884
885 widget = myScreenGetGtkWidget (screen_info);
886 return getUIPangoFontDesc (widget);
887 }
888
889 void
myScreenUpdateFontAttr(ScreenInfo * screen_info)890 myScreenUpdateFontAttr (ScreenInfo *screen_info)
891 {
892 PangoAttribute *attr;
893 GtkWidget *widget;
894 gint scale;
895
896 g_clear_pointer (&screen_info->pango_attr_list, pango_attr_list_unref);
897
898 widget = myScreenGetGtkWidget (screen_info);
899 scale = gtk_widget_get_scale_factor (widget);
900 screen_info->pango_attr_list = pango_attr_list_new ();
901 attr = pango_attr_scale_new (scale);
902 pango_attr_list_insert (screen_info->pango_attr_list, attr);
903 }
904
905