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 <glib.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <glib.h>
33 #include <libxfce4util/libxfce4util.h>
34 #include "mypixmap.h"
35 #include "mywindow.h"
36 #include "screen.h"
37 
38 static void
xfwmWindowSetVisual(xfwmWindow * win,Visual * visual,gint depth)39 xfwmWindowSetVisual (xfwmWindow * win, Visual *visual, gint depth)
40 {
41     g_return_if_fail (win->screen_info != NULL);
42 
43     if (visual)
44     {
45         win->visual = visual;
46     }
47     else
48     {
49         win->visual = win->screen_info->visual;
50     }
51 
52     if (depth)
53     {
54         win->depth = depth;
55     }
56     else
57     {
58         win->depth = win->screen_info->depth;
59     }
60 }
61 
62 void
xfwmWindowInit(xfwmWindow * win)63 xfwmWindowInit (xfwmWindow * win)
64 {
65     g_return_if_fail (win != NULL);
66 
67     win->window = None;
68     win->map = FALSE;
69     win->screen_info = NULL;
70     win->depth = 0;
71     win->x = 0;
72     win->y = 0;
73     win->width = 1;
74     win->height = 1;
75 #ifdef HAVE_RENDER
76     win->pict_format = NULL;
77 #endif
78 }
79 
80 void
xfwmWindowSetCursor(xfwmWindow * win,Cursor cursor)81 xfwmWindowSetCursor (xfwmWindow * win, Cursor cursor)
82 {
83     ScreenInfo *screen_info;
84     DisplayInfo *display_info;
85 
86     g_return_if_fail (win != NULL);
87 
88     screen_info = win->screen_info;
89     display_info = screen_info->display_info;
90 
91     if ((win->window != None) && (cursor != None))
92     {
93         myDisplayErrorTrapPush (display_info);
94         XDefineCursor (myScreenGetXDisplay (screen_info), win->window, cursor);
95         myDisplayErrorTrapPopIgnored (display_info);
96     }
97 }
98 
99 void
xfwmWindowCreate(ScreenInfo * screen_info,Visual * visual,gint depth,Window parent,xfwmWindow * win,long eventmask,Cursor cursor)100 xfwmWindowCreate (ScreenInfo * screen_info, Visual *visual, gint depth, Window parent,
101                   xfwmWindow * win, long eventmask, Cursor cursor)
102 {
103     XSetWindowAttributes attributes;
104     unsigned long valuemask;
105 
106     TRACE ("parent (0x%lx)", parent);
107 
108     g_return_if_fail (screen_info != NULL);
109 
110     attributes.event_mask = eventmask;
111     valuemask = 0L;
112     if (eventmask != NoEventMask)
113     {
114         valuemask |= CWEventMask;
115     }
116 
117     win->window = XCreateWindow (myScreenGetXDisplay (screen_info),
118                                  parent, 0, 0, 1, 1, 0, 0,
119                                  InputOutput, CopyFromParent,
120                                  valuemask, &attributes);
121 
122     TRACE ("new XID (0x%lx)", win->window);
123 
124     win->map = FALSE;
125     win->screen_info = screen_info;
126     win->x = 0;
127     win->y = 0;
128     win->width = 1;
129     win->height = 1;
130     xfwmWindowSetVisual (win, visual, depth);
131     xfwmWindowSetCursor (win, cursor);
132 #ifdef HAVE_RENDER
133     win->pict_format = XRenderFindVisualFormat (myScreenGetXDisplay (screen_info), win->visual);
134 #endif
135 #ifdef HAVE_XI2
136     xfwm_device_configure_xi2_event_mask (screen_info->display_info->devices,
137                                           screen_info->display_info->dpy,
138                                           win->window, eventmask);
139 #endif
140 }
141 
142 void
xfwmWindowDelete(xfwmWindow * win)143 xfwmWindowDelete (xfwmWindow * win)
144 {
145     TRACE ("win %p (0x%lx)", win, win->window);
146 
147     if (win->window != None)
148     {
149         XDestroyWindow (myScreenGetXDisplay (win->screen_info),
150                         win->window);
151         win->window = None;
152     }
153     win->map = FALSE;
154 }
155 
156 void
xfwmWindowShow(xfwmWindow * win,int x,int y,int width,int height,gboolean refresh)157 xfwmWindowShow (xfwmWindow * win, int x, int y, int width, int height,
158     gboolean refresh)
159 {
160     ScreenInfo *screen_info;
161     DisplayInfo *display_info;
162 
163     TRACE ("win %p (0x%lx) at (%i,%i) [%i×%i]", win, win->window, x, y, width, height);
164 
165     if (!(win->window))
166     {
167         return;
168     }
169     if ((width < 1) || (height < 1))
170     {
171         xfwmWindowHide (win);
172         return;
173     }
174 
175     screen_info = win->screen_info;
176     display_info = screen_info->display_info;
177     myDisplayErrorTrapPush (display_info);
178 
179     if (!(win->map))
180     {
181         XMapWindow (myScreenGetXDisplay (screen_info),
182                     win->window);
183         win->map = TRUE;
184     }
185 
186     if (((x != win->x) || (y != win->y)) && ((width != win->width)
187             || (height != win->height)))
188     {
189         XMoveResizeWindow (myScreenGetXDisplay (screen_info),
190                            win->window, x, y,
191                            (unsigned int) width,
192                            (unsigned int) height);
193         win->x = x;
194         win->y = y;
195         win->width = width;
196         win->height = height;
197     }
198     else if ((x != win->x) || (y != win->y))
199     {
200         XMoveWindow (myScreenGetXDisplay (screen_info),
201                      win->window,
202                      x, y);
203         if (refresh)
204         {
205             XClearWindow (myScreenGetXDisplay (screen_info),
206                           win->window);
207         }
208         win->x = x;
209         win->y = y;
210     }
211     else if ((width != win->width) || (height != win->height))
212     {
213         XResizeWindow (myScreenGetXDisplay (screen_info),
214                        win->window,
215                        (unsigned int) width,
216                        (unsigned int) height);
217         win->width = width;
218         win->height = height;
219     }
220     else if (refresh)
221     {
222         XClearWindow (myScreenGetXDisplay (screen_info),
223                       win->window);
224     }
225     myDisplayErrorTrapPopIgnored (display_info);
226 }
227 
228 void
xfwmWindowHide(xfwmWindow * win)229 xfwmWindowHide (xfwmWindow * win)
230 {
231     TRACE ("win %p (0x%lx)", win, win->window);
232 
233     if (win->map)
234     {
235         g_assert (win->window);
236         XUnmapWindow (myScreenGetXDisplay (win->screen_info), win->window);
237         win->map = FALSE;
238     }
239 }
240 
241 gboolean
xfwmWindowVisible(xfwmWindow * win)242 xfwmWindowVisible (xfwmWindow *win)
243 {
244     g_return_val_if_fail (win, FALSE);
245 
246     return win->map;
247 }
248 
249 gboolean
xfwmWindowDeleted(xfwmWindow * win)250 xfwmWindowDeleted (xfwmWindow *win)
251 {
252     g_return_val_if_fail (win, TRUE);
253 
254     return (win->window == None);
255 }
256 
257 void
xfwmWindowTemp(ScreenInfo * screen_info,Visual * visual,gint depth,Window parent,xfwmWindow * win,int x,int y,int width,int height,long eventmask,gboolean bottom)258 xfwmWindowTemp (ScreenInfo *screen_info, Visual *visual,
259                 gint depth, Window parent,
260                 xfwmWindow * win,
261                 int x, int y, int width, int height,
262                 long eventmask,
263                 gboolean bottom)
264 {
265     XSetWindowAttributes attributes;
266     DisplayInfo *display_info;
267 
268     display_info = screen_info->display_info;
269     myDisplayErrorTrapPush (display_info);
270 
271     attributes.event_mask = eventmask;
272     attributes.override_redirect = TRUE;
273     win->window = XCreateWindow (myScreenGetXDisplay (screen_info),
274                                  parent, x, y, width, height, 0, 0,
275                                  InputOnly, CopyFromParent,
276                                  CWEventMask | CWOverrideRedirect,
277                                  &attributes);
278     if (bottom)
279     {
280         XLowerWindow (myScreenGetXDisplay (screen_info), win->window);
281     }
282     else
283     {
284         XRaiseWindow (myScreenGetXDisplay (screen_info), win->window);
285     }
286 
287     XMapWindow (myScreenGetXDisplay (screen_info), win->window);
288     win->map = TRUE;
289     win->screen_info = screen_info;
290     win->x = x;
291     win->y = y;
292     win->width = width;
293     win->height = height;
294     xfwmWindowSetVisual (win, visual, depth);
295 #ifdef HAVE_XI2
296     xfwm_device_configure_xi2_event_mask (screen_info->display_info->devices,
297                                           screen_info->display_info->dpy,
298                                           win->window, eventmask);
299 #endif
300     myDisplayErrorTrapPopIgnored (display_info);
301 }
302 
303 #ifdef HAVE_RENDER
304 static gboolean
xfwmWindowCopyComposite(xfwmWindow * win,xfwmPixmap * pix)305 xfwmWindowCopyComposite (xfwmWindow * win, xfwmPixmap * pix)
306 {
307     if (myDisplayHaveRender (win->screen_info->display_info))
308     {
309         Picture pict;
310         Pixmap temp;
311 
312         if (!pix->pict)
313         {
314             TRACE ("pixmap picture does not exist");
315             return FALSE;
316         }
317 
318         if (!win->pict_format)
319         {
320             TRACE ("window picture format is unknown");
321             return FALSE;
322         }
323 
324         temp = XCreatePixmap (myScreenGetXDisplay (win->screen_info),
325                               win->window,
326                               pix->width, pix->height, win->depth);
327 
328         if (!temp)
329         {
330             return FALSE;
331         }
332 
333         pict = XRenderCreatePicture (myScreenGetXDisplay (win->screen_info),
334                                      temp, win->pict_format, 0, NULL);
335 
336         if (!pict)
337         {
338             XFreePixmap (myScreenGetXDisplay (win->screen_info), temp);
339             return FALSE;
340         }
341 
342         XRenderComposite (myScreenGetXDisplay (win->screen_info), PictOpSrc, pix->pict, None, pict, 0, 0, 0, 0, 0, 0, pix->width, pix->height);
343 
344         XRenderFreePicture (myScreenGetXDisplay (win->screen_info), pict);
345 
346         XSetWindowBackgroundPixmap (myScreenGetXDisplay (win->screen_info), win->window, temp);
347 
348         XFreePixmap (myScreenGetXDisplay (win->screen_info), temp);
349         return TRUE;
350     }
351     return FALSE;
352 }
353 #endif
354 
355 void
xfwmWindowSetBG(xfwmWindow * win,xfwmPixmap * pix)356 xfwmWindowSetBG (xfwmWindow * win, xfwmPixmap * pix)
357 {
358     ScreenInfo *screen_info;
359     DisplayInfo *display_info;
360     gboolean done;
361 
362     if ((win->width < 1) || (win->height < 1) || (pix->width < 1) || (pix->height < 1))
363     {
364         return;
365     }
366 
367     screen_info = win->screen_info;
368     display_info = screen_info->display_info;
369     myDisplayErrorTrapPush (display_info);
370 
371     done = FALSE;
372 #ifdef HAVE_RENDER
373     if ((win->visual != screen_info->visual) ||
374         (win->depth  != screen_info->depth))
375     {
376         /* Try to use Render */
377         done = xfwmWindowCopyComposite (win, pix);
378     }
379 #endif
380 
381     if (!done)
382     {
383         /* Use the good old way */
384         XSetWindowBackgroundPixmap (myScreenGetXDisplay (screen_info), win->window, pix->pixmap);
385     }
386 
387     myDisplayErrorTrapPopIgnored (display_info);
388 }
389