Fix changelog email address
[freerdp-ubuntu-pcb-backport.git] / client / X11 / xf_window.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol Client
3  * X11 Windows
4  *
5  * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 #include <stdarg.h>
21 #include <X11/Xlib.h>
22 #include <X11/Xutil.h>
23 #include <X11/Xatom.h>
24
25 #include <freerdp/rail.h>
26 #include <freerdp/utils/rail.h>
27
28 #ifdef WITH_XEXT
29 #include <X11/extensions/shape.h>
30 #endif
31
32 #include "FreeRDP_Icon_256px.h"
33 #define xf_icon_prop FreeRDP_Icon_256px_prop
34
35 #include "xf_window.h"
36
37 /* Extended Window Manager Hints: http://standards.freedesktop.org/wm-spec/wm-spec-1.3.html */
38
39 /* bit definitions for MwmHints.flags */
40 #define MWM_HINTS_FUNCTIONS     (1L << 0)
41 #define MWM_HINTS_DECORATIONS   (1L << 1)
42 #define MWM_HINTS_INPUT_MODE    (1L << 2)
43 #define MWM_HINTS_STATUS        (1L << 3)
44
45 /* bit definitions for MwmHints.functions */
46 #define MWM_FUNC_ALL            (1L << 0)
47 #define MWM_FUNC_RESIZE         (1L << 1)
48 #define MWM_FUNC_MOVE           (1L << 2)
49 #define MWM_FUNC_MINIMIZE       (1L << 3)
50 #define MWM_FUNC_MAXIMIZE       (1L << 4)
51 #define MWM_FUNC_CLOSE          (1L << 5)
52
53 /* bit definitions for MwmHints.decorations */
54 #define MWM_DECOR_ALL           (1L << 0)
55 #define MWM_DECOR_BORDER        (1L << 1)
56 #define MWM_DECOR_RESIZEH       (1L << 2)
57 #define MWM_DECOR_TITLE         (1L << 3)
58 #define MWM_DECOR_MENU          (1L << 4)
59 #define MWM_DECOR_MINIMIZE      (1L << 5)
60 #define MWM_DECOR_MAXIMIZE      (1L << 6)
61
62 #define PROP_MOTIF_WM_HINTS_ELEMENTS    5
63
64 struct _PropMotifWmHints
65 {
66         unsigned long flags;
67         unsigned long functions;
68         unsigned long decorations;
69         long inputMode;
70         unsigned long status;
71 };
72 typedef struct _PropMotifWmHints PropMotifWmHints;
73
74 /**
75  * Post an event from the client to the X server
76  */
77 void xf_SendClientEvent(xfInfo *xfi, xfWindow* window, Atom atom, unsigned int numArgs, ...)
78 {
79        XEvent xevent;
80        unsigned int i;
81        va_list argp;
82
83        va_start(argp, numArgs);
84
85        xevent.xclient.type = ClientMessage;
86        xevent.xclient.serial = 0;
87        xevent.xclient.send_event = False;
88        xevent.xclient.display = xfi->display;
89        xevent.xclient.window = window->handle;
90        xevent.xclient.message_type = atom;
91        xevent.xclient.format = 32;
92
93        for (i=0; i<numArgs; i++)
94        {
95                xevent.xclient.data.l[i] = va_arg(argp, int);
96        }
97
98        DEBUG_X11("Send ClientMessage Event: wnd=0x%04X", (unsigned int) xevent.xclient.window);
99        XSendEvent(xfi->display, RootWindowOfScreen(xfi->screen), False, 
100                 SubstructureRedirectMask | SubstructureNotifyMask, &xevent);
101        XSync(xfi->display, False);
102
103        va_end(argp);
104 }
105
106 void xf_SetWindowFullscreen(xfInfo* xfi, xfWindow* window, boolean fullscreen)
107 {
108         if (fullscreen)
109         {
110                 xf_SetWindowDecorations(xfi, window, false);
111
112                 XMoveResizeWindow(xfi->display, window->handle, 0, 0, window->width, window->height);
113                 XMapRaised(xfi->display, window->handle);
114
115                 window->fullscreen = true;
116         }
117 }
118
119 /* http://tronche.com/gui/x/xlib/window-information/XGetWindowProperty.html */
120
121 boolean xf_GetWindowProperty(xfInfo* xfi, Window window, Atom property, int length,
122                 unsigned long* nitems, unsigned long* bytes, uint8** prop)
123 {
124         int status;
125         Atom actual_type;
126         int actual_format;
127
128         if (property == None)
129                 return false;
130
131         status = XGetWindowProperty(xfi->display, window,
132                         property, 0, length, false, AnyPropertyType,
133                         &actual_type, &actual_format, nitems, bytes, prop);
134
135         if (status != Success)
136                 return false;
137
138         if (actual_type == None)
139         {
140                 DEBUG_WARN("Property %lu does not exist", property);
141                 return false;
142         }
143
144         return true;
145 }
146
147 boolean xf_GetCurrentDesktop(xfInfo* xfi)
148 {
149         boolean status;
150         unsigned long nitems;
151         unsigned long bytes;
152         unsigned char* prop;
153
154         status = xf_GetWindowProperty(xfi, DefaultRootWindow(xfi->display),
155                         xfi->_NET_CURRENT_DESKTOP, 1, &nitems, &bytes, &prop);
156
157         if (status != true) {
158                 return false;
159         }
160
161         xfi->current_desktop = (int) *prop;
162         xfree(prop);
163
164         return true;
165 }
166
167 boolean xf_GetWorkArea(xfInfo* xfi)
168 {
169         long* plong;
170         boolean status;
171         unsigned long nitems;
172         unsigned long bytes;
173         unsigned char* prop;
174
175         status = xf_GetCurrentDesktop(xfi);
176
177         if (status != true)
178                 return false;
179
180         status = xf_GetWindowProperty(xfi, DefaultRootWindow(xfi->display),
181                         xfi->_NET_WORKAREA, 32 * 4, &nitems, &bytes, &prop);
182
183         if (status != true)
184                 return false;
185
186         if ((xfi->current_desktop * 4 + 3) >= nitems) {
187                 xfree(prop);
188                 return false;
189         }
190
191         plong = (long*) prop;
192
193         xfi->workArea.x = plong[xfi->current_desktop * 4 + 0];
194         xfi->workArea.y = plong[xfi->current_desktop * 4 + 1];
195         xfi->workArea.width = plong[xfi->current_desktop * 4 + 2];
196         xfi->workArea.height = plong[xfi->current_desktop * 4 + 3];
197         xfree(prop);
198
199         return true;
200 }
201
202 void xf_SetWindowDecorations(xfInfo* xfi, xfWindow* window, boolean show)
203 {
204         PropMotifWmHints hints;
205
206         hints.decorations = (show) ? MWM_DECOR_ALL : 0;
207         hints.functions = MWM_FUNC_ALL ; 
208         hints.flags = MWM_HINTS_DECORATIONS | MWM_HINTS_FUNCTIONS;
209
210         XChangeProperty(xfi->display, window->handle, xfi->_MOTIF_WM_HINTS, xfi->_MOTIF_WM_HINTS, 32,
211                 PropModeReplace, (uint8*) &hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
212 }
213
214 void xf_SetWindowUnlisted(xfInfo* xfi, xfWindow* window)
215 {
216         Atom window_state[2];
217
218         window_state[0] = xfi->_NET_WM_STATE_SKIP_PAGER;
219         window_state[1] = xfi->_NET_WM_STATE_SKIP_TASKBAR;
220
221         XChangeProperty(xfi->display, window->handle, xfi->_NET_WM_STATE,
222                 XA_ATOM, 32, PropModeReplace, (uint8*) &window_state, 2);
223 }
224
225 void xf_SetWindowStyle(xfInfo* xfi, xfWindow* window, uint32 style, uint32 ex_style)
226 {
227         Atom window_type;
228
229         if ((ex_style & WS_EX_TOPMOST) || (ex_style & WS_EX_TOOLWINDOW))
230         {
231                 /*
232                  * These include tool tips, dropdown menus, etc.  These won't work
233                  * correctly if the local window manager resizes or moves them.
234                  * Set override redirect to prevent this from occurring.
235                  */
236  
237                 XSetWindowAttributes attrs;
238                 attrs.override_redirect = True;
239                 XChangeWindowAttributes(xfi->display, window->handle, CWOverrideRedirect, &attrs);
240                 window->is_transient = true;
241                 xf_SetWindowUnlisted(xfi, window);
242
243                 window_type = xfi->_NET_WM_WINDOW_TYPE_POPUP;
244         }
245         else if (style & WS_POPUP)
246         {
247                 /* this includes dialogs, popups, etc, that need to be full-fledged windows */
248                 window_type = xfi->_NET_WM_WINDOW_TYPE_DIALOG;
249                 xf_SetWindowUnlisted(xfi, window);
250         }
251         else
252         {
253                 window_type = xfi->_NET_WM_WINDOW_TYPE_NORMAL;
254         }
255
256         XChangeProperty(xfi->display, window->handle, xfi->_NET_WM_WINDOW_TYPE,
257                 XA_ATOM, 32, PropModeReplace, (uint8*) &window_type, 1);
258
259 }
260
261 xfWindow* xf_CreateDesktopWindow(xfInfo* xfi, char* name, int width, int height, boolean decorations)
262 {
263         xfWindow* window;
264
265         window = (xfWindow*) xzalloc(sizeof(xfWindow));
266
267         if (window != NULL)
268         {
269                 int input_mask;
270                 XClassHint* class_hints;
271
272                 window->width = width;
273                 window->height = height;
274                 window->fullscreen = false;
275                 window->decorations = decorations;
276                 window->local_move.state = LMS_NOT_ACTIVE;
277                 window->is_mapped = false;
278                 window->is_transient = false;
279
280                 window->handle = XCreateWindow(xfi->display, RootWindowOfScreen(xfi->screen),
281                         xfi->workArea.x, xfi->workArea.y, xfi->width, xfi->height, 0, xfi->depth, InputOutput, xfi->visual,
282                         CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap | 
283                         CWBorderPixel | CWWinGravity | CWBitGravity, &xfi->attribs);
284
285                 class_hints = XAllocClassHint();
286
287                 if (class_hints != NULL)
288                 {
289                         class_hints->res_name = "xfreerdp";
290                         class_hints->res_class = "xfreerdp";
291                         XSetClassHint(xfi->display, window->handle, class_hints);
292                         XFree(class_hints);
293                 }
294
295                 xf_ResizeDesktopWindow(xfi, window, width, height);
296                 xf_SetWindowDecorations(xfi, window, decorations);
297
298                 input_mask =
299                         KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
300                         VisibilityChangeMask | FocusChangeMask | StructureNotifyMask |
301                         PointerMotionMask | ExposureMask | PropertyChangeMask;
302
303                 if (xfi->grab_keyboard)
304                         input_mask |= EnterWindowMask | LeaveWindowMask;
305
306                 XChangeProperty(xfi->display, window->handle, xfi->_NET_WM_ICON, XA_CARDINAL, 32,
307                                 PropModeReplace, (uint8*) xf_icon_prop, sizeof(xf_icon_prop) / sizeof(long));
308
309                 XSelectInput(xfi->display, window->handle, input_mask);
310                 XMapWindow(xfi->display, window->handle);
311         }
312
313         XStoreName(xfi->display, window->handle, name);
314
315         return window;
316 }
317
318 void xf_ResizeDesktopWindow(xfInfo* xfi, xfWindow* window, int width, int height)
319 {
320         XSizeHints* size_hints;
321
322         size_hints = XAllocSizeHints();
323
324         if (size_hints)
325         {
326                 size_hints->flags = PMinSize | PMaxSize;
327                 size_hints->min_width = size_hints->max_width = xfi->width;
328                 size_hints->min_height = size_hints->max_height = xfi->height;
329                 XSetWMNormalHints(xfi->display, window->handle, size_hints);
330                 XFree(size_hints);
331         }
332 }
333
334 void xf_FixWindowCoordinates(xfInfo* xfi, int* x, int* y, int* width, int* height)
335 {
336         int vscreen_width;
337         int vscreen_height;
338
339         vscreen_width = xfi->vscreen.area.right - xfi->vscreen.area.left + 1;
340         vscreen_height = xfi->vscreen.area.bottom - xfi->vscreen.area.top + 1;
341
342         if (*width < 1) 
343         {
344                 *width = 1;
345         }
346         if (*height < 1)
347         {
348                 *height = 1;
349         }
350         if (*x < xfi->vscreen.area.left)
351         {
352                 *width += *x;
353                 *x = xfi->vscreen.area.left;
354         }
355         if (*y < xfi->vscreen.area.top)
356         {
357                 *height += *y;
358                 *y = xfi->vscreen.area.top;
359         }
360         if (*width > vscreen_width)
361         {
362                 *width = vscreen_width;
363         }
364         if (*height > vscreen_height)
365         {
366                 *height = vscreen_height;
367         }
368 }
369
370 char rail_window_class[] = "RAIL:00000000";
371
372 xfWindow* xf_CreateWindow(xfInfo* xfi, rdpWindow* wnd, int x, int y, int width, int height, uint32 id)
373 {
374         xfWindow* window;
375
376         window = (xfWindow*) xzalloc(sizeof(xfWindow));
377
378         xf_FixWindowCoordinates(xfi, &x, &y, &width, &height);
379
380         window->left = x;
381         window->top = y;
382         window->right = x + width - 1;
383         window->bottom = y + height - 1;
384         window->width = width;
385         window->height = height;
386
387         XGCValues gcv;
388         XClassHint* class_hints;
389         int input_mask;
390
391         window->decorations = false;
392         window->fullscreen = false;
393         window->window = wnd;
394         window->local_move.state = LMS_NOT_ACTIVE;
395         window->is_mapped = false;
396         window->is_transient = false;
397
398         window->handle = XCreateWindow(xfi->display, RootWindowOfScreen(xfi->screen),
399                 x, y, window->width, window->height, 0, xfi->depth, InputOutput, xfi->visual,
400                 CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap | 
401                 CWBorderPixel | CWWinGravity | CWBitGravity, &xfi->attribs);
402
403         DEBUG_X11_LMS("Create  window=0x%X rc={l=%d t=%d r=%d b=%d} w=%d h=%d  rdp=0x%X",
404                         (uint32) window->handle, window->left, window->top, window->right, window->bottom,
405                         window->width, window->height, wnd->windowId);
406
407         xf_SetWindowDecorations(xfi, window, window->decorations);
408         xf_SetWindowStyle(xfi, window, wnd->style, wnd->extendedStyle);
409
410         class_hints = XAllocClassHint();
411
412         if (class_hints != NULL)
413         {
414                 char* class;
415                 class = xmalloc(sizeof(rail_window_class));
416                 snprintf(class, sizeof(rail_window_class), "RAIL:%08X", id);
417                 class_hints->res_name = "RAIL";
418                 class_hints->res_class = class;
419                 XSetClassHint(xfi->display, window->handle, class_hints);
420                 XFree(class_hints);
421                 xfree(class);
422         }
423
424         XSetWMProtocols(xfi->display, window->handle, &(xfi->WM_DELETE_WINDOW), 1);
425
426         input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask |
427                 ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | 
428                 PointerMotionMask | Button1MotionMask | Button2MotionMask | 
429                 Button3MotionMask | Button4MotionMask | Button5MotionMask |
430                 ButtonMotionMask | KeymapStateMask | ExposureMask | 
431                 VisibilityChangeMask | StructureNotifyMask | SubstructureNotifyMask | 
432                 SubstructureRedirectMask | FocusChangeMask | PropertyChangeMask |
433                 ColormapChangeMask | OwnerGrabButtonMask;
434
435         XSelectInput(xfi->display, window->handle, input_mask);
436         XMapWindow(xfi->display, window->handle);
437
438         memset(&gcv, 0, sizeof(gcv));
439         window->gc = XCreateGC(xfi->display, window->handle, GCGraphicsExposures, &gcv);
440
441         xf_MoveWindow(xfi, window, x, y, width, height);
442
443         return window;
444 }
445
446 void xf_SetWindowMinMaxInfo(xfInfo* xfi, xfWindow* window,
447                 int maxWidth, int maxHeight, int maxPosX, int maxPosY,
448                 int minTrackWidth, int minTrackHeight, int maxTrackWidth, int maxTrackHeight)
449 {
450         XSizeHints* size_hints;
451
452         size_hints = XAllocSizeHints();
453
454         if (size_hints)
455         {
456                 size_hints->flags = PMinSize | PMaxSize | PResizeInc;
457
458                 size_hints->min_width  = minTrackWidth;
459                 size_hints->min_height = minTrackHeight;
460
461                 size_hints->max_width  = maxTrackWidth;
462                 size_hints->max_height = maxTrackHeight;
463
464                 /* to speedup window drawing we need to select optimal value for sizing step. */
465                 size_hints->width_inc = size_hints->height_inc = 1;
466
467                 XSetWMNormalHints(xfi->display, window->handle, size_hints);
468                 XFree(size_hints);
469         }
470 }
471
472 void xf_StartLocalMoveSize(xfInfo* xfi, xfWindow* window, int direction, int x, int y)
473 {
474         Window child_window;
475
476         if (window->local_move.state != LMS_NOT_ACTIVE)
477                 return;
478
479         DEBUG_X11_LMS("direction=%d window=0x%X rc={l=%d t=%d r=%d b=%d} w=%d h=%d   "
480                 "RDP=0x%X rc={l=%d t=%d} w=%d h=%d  mouse_x=%d mouse_y=%d",
481                 direction, (uint32) window->handle, 
482                 window->left, window->top, window->right, window->bottom,
483                 window->width, window->height, window->window->windowId,
484                 window->window->windowOffsetX, window->window->windowOffsetY, 
485                 window->window->windowWidth, window->window->windowHeight, x, y);
486
487         window->local_move.root_x = x; 
488         window->local_move.root_y = y;
489         window->local_move.state = LMS_STARTING;
490
491         XTranslateCoordinates(xfi->display, RootWindowOfScreen(xfi->screen), window->handle, 
492                 window->local_move.root_x, 
493                 window->local_move.root_y,
494                 &window->local_move.window_x, 
495                 &window->local_move.window_y, 
496                 &child_window);
497
498         XUngrabPointer(xfi->display, CurrentTime);
499
500         xf_SendClientEvent(xfi, window, 
501                         xfi->_NET_WM_MOVERESIZE, /* request X window manager to initiate a local move */
502                         5, /* 5 arguments to follow */
503                         x, /* x relative to root window */
504                         y, /* y relative to root window */
505                         direction, /* extended ICCM direction flag */
506                         1, /* simulated mouse button 1 */
507                         1); /* 1 == application request per extended ICCM */
508 }
509
510 void xf_EndLocalMoveSize(xfInfo *xfi, xfWindow *window)
511 {
512
513         DEBUG_X11_LMS("state=%d window=0x%X rc={l=%d t=%d r=%d b=%d} w=%d h=%d  "
514                 "RDP=0x%X rc={l=%d t=%d} w=%d h=%d",
515                 window->local_move.state, 
516                 (uint32) window->handle, window->left, window->top, window->right, window->bottom,
517                 window->width, window->height, window->window->windowId,
518                 window->window->windowOffsetX, window->window->windowOffsetY, 
519                 window->window->windowWidth, window->window->windowHeight);
520
521         if (window->local_move.state == LMS_NOT_ACTIVE)
522                 return;
523
524         if (window->local_move.state == LMS_STARTING)
525         {
526                 /*
527                  * The move never was property started. This can happen due to race
528                  * conditions between the mouse button up and the communications to the
529                  * RDP server for local moves. We must cancel the X window manager move.
530                  * Per ICCM, the X client can ask to cancel an active move. 
531                  */
532                 xf_SendClientEvent(xfi, window, 
533                         xfi->_NET_WM_MOVERESIZE, /* request X window manager to abort a local move */
534                         5, /* 5 arguments to follow */
535                         window->local_move.root_x, /* x relative to root window */
536                         window->local_move.root_y, /* y relative to root window */
537                         _NET_WM_MOVERESIZE_CANCEL, /* extended ICCM direction flag */
538                         1, /* simulated mouse button 1 */
539                         1); /* 1 == application request per extended ICCM */
540         }
541
542         window->local_move.state = LMS_NOT_ACTIVE;
543 }
544
545 void xf_MoveWindow(xfInfo* xfi, xfWindow* window, int x, int y, int width, int height)
546 {
547         boolean resize = false;
548
549         if ((width * height) < 1)
550                 return;
551
552         if ((window->width != width) || (window->height != height))
553                 resize = true;
554
555         if (window->local_move.state == LMS_STARTING ||
556                 window->local_move.state == LMS_ACTIVE)
557                 return;
558
559         DEBUG_X11_LMS("window=0x%X rc={l=%d t=%d r=%d b=%d} w=%u h=%u  "
560                 "new rc={l=%d t=%d r=%d b=%d} w=%u h=%u"
561                 "  RDP=0x%X rc={l=%d t=%d} w=%d h=%d",
562                 (uint32) window->handle, window->left, window->top, 
563                 window->right, window->bottom, window->width, window->height,
564                 x, y, x + width -1, y + height -1, width, height, 
565                 window->window->windowId,
566                 window->window->windowOffsetX, window->window->windowOffsetY, 
567                 window->window->windowWidth, window->window->windowHeight);
568
569         window->left = x;
570         window->top = y;
571         window->right = x + width - 1;
572         window->bottom = y + height - 1;
573         window->width = width;
574         window->height = height;
575
576         if (resize)
577                 XMoveResizeWindow(xfi->display, window->handle, x, y, width, height);
578         else
579                 XMoveWindow(xfi->display, window->handle, x, y);
580
581         xf_UpdateWindowArea(xfi, window, 0, 0, width, height);
582 }
583
584 void xf_ShowWindow(xfInfo* xfi, xfWindow* window, uint8 state)
585 {
586         switch (state)
587         {
588                 case WINDOW_HIDE:
589                         XWithdrawWindow(xfi->display, window->handle, xfi->screen_number);
590                         break;
591
592                 case WINDOW_SHOW_MINIMIZED:
593                         XIconifyWindow(xfi->display, window->handle, xfi->screen_number);
594                         break;
595
596                 case WINDOW_SHOW_MAXIMIZED:
597                         XRaiseWindow(xfi->display, window->handle);
598                         break;
599
600                 case WINDOW_SHOW:
601                         XMapWindow(xfi->display, window->handle);
602                         break;
603         }
604
605         XFlush(xfi->display);
606 }
607
608 void xf_SetWindowIcon(xfInfo* xfi, xfWindow* window, rdpIcon* icon)
609 {
610         int x, y;
611         int pixels;
612         int propsize;
613         long* propdata;
614         long* dstp;
615         uint32* srcp;
616
617         if (icon->big != true)
618                 return;
619
620         pixels = icon->entry->width * icon->entry->height;
621         propsize = 2 + pixels;
622         propdata = xmalloc(propsize * sizeof(long));
623
624         propdata[0] = icon->entry->width;
625         propdata[1] = icon->entry->height;
626         dstp = &(propdata[2]);
627         srcp = (uint32*) icon->extra;
628
629         for (y = 0; y < icon->entry->height; y++)
630         {
631                 for (x = 0; x < icon->entry->width; x++)
632                 {
633                         *dstp++ = *srcp++;
634                 }
635         }
636
637         XChangeProperty(xfi->display, window->handle, xfi->_NET_WM_ICON, XA_CARDINAL, 32,
638                 PropModeReplace, (uint8*) propdata, propsize);
639
640         XFlush(xfi->display);
641 }
642
643 void xf_SetWindowRects(xfInfo* xfi, xfWindow* window, RECTANGLE_16* rects, int nrects)
644 {
645         int i;
646         XRectangle* xrects;
647
648         xrects = xmalloc(sizeof(XRectangle) * nrects);
649
650         for (i = 0; i < nrects; i++)
651         {
652                 xrects[i].x = rects[i].left;
653                 xrects[i].y = rects[i].top;
654                 xrects[i].width = rects[i].right - rects[i].left;
655                 xrects[i].height = rects[i].bottom - rects[i].top;
656         }
657
658 #ifdef WITH_XEXT
659         XShapeCombineRectangles(xfi->display, window->handle, ShapeBounding, 0, 0, xrects, nrects, ShapeSet, 0);
660 #endif
661
662         xfree(xrects);
663 }
664
665 void xf_SetWindowVisibilityRects(xfInfo* xfi, xfWindow* window, RECTANGLE_16* rects, int nrects)
666 {
667         int i;
668         XRectangle* xrects;
669
670         xrects = xmalloc(sizeof(XRectangle) * nrects);
671
672         for (i = 0; i < nrects; i++)
673         {
674                 xrects[i].x = rects[i].left;
675                 xrects[i].y = rects[i].top;
676                 xrects[i].width = rects[i].right - rects[i].left;
677                 xrects[i].height = rects[i].bottom - rects[i].top;
678         }
679
680 #ifdef WITH_XEXT
681         //XShapeCombineRectangles(xfi->display, window->handle, ShapeBounding, 0, 0, xrects, nrects, ShapeSet, 0);
682 #endif
683
684         xfree(xrects);
685 }
686
687 void xf_UpdateWindowArea(xfInfo* xfi, xfWindow* window, int x, int y, int width, int height)
688 {
689         int ax, ay;
690         rdpWindow* wnd;
691         wnd = window->window;
692
693         ax = x + wnd->windowOffsetX;
694         ay = y + wnd->windowOffsetY;
695
696         if (ax + width > wnd->windowOffsetX + wnd->windowWidth)
697                 width = (wnd->windowOffsetX + wnd->windowWidth - 1) - ax;
698
699         if (ay + height > wnd->windowOffsetY + wnd->windowHeight)
700                 height = (wnd->windowOffsetY + wnd->windowHeight - 1) - ay;
701
702         if (xfi->sw_gdi)
703         {
704                 XPutImage(xfi->display, xfi->primary, window->gc, xfi->image,
705                         ax, ay, ax, ay, width, height);
706         }
707
708         XCopyArea(xfi->display, xfi->primary, window->handle, window->gc,
709                         ax, ay, width, height, x, y);
710
711         XFlush(xfi->display);
712 }
713
714 boolean xf_IsWindowBorder(xfInfo* xfi, xfWindow* xfw, int x, int y)
715 {
716         rdpWindow* wnd;
717         boolean clientArea = false;
718         boolean windowArea = false;
719
720         wnd = xfw->window;
721
722         if (((x > wnd->clientOffsetX) && (x < wnd->clientOffsetX + wnd->clientAreaWidth)) &&
723                 ((y > wnd->clientOffsetY) && (y < wnd->clientOffsetY + wnd->clientAreaHeight)))
724                 clientArea = true;
725
726         if (((x > wnd->windowOffsetX) && (x < wnd->windowOffsetX + wnd->windowWidth)) &&
727                 ((y > wnd->windowOffsetY) && (y < wnd->windowOffsetY + wnd->windowHeight)))
728                 windowArea = true;
729
730         return (windowArea && !(clientArea));
731 }
732
733 void xf_DestroyWindow(xfInfo* xfi, xfWindow* window)
734 {
735         if (window == NULL)
736                 return;
737
738         if (xfi->window == window)
739                 xfi->window = NULL;
740
741         if (window->gc)
742                 XFreeGC(xfi->display, window->gc);
743
744         if (window->handle)
745         {
746                 XUnmapWindow(xfi->display, window->handle);
747                 XDestroyWindow(xfi->display, window->handle);
748         }
749
750         xfree(window);
751 }