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)
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.
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., 675 Mass Ave, Cambridge, MA 02139, USA.
17 xfwm4 - (c) 2002-2007 Olivier Fourdan
27 #include <X11/Xutil.h>
28 #include <X11/cursorfont.h>
29 #include <X11/extensions/shape.h>
34 #include <libxfce4util/libxfce4util.h>
36 #include <X11/extensions/Xrender.h>
39 #include "spinning_cursor.h"
43 #include "compositor.h"
45 #ifndef MAX_HOSTNAME_LENGTH
46 #define MAX_HOSTNAME_LENGTH 32
47 #endif /* MAX_HOSTNAME_LENGTH */
50 #define CURSOR_ROOT XC_left_ptr
54 #define CURSOR_MOVE XC_fleur
58 handleXError (Display
* dpy
, XErrorEvent
* err
)
63 XGetErrorText (dpy
, err
->error_code
, buf
, 63);
64 g_print ("XError: %s\n", buf
);
65 g_print ("==> XID 0x%lx, Request %d, Error %d <==\n",
66 err
->resourceid
, err
->request_code
, err
->error_code
);
72 myDisplayInitAtoms (DisplayInfo
*display_info
)
74 static const char *atom_names
[] = {
75 "COMPOSITING_MANAGER",
76 "GNOME_PANEL_DESKTOP_AREA",
77 "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR",
83 "_NET_CLIENT_LIST_STACKING",
85 "_NET_CURRENT_DESKTOP",
86 "_NET_DESKTOP_GEOMETRY",
87 "_NET_DESKTOP_LAYOUT",
89 "_NET_DESKTOP_VIEWPORT",
91 "_NET_NUMBER_OF_DESKTOPS",
92 "_NET_REQUEST_FRAME_EXTENTS",
93 "_NET_SHOWING_DESKTOP",
96 "_NET_SUPPORTING_WM_CHECK",
97 "_NET_SYSTEM_TRAY_OPCODE",
98 "_NET_WM_ACTION_CHANGE_DESKTOP",
99 "_NET_WM_ACTION_CLOSE",
100 "_NET_WM_ACTION_MAXIMIZE_HORZ",
101 "_NET_WM_ACTION_MAXIMIZE_VERT",
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_CONTEXT_HELP",
110 "_NET_WM_ICON_GEOMETRY",
112 "_NET_WM_MOVERESIZE",
114 "_NET_WM_WINDOW_OPACITY",
115 "_NET_WM_WINDOW_OPACITY_LOCKED",
117 "_NET_WM_STATE_ABOVE",
118 "_NET_WM_STATE_BELOW",
119 "_NET_WM_STATE_DEMANDS_ATTENTION",
120 "_NET_WM_STATE_FULLSCREEN",
121 "_NET_WM_STATE_HIDDEN",
122 "_NET_WM_STATE_MAXIMIZED_HORZ",
123 "_NET_WM_STATE_MAXIMIZED_VERT",
124 "_NET_WM_STATE_MODAL",
125 "_NET_WM_STATE_SHADED",
126 "_NET_WM_STATE_SKIP_PAGER",
127 "_NET_WM_STATE_SKIP_TASKBAR",
128 "_NET_WM_STATE_STICKY",
130 "_NET_WM_STRUT_PARTIAL",
131 "_NET_WM_SYNC_REQUEST",
132 "_NET_WM_SYNC_REQUEST_COUNTER",
134 "_NET_WM_WINDOW_TYPE",
135 "_NET_WM_WINDOW_TYPE_DESKTOP",
136 "_NET_WM_WINDOW_TYPE_DIALOG",
137 "_NET_WM_WINDOW_TYPE_DOCK",
138 "_NET_WM_WINDOW_TYPE_MENU",
139 "_NET_WM_WINDOW_TYPE_NORMAL",
140 "_NET_WM_WINDOW_TYPE_SPLASH",
141 "_NET_WM_WINDOW_TYPE_TOOLBAR",
142 "_NET_WM_WINDOW_TYPE_UTILITY",
149 "_WIN_DESKTOP_BUTTON_PROXY",
154 "_WIN_SUPPORTING_WM_CHECK",
156 "_WIN_WORKSPACE_COUNT",
160 "WM_COLORMAP_WINDOWS",
168 "XFWM4_COMPOSITING_MANAGER",
169 "XFWM4_TIMESTAMP_PROP",
174 g_assert (ATOM_COUNT
== G_N_ELEMENTS (atom_names
));
175 return (XInternAtoms (display_info
->dpy
,
176 (char **) atom_names
,
178 FALSE
, display_info
->atoms
) != 0);
182 myDisplayCreateTimestampWin (DisplayInfo
*display_info
)
184 XSetWindowAttributes attributes
;
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
);
195 myDisplayInit (GdkDisplay
*gdisplay
)
197 DisplayInfo
*display
;
201 display
= g_new0 (DisplayInfo
, 1);
203 display
->gdisplay
= gdisplay
;
204 display
->dpy
= (Display
*) gdk_x11_display_get_xdisplay (gdisplay
);
206 display
->session
= NULL
;
207 display
->quit
= FALSE
;
208 display
->reload
= FALSE
;
210 XSetErrorHandler (handleXError
);
212 /* Initialize internal atoms */
213 if (!myDisplayInitAtoms (display
))
215 g_warning ("Some internal atoms were not properly created.");
218 /* Test XShape extension support */
221 display
->shape_version
= 0;
222 if (XShapeQueryExtension (display
->dpy
,
223 &display
->shape_event_base
,
226 display
->have_shape
= TRUE
;
227 if (XShapeQueryVersion (display
->dpy
, &major
, &minor
))
229 display
->shape_version
= major
* 1000 + minor
;
234 g_warning ("The display does not support the XShape extension.");
235 display
->have_shape
= FALSE
;
236 display
->shape_event_base
= 0;
240 display
->have_xsync
= FALSE
;
242 display
->xsync_error_base
= 0;
243 display
->xsync_event_base
= 0;
245 major
= SYNC_MAJOR_VERSION
;
246 minor
= SYNC_MINOR_VERSION
;
248 if (XSyncQueryExtension (display
->dpy
,
249 &display
->xsync_event_base
,
250 &display
->xsync_error_base
)
251 && XSyncInitialize (display
->dpy
,
255 display
->have_xsync
= TRUE
;
259 g_warning ("The display does not support the XSync extension.");
260 display
->have_xsync
= FALSE
;
261 display
->xsync_event_base
= 0;
262 display
->xsync_error_base
= 0;
264 #endif /* HAVE_XSYNC */
267 if (XRenderQueryExtension (display
->dpy
,
268 &display
->render_event_base
,
269 &display
->render_error_base
))
271 display
->have_render
= TRUE
;
275 g_warning ("The display does not support the XRender extension.");
276 display
->have_render
= FALSE
;
277 display
->render_event_base
= 0;
278 display
->render_error_base
= 0;
280 #else /* HAVE_RENDER */
281 display
->have_render
= FALSE
;
282 #endif /* HAVE_RENDER */
285 if (XRRQueryExtension (display
->dpy
,
286 &display
->xrandr_event_base
,
287 &display
->xrandr_error_base
))
289 display
->have_xrandr
= TRUE
;
293 g_warning ("The display does not support the XRandr extension.");
294 display
->have_xrandr
= FALSE
;
295 display
->xrandr_event_base
= 0;
296 display
->xrandr_error_base
= 0;
298 #else /* HAVE_RANDR */
299 display
->have_xrandr
= FALSE
;
300 #endif /* HAVE_RANDR */
302 display
->root_cursor
=
303 XCreateFontCursor (display
->dpy
, CURSOR_ROOT
);
304 display
->move_cursor
=
305 XCreateFontCursor (display
->dpy
, CURSOR_MOVE
);
306 display
->busy_cursor
=
307 cursorCreateSpinning (display
->dpy
);
308 display
->resize_cursor
[CORNER_TOP_LEFT
] =
309 XCreateFontCursor (display
->dpy
, XC_top_left_corner
);
310 display
->resize_cursor
[CORNER_TOP_RIGHT
] =
311 XCreateFontCursor (display
->dpy
, XC_top_right_corner
);
312 display
->resize_cursor
[CORNER_BOTTOM_LEFT
] =
313 XCreateFontCursor (display
->dpy
, XC_bottom_left_corner
);
314 display
->resize_cursor
[CORNER_BOTTOM_RIGHT
] =
315 XCreateFontCursor (display
->dpy
, XC_bottom_right_corner
);
316 display
->resize_cursor
[CORNER_COUNT
+ SIDE_LEFT
] =
317 XCreateFontCursor (display
->dpy
, XC_left_side
);
318 display
->resize_cursor
[CORNER_COUNT
+ SIDE_RIGHT
] =
319 XCreateFontCursor (display
->dpy
, XC_right_side
);
320 display
->resize_cursor
[CORNER_COUNT
+ SIDE_TOP
] =
321 XCreateFontCursor (display
->dpy
, XC_top_side
);
322 display
->resize_cursor
[CORNER_COUNT
+ SIDE_BOTTOM
] =
323 XCreateFontCursor (display
->dpy
, XC_bottom_side
);
325 myDisplayCreateTimestampWin (display
);
327 display
->xfilter
= NULL
;
328 display
->screens
= NULL
;
329 display
->clients
= NULL
;
330 display
->xgrabcount
= 0;
331 display
->dbl_click_time
= 300;
332 display
->nb_screens
= 0;
333 display
->current_time
= CurrentTime
;
335 display
->hostname
= g_new0 (gchar
, (size_t) MAX_HOSTNAME_LENGTH
);
336 if (gethostname ((char *) display
->hostname
, MAX_HOSTNAME_LENGTH
- 1))
338 g_free (display
->hostname
);
339 display
->hostname
= NULL
;
342 compositorInitDisplay (display
);
348 myDisplayClose (DisplayInfo
*display
)
352 XFreeCursor (display
->dpy
, display
->busy_cursor
);
353 display
->busy_cursor
= None
;
354 XFreeCursor (display
->dpy
, display
->move_cursor
);
355 display
->move_cursor
= None
;
356 XFreeCursor (display
->dpy
, display
->root_cursor
);
357 display
->root_cursor
= None
;
358 XDestroyWindow (display
->dpy
, display
->timestamp_win
);
359 display
->timestamp_win
= None
;
361 if (display
->hostname
)
363 g_free (display
->hostname
);
364 display
->hostname
= NULL
;
367 for (i
= 0; i
< SIDE_COUNT
+ CORNER_COUNT
; i
++)
369 XFreeCursor (display
->dpy
, display
->resize_cursor
[i
]);
370 display
->resize_cursor
[i
] = None
;
373 g_slist_free (display
->clients
);
374 display
->clients
= NULL
;
376 g_slist_free (display
->screens
);
377 display
->screens
= NULL
;
383 myDisplayHaveShape (DisplayInfo
*display
)
385 g_return_val_if_fail (display
!= NULL
, FALSE
);
387 return (display
->have_shape
);
391 myDisplayHaveRender (DisplayInfo
*display
)
393 g_return_val_if_fail (display
!= NULL
, FALSE
);
395 return (display
->have_render
);
399 myDisplayGetCursorBusy (DisplayInfo
*display
)
401 g_return_val_if_fail (display
, None
);
403 return display
->busy_cursor
;
407 myDisplayGetCursorMove (DisplayInfo
*display
)
409 g_return_val_if_fail (display
, None
);
411 return display
->move_cursor
;
415 myDisplayGetCursorRoot (DisplayInfo
*display
)
417 g_return_val_if_fail (display
, None
);
419 return display
->root_cursor
;
423 myDisplayGetCursorResize (DisplayInfo
*display
, guint index
)
425 g_return_val_if_fail (display
, None
);
426 g_return_val_if_fail (index
< 8, None
);
428 return display
->resize_cursor
[index
];
433 myDisplayGrabServer (DisplayInfo
*display
)
435 g_return_if_fail (display
);
437 DBG ("entering myDisplayGrabServer");
438 if (display
->xgrabcount
== 0)
440 DBG ("grabbing server");
441 XGrabServer (display
->dpy
);
443 display
->xgrabcount
++;
444 DBG ("grabs : %i", display
->xgrabcount
);
448 myDisplayUngrabServer (DisplayInfo
*display
)
450 g_return_if_fail (display
);
452 DBG ("entering myDisplayUngrabServer");
453 display
->xgrabcount
= display
->xgrabcount
- 1;
454 if (display
->xgrabcount
< 0) /* should never happen */
456 display
->xgrabcount
= 0;
458 if (display
->xgrabcount
== 0)
460 DBG ("ungrabbing server");
461 XUngrabServer (display
->dpy
);
462 XFlush (display
->dpy
);
464 DBG ("grabs : %i", display
->xgrabcount
);
468 myDisplayAddClient (DisplayInfo
*display
, Client
*c
)
470 g_return_if_fail (c
!= None
);
471 g_return_if_fail (display
!= NULL
);
473 display
->clients
= g_slist_append (display
->clients
, c
);
477 myDisplayRemoveClient (DisplayInfo
*display
, Client
*c
)
479 g_return_if_fail (c
!= None
);
480 g_return_if_fail (display
!= NULL
);
482 display
->clients
= g_slist_remove (display
->clients
, c
);
486 myDisplayGetClientFromWindow (DisplayInfo
*display
, Window w
, unsigned short mode
)
490 g_return_val_if_fail (w
!= None
, NULL
);
491 g_return_val_if_fail (display
!= NULL
, NULL
);
493 for (index
= display
->clients
; index
; index
= g_slist_next (index
))
495 Client
*c
= (Client
*) index
->data
;
496 if (clientGetFromWindow (c
, w
, mode
))
501 TRACE ("no client found");
507 myDisplayAddScreen (DisplayInfo
*display
, ScreenInfo
*screen
)
509 g_return_if_fail (screen
!= NULL
);
510 g_return_if_fail (display
!= NULL
);
512 display
->screens
= g_slist_append (display
->screens
, screen
);
513 display
->nb_screens
= display
->nb_screens
+ 1;
517 myDisplayRemoveScreen (DisplayInfo
*display
, ScreenInfo
*screen
)
519 g_return_if_fail (screen
!= NULL
);
520 g_return_if_fail (display
!= NULL
);
522 display
->screens
= g_slist_remove (display
->screens
, screen
);
523 display
->nb_screens
= display
->nb_screens
- 1;
524 if (display
->nb_screens
< 0)
526 display
->nb_screens
= 0;
531 myDisplayGetScreenFromRoot (DisplayInfo
*display
, Window root
)
535 g_return_val_if_fail (root
!= None
, NULL
);
536 g_return_val_if_fail (display
!= NULL
, NULL
);
538 for (index
= display
->screens
; index
; index
= g_slist_next (index
))
540 ScreenInfo
*screen
= (ScreenInfo
*) index
->data
;
541 if (screen
->xroot
== root
)
546 TRACE ("myDisplayGetScreenFromRoot: no screen found");
552 myDisplayGetScreenFromNum (DisplayInfo
*display
, int num
)
556 g_return_val_if_fail (display
!= NULL
, NULL
);
558 for (index
= display
->screens
; index
; index
= g_slist_next (index
))
560 ScreenInfo
*screen
= (ScreenInfo
*) index
->data
;
561 if (screen
->screen
== num
)
566 TRACE ("myDisplayGetScreenFromNum: no screen found");
572 myDisplayGetRootFromWindow(DisplayInfo
*display
, Window w
)
574 XWindowAttributes attributes
;
576 g_return_val_if_fail (w
!= None
, None
);
577 g_return_val_if_fail (display
!= NULL
, None
);
579 if (!XGetWindowAttributes(display
->dpy
, w
, &attributes
))
581 TRACE ("myDisplayGetRootFromWindow: no root found for 0x%lx", w
);
584 return attributes
.root
;
588 myDisplayGetScreenFromWindow (DisplayInfo
*display
, Window w
)
592 g_return_val_if_fail (w
!= None
, NULL
);
593 g_return_val_if_fail (display
!= NULL
, NULL
);
595 root
= myDisplayGetRootFromWindow (display
, w
);
598 return myDisplayGetScreenFromRoot (display
, root
);
600 TRACE ("myDisplayGetScreenFromWindow: no screen found");
605 #ifdef ENABLE_KDE_SYSTRAY_PROXY
607 myDisplayGetScreenFromSystray (DisplayInfo
*display
, Window w
)
611 g_return_val_if_fail (w
!= None
, NULL
);
612 g_return_val_if_fail (display
!= NULL
, NULL
);
614 for (index
= display
->screens
; index
; index
= g_slist_next (index
))
616 ScreenInfo
*screen
= (ScreenInfo
*) index
->data
;
617 if (screen
->systray
== w
)
622 TRACE ("myDisplayGetScreenFromSystray: no screen found");
626 #endif /* ENABLE_KDE_SYSTRAY_PROXY */
630 myDisplayGetClientFromXSyncAlarm (DisplayInfo
*display
, XSyncAlarm alarm
)
634 g_return_val_if_fail (alarm
!= None
, NULL
);
635 g_return_val_if_fail (display
!= NULL
, NULL
);
637 for (index
= display
->clients
; index
; index
= g_slist_next (index
))
639 Client
*c
= (Client
*) index
->data
;
640 if (alarm
== c
->xsync_alarm
)
645 TRACE ("no client found");
649 #endif /* HAVE_XSYNC */
652 myDisplayGetDefaultScreen (DisplayInfo
*display
)
656 g_return_val_if_fail (display
!= NULL
, NULL
);
658 index
= display
->screens
;
661 return (ScreenInfo
*) index
->data
;
668 myDisplayUpdateCurrentTime (DisplayInfo
*display
, XEvent
*ev
)
670 g_return_val_if_fail (display
!= NULL
, (Time
) CurrentTime
);
676 display
->current_time
= (Time
) ev
->xkey
.time
;
680 display
->current_time
= (Time
) ev
->xbutton
.time
;
683 display
->current_time
= (Time
) ev
->xmotion
.time
;
687 display
->current_time
= (Time
) ev
->xcrossing
.time
;
690 display
->current_time
= (Time
) ev
->xproperty
.time
;
693 display
->current_time
= (Time
) ev
->xselectionclear
.time
;
695 case SelectionRequest
:
696 display
->current_time
= (Time
) ev
->xselectionrequest
.time
;
698 case SelectionNotify
:
699 display
->current_time
= (Time
) ev
->xselection
.time
;
702 display
->current_time
= (Time
) CurrentTime
;
705 return display
->current_time
;
709 myDisplayGetCurrentTime (DisplayInfo
*display
)
711 g_return_val_if_fail (display
!= NULL
, (Time
) CurrentTime
);
713 TRACE ("myDisplayGetCurrentTime gives timestamp=%u", (unsigned int) display
->current_time
);
714 return (Time
) display
->current_time
;
718 myDisplayGetTime (DisplayInfo
* display
, Time timestamp
)
723 if (time
== (Time
) CurrentTime
)
725 time
= getXServerTime (display
);
728 TRACE ("myDisplayGetTime gives timestamp=%u", (unsigned int) time
);
733 myDisplayGetLastUserTime (DisplayInfo
*display
)
735 g_return_val_if_fail (display
!= NULL
, (Time
) CurrentTime
);
737 TRACE ("myDisplayGetLastUserTime gives timestamp=%u", (unsigned int) display
->last_user_time
);
738 return (Time
) display
->last_user_time
;
742 myDisplaySetLastUserTime (DisplayInfo
*display
, Time timestamp
)
744 g_return_if_fail (display
!= NULL
);
746 if (TIMESTAMP_IS_BEFORE(display
->last_user_time
, timestamp
))
748 display
->last_user_time
= timestamp
;
753 myDisplayTestXrender (DisplayInfo
*display
, gdouble min_time
)
759 Picture picture1
, picture2
, picture3
;
760 XRenderPictFormat
*format_src
, *format_dst
;
761 Pixmap fillPixmap
, rootPixmap
;
762 XRenderPictureAttributes pa
;
763 XSetWindowAttributes attrs
;
774 g_return_val_if_fail (display
!= NULL
, FALSE
);
775 TRACE ("entering myDisplayTesxrender");
783 screen_number
= DefaultScreen (dpy
);
784 screen
= DefaultScreenOfDisplay (dpy
);
785 visual
= DefaultVisual (dpy
, screen_number
);
786 depth
= DefaultDepth (dpy
, screen_number
);
788 w
= WidthOfScreen(screen
) / 16;
789 h
= HeightOfScreen(screen
) / 16;
790 x
= (WidthOfScreen(screen
) - w
);
791 y
= (HeightOfScreen(screen
) - h
);
793 format_dst
= XRenderFindVisualFormat (dpy
, visual
);
794 g_return_val_if_fail (format_dst
!= NULL
, FALSE
);
796 format_src
= XRenderFindStandardFormat (dpy
, PictStandardA8
);
797 g_return_val_if_fail (format_src
!= NULL
, FALSE
);
799 ximage
= XGetImage (dpy
,
800 DefaultRootWindow(dpy
),
803 g_return_val_if_fail (ximage
!= NULL
, FALSE
);
805 rootPixmap
= XCreatePixmap (dpy
,
806 DefaultRootWindow(dpy
),
808 XPutImage (dpy
, rootPixmap
,
809 DefaultGC (dpy
, screen_number
), ximage
,
811 XDestroyImage (ximage
);
813 attrs
.override_redirect
= TRUE
;
814 output
= XCreateWindow (dpy
,
815 DefaultRootWindow(dpy
),
817 0, CopyFromParent
, CopyFromParent
,
818 (Visual
*) CopyFromParent
,
819 CWOverrideRedirect
, &attrs
);
820 XMapRaised (dpy
, output
);
822 fillPixmap
= XCreatePixmap (dpy
,
823 DefaultRootWindow(dpy
),
826 g_get_current_time (&t1
);
829 picture1
= XRenderCreatePicture (dpy
,
831 format_dst
, 0, NULL
);
832 picture2
= XRenderCreatePicture (dpy
,
834 format_src
, CPRepeat
, &pa
);
835 picture3
= XRenderCreatePicture (dpy
,
837 format_dst
, 0, NULL
);
838 XRenderComposite (dpy
, PictOpSrc
,
839 picture1
, None
, picture3
,
840 0, 0, 0, 0, 0, 0, w
, h
);
841 XRenderFillRectangle (dpy
, PictOpSrc
,
844 for (iterations
= 0; iterations
< 10; iterations
++)
846 XRenderComposite (dpy
, PictOpOver
,
847 picture1
, picture2
, picture3
,
848 0, 0, 0, 0, 0, 0, w
, h
);
849 ximage
= XGetImage (dpy
, output
,
854 XDestroyImage (ximage
);
857 XRenderFreePicture (dpy
, picture1
);
858 XRenderFreePicture (dpy
, picture2
);
859 XRenderFreePicture (dpy
, picture3
);
861 XFreePixmap (dpy
, fillPixmap
);
862 XFreePixmap (dpy
, rootPixmap
);
864 XDestroyWindow (dpy
, output
);
866 g_get_current_time (&t2
);
868 dt
= (gdouble
) (t2
.tv_sec
- t1
.tv_sec
) * G_USEC_PER_SEC
+
869 (gdouble
) (t2
.tv_usec
- t1
.tv_usec
) / 1000.0;
873 TRACE ("XRender test passed (target %3.4f sec., measured %3.4f sec.).", min_time
, dt
);
876 g_print ("XRender test failed (target %3.4f sec., measured %3.4f sec.).\n", min_time
, dt
);
878 #else /* HAVE_RENDER */
880 #endif /* HAVE_RENDER */