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