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-2020 Olivier Fourdan
20
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <stdio.h>
28 #include <X11/X.h>
29 #include <X11/Xlib.h>
30 #include <X11/Xutil.h>
31 #include <X11/cursorfont.h>
32 #include <X11/extensions/shape.h>
33 #include <glib.h>
34 #include <gdk/gdk.h>
35 #include <gdk/gdkx.h>
36 #include <gtk/gtk.h>
37 #include <libxfce4util/libxfce4util.h>
38 #ifdef HAVE_RENDER
39 #include <X11/extensions/Xrender.h>
40 #endif
41 #ifdef HAVE_XRES
42 #include <X11/extensions/XRes.h>
43 #endif
44 #include "spinning_cursor.h"
45 #include "display.h"
46 #include "screen.h"
47 #include "client.h"
48 #include "compositor.h"
49
50 #ifndef MAX_HOSTNAME_LENGTH
51 #define MAX_HOSTNAME_LENGTH 512
52 #endif /* MAX_HOSTNAME_LENGTH */
53
54 #ifndef CURSOR_ROOT
55 #define CURSOR_ROOT XC_left_ptr
56 #endif
57
58 #ifndef CURSOR_MOVE
59 #define CURSOR_MOVE XC_fleur
60 #endif
61
62 static DisplayInfo *default_display;
63
64 static gboolean
myDisplayInitAtoms(DisplayInfo * display_info)65 myDisplayInitAtoms (DisplayInfo *display_info)
66 {
67 static const char *atom_names[] = {
68 "COMPOSITING_MANAGER",
69 "_GTK_FRAME_EXTENTS",
70 "_GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED",
71 "_GTK_SHOW_WINDOW_MENU",
72 "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR",
73 "KWM_WIN_ICON",
74 "_MOTIF_WM_HINTS",
75 "_MOTIF_WM_INFO",
76 "_NET_ACTIVE_WINDOW",
77 "_NET_CLIENT_LIST",
78 "_NET_CLIENT_LIST_STACKING",
79 "_NET_CLOSE_WINDOW",
80 "_NET_CURRENT_DESKTOP",
81 "_NET_DESKTOP_GEOMETRY",
82 "_NET_DESKTOP_LAYOUT",
83 "_NET_DESKTOP_NAMES",
84 "_NET_DESKTOP_VIEWPORT",
85 "_NET_FRAME_EXTENTS",
86 "_NET_MOVERESIZE_WINDOW",
87 "_NET_NUMBER_OF_DESKTOPS",
88 "_NET_REQUEST_FRAME_EXTENTS",
89 "_NET_SHOWING_DESKTOP",
90 "_NET_STARTUP_ID",
91 "_NET_SUPPORTED",
92 "_NET_SUPPORTING_WM_CHECK",
93 "_NET_SYSTEM_TRAY_OPCODE",
94 "_NET_WM_ACTION_ABOVE",
95 "_NET_WM_ACTION_BELOW",
96 "_NET_WM_ACTION_CHANGE_DESKTOP",
97 "_NET_WM_ACTION_CLOSE",
98 "_NET_WM_ACTION_FULLSCREEN",
99 "_NET_WM_ACTION_MAXIMIZE_HORZ",
100 "_NET_WM_ACTION_MAXIMIZE_VERT",
101 "_NET_WM_ACTION_MINIMIZE",
102 "_NET_WM_ACTION_MOVE",
103 "_NET_WM_ACTION_RESIZE",
104 "_NET_WM_ACTION_SHADE",
105 "_NET_WM_ACTION_STICK",
106 "_NET_WM_ALLOWED_ACTIONS",
107 "_NET_WM_BYPASS_COMPOSITOR",
108 "_NET_WM_CONTEXT_HELP",
109 "_NET_WM_DESKTOP",
110 "_NET_WM_FULLSCREEN_MONITORS",
111 "_NET_WM_ICON",
112 "_NET_WM_ICON_GEOMETRY",
113 "_NET_WM_ICON_NAME",
114 "_NET_WM_MOVERESIZE",
115 "_NET_WM_NAME",
116 "_NET_WM_OPAQUE_REGION",
117 "_NET_WM_PID",
118 "_NET_WM_PING",
119 "_NET_WM_WINDOW_OPACITY",
120 "_NET_WM_WINDOW_OPACITY_LOCKED",
121 "_NET_WM_STATE",
122 "_NET_WM_STATE_ABOVE",
123 "_NET_WM_STATE_BELOW",
124 "_NET_WM_STATE_DEMANDS_ATTENTION",
125 "_NET_WM_STATE_FOCUSED",
126 "_NET_WM_STATE_FULLSCREEN",
127 "_NET_WM_STATE_HIDDEN",
128 "_NET_WM_STATE_MAXIMIZED_HORZ",
129 "_NET_WM_STATE_MAXIMIZED_VERT",
130 "_NET_WM_STATE_MODAL",
131 "_NET_WM_STATE_SHADED",
132 "_NET_WM_STATE_SKIP_PAGER",
133 "_NET_WM_STATE_SKIP_TASKBAR",
134 "_NET_WM_STATE_STICKY",
135 "_NET_WM_STRUT",
136 "_NET_WM_STRUT_PARTIAL",
137 "_NET_WM_SYNC_REQUEST",
138 "_NET_WM_SYNC_REQUEST_COUNTER",
139 "_NET_WM_USER_TIME",
140 "_NET_WM_USER_TIME_WINDOW",
141 "_NET_WM_WINDOW_TYPE",
142 "_NET_WM_WINDOW_TYPE_DESKTOP",
143 "_NET_WM_WINDOW_TYPE_DIALOG",
144 "_NET_WM_WINDOW_TYPE_DOCK",
145 "_NET_WM_WINDOW_TYPE_MENU",
146 "_NET_WM_WINDOW_TYPE_NORMAL",
147 "_NET_WM_WINDOW_TYPE_SPLASH",
148 "_NET_WM_WINDOW_TYPE_TOOLBAR",
149 "_NET_WM_WINDOW_TYPE_UTILITY",
150 "_NET_WM_WINDOW_TYPE_NOTIFICATION",
151 "_NET_WORKAREA",
152 "MANAGER",
153 "PIXMAP",
154 "SM_CLIENT_ID",
155 "UTF8_STRING",
156 "WM_CHANGE_STATE",
157 "WM_CLIENT_LEADER",
158 "WM_CLIENT_MACHINE",
159 "WM_COLORMAP_WINDOWS",
160 "WM_DELETE_WINDOW",
161 "WM_HINTS",
162 "WM_PROTOCOLS",
163 "WM_STATE",
164 "WM_TAKE_FOCUS",
165 "WM_TRANSIENT_FOR",
166 "WM_WINDOW_ROLE",
167 "XFWM4_COMPOSITING_MANAGER",
168 "XFWM4_TIMESTAMP_PROP",
169 "_XROOTPMAP_ID",
170 "_XSETROOT_ID",
171 "_GTK_READ_RCFILES"
172 };
173
174 g_assert (ATOM_COUNT == G_N_ELEMENTS (atom_names));
175 return (XInternAtoms (display_info->dpy,
176 (char **) atom_names,
177 ATOM_COUNT,
178 FALSE, display_info->atoms) != 0);
179 }
180
181 static void
myDisplayCreateTimestampWin(DisplayInfo * display_info)182 myDisplayCreateTimestampWin (DisplayInfo *display_info)
183 {
184 XSetWindowAttributes attributes;
185
186 attributes.event_mask = PropertyChangeMask;
187 attributes.override_redirect = TRUE;
188 display_info->timestamp_win =
189 XCreateWindow (display_info->dpy, DefaultRootWindow (display_info->dpy),
190 -100, -100, 10, 10, 0, 0, CopyFromParent, CopyFromParent,
191 CWEventMask | CWOverrideRedirect, &attributes);
192 }
193
194 DisplayInfo *
myDisplayInit(GdkDisplay * gdisplay)195 myDisplayInit (GdkDisplay *gdisplay)
196 {
197 DisplayInfo *display;
198 int major, minor;
199 int dummy;
200 gchar *hostnametmp;
201
202 display = g_new0 (DisplayInfo, 1);
203
204 if (!default_display)
205 {
206 default_display = display;
207 }
208
209 display->gdisplay = gdisplay;
210 display->dpy = (Display *) gdk_x11_display_get_xdisplay (gdisplay);
211
212 display->session = NULL;
213 display->quit = FALSE;
214 display->reload = FALSE;
215
216 /* Initialize internal atoms */
217 if (!myDisplayInitAtoms (display))
218 {
219 g_warning ("Some internal atoms were not properly created.");
220 }
221
222 display->devices = xfwm_devices_new (gdisplay);
223
224 /* Test XShape extension support */
225 major = 0;
226 minor = 0;
227 display->shape_version = 0;
228 if (XShapeQueryExtension (display->dpy,
229 &display->shape_event_base,
230 &dummy))
231 {
232 display->have_shape = TRUE;
233 if (XShapeQueryVersion (display->dpy, &major, &minor))
234 {
235 display->shape_version = major * 1000 + minor;
236 }
237 }
238 else
239 {
240 g_warning ("The display does not support the XShape extension.");
241 display->have_shape = FALSE;
242 display->shape_event_base = 0;
243 }
244
245 #ifdef HAVE_XSYNC
246 display->have_xsync = FALSE;
247 display->xsync_error_base = 0;
248 display->xsync_event_base = 0;
249
250 if (XSyncQueryExtension (display->dpy,
251 &display->xsync_event_base,
252 &display->xsync_error_base))
253 {
254 if (XSyncInitialize (display->dpy, &major, &minor))
255 {
256 if ((major > SYNC_MAJOR_VERSION) ||
257 (major == SYNC_MAJOR_VERSION && minor >= SYNC_MINOR_VERSION))
258 {
259 display->have_xsync = TRUE;
260 XSyncSetPriority (display->dpy, None, 10);
261 }
262 else
263 {
264 g_warning ("XSync extension too old (%i.%i).", major, minor);
265 }
266 }
267 else
268 {
269 g_warning ("Failed to initialize XSync extension.");
270 }
271 }
272 else
273 {
274 g_warning ("The display does not support the XSync extension.");
275 }
276 #endif /* HAVE_XSYNC */
277
278 #ifdef HAVE_RENDER
279 if (XRenderQueryExtension (display->dpy,
280 &display->render_event_base,
281 &display->render_error_base))
282 {
283 display->have_render = TRUE;
284 }
285 else
286 {
287 g_warning ("The display does not support the XRender extension.");
288 display->have_render = FALSE;
289 display->render_event_base = 0;
290 display->render_error_base = 0;
291 }
292 #else /* HAVE_RENDER */
293 display->have_render = FALSE;
294 #endif /* HAVE_RENDER */
295
296 #ifdef HAVE_RANDR
297 if (XRRQueryExtension (display->dpy,
298 &display->xrandr_event_base,
299 &display->xrandr_error_base))
300 {
301 display->have_xrandr = TRUE;
302 }
303 else
304 {
305 g_warning ("The display does not support the XRandr extension.");
306 display->have_xrandr = FALSE;
307 display->xrandr_event_base = 0;
308 display->xrandr_error_base = 0;
309 }
310 #else /* HAVE_RANDR */
311 display->have_xrandr = FALSE;
312 #endif /* HAVE_RANDR */
313
314 #ifdef HAVE_XRES
315 if (XResQueryExtension (display->dpy,
316 &display->xres_event_base,
317 &display->xres_error_base))
318 {
319 display->have_xres = TRUE;
320 }
321 else
322 {
323 g_warning ("The display does not support the XRes extension.");
324 display->have_xres = FALSE;
325 display->xres_event_base = 0;
326 display->xres_error_base = 0;
327 }
328 #else /* HAVE_XRES */
329 display->have_xres = FALSE;
330 #endif /* HAVE_XRES */
331
332 myDisplayCreateCursor (display);
333
334 myDisplayCreateTimestampWin (display);
335
336 display->xfilter = NULL;
337 display->screens = NULL;
338 display->clients = NULL;
339 display->xgrabcount = 0;
340 display->double_click_time = 250;
341 display->double_click_distance = 5;
342 display->nb_screens = 0;
343 display->current_time = CurrentTime;
344
345 hostnametmp = g_new0 (gchar, (size_t) MAX_HOSTNAME_LENGTH + 1);
346 if (gethostname ((char *) hostnametmp, MAX_HOSTNAME_LENGTH))
347 {
348 g_warning ("The display's hostname could not be determined.");
349 display->hostname = NULL;
350 } else {
351 hostnametmp[MAX_HOSTNAME_LENGTH] = '\0';
352 display->hostname = g_strdup(hostnametmp);
353 }
354 g_free (hostnametmp);
355
356 compositorInitDisplay (display);
357
358 return display;
359 }
360
361 DisplayInfo *
myDisplayClose(DisplayInfo * display)362 myDisplayClose (DisplayInfo *display)
363 {
364 myDisplayFreeCursor (display);
365 XDestroyWindow (display->dpy, display->timestamp_win);
366 display->timestamp_win = None;
367
368 if (default_display == display)
369 {
370 default_display = NULL;
371 }
372
373 if (display->hostname)
374 {
375 g_free (display->hostname);
376 display->hostname = NULL;
377 }
378
379 g_slist_free (display->clients);
380 display->clients = NULL;
381
382 g_slist_free (display->screens);
383 display->screens = NULL;
384
385 g_free (display->devices);
386 display->devices = NULL;
387
388 return display;
389 }
390
391 DisplayInfo *
myDisplayGetDefault(void)392 myDisplayGetDefault (void)
393 {
394 return default_display;
395 }
396
397 gboolean
myDisplayHaveShape(DisplayInfo * display)398 myDisplayHaveShape (DisplayInfo *display)
399 {
400 g_return_val_if_fail (display != NULL, FALSE);
401
402 return (display->have_shape);
403 }
404
405 gboolean
myDisplayHaveShapeInput(DisplayInfo * display)406 myDisplayHaveShapeInput (DisplayInfo *display)
407 {
408 g_return_val_if_fail (display != NULL, FALSE);
409
410 return ((display->have_shape) && (display->shape_version >= 1001));
411 }
412
413 gboolean
myDisplayHaveRender(DisplayInfo * display)414 myDisplayHaveRender (DisplayInfo *display)
415 {
416 g_return_val_if_fail (display != NULL, FALSE);
417
418 return (display->have_render);
419 }
420
421 void
myDisplayCreateCursor(DisplayInfo * display)422 myDisplayCreateCursor (DisplayInfo *display)
423 {
424 display->root_cursor =
425 XCreateFontCursor (display->dpy, CURSOR_ROOT);
426 display->move_cursor =
427 XCreateFontCursor (display->dpy, CURSOR_MOVE);
428 display->busy_cursor =
429 cursorCreateSpinning (display->dpy);
430 display->resize_cursor[CORNER_TOP_LEFT] =
431 XCreateFontCursor (display->dpy, XC_top_left_corner);
432 display->resize_cursor[CORNER_TOP_RIGHT] =
433 XCreateFontCursor (display->dpy, XC_top_right_corner);
434 display->resize_cursor[CORNER_BOTTOM_LEFT] =
435 XCreateFontCursor (display->dpy, XC_bottom_left_corner);
436 display->resize_cursor[CORNER_BOTTOM_RIGHT] =
437 XCreateFontCursor (display->dpy, XC_bottom_right_corner);
438 display->resize_cursor[CORNER_COUNT + SIDE_LEFT] =
439 XCreateFontCursor (display->dpy, XC_left_side);
440 display->resize_cursor[CORNER_COUNT + SIDE_RIGHT] =
441 XCreateFontCursor (display->dpy, XC_right_side);
442 display->resize_cursor[CORNER_COUNT + SIDE_TOP] =
443 XCreateFontCursor (display->dpy, XC_top_side);
444 display->resize_cursor[CORNER_COUNT + SIDE_BOTTOM] =
445 XCreateFontCursor (display->dpy, XC_bottom_side);
446 }
447
448 void
myDisplayFreeCursor(DisplayInfo * display)449 myDisplayFreeCursor (DisplayInfo *display)
450 {
451 int i;
452
453 XFreeCursor (display->dpy, display->busy_cursor);
454 display->busy_cursor = None;
455 XFreeCursor (display->dpy, display->move_cursor);
456 display->move_cursor = None;
457 XFreeCursor (display->dpy, display->root_cursor);
458 display->root_cursor = None;
459
460 for (i = 0; i < SIDE_COUNT + CORNER_COUNT; i++)
461 {
462 XFreeCursor (display->dpy, display->resize_cursor[i]);
463 display->resize_cursor[i] = None;
464 }
465 }
466
467 Cursor
myDisplayGetCursorBusy(DisplayInfo * display)468 myDisplayGetCursorBusy (DisplayInfo *display)
469 {
470 g_return_val_if_fail (display, None);
471
472 return display->busy_cursor;
473 }
474
475 Cursor
myDisplayGetCursorMove(DisplayInfo * display)476 myDisplayGetCursorMove (DisplayInfo *display)
477 {
478 g_return_val_if_fail (display, None);
479
480 return display->move_cursor;
481 }
482
483 Cursor
myDisplayGetCursorRoot(DisplayInfo * display)484 myDisplayGetCursorRoot (DisplayInfo *display)
485 {
486 g_return_val_if_fail (display, None);
487
488 return display->root_cursor;
489 }
490
491 Cursor
myDisplayGetCursorResize(DisplayInfo * display,guint list)492 myDisplayGetCursorResize (DisplayInfo *display, guint list)
493 {
494 g_return_val_if_fail (display, None);
495 g_return_val_if_fail (list < 8, None);
496
497 return display->resize_cursor [list];
498 }
499
500
501 void
myDisplayGrabServer(DisplayInfo * display)502 myDisplayGrabServer (DisplayInfo *display)
503 {
504 g_return_if_fail (display);
505
506 DBG ("entering myDisplayGrabServer");
507 if (display->xgrabcount == 0)
508 {
509 DBG ("grabbing server");
510 XGrabServer (display->dpy);
511 }
512 display->xgrabcount++;
513 DBG ("grabs : %i", display->xgrabcount);
514 }
515
516 void
myDisplayUngrabServer(DisplayInfo * display)517 myDisplayUngrabServer (DisplayInfo *display)
518 {
519 g_return_if_fail (display);
520
521 DBG ("entering myDisplayUngrabServer");
522 display->xgrabcount = display->xgrabcount - 1;
523 if (display->xgrabcount < 0) /* should never happen */
524 {
525 display->xgrabcount = 0;
526 }
527 if (display->xgrabcount == 0)
528 {
529 DBG ("ungrabbing server");
530 XUngrabServer (display->dpy);
531 XFlush (display->dpy);
532 }
533 DBG ("grabs : %i", display->xgrabcount);
534 }
535
536 void
myDisplayAddClient(DisplayInfo * display,Client * c)537 myDisplayAddClient (DisplayInfo *display, Client *c)
538 {
539 g_return_if_fail (c != None);
540 g_return_if_fail (display != NULL);
541
542 display->clients = g_slist_append (display->clients, c);
543 }
544
545 void
myDisplayRemoveClient(DisplayInfo * display,Client * c)546 myDisplayRemoveClient (DisplayInfo *display, Client *c)
547 {
548 g_return_if_fail (c != None);
549 g_return_if_fail (display != NULL);
550
551 display->clients = g_slist_remove (display->clients, c);
552 }
553
554 Client *
myDisplayGetClientFromWindow(DisplayInfo * display,Window w,unsigned short mode)555 myDisplayGetClientFromWindow (DisplayInfo *display, Window w, unsigned short mode)
556 {
557 GSList *list;
558
559 g_return_val_if_fail (w != None, NULL);
560 g_return_val_if_fail (display != NULL, NULL);
561
562 for (list = display->clients; list; list = g_slist_next (list))
563 {
564 Client *c = (Client *) list->data;
565 if (clientGetFromWindow (c, w, mode))
566 {
567 return (c);
568 }
569 }
570 TRACE ("no client found");
571
572 return NULL;
573 }
574
575 void
myDisplayAddScreen(DisplayInfo * display,ScreenInfo * screen)576 myDisplayAddScreen (DisplayInfo *display, ScreenInfo *screen)
577 {
578 g_return_if_fail (screen != NULL);
579 g_return_if_fail (display != NULL);
580
581 display->screens = g_slist_append (display->screens, screen);
582 display->nb_screens = display->nb_screens + 1;
583 }
584
585 void
myDisplayRemoveScreen(DisplayInfo * display,ScreenInfo * screen)586 myDisplayRemoveScreen (DisplayInfo *display, ScreenInfo *screen)
587 {
588 g_return_if_fail (screen != NULL);
589 g_return_if_fail (display != NULL);
590
591 display->screens = g_slist_remove (display->screens, screen);
592 display->nb_screens = display->nb_screens - 1;
593 if (display->nb_screens < 0)
594 {
595 display->nb_screens = 0;
596 }
597 }
598
599 ScreenInfo *
myDisplayGetScreenFromRoot(DisplayInfo * display,Window root)600 myDisplayGetScreenFromRoot (DisplayInfo *display, Window root)
601 {
602 GSList *list;
603
604 g_return_val_if_fail (root != None, NULL);
605 g_return_val_if_fail (display != NULL, NULL);
606
607 for (list = display->screens; list; list = g_slist_next (list))
608 {
609 ScreenInfo *screen = (ScreenInfo *) list->data;
610 if (screen->xroot == root)
611 {
612 return screen;
613 }
614 }
615 TRACE ("no screen found");
616
617 return NULL;
618 }
619
620 ScreenInfo *
myDisplayGetScreenFromOutput(DisplayInfo * display,Window output)621 myDisplayGetScreenFromOutput (DisplayInfo *display, Window output)
622 {
623 #ifdef HAVE_COMPOSITOR
624 GSList *list;
625
626 g_return_val_if_fail (display != NULL, NULL);
627
628 for (list = display->screens; list; list = g_slist_next (list))
629 {
630 ScreenInfo *screen = (ScreenInfo *) list->data;
631 if (screen->output == output)
632 {
633 return screen;
634 }
635 }
636 TRACE ("no screen found for output window 0x%lx", output);
637 #endif
638
639 return NULL;
640 }
641
642
643 ScreenInfo *
myDisplayGetScreenFromNum(DisplayInfo * display,int num)644 myDisplayGetScreenFromNum (DisplayInfo *display, int num)
645 {
646 GSList *list;
647
648 g_return_val_if_fail (display != NULL, NULL);
649
650 for (list = display->screens; list; list = g_slist_next (list))
651 {
652 ScreenInfo *screen = (ScreenInfo *) list->data;
653 if (screen->screen == num)
654 {
655 return screen;
656 }
657 }
658 TRACE ("no screen found");
659
660 return NULL;
661 }
662
663 Window
myDisplayGetRootFromWindow(DisplayInfo * display_info,Window w)664 myDisplayGetRootFromWindow(DisplayInfo *display_info, Window w)
665 {
666 XWindowAttributes attributes;
667 int result, status;
668
669 g_return_val_if_fail (w != None, None);
670 g_return_val_if_fail (display_info != NULL, None);
671
672 myDisplayErrorTrapPush (display_info);
673 status = XGetWindowAttributes(display_info->dpy, w, &attributes);
674 result = myDisplayErrorTrapPop (display_info);
675
676 if ((result != Success) || !status)
677 {
678 TRACE ("no root found for 0x%lx", w);
679 return None;
680 }
681 return attributes.root;
682 }
683
684 ScreenInfo *
myDisplayGetScreenFromWindow(DisplayInfo * display,Window w)685 myDisplayGetScreenFromWindow (DisplayInfo *display, Window w)
686 {
687 ScreenInfo *screen;
688 Window root;
689
690 g_return_val_if_fail (w != None, NULL);
691 g_return_val_if_fail (display != NULL, NULL);
692
693 /* First check if this is a known root window */
694 screen = myDisplayGetScreenFromRoot (display, w);
695 if (screen)
696 {
697 return screen;
698 }
699
700 /* Else retrieve the window's root window */
701 root = myDisplayGetRootFromWindow (display, w);
702 if (root != None)
703 {
704 screen = myDisplayGetScreenFromRoot (display, root);
705 if (screen)
706 {
707 return screen;
708 }
709 }
710 TRACE ("no screen found for 0x%lx", w);
711
712 return NULL;
713 }
714
715 #ifdef ENABLE_KDE_SYSTRAY_PROXY
716 ScreenInfo *
myDisplayGetScreenFromSystray(DisplayInfo * display,Window w)717 myDisplayGetScreenFromSystray (DisplayInfo *display, Window w)
718 {
719 GSList *list;
720
721 g_return_val_if_fail (w != None, NULL);
722 g_return_val_if_fail (display != NULL, NULL);
723
724 for (list = display->screens; list; list = g_slist_next (list))
725 {
726 ScreenInfo *screen = (ScreenInfo *) list->data;
727 if (screen->systray == w)
728 {
729 return screen;
730 }
731 }
732 TRACE ("no screen found");
733
734 return NULL;
735 }
736 #endif /* ENABLE_KDE_SYSTRAY_PROXY */
737
738 #ifdef HAVE_XSYNC
739 Client *
myDisplayGetClientFromXSyncAlarm(DisplayInfo * display,XSyncAlarm xalarm)740 myDisplayGetClientFromXSyncAlarm (DisplayInfo *display, XSyncAlarm xalarm)
741 {
742 GSList *list;
743
744 g_return_val_if_fail (xalarm != None, NULL);
745 g_return_val_if_fail (display != NULL, NULL);
746
747 for (list = display->clients; list; list = g_slist_next (list))
748 {
749 Client *c = (Client *) list->data;
750 if (xalarm == c->xsync_alarm)
751 {
752 return (c);
753 }
754 }
755 TRACE ("no client found");
756
757 return NULL;
758 }
759 #endif /* HAVE_XSYNC */
760
761 ScreenInfo *
myDisplayGetDefaultScreen(DisplayInfo * display)762 myDisplayGetDefaultScreen (DisplayInfo *display)
763 {
764 GSList *list;
765
766 g_return_val_if_fail (display != NULL, NULL);
767
768 list = display->screens;
769 if (list)
770 {
771 return (ScreenInfo *) list->data;
772 }
773
774 return NULL;
775 }
776
777 guint32
myDisplayUpdateCurrentTime(DisplayInfo * display,XfwmEvent * event)778 myDisplayUpdateCurrentTime (DisplayInfo *display, XfwmEvent *event)
779 {
780 guint32 timestamp;
781 XEvent *xevent;
782
783 g_return_val_if_fail (display != NULL, (guint32) CurrentTime);
784
785 timestamp = (guint32) CurrentTime;
786 switch (event->meta.type)
787 {
788 case XFWM_EVENT_KEY:
789 timestamp = (guint32) event->key.time;
790 break;
791 case XFWM_EVENT_BUTTON:
792 timestamp = (guint32) event->button.time;
793 break;
794 case XFWM_EVENT_MOTION:
795 timestamp = (guint32) event->motion.time;
796 break;
797 case XFWM_EVENT_CROSSING:
798 timestamp = (guint32) event->crossing.time;
799 break;
800 case XFWM_EVENT_XEVENT:
801 xevent = event->meta.xevent;
802
803 switch (xevent->type)
804 {
805 case KeyPress:
806 case KeyRelease:
807 timestamp = (guint32) xevent->xkey.time;
808 break;
809 case ButtonPress:
810 case ButtonRelease:
811 timestamp = (guint32) xevent->xbutton.time;
812 break;
813 case MotionNotify:
814 timestamp = (guint32) xevent->xmotion.time;
815 break;
816 case EnterNotify:
817 case LeaveNotify:
818 timestamp = (guint32) xevent->xcrossing.time;
819 break;
820 case PropertyNotify:
821 timestamp = (guint32) xevent->xproperty.time;
822 break;
823 case SelectionClear:
824 timestamp = (guint32) xevent->xselectionclear.time;
825 break;
826 case SelectionRequest:
827 timestamp = (guint32) xevent->xselectionrequest.time;
828 break;
829 case SelectionNotify:
830 timestamp = (guint32) xevent->xselection.time;
831 break;
832 default:
833 #ifdef HAVE_XSYNC
834 if ((display->have_xsync) &&
835 (xevent->type == display->xsync_event_base + XSyncAlarmNotify))
836 {
837 timestamp = ((XSyncAlarmNotifyEvent*) xevent)->time;
838 }
839 #endif /* HAVE_XSYNC */
840 break;
841 }
842 }
843
844 if ((timestamp != (guint32) CurrentTime))
845 {
846 display->current_time = timestamp;
847 }
848
849 return display->current_time;
850 }
851
852 guint32
myDisplayGetCurrentTime(DisplayInfo * display)853 myDisplayGetCurrentTime (DisplayInfo *display)
854 {
855 g_return_val_if_fail (display != NULL, (guint32) CurrentTime);
856
857 TRACE ("timestamp=%u", (guint32) display->current_time);
858 return display->current_time;
859 }
860
861 guint32
myDisplayGetTime(DisplayInfo * display,guint32 timestamp)862 myDisplayGetTime (DisplayInfo * display, guint32 timestamp)
863 {
864 guint32 display_timestamp;
865
866 display_timestamp = timestamp;
867 if (display_timestamp == (guint32) CurrentTime)
868 {
869 display_timestamp = getXServerTime (display);
870 }
871
872 TRACE ("timestamp=%u", (guint32) display_timestamp);
873 return display_timestamp;
874 }
875
876 guint32
myDisplayGetLastUserTime(DisplayInfo * display)877 myDisplayGetLastUserTime (DisplayInfo *display)
878 {
879 g_return_val_if_fail (display != NULL, (guint32) CurrentTime);
880
881 TRACE ("timestamp=%u", (guint32) display->last_user_time);
882 return display->last_user_time;
883 }
884
885 void
myDisplaySetLastUserTime(DisplayInfo * display,guint32 timestamp)886 myDisplaySetLastUserTime (DisplayInfo *display, guint32 timestamp)
887 {
888 g_return_if_fail (display != NULL);
889 g_return_if_fail (timestamp != 0);
890
891 if (TIMESTAMP_IS_BEFORE(timestamp, display->last_user_time))
892 {
893 g_warning ("Last user time set back to %u (was %u)", (unsigned int) timestamp, (unsigned int) display->last_user_time);
894 }
895 display->last_user_time = timestamp;
896 }
897
898 void
myDisplayUpdateLastUserTime(DisplayInfo * display,guint32 timestamp)899 myDisplayUpdateLastUserTime (DisplayInfo *display, guint32 timestamp)
900 {
901 g_return_if_fail (display != NULL);
902 g_return_if_fail (timestamp != 0);
903
904 if (TIMESTAMP_IS_BEFORE(display->last_user_time, timestamp))
905 {
906 display->last_user_time = timestamp;
907 }
908 }
909
910 gboolean
myDisplayTestXrender(DisplayInfo * display,gdouble min_time)911 myDisplayTestXrender (DisplayInfo *display, gdouble min_time)
912 {
913 #ifdef HAVE_RENDER
914 gint64 t1, t2;
915 gdouble dt;
916 Display *dpy;
917 Picture picture1, picture2, picture3;
918 XRenderPictFormat *format_src, *format_dst;
919 Pixmap fillPixmap, rootPixmap;
920 XRenderPictureAttributes pa;
921 XSetWindowAttributes attrs;
922 XImage *ximage;
923 Window output;
924 XRenderColor c;
925 Visual *visual;
926 Screen *screen;
927 int x, y, w, h;
928 int screen_number;
929 int depth;
930 int iterations;
931
932 g_return_val_if_fail (display != NULL, FALSE);
933 TRACE ("entering");
934
935 c.alpha = 0x7FFF;
936 c.red = 0xFFFF;
937 c.green = 0xFFFF;
938 c.blue = 0xFFFF;
939
940 dpy = display->dpy;
941 screen_number = DefaultScreen (dpy);
942 screen = DefaultScreenOfDisplay (dpy);
943 visual = DefaultVisual (dpy, screen_number);
944 depth = DefaultDepth (dpy, screen_number);
945
946 w = WidthOfScreen(screen) / 16;
947 h = HeightOfScreen(screen) / 16;
948 x = (WidthOfScreen(screen) - w);
949 y = (HeightOfScreen(screen) - h);
950
951 format_dst = XRenderFindVisualFormat (dpy, visual);
952 g_return_val_if_fail (format_dst != NULL , FALSE);
953
954 format_src = XRenderFindStandardFormat (dpy, PictStandardA8);
955 g_return_val_if_fail (format_src != NULL , FALSE);
956
957 ximage = XGetImage (dpy,
958 DefaultRootWindow(dpy),
959 x, y, w, h,
960 AllPlanes, ZPixmap);
961 g_return_val_if_fail (ximage != NULL , FALSE);
962
963 rootPixmap = XCreatePixmap (dpy,
964 DefaultRootWindow(dpy),
965 w, h, depth);
966 XPutImage (dpy, rootPixmap,
967 DefaultGC (dpy, screen_number), ximage,
968 0, 0, 0, 0, w, h);
969 XDestroyImage (ximage);
970
971 attrs.override_redirect = TRUE;
972 output = XCreateWindow (dpy,
973 DefaultRootWindow(dpy),
974 x, y, w, h,
975 0, CopyFromParent, CopyFromParent,
976 (Visual *) CopyFromParent,
977 CWOverrideRedirect, &attrs);
978 XMapRaised (dpy, output);
979
980 fillPixmap = XCreatePixmap (dpy,
981 DefaultRootWindow(dpy),
982 1, 1, 8);
983
984 t1 = g_get_monotonic_time ();
985
986 pa.repeat = TRUE;
987 picture1 = XRenderCreatePicture (dpy,
988 rootPixmap,
989 format_dst, 0, NULL);
990 picture2 = XRenderCreatePicture (dpy,
991 fillPixmap,
992 format_src, CPRepeat, &pa);
993 picture3 = XRenderCreatePicture (dpy,
994 output,
995 format_dst, 0, NULL);
996 XRenderComposite (dpy, PictOpSrc,
997 picture1, None, picture3,
998 0, 0, 0, 0, 0, 0, w, h);
999 XRenderFillRectangle (dpy, PictOpSrc,
1000 picture2, &c, 0, 0,
1001 1, 1);
1002 for (iterations = 0; iterations < 10; iterations++)
1003 {
1004 XRenderComposite (dpy, PictOpOver,
1005 picture1, picture2, picture3,
1006 0, 0, 0, 0, 0, 0, w, h);
1007 ximage = XGetImage (dpy, output,
1008 0, 0, 1, 1,
1009 AllPlanes, ZPixmap);
1010 if (ximage)
1011 {
1012 XDestroyImage (ximage);
1013 }
1014 }
1015 XRenderFreePicture (dpy, picture1);
1016 XRenderFreePicture (dpy, picture2);
1017 XRenderFreePicture (dpy, picture3);
1018
1019 XFreePixmap (dpy, fillPixmap);
1020 XFreePixmap (dpy, rootPixmap);
1021
1022 XDestroyWindow (dpy, output);
1023
1024 t2 = g_get_monotonic_time ();
1025 dt = (gdouble) (t2 - t1) / 1000.0;
1026
1027 if (dt < min_time)
1028 {
1029 TRACE ("XRender test passed (target %3.4f sec., measured %3.4f sec.).", min_time, dt);
1030 return TRUE;
1031 }
1032 g_print ("XRender test failed (target %3.4f sec., measured %3.4f sec.).\n", min_time, dt);
1033 return FALSE;
1034 #else /* HAVE_RENDER */
1035 return FALSE;
1036 #endif /* HAVE_RENDER */
1037 }
1038
1039 void
myDisplayErrorTrapPush(DisplayInfo * display_info)1040 myDisplayErrorTrapPush (DisplayInfo *display_info)
1041 {
1042 gdk_x11_display_error_trap_push (display_info->gdisplay);
1043 }
1044
1045 gint
myDisplayErrorTrapPop(DisplayInfo * display_info)1046 myDisplayErrorTrapPop (DisplayInfo *display_info)
1047 {
1048 return gdk_x11_display_error_trap_pop (display_info->gdisplay);
1049 }
1050
1051 void
myDisplayErrorTrapPopIgnored(DisplayInfo * display_info)1052 myDisplayErrorTrapPopIgnored (DisplayInfo *display_info)
1053 {
1054 gdk_x11_display_error_trap_pop_ignored (display_info->gdisplay);
1055 }
1056
1057 void
myDisplayBeep(DisplayInfo * display_info)1058 myDisplayBeep (DisplayInfo *display_info)
1059 {
1060 gdk_display_beep (display_info->gdisplay);;
1061 }
1062
1063 GdkKeymap *
myDisplayGetKeymap(DisplayInfo * display_info)1064 myDisplayGetKeymap (DisplayInfo *display_info)
1065 {
1066 return gdk_keymap_get_for_display (display_info->gdisplay);
1067 }
1068