1 /* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 User interface services - X Window System
4 Copyright (C) Matthew Chapman 1999-2005
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include <X11/Xutil.h>
31 /* We can't include Xproto.h because of conflicting defines for BOOL */
32 #define X_ConfigureWindow 12
35 #define MWM_HINTS_DECORATIONS (1L << 1)
36 #define PROP_MOTIF_WM_HINTS_ELEMENTS 5
40 unsigned long functions
;
41 unsigned long decorations
;
55 #define ON_ALL_SEAMLESS_WINDOWS(func, args) \
57 seamless_window *sw; \
59 if (!This->xwin.seamless_windows) break; \
60 for (sw = This->xwin.seamless_windows; sw; sw = sw->next) { \
61 rect.x = This->xwin.clip_rectangle.x - sw->xoffset; \
62 rect.y = This->xwin.clip_rectangle.y - sw->yoffset; \
63 rect.width = This->xwin.clip_rectangle.width; \
64 rect.height = This->xwin.clip_rectangle.height; \
65 XSetClipRectangles(This->display, This->xwin.gc, 0, 0, &rect, 1, YXBanded); \
68 XSetClipRectangles(This->display, This->xwin.gc, 0, 0, &This->xwin.clip_rectangle, 1, YXBanded); \
72 seamless_XFillPolygon(RDPCLIENT
* This
, Drawable d
, XPoint
* points
, int npoints
, int xoffset
, int yoffset
)
74 points
[0].x
-= xoffset
;
75 points
[0].y
-= yoffset
;
76 XFillPolygon(This
->display
, d
, This
->xwin
.gc
, points
, npoints
, Complex
, CoordModePrevious
);
77 points
[0].x
+= xoffset
;
78 points
[0].y
+= yoffset
;
82 seamless_XDrawLines(RDPCLIENT
* This
, Drawable d
, XPoint
* points
, int npoints
, int xoffset
, int yoffset
)
84 points
[0].x
-= xoffset
;
85 points
[0].y
-= yoffset
;
86 XDrawLines(This
->display
, d
, This
->xwin
.gc
, points
, npoints
, CoordModePrevious
);
87 points
[0].x
+= xoffset
;
88 points
[0].y
+= yoffset
;
91 #define FILL_RECTANGLE(x,y,cx,cy)\
93 XFillRectangle(This->display, This->wnd, This->xwin.gc, x, y, cx, cy); \
94 ON_ALL_SEAMLESS_WINDOWS(XFillRectangle, (This->display, sw->wnd, This->xwin.gc, x-sw->xoffset, y-sw->yoffset, cx, cy)); \
95 if (This->ownbackstore) \
96 XFillRectangle(This->display, This->xwin.backstore, This->xwin.gc, x, y, cx, cy); \
99 #define FILL_RECTANGLE_BACKSTORE(x,y,cx,cy)\
101 XFillRectangle(This->display, This->ownbackstore ? This->xwin.backstore : This->wnd, This->xwin.gc, x, y, cx, cy); \
104 #define FILL_POLYGON(p,np)\
106 XFillPolygon(This->display, This->wnd, This->xwin.gc, p, np, Complex, CoordModePrevious); \
107 if (This->ownbackstore) \
108 XFillPolygon(This->display, This->xwin.backstore, This->xwin.gc, p, np, Complex, CoordModePrevious); \
109 ON_ALL_SEAMLESS_WINDOWS(seamless_XFillPolygon, (This, sw->wnd, p, np, sw->xoffset, sw->yoffset)); \
112 #define DRAW_ELLIPSE(x,y,cx,cy,m)\
116 case 0: /* Outline */ \
117 XDrawArc(This->display, This->wnd, This->xwin.gc, x, y, cx, cy, 0, 360*64); \
118 ON_ALL_SEAMLESS_WINDOWS(XDrawArc, (This->display, sw->wnd, This->xwin.gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
119 if (This->ownbackstore) \
120 XDrawArc(This->display, This->xwin.backstore, This->xwin.gc, x, y, cx, cy, 0, 360*64); \
122 case 1: /* Filled */ \
123 XFillArc(This->display, This->wnd, This->xwin.gc, x, y, cx, cy, 0, 360*64); \
124 ON_ALL_SEAMLESS_WINDOWS(XCopyArea, (This->display, This->ownbackstore ? This->xwin.backstore : This->wnd, sw->wnd, This->xwin.gc, \
125 x, y, cx, cy, x-sw->xoffset, y-sw->yoffset)); \
126 if (This->ownbackstore) \
127 XFillArc(This->display, This->xwin.backstore, This->xwin.gc, x, y, cx, cy, 0, 360*64); \
132 #define TRANSLATE(col) ( This->server_depth != 8 ? translate_colour(This, col) : This->owncolmap ? col : This->xwin.colmap[col] )
133 #define SET_FOREGROUND(col) XSetForeground(This->display, This->xwin.gc, TRANSLATE(col));
134 #define SET_BACKGROUND(col) XSetBackground(This->display, This->xwin.gc, TRANSLATE(col));
136 static const int rop2_map
[] = {
139 GXandInverted
, /* DPna */
140 GXcopyInverted
, /* Pn */
141 GXandReverse
, /* PDna */
148 GXorInverted
, /* DPno */
150 GXorReverse
, /* PDno */
155 #define SET_FUNCTION(rop2) { if (rop2 != ROP2_COPY) XSetFunction(This->display, This->xwin.gc, rop2_map[rop2]); }
156 #define RESET_FUNCTION(rop2) { if (rop2 != ROP2_COPY) XSetFunction(This->display, This->xwin.gc, GXcopy); }
158 static seamless_window
*
159 sw_get_window_by_id(RDPCLIENT
* This
, unsigned long id
)
162 for (sw
= This
->xwin
.seamless_windows
; sw
; sw
= sw
->next
)
171 static seamless_window
*
172 sw_get_window_by_wnd(RDPCLIENT
* This
, Window wnd
)
175 for (sw
= This
->xwin
.seamless_windows
; sw
; sw
= sw
->next
)
185 sw_remove_window(RDPCLIENT
* This
, seamless_window
* win
)
187 seamless_window
*sw
, **prevnext
= &This
->xwin
.seamless_windows
;
188 for (sw
= This
->xwin
.seamless_windows
; sw
; sw
= sw
->next
)
192 *prevnext
= sw
->next
;
194 if (sw
->group
->refcnt
== 0)
196 XDestroyWindow(This
->display
, sw
->group
->wnd
);
199 xfree(sw
->position_timer
);
203 prevnext
= &sw
->next
;
209 /* Move all windows except wnd to new desktop */
211 sw_all_to_desktop(RDPCLIENT
* This
, Window wnd
, unsigned int desktop
)
214 for (sw
= This
->xwin
.seamless_windows
; sw
; sw
= sw
->next
)
218 if (sw
->desktop
!= desktop
)
220 ewmh_move_to_desktop(This
, sw
->wnd
, desktop
);
221 sw
->desktop
= desktop
;
227 /* Send our position */
229 sw_update_position(RDPCLIENT
* This
, seamless_window
* sw
)
231 XWindowAttributes wa
;
236 XGetWindowAttributes(This
->display
, sw
->wnd
, &wa
);
237 XTranslateCoordinates(This
->display
, sw
->wnd
, wa
.root
,
238 -wa
.border_width
, -wa
.border_width
, &x
, &y
, &child_return
);
240 serial
= seamless_send_position(This
, sw
->id
, x
, y
, wa
.width
, wa
.height
, 0);
242 sw
->outstanding_position
= True
;
243 sw
->outpos_serial
= serial
;
245 sw
->outpos_xoffset
= x
;
246 sw
->outpos_yoffset
= y
;
247 sw
->outpos_width
= wa
.width
;
248 sw
->outpos_height
= wa
.height
;
252 /* Check if it's time to send our position */
254 sw_check_timers(RDPCLIENT
* This
)
259 gettimeofday(&now
, NULL
);
260 for (sw
= This
->xwin
.seamless_windows
; sw
; sw
= sw
->next
)
262 if (timerisset(sw
->position_timer
) && timercmp(sw
->position_timer
, &now
, <))
264 timerclear(sw
->position_timer
);
265 sw_update_position(This
, sw
);
272 sw_restack_window(RDPCLIENT
* This
, seamless_window
* sw
, unsigned long behind
)
274 seamless_window
*sw_above
;
276 /* Remove window from stack */
277 for (sw_above
= This
->xwin
.seamless_windows
; sw_above
; sw_above
= sw_above
->next
)
279 if (sw_above
->behind
== sw
->id
)
284 sw_above
->behind
= sw
->behind
;
286 /* And then add it at the new position */
287 for (sw_above
= This
->xwin
.seamless_windows
; sw_above
; sw_above
= sw_above
->next
)
289 if (sw_above
->behind
== behind
)
294 sw_above
->behind
= sw
->id
;
301 sw_handle_restack(RDPCLIENT
* This
, seamless_window
* sw
)
304 Window root
, parent
, *children
;
305 unsigned int nchildren
, i
;
306 seamless_window
*sw_below
;
308 status
= XQueryTree(This
->display
, RootWindowOfScreen(This
->xwin
.screen
),
309 &root
, &parent
, &children
, &nchildren
);
310 if (!status
|| !nchildren
)
316 while (children
[i
] != sw
->wnd
)
323 for (i
++; i
< nchildren
; i
++)
325 sw_below
= sw_get_window_by_wnd(This
, children
[i
]);
330 if (!sw_below
&& !sw
->behind
)
332 if (sw_below
&& (sw_below
->id
== sw
->behind
))
337 seamless_send_zchange(This
, sw
->id
, sw_below
->id
, 0);
338 sw_restack_window(This
, sw
, sw_below
->id
);
342 seamless_send_zchange(This
, sw
->id
, 0, 0);
343 sw_restack_window(This
, sw
, 0);
351 static seamless_group
*
352 sw_find_group(RDPCLIENT
* This
, unsigned long id
, BOOL dont_create
)
356 XSetWindowAttributes attribs
;
358 for (sw
= This
->xwin
.seamless_windows
; sw
; sw
= sw
->next
)
360 if (sw
->group
->id
== id
)
367 sg
= xmalloc(sizeof(seamless_group
));
370 XCreateWindow(This
->display
, RootWindowOfScreen(This
->xwin
.screen
), -1, -1, 1, 1, 0,
371 CopyFromParent
, CopyFromParent
, CopyFromParent
, 0, &attribs
);
381 mwm_hide_decorations(RDPCLIENT
* This
, Window wnd
)
383 PropMotifWmHints motif_hints
;
386 /* setup the property */
387 motif_hints
.flags
= MWM_HINTS_DECORATIONS
;
388 motif_hints
.decorations
= 0;
390 /* get the atom for the property */
391 hintsatom
= XInternAtom(This
->display
, "_MOTIF_WM_HINTS", False
);
394 warning("Failed to get atom _MOTIF_WM_HINTS: probably your window manager does not support MWM hints\n");
398 XChangeProperty(This
->display
, wnd
, hintsatom
, hintsatom
, 32, PropModeReplace
,
399 (unsigned char *) &motif_hints
, PROP_MOTIF_WM_HINTS_ELEMENTS
);
403 #define SPLITCOLOUR15(colour, rv) \
405 rv.red = ((colour >> 7) & 0xf8) | ((colour >> 12) & 0x7); \
406 rv.green = ((colour >> 2) & 0xf8) | ((colour >> 8) & 0x7); \
407 rv.blue = ((colour << 3) & 0xf8) | ((colour >> 2) & 0x7); \
410 #define SPLITCOLOUR16(colour, rv) \
412 rv.red = ((colour >> 8) & 0xf8) | ((colour >> 13) & 0x7); \
413 rv.green = ((colour >> 3) & 0xfc) | ((colour >> 9) & 0x3); \
414 rv.blue = ((colour << 3) & 0xf8) | ((colour >> 2) & 0x7); \
417 #define SPLITCOLOUR24(colour, rv) \
419 rv.blue = (colour & 0xff0000) >> 16; \
420 rv.green = (colour & 0x00ff00) >> 8; \
421 rv.red = (colour & 0x0000ff); \
424 #define MAKECOLOUR(pc) \
425 ((pc.red >> This->xwin.red_shift_r) << This->xwin.red_shift_l) \
426 | ((pc.green >> This->xwin.green_shift_r) << This->xwin.green_shift_l) \
427 | ((pc.blue >> This->xwin.blue_shift_r) << This->xwin.blue_shift_l) \
429 #define BSWAP16(x) { x = (((x & 0xff) << 8) | (x >> 8)); }
430 #define BSWAP24(x) { x = (((x & 0xff) << 16) | (x >> 16) | (x & 0xff00)); }
431 #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \
432 x = (x << 16) | (x >> 16); }
434 /* The following macros output the same octet sequences
435 on both BE and LE hosts: */
437 #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }
438 #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
439 #define BOUT32(o, x) { *(o++) = x >> 24; *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
440 #define LOUT16(o, x) { *(o++) = x; *(o++) = x >> 8; }
441 #define LOUT24(o, x) { *(o++) = x; *(o++) = x >> 8; *(o++) = x >> 16; }
442 #define LOUT32(o, x) { *(o++) = x; *(o++) = x >> 8; *(o++) = x >> 16; *(o++) = x >> 24; }
445 translate_colour(RDPCLIENT
* This
, uint32 colour
)
448 switch (This
->server_depth
)
451 SPLITCOLOUR15(colour
, pc
);
454 SPLITCOLOUR16(colour
, pc
);
457 SPLITCOLOUR24(colour
, pc
);
466 return MAKECOLOUR(pc
);
469 /* indent is confused by UNROLL8 */
472 /* repeat and unroll, similar to bitmap.c */
473 /* potentialy any of the following translate */
474 /* functions can use repeat but just doing */
475 /* the most common ones */
477 #define UNROLL8(stm) { stm stm stm stm stm stm stm stm }
478 /* 2 byte output repeat */
479 #define REPEAT2(stm) \
481 while (out <= end - 8 * 2) \
486 /* 3 byte output repeat */
487 #define REPEAT3(stm) \
489 while (out <= end - 8 * 3) \
494 /* 4 byte output repeat */
495 #define REPEAT4(stm) \
497 while (out <= end - 8 * 4) \
505 translate8to8(RDPCLIENT
* This
, const uint8
* data
, uint8
* out
, uint8
* end
)
508 *(out
++) = (uint8
) This
->xwin
.colmap
[*(data
++)];
512 translate8to16(RDPCLIENT
* This
, const uint8
* data
, uint8
* out
, uint8
* end
)
516 if (This
->xwin
.compatible_arch
)
521 *((uint16
*) out
) = This
->xwin
.colmap
[*(data
++)];
526 else if (This
->xwin
.xserver_be
)
530 value
= (uint16
) This
->xwin
.colmap
[*(data
++)];
538 value
= (uint16
) This
->xwin
.colmap
[*(data
++)];
544 /* little endian - conversion happens when colourmap is built */
546 translate8to24(RDPCLIENT
* This
, const uint8
* data
, uint8
* out
, uint8
* end
)
550 if (This
->xwin
.compatible_arch
)
554 value
= This
->xwin
.colmap
[*(data
++)];
562 value
= This
->xwin
.colmap
[*(data
++)];
569 translate8to32(RDPCLIENT
* This
, const uint8
* data
, uint8
* out
, uint8
* end
)
573 if (This
->xwin
.compatible_arch
)
578 *((uint32
*) out
) = This
->xwin
.colmap
[*(data
++)];
583 else if (This
->xwin
.xserver_be
)
587 value
= This
->xwin
.colmap
[*(data
++)];
595 value
= This
->xwin
.colmap
[*(data
++)];
602 translate15to16(RDPCLIENT
* This
, const uint16
* data
, uint8
* out
, uint8
* end
)
608 if (This
->xwin
.xserver_be
)
613 if (This
->xwin
.host_be
)
617 SPLITCOLOUR15(pixel
, pc
);
618 value
= MAKECOLOUR(pc
);
627 if (This
->xwin
.host_be
)
631 SPLITCOLOUR15(pixel
, pc
);
632 value
= MAKECOLOUR(pc
);
639 translate15to24(RDPCLIENT
* This
, const uint16
* data
, uint8
* out
, uint8
* end
)
645 if (This
->xwin
.compatible_arch
)
651 SPLITCOLOUR15(pixel
, pc
);
658 else if (This
->xwin
.xserver_be
)
663 if (This
->xwin
.host_be
)
667 SPLITCOLOUR15(pixel
, pc
);
668 value
= MAKECOLOUR(pc
);
677 if (This
->xwin
.host_be
)
681 SPLITCOLOUR15(pixel
, pc
);
682 value
= MAKECOLOUR(pc
);
689 translate15to32(RDPCLIENT
* This
, const uint16
* data
, uint8
* out
, uint8
* end
)
695 if (This
->xwin
.compatible_arch
)
701 SPLITCOLOUR15(pixel
, pc
);
709 else if (This
->xwin
.xserver_be
)
714 if (This
->xwin
.host_be
)
718 SPLITCOLOUR15(pixel
, pc
);
719 value
= MAKECOLOUR(pc
);
728 if (This
->xwin
.host_be
)
732 SPLITCOLOUR15(pixel
, pc
);
733 value
= MAKECOLOUR(pc
);
740 translate16to16(RDPCLIENT
* This
, const uint16
* data
, uint8
* out
, uint8
* end
)
746 if (This
->xwin
.xserver_be
)
748 if (This
->xwin
.host_be
)
754 SPLITCOLOUR16(pixel
, pc
);
755 value
= MAKECOLOUR(pc
);
764 SPLITCOLOUR16(pixel
, pc
);
765 value
= MAKECOLOUR(pc
);
772 if (This
->xwin
.host_be
)
778 SPLITCOLOUR16(pixel
, pc
);
779 value
= MAKECOLOUR(pc
);
788 SPLITCOLOUR16(pixel
, pc
);
789 value
= MAKECOLOUR(pc
);
797 translate16to24(RDPCLIENT
* This
, const uint16
* data
, uint8
* out
, uint8
* end
)
803 if (This
->xwin
.compatible_arch
)
809 SPLITCOLOUR16(pixel
, pc
);
816 else if (This
->xwin
.xserver_be
)
818 if (This
->xwin
.host_be
)
824 SPLITCOLOUR16(pixel
, pc
);
825 value
= MAKECOLOUR(pc
);
834 SPLITCOLOUR16(pixel
, pc
);
835 value
= MAKECOLOUR(pc
);
842 if (This
->xwin
.host_be
)
848 SPLITCOLOUR16(pixel
, pc
);
849 value
= MAKECOLOUR(pc
);
858 SPLITCOLOUR16(pixel
, pc
);
859 value
= MAKECOLOUR(pc
);
867 translate16to32(RDPCLIENT
* This
, const uint16
* data
, uint8
* out
, uint8
* end
)
873 if (This
->xwin
.compatible_arch
)
879 SPLITCOLOUR16(pixel
, pc
);
887 else if (This
->xwin
.xserver_be
)
889 if (This
->xwin
.host_be
)
895 SPLITCOLOUR16(pixel
, pc
);
896 value
= MAKECOLOUR(pc
);
905 SPLITCOLOUR16(pixel
, pc
);
906 value
= MAKECOLOUR(pc
);
913 if (This
->xwin
.host_be
)
919 SPLITCOLOUR16(pixel
, pc
);
920 value
= MAKECOLOUR(pc
);
929 SPLITCOLOUR16(pixel
, pc
);
930 value
= MAKECOLOUR(pc
);
938 translate24to16(RDPCLIENT
* This
, const uint8
* data
, uint8
* out
, uint8
* end
)
946 pixel
= *(data
++) << 16;
947 pixel
|= *(data
++) << 8;
949 SPLITCOLOUR24(pixel
, pc
);
950 value
= MAKECOLOUR(pc
);
951 if (This
->xwin
.xserver_be
)
963 translate24to24(RDPCLIENT
* This
, const uint8
* data
, uint8
* out
, uint8
* end
)
969 if (This
->xwin
.xserver_be
)
973 pixel
= *(data
++) << 16;
974 pixel
|= *(data
++) << 8;
976 SPLITCOLOUR24(pixel
, pc
);
977 value
= MAKECOLOUR(pc
);
985 pixel
= *(data
++) << 16;
986 pixel
|= *(data
++) << 8;
988 SPLITCOLOUR24(pixel
, pc
);
989 value
= MAKECOLOUR(pc
);
996 translate24to32(RDPCLIENT
* This
, const uint8
* data
, uint8
* out
, uint8
* end
)
1002 if (This
->xwin
.compatible_arch
)
1008 *(out
++) = *(data
++);
1009 *(out
++) = *(data
++);
1010 *(out
++) = *(data
++);
1016 /* Only read 3 bytes. Reading 4 bytes means reading beyond buffer. */
1017 *((uint32
*) out
) = *((uint16
*) data
) + (*((uint8
*) data
+ 2) << 16);
1024 else if (This
->xwin
.xserver_be
)
1028 pixel
= *(data
++) << 16;
1029 pixel
|= *(data
++) << 8;
1031 SPLITCOLOUR24(pixel
, pc
);
1032 value
= MAKECOLOUR(pc
);
1040 pixel
= *(data
++) << 16;
1041 pixel
|= *(data
++) << 8;
1043 SPLITCOLOUR24(pixel
, pc
);
1044 value
= MAKECOLOUR(pc
);
1051 translate_image(RDPCLIENT
* This
, int width
, int height
, uint8
* data
)
1058 If RDP depth and X Visual depths match,
1059 and arch(endian) matches, no need to translate:
1061 Note: select_visual should've already ensured g_no_translate
1062 is only set for compatible depths, but the RDP depth might've
1063 changed during connection negotiations.
1065 if (This
->xwin
.no_translate_image
)
1067 if ((This
->xwin
.depth
== 15 && This
->server_depth
== 15) ||
1068 (This
->xwin
.depth
== 16 && This
->server_depth
== 16) ||
1069 (This
->xwin
.depth
== 24 && This
->server_depth
== 24))
1073 size
= width
* height
* (This
->xwin
.bpp
/ 8);
1074 out
= (uint8
*) xmalloc(size
);
1077 switch (This
->server_depth
)
1080 switch (This
->xwin
.bpp
)
1083 translate24to32(This
, data
, out
, end
);
1086 translate24to24(This
, data
, out
, end
);
1089 translate24to16(This
, data
, out
, end
);
1094 switch (This
->xwin
.bpp
)
1097 translate16to32(This
, (uint16
*) data
, out
, end
);
1100 translate16to24(This
, (uint16
*) data
, out
, end
);
1103 translate16to16(This
, (uint16
*) data
, out
, end
);
1108 switch (This
->xwin
.bpp
)
1111 translate15to32(This
, (uint16
*) data
, out
, end
);
1114 translate15to24(This
, (uint16
*) data
, out
, end
);
1117 translate15to16(This
, (uint16
*) data
, out
, end
);
1122 switch (This
->xwin
.bpp
)
1125 translate8to8(This
, data
, out
, end
);
1128 translate8to16(This
, data
, out
, end
);
1131 translate8to24(This
, data
, out
, end
);
1134 translate8to32(This
, data
, out
, end
);
1143 get_key_state(RDPCLIENT
* This
, unsigned int state
, uint32 keysym
)
1145 int modifierpos
, key
, keysymMask
= 0;
1148 KeyCode keycode
= XKeysymToKeycode(This
->display
, keysym
);
1150 if (keycode
== NoSymbol
)
1153 for (modifierpos
= 0; modifierpos
< 8; modifierpos
++)
1155 offset
= This
->xwin
.mod_map
->max_keypermod
* modifierpos
;
1157 for (key
= 0; key
< This
->xwin
.mod_map
->max_keypermod
; key
++)
1159 if (This
->xwin
.mod_map
->modifiermap
[offset
+ key
] == keycode
)
1160 keysymMask
|= 1 << modifierpos
;
1164 return (state
& keysymMask
) ? True
: False
;
1168 calculate_shifts(uint32 mask
, int *shift_r
, int *shift_l
)
1170 *shift_l
= ffs(mask
) - 1;
1172 *shift_r
= 8 - ffs(mask
& ~(mask
>> 1));
1175 /* Given a mask of a colour channel (e.g. XVisualInfo.red_mask),
1176 calculates the bits-per-pixel of this channel (a.k.a. colour weight).
1179 calculate_mask_weight(uint32 mask
)
1181 unsigned weight
= 0;
1184 weight
+= (mask
& 1);
1191 select_visual(RDPCLIENT
* This
)
1193 XPixmapFormatValues
*pfm
;
1194 int pixmap_formats_count
, visuals_count
;
1195 XVisualInfo
*vmatches
= NULL
;
1196 XVisualInfo
template;
1198 unsigned red_weight
, blue_weight
, green_weight
;
1200 red_weight
= blue_weight
= green_weight
= 0;
1202 if (This
->server_depth
== -1)
1204 This
->server_depth
= DisplayPlanes(This
->display
, DefaultScreen(This
->display
));
1207 pfm
= XListPixmapFormats(This
->display
, &pixmap_formats_count
);
1210 error("Unable to get list of pixmap formats from display.\n");
1211 XCloseDisplay(This
->display
);
1215 /* Search for best TrueColor visual */
1216 template.class = TrueColor
;
1217 vmatches
= XGetVisualInfo(This
->display
, VisualClassMask
, &template, &visuals_count
);
1218 This
->xwin
.visual
= NULL
;
1219 This
->xwin
.no_translate_image
= False
;
1220 This
->xwin
.compatible_arch
= False
;
1221 if (vmatches
!= NULL
)
1223 for (i
= 0; i
< visuals_count
; ++i
)
1225 XVisualInfo
*visual_info
= &vmatches
[i
];
1226 BOOL can_translate_to_bpp
= False
;
1229 /* Try to find a no-translation visual that'll
1230 allow us to use RDP bitmaps directly as ZPixmaps. */
1231 if (!This
->xwin
.xserver_be
&& (((visual_info
->depth
== 15) &&
1233 (visual_info
->red_mask
== 0x7c00) &&
1234 (visual_info
->green_mask
== 0x3e0) &&
1235 (visual_info
->blue_mask
== 0x1f)) ||
1236 ((visual_info
->depth
== 16) &&
1238 (visual_info
->red_mask
== 0xf800) &&
1239 (visual_info
->green_mask
== 0x7e0) &&
1240 (visual_info
->blue_mask
== 0x1f)) ||
1241 ((visual_info
->depth
== 24) &&
1243 (visual_info
->red_mask
== 0xff0000) &&
1244 (visual_info
->green_mask
== 0xff00) &&
1245 (visual_info
->blue_mask
== 0xff))))
1247 This
->xwin
.visual
= visual_info
->visual
;
1248 This
->xwin
.depth
= visual_info
->depth
;
1249 This
->xwin
.compatible_arch
= !This
->xwin
.host_be
;
1250 This
->xwin
.no_translate_image
= (visual_info
->depth
== This
->server_depth
);
1251 if (This
->xwin
.no_translate_image
)
1252 /* We found the best visual */
1257 This
->xwin
.compatible_arch
= False
;
1260 if (visual_info
->depth
> 24)
1262 /* Avoid 32-bit visuals and likes like the plague.
1263 They're either untested or proven to work bad
1264 (e.g. nvidia's Composite 32-bit visual).
1265 Most implementation offer a 24-bit visual anyway. */
1269 /* Only care for visuals, for whose BPPs (not depths!)
1270 we have a translateXtoY function. */
1271 for (j
= 0; j
< pixmap_formats_count
; ++j
)
1273 if (pfm
[j
].depth
== visual_info
->depth
)
1275 if ((pfm
[j
].bits_per_pixel
== 16) ||
1276 (pfm
[j
].bits_per_pixel
== 24) ||
1277 (pfm
[j
].bits_per_pixel
== 32))
1279 can_translate_to_bpp
= True
;
1285 /* Prefer formats which have the most colour depth.
1286 We're being truly aristocratic here, minding each
1287 weight on its own. */
1288 if (can_translate_to_bpp
)
1290 unsigned vis_red_weight
=
1291 calculate_mask_weight(visual_info
->red_mask
);
1292 unsigned vis_green_weight
=
1293 calculate_mask_weight(visual_info
->green_mask
);
1294 unsigned vis_blue_weight
=
1295 calculate_mask_weight(visual_info
->blue_mask
);
1296 if ((vis_red_weight
>= red_weight
)
1297 && (vis_green_weight
>= green_weight
)
1298 && (vis_blue_weight
>= blue_weight
))
1300 red_weight
= vis_red_weight
;
1301 green_weight
= vis_green_weight
;
1302 blue_weight
= vis_blue_weight
;
1303 This
->xwin
.visual
= visual_info
->visual
;
1304 This
->xwin
.depth
= visual_info
->depth
;
1311 if (This
->xwin
.visual
!= NULL
)
1313 This
->owncolmap
= False
;
1314 calculate_shifts(This
->xwin
.visual
->red_mask
, &This
->xwin
.red_shift_r
, &This
->xwin
.red_shift_l
);
1315 calculate_shifts(This
->xwin
.visual
->green_mask
, &This
->xwin
.green_shift_r
, &This
->xwin
.green_shift_l
);
1316 calculate_shifts(This
->xwin
.visual
->blue_mask
, &This
->xwin
.blue_shift_r
, &This
->xwin
.blue_shift_l
);
1320 template.class = PseudoColor
;
1322 template.colormap_size
= 256;
1324 XGetVisualInfo(This
->display
,
1325 VisualClassMask
| VisualDepthMask
| VisualColormapSizeMask
,
1326 &template, &visuals_count
);
1327 if (vmatches
== NULL
)
1329 error("No usable TrueColor or PseudoColor visuals on this display.\n");
1330 XCloseDisplay(This
->display
);
1335 /* we use a colourmap, so the default visual should do */
1336 This
->owncolmap
= True
;
1337 This
->xwin
.visual
= vmatches
[0].visual
;
1338 This
->xwin
.depth
= vmatches
[0].depth
;
1342 for (i
= 0; i
< pixmap_formats_count
; ++i
)
1344 XPixmapFormatValues
*pf
= &pfm
[i
];
1345 if (pf
->depth
== This
->xwin
.depth
)
1347 This
->xwin
.bpp
= pf
->bits_per_pixel
;
1349 if (This
->xwin
.no_translate_image
)
1351 switch (This
->server_depth
)
1355 if (This
->xwin
.bpp
!= 16)
1356 This
->xwin
.no_translate_image
= False
;
1359 /* Yes, this will force image translation
1360 on most modern servers which use 32 bits
1362 if (This
->xwin
.bpp
!= 24)
1363 This
->xwin
.no_translate_image
= False
;
1366 This
->xwin
.no_translate_image
= False
;
1371 /* Pixmap formats list is a depth-to-bpp mapping --
1372 there's just a single entry for every depth,
1373 so we can safely break here */
1384 error_handler(RDPCLIENT * This, Display * dpy, XErrorEvent * eev)
1386 if ((eev->error_code == BadMatch) && (eev->request_code == X_ConfigureWindow))
1388 fprintf(stderr, "Got \"BadMatch\" when trying to restack windows.\n");
1390 "This is most likely caused by a broken window manager (commonly KWin).\n");
1394 return This->xwin.old_error_handler(dpy, eev);
1399 ui_init(RDPCLIENT
* This
)
1403 This
->display
= XOpenDisplay(NULL
);
1404 if (This
->display
== NULL
)
1406 error("Failed to open display: %s\n", XDisplayName(NULL
));
1411 uint16 endianess_test
= 1;
1412 This
->xwin
.host_be
= !(BOOL
) (*(uint8
*) (&endianess_test
));
1415 /*This->xwin.old_error_handler = XSetErrorHandler(error_handler);*/
1416 This
->xwin
.xserver_be
= (ImageByteOrder(This
->display
) == MSBFirst
);
1417 screen_num
= DefaultScreen(This
->display
);
1418 This
->xwin
.x_socket
= ConnectionNumber(This
->display
);
1419 This
->xwin
.screen
= ScreenOfDisplay(This
->display
, screen_num
);
1420 This
->xwin
.depth
= DefaultDepthOfScreen(This
->xwin
.screen
);
1422 if (!select_visual(This
))
1425 if (This
->xwin
.no_translate_image
)
1427 DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
1430 if (This
->server_depth
> This
->xwin
.bpp
)
1432 warning("Remote desktop colour depth %d higher than display colour depth %d.\n",
1433 This
->server_depth
, This
->xwin
.bpp
);
1436 DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n",
1437 This
->server_depth
, This
->xwin
.depth
, This
->xwin
.bpp
, This
->xwin
.xserver_be
, This
->xwin
.host_be
));
1439 if (!This
->owncolmap
)
1441 This
->xwin
.xcolmap
=
1442 XCreateColormap(This
->display
, RootWindowOfScreen(This
->xwin
.screen
), This
->xwin
.visual
,
1444 if (This
->xwin
.depth
<= 8)
1445 warning("Display colour depth is %d bit: you may want to use -C for a private colourmap.\n", This
->xwin
.depth
);
1448 if ((!This
->ownbackstore
) && (DoesBackingStore(This
->xwin
.screen
) != Always
))
1450 warning("External BackingStore not available. Using internal.\n");
1451 This
->ownbackstore
= True
;
1455 * Determine desktop size
1457 if (This
->fullscreen
)
1459 This
->width
= WidthOfScreen(This
->xwin
.screen
);
1460 This
->height
= HeightOfScreen(This
->xwin
.screen
);
1461 This
->xwin
.using_full_workarea
= True
;
1463 else if (This
->width
< 0)
1465 /* Percent of screen */
1466 if (-This
->width
>= 100)
1467 This
->xwin
.using_full_workarea
= True
;
1468 This
->height
= HeightOfScreen(This
->xwin
.screen
) * (-This
->width
) / 100;
1469 This
->width
= WidthOfScreen(This
->xwin
.screen
) * (-This
->width
) / 100;
1471 else if (This
->width
== 0)
1473 /* Fetch geometry from _NET_WORKAREA */
1474 uint32 x
, y
, cx
, cy
;
1475 if (get_current_workarea(This
, &x
, &y
, &cx
, &cy
) == 0)
1479 This
->xwin
.using_full_workarea
= True
;
1483 warning("Failed to get workarea: probably your window manager does not support extended hints\n");
1484 This
->width
= WidthOfScreen(This
->xwin
.screen
);
1485 This
->height
= HeightOfScreen(This
->xwin
.screen
);
1489 /* make sure width is a multiple of 4 */
1490 This
->width
= (This
->width
+ 3) & ~3;
1492 This
->xwin
.mod_map
= XGetModifierMapping(This
->display
);
1496 if (This
->enable_compose
)
1497 This
->xwin
.IM
= XOpenIM(This
->display
, NULL
, NULL
, NULL
);
1501 if (This
->seamless_rdp
)
1502 seamless_init(This
);
1504 DEBUG_RDP5(("server bpp %d client bpp %d depth %d\n", This
->server_depth
, This
->xwin
.bpp
, This
->xwin
.depth
));
1510 ui_deinit(RDPCLIENT
* This
)
1512 while (This
->xwin
.seamless_windows
)
1514 XDestroyWindow(This
->display
, This
->xwin
.seamless_windows
->wnd
);
1515 sw_remove_window(This
, This
->xwin
.seamless_windows
);
1520 if (This
->xwin
.IM
!= NULL
)
1521 XCloseIM(This
->xwin
.IM
);
1523 if (This
->xwin
.null_cursor
!= NULL
)
1524 ui_destroy_cursor(This
, This
->xwin
.null_cursor
);
1526 XFreeModifiermap(This
->xwin
.mod_map
);
1528 if (This
->ownbackstore
)
1529 XFreePixmap(This
->display
, This
->xwin
.backstore
);
1531 XFreeGC(This
->display
, This
->xwin
.gc
);
1532 XCloseDisplay(This
->display
);
1533 This
->display
= NULL
;
1538 get_window_attribs(RDPCLIENT
* This
, XSetWindowAttributes
* attribs
)
1540 attribs
->background_pixel
= BlackPixelOfScreen(This
->xwin
.screen
);
1541 attribs
->background_pixel
= WhitePixelOfScreen(This
->xwin
.screen
);
1542 attribs
->border_pixel
= WhitePixelOfScreen(This
->xwin
.screen
);
1543 attribs
->backing_store
= This
->ownbackstore
? NotUseful
: Always
;
1544 attribs
->override_redirect
= This
->fullscreen
;
1545 attribs
->colormap
= This
->xwin
.xcolmap
;
1549 get_input_mask(RDPCLIENT
* This
, long *input_mask
)
1551 *input_mask
= KeyPressMask
| KeyReleaseMask
| ButtonPressMask
| ButtonReleaseMask
|
1552 VisibilityChangeMask
| FocusChangeMask
| StructureNotifyMask
;
1554 if (This
->sendmotion
)
1555 *input_mask
|= PointerMotionMask
;
1556 if (This
->ownbackstore
)
1557 *input_mask
|= ExposureMask
;
1558 if (This
->fullscreen
|| This
->grab_keyboard
)
1559 *input_mask
|= EnterWindowMask
;
1560 if (This
->grab_keyboard
)
1561 *input_mask
|= LeaveWindowMask
;
1565 ui_create_window(RDPCLIENT
* This
)
1567 uint8 null_pointer_mask
[1] = { 0x80 };
1568 uint8 null_pointer_data
[24] = { 0x00 };
1570 XSetWindowAttributes attribs
;
1571 XClassHint
*classhints
;
1572 XSizeHints
*sizehints
;
1573 int wndwidth
, wndheight
;
1574 long input_mask
, ic_input_mask
;
1577 wndwidth
= This
->fullscreen
? WidthOfScreen(This
->xwin
.screen
) : This
->width
;
1578 wndheight
= This
->fullscreen
? HeightOfScreen(This
->xwin
.screen
) : This
->height
;
1580 /* Handle -x-y portion of geometry string */
1581 if (This
->xpos
< 0 || (This
->xpos
== 0 && (This
->pos
& 2)))
1582 This
->xpos
= WidthOfScreen(This
->xwin
.screen
) + This
->xpos
- This
->width
;
1583 if (This
->ypos
< 0 || (This
->ypos
== 0 && (This
->pos
& 4)))
1584 This
->ypos
= HeightOfScreen(This
->xwin
.screen
) + This
->ypos
- This
->height
;
1586 get_window_attribs(This
, &attribs
);
1588 This
->wnd
= XCreateWindow(This
->display
, RootWindowOfScreen(This
->xwin
.screen
), This
->xpos
, This
->ypos
, wndwidth
,
1589 wndheight
, 0, This
->xwin
.depth
, InputOutput
, This
->xwin
.visual
,
1590 CWBackPixel
| CWBackingStore
| CWOverrideRedirect
| CWColormap
|
1591 CWBorderPixel
, &attribs
);
1593 if (This
->xwin
.gc
== NULL
)
1595 This
->xwin
.gc
= XCreateGC(This
->display
, This
->wnd
, 0, NULL
);
1596 ui_reset_clip(This
);
1599 if (This
->xwin
.create_bitmap_gc
== NULL
)
1600 This
->xwin
.create_bitmap_gc
= XCreateGC(This
->display
, This
->wnd
, 0, NULL
);
1602 if ((This
->ownbackstore
) && (This
->xwin
.backstore
== 0))
1604 This
->xwin
.backstore
= XCreatePixmap(This
->display
, This
->wnd
, This
->width
, This
->height
, This
->xwin
.depth
);
1606 /* clear to prevent rubbish being exposed at startup */
1607 XSetForeground(This
->display
, This
->xwin
.gc
, BlackPixelOfScreen(This
->xwin
.screen
));
1608 XFillRectangle(This
->display
, This
->xwin
.backstore
, This
->xwin
.gc
, 0, 0, This
->width
, This
->height
);
1611 XStoreName(This
->display
, This
->wnd
, This
->title
);
1613 if (This
->hide_decorations
)
1614 mwm_hide_decorations(This
, This
->wnd
);
1616 classhints
= XAllocClassHint();
1617 if (classhints
!= NULL
)
1619 classhints
->res_name
= classhints
->res_class
= "rdesktop";
1620 XSetClassHint(This
->display
, This
->wnd
, classhints
);
1624 sizehints
= XAllocSizeHints();
1627 sizehints
->flags
= PMinSize
| PMaxSize
;
1629 sizehints
->flags
|= PPosition
;
1630 sizehints
->min_width
= sizehints
->max_width
= This
->width
;
1631 sizehints
->min_height
= sizehints
->max_height
= This
->height
;
1632 XSetWMNormalHints(This
->display
, This
->wnd
, sizehints
);
1636 if (This
->embed_wnd
)
1638 XReparentWindow(This
->display
, This
->wnd
, (Window
) This
->embed_wnd
, 0, 0);
1641 get_input_mask(This
, &input_mask
);
1643 if (This
->xwin
.IM
!= NULL
)
1645 This
->xwin
.IC
= XCreateIC(This
->xwin
.IM
, XNInputStyle
, (XIMPreeditNothing
| XIMStatusNothing
),
1646 XNClientWindow
, This
->wnd
, XNFocusWindow
, This
->wnd
, NULL
);
1648 if ((This
->xwin
.IC
!= NULL
)
1649 && (XGetICValues(This
->xwin
.IC
, XNFilterEvents
, &ic_input_mask
, NULL
) == NULL
))
1650 input_mask
|= ic_input_mask
;
1653 XSelectInput(This
->display
, This
->wnd
, input_mask
);
1654 XMapWindow(This
->display
, This
->wnd
);
1656 /* wait for VisibilityNotify */
1659 XMaskEvent(This
->display
, VisibilityChangeMask
, &xevent
);
1661 while (xevent
.type
!= VisibilityNotify
);
1662 This
->Unobscured
= xevent
.xvisibility
.state
== VisibilityUnobscured
;
1664 This
->xwin
.focused
= False
;
1665 This
->xwin
.mouse_in_wnd
= False
;
1667 /* handle the WM_DELETE_WINDOW protocol */
1668 This
->xwin
.protocol_atom
= XInternAtom(This
->display
, "WM_PROTOCOLS", True
);
1669 This
->xwin
.kill_atom
= XInternAtom(This
->display
, "WM_DELETE_WINDOW", True
);
1670 XSetWMProtocols(This
->display
, This
->wnd
, &This
->xwin
.kill_atom
, 1);
1672 /* create invisible 1x1 cursor to be used as null cursor */
1673 if (This
->xwin
.null_cursor
== NULL
)
1674 This
->xwin
.null_cursor
= ui_create_cursor(This
, 0, 0, 1, 1, null_pointer_mask
, null_pointer_data
);
1680 ui_resize_window(RDPCLIENT
* This
)
1682 XSizeHints
*sizehints
;
1685 sizehints
= XAllocSizeHints();
1688 sizehints
->flags
= PMinSize
| PMaxSize
;
1689 sizehints
->min_width
= sizehints
->max_width
= This
->width
;
1690 sizehints
->min_height
= sizehints
->max_height
= This
->height
;
1691 XSetWMNormalHints(This
->display
, This
->wnd
, sizehints
);
1695 if (!(This
->fullscreen
|| This
->embed_wnd
))
1697 XResizeWindow(This
->display
, This
->wnd
, This
->width
, This
->height
);
1700 /* create new backstore pixmap */
1701 if (This
->xwin
.backstore
!= 0)
1703 bs
= XCreatePixmap(This
->display
, This
->wnd
, This
->width
, This
->height
, This
->xwin
.depth
);
1704 XSetForeground(This
->display
, This
->xwin
.gc
, BlackPixelOfScreen(This
->xwin
.screen
));
1705 XFillRectangle(This
->display
, bs
, This
->xwin
.gc
, 0, 0, This
->width
, This
->height
);
1706 XCopyArea(This
->display
, This
->xwin
.backstore
, bs
, This
->xwin
.gc
, 0, 0, This
->width
, This
->height
, 0, 0);
1707 XFreePixmap(This
->display
, This
->xwin
.backstore
);
1708 This
->xwin
.backstore
= bs
;
1713 ui_destroy_window(RDPCLIENT
* This
)
1715 if (This
->xwin
.IC
!= NULL
)
1716 XDestroyIC(This
->xwin
.IC
);
1718 XDestroyWindow(This
->display
, This
->wnd
);
1722 xwin_toggle_fullscreen(RDPCLIENT
* This
)
1724 Pixmap contents
= 0;
1726 if (This
->xwin
.seamless_active
)
1727 /* Turn off SeamlessRDP mode */
1728 ui_seamless_toggle(This
);
1730 if (!This
->ownbackstore
)
1732 /* need to save contents of window */
1733 contents
= XCreatePixmap(This
->display
, This
->wnd
, This
->width
, This
->height
, This
->xwin
.depth
);
1734 XCopyArea(This
->display
, This
->wnd
, contents
, This
->xwin
.gc
, 0, 0, This
->width
, This
->height
, 0, 0);
1737 ui_destroy_window(This
);
1738 This
->fullscreen
= !This
->fullscreen
;
1739 ui_create_window(This
);
1741 XDefineCursor(This
->display
, This
->wnd
, This
->xwin
.current_cursor
);
1743 if (!This
->ownbackstore
)
1745 XCopyArea(This
->display
, contents
, This
->wnd
, This
->xwin
.gc
, 0, 0, This
->width
, This
->height
, 0, 0);
1746 XFreePixmap(This
->display
, contents
);
1751 handle_button_event(RDPCLIENT
* This
, XEvent xevent
, BOOL down
)
1753 uint16 button
, flags
= 0;
1754 This
->last_gesturetime
= xevent
.xbutton
.time
;
1755 button
= xkeymap_translate_button(xevent
.xbutton
.button
);
1760 flags
= MOUSE_FLAG_DOWN
;
1762 /* Stop moving window when button is released, regardless of cursor position */
1763 if (This
->xwin
.moving_wnd
&& (xevent
.type
== ButtonRelease
))
1764 This
->xwin
.moving_wnd
= False
;
1766 /* If win_button_sizee is nonzero, enable single app mode */
1767 if (xevent
.xbutton
.y
< This
->win_button_size
)
1769 /* Check from right to left: */
1770 if (xevent
.xbutton
.x
>= This
->width
- This
->win_button_size
)
1772 /* The close button, continue */
1775 else if (xevent
.xbutton
.x
>= This
->width
- This
->win_button_size
* 2)
1777 /* The maximize/restore button. Do not send to
1778 server. It might be a good idea to change the
1779 cursor or give some other visible indication
1780 that rdesktop inhibited this click */
1781 if (xevent
.type
== ButtonPress
)
1784 else if (xevent
.xbutton
.x
>= This
->width
- This
->win_button_size
* 3)
1786 /* The minimize button. Iconify window. */
1787 if (xevent
.type
== ButtonRelease
)
1789 /* Release the mouse button outside the minimize button, to prevent the
1790 actual minimazation to happen */
1791 rdp_send_input(This
, time(NULL
), RDP_INPUT_MOUSE
, button
, 1, 1);
1792 XIconifyWindow(This
->display
, This
->wnd
, DefaultScreen(This
->display
));
1796 else if (xevent
.xbutton
.x
<= This
->win_button_size
)
1798 /* The system menu. Ignore. */
1799 if (xevent
.type
== ButtonPress
)
1804 /* The title bar. */
1805 if (xevent
.type
== ButtonPress
)
1807 if (!This
->fullscreen
&& This
->hide_decorations
&& !This
->xwin
.using_full_workarea
)
1809 This
->xwin
.moving_wnd
= True
;
1810 This
->xwin
.move_x_offset
= xevent
.xbutton
.x
;
1811 This
->xwin
.move_y_offset
= xevent
.xbutton
.y
;
1818 if (xevent
.xmotion
.window
== This
->wnd
)
1820 rdp_send_input(This
, time(NULL
), RDP_INPUT_MOUSE
,
1821 flags
| button
, xevent
.xbutton
.x
, xevent
.xbutton
.y
);
1826 rdp_send_input(This
, time(NULL
), RDP_INPUT_MOUSE
,
1827 flags
| button
, xevent
.xbutton
.x_root
, xevent
.xbutton
.y_root
);
1832 /* Process events in Xlib queue
1833 Returns 0 after user quit, 1 otherwise */
1835 xwin_process_events(RDPCLIENT
* This
)
1843 seamless_window
*sw
;
1845 while ((XPending(This
->display
) > 0) && events
++ < 20)
1847 XNextEvent(This
->display
, &xevent
);
1849 if ((This
->xwin
.IC
!= NULL
) && (XFilterEvent(&xevent
, None
) == True
))
1851 DEBUG_KBD(("Filtering event\n"));
1855 switch (xevent
.type
)
1857 case VisibilityNotify
:
1858 if (xevent
.xvisibility
.window
== This
->wnd
)
1860 xevent
.xvisibility
.state
== VisibilityUnobscured
;
1864 /* the window manager told us to quit */
1865 if ((xevent
.xclient
.message_type
== This
->xwin
.protocol_atom
)
1866 && ((Atom
) xevent
.xclient
.data
.l
[0] == This
->xwin
.kill_atom
))
1872 This
->last_gesturetime
= xevent
.xkey
.time
;
1873 if (This
->xwin
.IC
!= NULL
)
1874 /* Multi_key compatible version */
1876 XmbLookupString(This
->xwin
.IC
,
1877 &xevent
.xkey
, str
, sizeof(str
), &keysym
,
1879 if (!((status
== XLookupKeySym
) || (status
== XLookupBoth
)))
1881 error("XmbLookupString failed with status 0x%x\n",
1888 /* Plain old XLookupString */
1889 DEBUG_KBD(("\nNo input context, using XLookupString\n"));
1890 XLookupString((XKeyEvent
*) & xevent
,
1891 str
, sizeof(str
), &keysym
, NULL
);
1894 DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym
,
1895 get_ksname(keysym
)));
1897 ev_time
= time(NULL
);
1898 if (handle_special_keys(This
, keysym
, xevent
.xkey
.state
, ev_time
, True
))
1901 xkeymap_send_keys(This
, keysym
, xevent
.xkey
.keycode
, xevent
.xkey
.state
,
1906 This
->last_gesturetime
= xevent
.xkey
.time
;
1907 XLookupString((XKeyEvent
*) & xevent
, str
,
1908 sizeof(str
), &keysym
, NULL
);
1910 DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym
,
1911 get_ksname(keysym
)));
1913 ev_time
= time(NULL
);
1914 if (handle_special_keys(This
, keysym
, xevent
.xkey
.state
, ev_time
, False
))
1917 xkeymap_send_keys(This
, keysym
, xevent
.xkey
.keycode
, xevent
.xkey
.state
,
1922 handle_button_event(This
, xevent
, True
);
1926 handle_button_event(This
, xevent
, False
);
1930 if (This
->xwin
.moving_wnd
)
1932 XMoveWindow(This
->display
, This
->wnd
,
1933 xevent
.xmotion
.x_root
- This
->xwin
.move_x_offset
,
1934 xevent
.xmotion
.y_root
- This
->xwin
.move_y_offset
);
1938 if (This
->fullscreen
&& !This
->xwin
.focused
)
1939 XSetInputFocus(This
->display
, This
->wnd
, RevertToPointerRoot
,
1942 if (xevent
.xmotion
.window
== This
->wnd
)
1944 rdp_send_input(This
, time(NULL
), RDP_INPUT_MOUSE
, MOUSE_FLAG_MOVE
,
1945 xevent
.xmotion
.x
, xevent
.xmotion
.y
);
1950 rdp_send_input(This
, time(NULL
), RDP_INPUT_MOUSE
, MOUSE_FLAG_MOVE
,
1951 xevent
.xmotion
.x_root
,
1952 xevent
.xmotion
.y_root
);
1957 if (xevent
.xfocus
.mode
== NotifyGrab
)
1959 This
->xwin
.focused
= True
;
1960 reset_modifier_keys(This
);
1961 if (This
->grab_keyboard
&& This
->xwin
.mouse_in_wnd
)
1962 XGrabKeyboard(This
->display
, This
->wnd
, True
,
1963 GrabModeAsync
, GrabModeAsync
, CurrentTime
);
1965 sw
= sw_get_window_by_wnd(This
, xevent
.xfocus
.window
);
1969 if (sw
->id
!= This
->xwin
.seamless_focused
)
1971 seamless_send_focus(This
, sw
->id
, 0);
1972 This
->xwin
.seamless_focused
= sw
->id
;
1977 if (xevent
.xfocus
.mode
== NotifyUngrab
)
1979 This
->xwin
.focused
= False
;
1980 if (xevent
.xfocus
.mode
== NotifyWhileGrabbed
)
1981 XUngrabKeyboard(This
->display
, CurrentTime
);
1985 /* we only register for this event when in fullscreen mode */
1986 /* or grab_keyboard */
1987 This
->xwin
.mouse_in_wnd
= True
;
1988 if (This
->fullscreen
)
1990 XSetInputFocus(This
->display
, This
->wnd
, RevertToPointerRoot
,
1994 if (This
->xwin
.focused
)
1995 XGrabKeyboard(This
->display
, This
->wnd
, True
,
1996 GrabModeAsync
, GrabModeAsync
, CurrentTime
);
2000 /* we only register for this event when grab_keyboard */
2001 This
->xwin
.mouse_in_wnd
= False
;
2002 XUngrabKeyboard(This
->display
, CurrentTime
);
2006 if (xevent
.xexpose
.window
== This
->wnd
)
2008 XCopyArea(This
->display
, This
->xwin
.backstore
, xevent
.xexpose
.window
,
2010 xevent
.xexpose
.x
, xevent
.xexpose
.y
,
2011 xevent
.xexpose
.width
, xevent
.xexpose
.height
,
2012 xevent
.xexpose
.x
, xevent
.xexpose
.y
);
2016 sw
= sw_get_window_by_wnd(This
, xevent
.xexpose
.window
);
2019 XCopyArea(This
->display
, This
->xwin
.backstore
,
2020 xevent
.xexpose
.window
, This
->xwin
.gc
,
2021 xevent
.xexpose
.x
+ sw
->xoffset
,
2022 xevent
.xexpose
.y
+ sw
->yoffset
,
2023 xevent
.xexpose
.width
,
2024 xevent
.xexpose
.height
, xevent
.xexpose
.x
,
2031 /* Refresh keyboard mapping if it has changed. This is important for
2032 Xvnc, since it allocates keycodes dynamically */
2033 if (xevent
.xmapping
.request
== MappingKeyboard
2034 || xevent
.xmapping
.request
== MappingModifier
)
2035 XRefreshKeyboardMapping(&xevent
.xmapping
);
2037 if (xevent
.xmapping
.request
== MappingModifier
)
2039 XFreeModifiermap(This
->xwin
.mod_map
);
2040 This
->xwin
.mod_map
= XGetModifierMapping(This
->display
);
2044 /* clipboard stuff */
2045 case SelectionNotify
:
2046 xclip_handle_SelectionNotify(This
, &xevent
.xselection
);
2048 case SelectionRequest
:
2049 xclip_handle_SelectionRequest(This
, &xevent
.xselectionrequest
);
2051 case SelectionClear
:
2052 xclip_handle_SelectionClear(This
);
2054 case PropertyNotify
:
2055 xclip_handle_PropertyNotify(This
, &xevent
.xproperty
);
2056 if (xevent
.xproperty
.window
== This
->wnd
)
2058 if (xevent
.xproperty
.window
== DefaultRootWindow(This
->display
))
2062 sw
= sw_get_window_by_wnd(This
, xevent
.xproperty
.window
);
2066 if ((xevent
.xproperty
.atom
== This
->net_wm_state_atom
)
2067 && (xevent
.xproperty
.state
== PropertyNewValue
))
2069 sw
->state
= ewmh_get_window_state(This
, sw
->wnd
);
2070 seamless_send_state(This
, sw
->id
, sw
->state
, 0);
2073 if ((xevent
.xproperty
.atom
== This
->net_wm_desktop_atom
)
2074 && (xevent
.xproperty
.state
== PropertyNewValue
))
2076 sw
->desktop
= ewmh_get_window_desktop(This
, sw
->wnd
);
2077 sw_all_to_desktop(This
, sw
->wnd
, sw
->desktop
);
2082 if (!This
->xwin
.seamless_active
)
2083 rdp_send_client_window_status(This
, 1);
2086 if (!This
->xwin
.seamless_active
)
2087 rdp_send_client_window_status(This
, 0);
2089 case ConfigureNotify
:
2090 if (!This
->xwin
.seamless_active
)
2093 sw
= sw_get_window_by_wnd(This
, xevent
.xconfigure
.window
);
2097 gettimeofday(sw
->position_timer
, NULL
);
2098 if (sw
->position_timer
->tv_usec
+ SEAMLESSRDP_POSITION_TIMER
>=
2101 sw
->position_timer
->tv_usec
+=
2102 SEAMLESSRDP_POSITION_TIMER
- 1000000;
2103 sw
->position_timer
->tv_sec
+= 1;
2107 sw
->position_timer
->tv_usec
+= SEAMLESSRDP_POSITION_TIMER
;
2110 sw_handle_restack(This
, sw
);
2118 /* Returns 0 after user quit, 1 otherwise */
2120 ui_select(RDPCLIENT
* This
, int rdp_socket
)
2125 BOOL s_timeout
= False
;
2129 n
= (rdp_socket
> This
->xwin
.x_socket
) ? rdp_socket
: This
->xwin
.x_socket
;
2130 /* Process any events already waiting */
2131 if (!xwin_process_events(This
))
2135 if (This
->xwin
.seamless_active
)
2136 sw_check_timers(This
);
2140 FD_SET(rdp_socket
, &rfds
);
2141 FD_SET(This
->xwin
.x_socket
, &rfds
);
2144 /* FIXME: there should be an API for registering fds */
2147 FD_SET(This
->dsp_fd
, &wfds
);
2148 n
= (This
->dsp_fd
> n
) ? This
->dsp_fd
: n
;
2151 /* default timeout */
2155 /* add redirection handles */
2156 rdpdr_add_fds(This
, &n
, &rfds
, &wfds
, &tv
, &s_timeout
);
2157 seamless_select_timeout(This
, &tv
);
2161 switch (select(n
, &rfds
, &wfds
, NULL
, &tv
))
2164 error("select: %s\n", strerror(errno
));
2167 /* Abort serial read calls */
2169 rdpdr_check_fds(This
, &rfds
, &wfds
, (BOOL
) True
);
2173 rdpdr_check_fds(This
, &rfds
, &wfds
, (BOOL
) False
);
2175 if (FD_ISSET(rdp_socket
, &rfds
))
2179 if (This
->dsp_busy
&& FD_ISSET(This
->dsp_fd
, &wfds
))
2186 ui_move_pointer(RDPCLIENT
* This
, int x
, int y
)
2188 XWarpPointer(This
->display
, This
->wnd
, This
->wnd
, 0, 0, 0, 0, x
, y
);
2192 ui_create_bitmap(RDPCLIENT
* This
, int width
, int height
, uint8
* data
)
2199 if (This
->server_depth
== 8)
2205 bitmap_pad
= This
->xwin
.bpp
;
2207 if (This
->xwin
.bpp
== 24)
2211 tdata
= (This
->owncolmap
? data
: translate_image(This
, width
, height
, data
));
2212 bitmap
= XCreatePixmap(This
->display
, This
->wnd
, width
, height
, This
->xwin
.depth
);
2213 image
= XCreateImage(This
->display
, This
->xwin
.visual
, This
->xwin
.depth
, ZPixmap
, 0,
2214 (char *) tdata
, width
, height
, bitmap_pad
, 0);
2216 XPutImage(This
->display
, bitmap
, This
->xwin
.create_bitmap_gc
, image
, 0, 0, 0, 0, width
, height
);
2221 return (HBITMAP
) bitmap
;
2225 ui_paint_bitmap(RDPCLIENT
* This
, int x
, int y
, int cx
, int cy
, int width
, int height
, uint8
* data
)
2231 if (This
->server_depth
== 8)
2237 bitmap_pad
= This
->xwin
.bpp
;
2239 if (This
->xwin
.bpp
== 24)
2243 tdata
= (This
->owncolmap
? data
: translate_image(This
, width
, height
, data
));
2244 image
= XCreateImage(This
->display
, This
->xwin
.visual
, This
->xwin
.depth
, ZPixmap
, 0,
2245 (char *) tdata
, width
, height
, bitmap_pad
, 0);
2247 if (This
->ownbackstore
)
2249 XPutImage(This
->display
, This
->xwin
.backstore
, This
->xwin
.gc
, image
, 0, 0, x
, y
, cx
, cy
);
2250 XCopyArea(This
->display
, This
->xwin
.backstore
, This
->wnd
, This
->xwin
.gc
, x
, y
, cx
, cy
, x
, y
);
2251 ON_ALL_SEAMLESS_WINDOWS(XCopyArea
,
2252 (This
->display
, This
->xwin
.backstore
, sw
->wnd
, This
->xwin
.gc
, x
, y
, cx
, cy
,
2253 x
- sw
->xoffset
, y
- sw
->yoffset
));
2257 XPutImage(This
->display
, This
->wnd
, This
->xwin
.gc
, image
, 0, 0, x
, y
, cx
, cy
);
2258 ON_ALL_SEAMLESS_WINDOWS(XCopyArea
,
2259 (This
->display
, This
->wnd
, sw
->wnd
, This
->xwin
.gc
, x
, y
, cx
, cy
,
2260 x
- sw
->xoffset
, y
- sw
->yoffset
));
2269 ui_destroy_bitmap(RDPCLIENT
* This
, HBITMAP bmp
)
2271 XFreePixmap(This
->display
, (Pixmap
) bmp
);
2275 ui_create_glyph(RDPCLIENT
* This
, int width
, int height
, const uint8
* data
)
2281 scanline
= (width
+ 7) / 8;
2283 bitmap
= XCreatePixmap(This
->display
, This
->wnd
, width
, height
, 1);
2284 if (This
->xwin
.create_glyph_gc
== 0)
2285 This
->xwin
.create_glyph_gc
= XCreateGC(This
->display
, bitmap
, 0, NULL
);
2287 image
= XCreateImage(This
->display
, This
->xwin
.visual
, 1, ZPixmap
, 0, (char *) data
,
2288 width
, height
, 8, scanline
);
2289 image
->byte_order
= MSBFirst
;
2290 image
->bitmap_bit_order
= MSBFirst
;
2293 XPutImage(This
->display
, bitmap
, This
->xwin
.create_glyph_gc
, image
, 0, 0, 0, 0, width
, height
);
2296 return (HGLYPH
) bitmap
;
2300 ui_destroy_glyph(RDPCLIENT
* This
, HGLYPH glyph
)
2302 XFreePixmap(This
->display
, (Pixmap
) glyph
);
2306 ui_create_cursor(RDPCLIENT
* This
, unsigned int x
, unsigned int y
, int width
, int height
,
2307 uint8
* andmask
, uint8
* xormask
)
2309 HGLYPH maskglyph
, cursorglyph
;
2312 uint8
*cursor
, *pcursor
;
2313 uint8
*mask
, *pmask
;
2315 int scanline
, offset
;
2318 scanline
= (width
+ 7) / 8;
2319 offset
= scanline
* height
;
2321 cursor
= (uint8
*) xmalloc(offset
);
2322 memset(cursor
, 0, offset
);
2324 mask
= (uint8
*) xmalloc(offset
);
2325 memset(mask
, 0, offset
);
2327 /* approximate AND and XOR masks with a monochrome X pointer */
2328 for (i
= 0; i
< height
; i
++)
2331 pcursor
= &cursor
[offset
];
2332 pmask
= &mask
[offset
];
2334 for (j
= 0; j
< scanline
; j
++)
2336 for (nextbit
= 0x80; nextbit
!= 0; nextbit
>>= 1)
2338 if (xormask
[0] || xormask
[1] || xormask
[2])
2340 *pcursor
|= (~(*andmask
) & nextbit
);
2345 *pcursor
|= ((*andmask
) & nextbit
);
2346 *pmask
|= (~(*andmask
) & nextbit
);
2358 fg
.red
= fg
.blue
= fg
.green
= 0xffff;
2359 bg
.red
= bg
.blue
= bg
.green
= 0x0000;
2360 fg
.flags
= bg
.flags
= DoRed
| DoBlue
| DoGreen
;
2362 cursorglyph
= ui_create_glyph(This
, width
, height
, cursor
);
2363 maskglyph
= ui_create_glyph(This
, width
, height
, mask
);
2366 XCreatePixmapCursor(This
->display
, (Pixmap
) cursorglyph
,
2367 (Pixmap
) maskglyph
, &fg
, &bg
, x
, y
);
2369 ui_destroy_glyph(This
, maskglyph
);
2370 ui_destroy_glyph(This
, cursorglyph
);
2373 return (HCURSOR
) xcursor
;
2377 ui_set_cursor(RDPCLIENT
* This
, HCURSOR cursor
)
2379 This
->xwin
.current_cursor
= (Cursor
) cursor
;
2380 XDefineCursor(This
->display
, This
->wnd
, This
->xwin
.current_cursor
);
2381 ON_ALL_SEAMLESS_WINDOWS(XDefineCursor
, (This
->display
, sw
->wnd
, This
->xwin
.current_cursor
));
2385 ui_destroy_cursor(RDPCLIENT
* This
, HCURSOR cursor
)
2387 XFreeCursor(This
->display
, (Cursor
) cursor
);
2391 ui_set_null_cursor(RDPCLIENT
* This
)
2393 ui_set_cursor(This
, This
->xwin
.null_cursor
);
2396 #define MAKE_XCOLOR(xc,c) \
2397 (xc)->red = ((c)->red << 8) | (c)->red; \
2398 (xc)->green = ((c)->green << 8) | (c)->green; \
2399 (xc)->blue = ((c)->blue << 8) | (c)->blue; \
2400 (xc)->flags = DoRed | DoGreen | DoBlue;
2404 ui_create_colourmap(RDPCLIENT
* This
, COLOURMAP
* colours
)
2407 int i
, ncolours
= colours
->ncolours
;
2408 if (!This
->owncolmap
)
2410 uint32
*map
= (uint32
*) xmalloc(sizeof(*This
->xwin
.colmap
) * ncolours
);
2412 XColor xc_cache
[256];
2414 int colLookup
= 256;
2415 for (i
= 0; i
< ncolours
; i
++)
2417 entry
= &colours
->colours
[i
];
2418 MAKE_XCOLOR(&xentry
, entry
);
2420 if (XAllocColor(This
->display
, This
->xwin
.xcolmap
, &xentry
) == 0)
2422 /* Allocation failed, find closest match. */
2424 int nMinDist
= 3 * 256 * 256;
2425 long nDist
= nMinDist
;
2427 /* only get the colors once */
2430 xc_cache
[colLookup
].pixel
= colLookup
;
2431 xc_cache
[colLookup
].red
= xc_cache
[colLookup
].green
=
2432 xc_cache
[colLookup
].blue
= 0;
2433 xc_cache
[colLookup
].flags
= 0;
2434 XQueryColor(This
->display
,
2435 DefaultColormap(This
->display
,
2436 DefaultScreen(This
->display
)),
2437 &xc_cache
[colLookup
]);
2441 /* approximate the pixel */
2444 if (xc_cache
[j
].flags
)
2446 nDist
= ((long) (xc_cache
[j
].red
>> 8) -
2447 (long) (xentry
.red
>> 8)) *
2448 ((long) (xc_cache
[j
].red
>> 8) -
2449 (long) (xentry
.red
>> 8)) +
2450 ((long) (xc_cache
[j
].green
>> 8) -
2451 (long) (xentry
.green
>> 8)) *
2452 ((long) (xc_cache
[j
].green
>> 8) -
2453 (long) (xentry
.green
>> 8)) +
2454 ((long) (xc_cache
[j
].blue
>> 8) -
2455 (long) (xentry
.blue
>> 8)) *
2456 ((long) (xc_cache
[j
].blue
>> 8) -
2457 (long) (xentry
.blue
>> 8));
2459 if (nDist
< nMinDist
)
2466 colour
= xentry
.pixel
;
2468 /* update our cache */
2469 if (xentry
.pixel
< 256)
2471 xc_cache
[xentry
.pixel
].red
= xentry
.red
;
2472 xc_cache
[xentry
.pixel
].green
= xentry
.green
;
2473 xc_cache
[xentry
.pixel
].blue
= xentry
.blue
;
2483 XColor
*xcolours
, *xentry
;
2486 xcolours
= (XColor
*) xmalloc(sizeof(XColor
) * ncolours
);
2487 for (i
= 0; i
< ncolours
; i
++)
2489 entry
= &colours
->colours
[i
];
2490 xentry
= &xcolours
[i
];
2492 MAKE_XCOLOR(xentry
, entry
);
2495 map
= XCreateColormap(This
->display
, This
->wnd
, This
->xwin
.visual
, AllocAll
);
2496 XStoreColors(This
->display
, map
, xcolours
, ncolours
);
2499 return (HCOLOURMAP
) map
;
2504 ui_destroy_colourmap(RDPCLIENT
* This
, HCOLOURMAP map
)
2506 if (!This
->owncolmap
)
2509 XFreeColormap(This
->display
, (Colormap
) map
);
2513 ui_set_colourmap(RDPCLIENT
* This
, HCOLOURMAP map
)
2515 if (!This
->owncolmap
)
2517 if (This
->xwin
.colmap
)
2518 xfree(This
->xwin
.colmap
);
2520 This
->xwin
.colmap
= (uint32
*) map
;
2524 XSetWindowColormap(This
->display
, This
->wnd
, (Colormap
) map
);
2525 ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap
, (This
->display
, sw
->wnd
, (Colormap
) map
));
2530 ui_set_clip(RDPCLIENT
* This
, int x
, int y
, int cx
, int cy
)
2532 This
->xwin
.clip_rectangle
.x
= x
;
2533 This
->xwin
.clip_rectangle
.y
= y
;
2534 This
->xwin
.clip_rectangle
.width
= cx
;
2535 This
->xwin
.clip_rectangle
.height
= cy
;
2536 XSetClipRectangles(This
->display
, This
->xwin
.gc
, 0, 0, &This
->xwin
.clip_rectangle
, 1, YXBanded
);
2540 ui_reset_clip(RDPCLIENT
* This
)
2542 This
->xwin
.clip_rectangle
.x
= 0;
2543 This
->xwin
.clip_rectangle
.y
= 0;
2544 This
->xwin
.clip_rectangle
.width
= This
->width
;
2545 This
->xwin
.clip_rectangle
.height
= This
->height
;
2546 XSetClipRectangles(This
->display
, This
->xwin
.gc
, 0, 0, &This
->xwin
.clip_rectangle
, 1, YXBanded
);
2550 ui_bell(RDPCLIENT
* This
)
2552 XBell(This
->display
, 0);
2556 ui_destblt(RDPCLIENT
* This
, uint8 opcode
,
2557 /* dest */ int x
, int y
, int cx
, int cy
)
2559 SET_FUNCTION(opcode
);
2560 FILL_RECTANGLE(x
, y
, cx
, cy
);
2561 RESET_FUNCTION(opcode
);
2564 static const uint8 hatch_patterns
[] = {
2565 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, /* 0 - bsHorizontal */
2566 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 1 - bsVertical */
2567 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, /* 2 - bsFDiagonal */
2568 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, /* 3 - bsBDiagonal */
2569 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, /* 4 - bsCross */
2570 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 /* 5 - bsDiagCross */
2574 ui_patblt(RDPCLIENT
* This
, uint8 opcode
,
2575 /* dest */ int x
, int y
, int cx
, int cy
,
2576 /* brush */ BRUSH
* brush
, int bgcolour
, int fgcolour
)
2579 uint8 i
, ipattern
[8];
2581 SET_FUNCTION(opcode
);
2583 switch (brush
->style
)
2586 SET_FOREGROUND(fgcolour
);
2587 FILL_RECTANGLE_BACKSTORE(x
, y
, cx
, cy
);
2591 fill
= (Pixmap
) ui_create_glyph(This
, 8, 8,
2592 hatch_patterns
+ brush
->pattern
[0] * 8);
2593 SET_FOREGROUND(fgcolour
);
2594 SET_BACKGROUND(bgcolour
);
2595 XSetFillStyle(This
->display
, This
->xwin
.gc
, FillOpaqueStippled
);
2596 XSetStipple(This
->display
, This
->xwin
.gc
, fill
);
2597 XSetTSOrigin(This
->display
, This
->xwin
.gc
, brush
->xorigin
, brush
->yorigin
);
2598 FILL_RECTANGLE_BACKSTORE(x
, y
, cx
, cy
);
2599 XSetFillStyle(This
->display
, This
->xwin
.gc
, FillSolid
);
2600 XSetTSOrigin(This
->display
, This
->xwin
.gc
, 0, 0);
2601 ui_destroy_glyph(This
, (HGLYPH
) fill
);
2604 case 3: /* Pattern */
2605 for (i
= 0; i
!= 8; i
++)
2606 ipattern
[7 - i
] = brush
->pattern
[i
];
2607 fill
= (Pixmap
) ui_create_glyph(This
, 8, 8, ipattern
);
2608 SET_FOREGROUND(bgcolour
);
2609 SET_BACKGROUND(fgcolour
);
2610 XSetFillStyle(This
->display
, This
->xwin
.gc
, FillOpaqueStippled
);
2611 XSetStipple(This
->display
, This
->xwin
.gc
, fill
);
2612 XSetTSOrigin(This
->display
, This
->xwin
.gc
, brush
->xorigin
, brush
->yorigin
);
2613 FILL_RECTANGLE_BACKSTORE(x
, y
, cx
, cy
);
2614 XSetFillStyle(This
->display
, This
->xwin
.gc
, FillSolid
);
2615 XSetTSOrigin(This
->display
, This
->xwin
.gc
, 0, 0);
2616 ui_destroy_glyph(This
, (HGLYPH
) fill
);
2620 unimpl("brush %d\n", brush
->style
);
2623 RESET_FUNCTION(opcode
);
2625 if (This
->ownbackstore
)
2626 XCopyArea(This
->display
, This
->xwin
.backstore
, This
->wnd
, This
->xwin
.gc
, x
, y
, cx
, cy
, x
, y
);
2627 ON_ALL_SEAMLESS_WINDOWS(XCopyArea
,
2628 (This
->display
, This
->ownbackstore
? This
->xwin
.backstore
: This
->wnd
, sw
->wnd
, This
->xwin
.gc
,
2629 x
, y
, cx
, cy
, x
- sw
->xoffset
, y
- sw
->yoffset
));
2633 ui_screenblt(RDPCLIENT
* This
, uint8 opcode
,
2634 /* dest */ int x
, int y
, int cx
, int cy
,
2635 /* src */ int srcx
, int srcy
)
2637 SET_FUNCTION(opcode
);
2638 if (This
->ownbackstore
)
2640 XCopyArea(This
->display
, This
->Unobscured
? This
->wnd
: This
->xwin
.backstore
,
2641 This
->wnd
, This
->xwin
.gc
, srcx
, srcy
, cx
, cy
, x
, y
);
2642 XCopyArea(This
->display
, This
->xwin
.backstore
, This
->xwin
.backstore
, This
->xwin
.gc
, srcx
, srcy
, cx
, cy
, x
, y
);
2646 XCopyArea(This
->display
, This
->wnd
, This
->wnd
, This
->xwin
.gc
, srcx
, srcy
, cx
, cy
, x
, y
);
2649 ON_ALL_SEAMLESS_WINDOWS(XCopyArea
,
2650 (This
->display
, This
->ownbackstore
? This
->xwin
.backstore
: This
->wnd
,
2651 sw
->wnd
, This
->xwin
.gc
, x
, y
, cx
, cy
, x
- sw
->xoffset
, y
- sw
->yoffset
));
2653 RESET_FUNCTION(opcode
);
2657 ui_memblt(RDPCLIENT
* This
, uint8 opcode
,
2658 /* dest */ int x
, int y
, int cx
, int cy
,
2659 /* src */ HBITMAP src
, int srcx
, int srcy
)
2661 SET_FUNCTION(opcode
);
2662 XCopyArea(This
->display
, (Pixmap
) src
, This
->wnd
, This
->xwin
.gc
, srcx
, srcy
, cx
, cy
, x
, y
);
2663 ON_ALL_SEAMLESS_WINDOWS(XCopyArea
,
2664 (This
->display
, (Pixmap
) src
, sw
->wnd
, This
->xwin
.gc
,
2665 srcx
, srcy
, cx
, cy
, x
- sw
->xoffset
, y
- sw
->yoffset
));
2666 if (This
->ownbackstore
)
2667 XCopyArea(This
->display
, (Pixmap
) src
, This
->xwin
.backstore
, This
->xwin
.gc
, srcx
, srcy
, cx
, cy
, x
, y
);
2668 RESET_FUNCTION(opcode
);
2672 ui_triblt(RDPCLIENT
* This
, uint8 opcode
,
2673 /* dest */ int x
, int y
, int cx
, int cy
,
2674 /* src */ HBITMAP src
, int srcx
, int srcy
,
2675 /* brush */ BRUSH
* brush
, int bgcolour
, int fgcolour
)
2677 /* This is potentially difficult to do in general. Until someone
2678 comes up with a more efficient way of doing it I am using cases. */
2682 case 0x69: /* PDSxxn */
2683 ui_memblt(This
, ROP2_XOR
, x
, y
, cx
, cy
, src
, srcx
, srcy
);
2684 ui_patblt(This
, ROP2_NXOR
, x
, y
, cx
, cy
, brush
, bgcolour
, fgcolour
);
2687 case 0xb8: /* PSDPxax */
2688 ui_patblt(This
, ROP2_XOR
, x
, y
, cx
, cy
, brush
, bgcolour
, fgcolour
);
2689 ui_memblt(This
, ROP2_AND
, x
, y
, cx
, cy
, src
, srcx
, srcy
);
2690 ui_patblt(This
, ROP2_XOR
, x
, y
, cx
, cy
, brush
, bgcolour
, fgcolour
);
2693 case 0xc0: /* PSa */
2694 ui_memblt(This
, ROP2_COPY
, x
, y
, cx
, cy
, src
, srcx
, srcy
);
2695 ui_patblt(This
, ROP2_AND
, x
, y
, cx
, cy
, brush
, bgcolour
, fgcolour
);
2699 unimpl("triblt 0x%x\n", opcode
);
2700 ui_memblt(This
, ROP2_COPY
, x
, y
, cx
, cy
, src
, srcx
, srcy
);
2705 ui_line(RDPCLIENT
* This
, uint8 opcode
,
2706 /* dest */ int startx
, int starty
, int endx
, int endy
,
2707 /* pen */ PEN
* pen
)
2709 SET_FUNCTION(opcode
);
2710 SET_FOREGROUND(pen
->colour
);
2711 XDrawLine(This
->display
, This
->wnd
, This
->xwin
.gc
, startx
, starty
, endx
, endy
);
2712 ON_ALL_SEAMLESS_WINDOWS(XDrawLine
, (This
->display
, sw
->wnd
, This
->xwin
.gc
,
2713 startx
- sw
->xoffset
, starty
- sw
->yoffset
,
2714 endx
- sw
->xoffset
, endy
- sw
->yoffset
));
2715 if (This
->ownbackstore
)
2716 XDrawLine(This
->display
, This
->xwin
.backstore
, This
->xwin
.gc
, startx
, starty
, endx
, endy
);
2717 RESET_FUNCTION(opcode
);
2721 ui_rect(RDPCLIENT
* This
,
2722 /* dest */ int x
, int y
, int cx
, int cy
,
2723 /* brush */ int colour
)
2725 SET_FOREGROUND(colour
);
2726 FILL_RECTANGLE(x
, y
, cx
, cy
);
2730 ui_polygon(RDPCLIENT
* This
, uint8 opcode
,
2731 /* mode */ uint8 fillmode
,
2732 /* dest */ POINT
* point
, int npoints
,
2733 /* brush */ BRUSH
* brush
, int bgcolour
, int fgcolour
)
2735 uint8 style
, i
, ipattern
[8];
2738 SET_FUNCTION(opcode
);
2743 XSetFillRule(This
->display
, This
->xwin
.gc
, EvenOddRule
);
2746 XSetFillRule(This
->display
, This
->xwin
.gc
, WindingRule
);
2749 unimpl("fill mode %d\n", fillmode
);
2753 style
= brush
->style
;
2760 SET_FOREGROUND(fgcolour
);
2761 FILL_POLYGON((XPoint
*) point
, npoints
);
2765 fill
= (Pixmap
) ui_create_glyph(This
, 8, 8,
2766 hatch_patterns
+ brush
->pattern
[0] * 8);
2767 SET_FOREGROUND(fgcolour
);
2768 SET_BACKGROUND(bgcolour
);
2769 XSetFillStyle(This
->display
, This
->xwin
.gc
, FillOpaqueStippled
);
2770 XSetStipple(This
->display
, This
->xwin
.gc
, fill
);
2771 XSetTSOrigin(This
->display
, This
->xwin
.gc
, brush
->xorigin
, brush
->yorigin
);
2772 FILL_POLYGON((XPoint
*) point
, npoints
);
2773 XSetFillStyle(This
->display
, This
->xwin
.gc
, FillSolid
);
2774 XSetTSOrigin(This
->display
, This
->xwin
.gc
, 0, 0);
2775 ui_destroy_glyph(This
, (HGLYPH
) fill
);
2778 case 3: /* Pattern */
2779 for (i
= 0; i
!= 8; i
++)
2780 ipattern
[7 - i
] = brush
->pattern
[i
];
2781 fill
= (Pixmap
) ui_create_glyph(This
, 8, 8, ipattern
);
2782 SET_FOREGROUND(bgcolour
);
2783 SET_BACKGROUND(fgcolour
);
2784 XSetFillStyle(This
->display
, This
->xwin
.gc
, FillOpaqueStippled
);
2785 XSetStipple(This
->display
, This
->xwin
.gc
, fill
);
2786 XSetTSOrigin(This
->display
, This
->xwin
.gc
, brush
->xorigin
, brush
->yorigin
);
2787 FILL_POLYGON((XPoint
*) point
, npoints
);
2788 XSetFillStyle(This
->display
, This
->xwin
.gc
, FillSolid
);
2789 XSetTSOrigin(This
->display
, This
->xwin
.gc
, 0, 0);
2790 ui_destroy_glyph(This
, (HGLYPH
) fill
);
2794 unimpl("brush %d\n", brush
->style
);
2797 RESET_FUNCTION(opcode
);
2801 ui_polyline(RDPCLIENT
* This
, uint8 opcode
,
2802 /* dest */ POINT
* points
, int npoints
,
2803 /* pen */ PEN
* pen
)
2805 /* TODO: set join style */
2806 SET_FUNCTION(opcode
);
2807 SET_FOREGROUND(pen
->colour
);
2808 XDrawLines(This
->display
, This
->wnd
, This
->xwin
.gc
, (XPoint
*) points
, npoints
, CoordModePrevious
);
2809 if (This
->ownbackstore
)
2810 XDrawLines(This
->display
, This
->xwin
.backstore
, This
->xwin
.gc
, (XPoint
*) points
, npoints
,
2813 ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines
,
2814 (This
, sw
->wnd
, (XPoint
*) points
, npoints
, sw
->xoffset
, sw
->yoffset
));
2816 RESET_FUNCTION(opcode
);
2820 ui_ellipse(RDPCLIENT
* This
, uint8 opcode
,
2821 /* mode */ uint8 fillmode
,
2822 /* dest */ int x
, int y
, int cx
, int cy
,
2823 /* brush */ BRUSH
* brush
, int bgcolour
, int fgcolour
)
2825 uint8 style
, i
, ipattern
[8];
2828 SET_FUNCTION(opcode
);
2831 style
= brush
->style
;
2838 SET_FOREGROUND(fgcolour
);
2839 DRAW_ELLIPSE(x
, y
, cx
, cy
, fillmode
);
2843 fill
= (Pixmap
) ui_create_glyph(This
, 8, 8,
2844 hatch_patterns
+ brush
->pattern
[0] * 8);
2845 SET_FOREGROUND(fgcolour
);
2846 SET_BACKGROUND(bgcolour
);
2847 XSetFillStyle(This
->display
, This
->xwin
.gc
, FillOpaqueStippled
);
2848 XSetStipple(This
->display
, This
->xwin
.gc
, fill
);
2849 XSetTSOrigin(This
->display
, This
->xwin
.gc
, brush
->xorigin
, brush
->yorigin
);
2850 DRAW_ELLIPSE(x
, y
, cx
, cy
, fillmode
);
2851 XSetFillStyle(This
->display
, This
->xwin
.gc
, FillSolid
);
2852 XSetTSOrigin(This
->display
, This
->xwin
.gc
, 0, 0);
2853 ui_destroy_glyph(This
, (HGLYPH
) fill
);
2856 case 3: /* Pattern */
2857 for (i
= 0; i
!= 8; i
++)
2858 ipattern
[7 - i
] = brush
->pattern
[i
];
2859 fill
= (Pixmap
) ui_create_glyph(This
, 8, 8, ipattern
);
2860 SET_FOREGROUND(bgcolour
);
2861 SET_BACKGROUND(fgcolour
);
2862 XSetFillStyle(This
->display
, This
->xwin
.gc
, FillOpaqueStippled
);
2863 XSetStipple(This
->display
, This
->xwin
.gc
, fill
);
2864 XSetTSOrigin(This
->display
, This
->xwin
.gc
, brush
->xorigin
, brush
->yorigin
);
2865 DRAW_ELLIPSE(x
, y
, cx
, cy
, fillmode
);
2866 XSetFillStyle(This
->display
, This
->xwin
.gc
, FillSolid
);
2867 XSetTSOrigin(This
->display
, This
->xwin
.gc
, 0, 0);
2868 ui_destroy_glyph(This
, (HGLYPH
) fill
);
2872 unimpl("brush %d\n", brush
->style
);
2875 RESET_FUNCTION(opcode
);
2878 /* warning, this function only draws on wnd or backstore, not both */
2880 ui_draw_glyph(RDPCLIENT
* This
, int mixmode
,
2881 /* dest */ int x
, int y
, int cx
, int cy
,
2882 /* src */ HGLYPH glyph
, int srcx
, int srcy
,
2883 int bgcolour
, int fgcolour
)
2885 SET_FOREGROUND(fgcolour
);
2886 SET_BACKGROUND(bgcolour
);
2888 XSetFillStyle(This
->display
, This
->xwin
.gc
,
2889 (mixmode
== MIX_TRANSPARENT
) ? FillStippled
: FillOpaqueStippled
);
2890 XSetStipple(This
->display
, This
->xwin
.gc
, (Pixmap
) glyph
);
2891 XSetTSOrigin(This
->display
, This
->xwin
.gc
, x
, y
);
2893 FILL_RECTANGLE_BACKSTORE(x
, y
, cx
, cy
);
2895 XSetFillStyle(This
->display
, This
->xwin
.gc
, FillSolid
);
2898 #define DO_GLYPH(ttext,idx) \
2900 glyph = cache_get_font (This, font, ttext[idx]);\
2901 if (!(flags & TEXT2_IMPLICIT_X))\
2903 xyoffset = ttext[++idx];\
2904 if ((xyoffset & 0x80))\
2906 if (flags & TEXT2_VERTICAL)\
2907 y += ttext[idx+1] | (ttext[idx+2] << 8);\
2909 x += ttext[idx+1] | (ttext[idx+2] << 8);\
2914 if (flags & TEXT2_VERTICAL)\
2922 x1 = x + glyph->offset;\
2923 y1 = y + glyph->baseline;\
2924 XSetStipple(This->display, This->xwin.gc, (Pixmap) glyph->pixmap);\
2925 XSetTSOrigin(This->display, This->xwin.gc, x1, y1);\
2926 FILL_RECTANGLE_BACKSTORE(x1, y1, glyph->width, glyph->height);\
2927 if (flags & TEXT2_IMPLICIT_X)\
2933 ui_draw_text(RDPCLIENT
* This
, uint8 font
, uint8 flags
, uint8 opcode
, int mixmode
, int x
, int y
,
2934 int clipx
, int clipy
, int clipcx
, int clipcy
,
2935 int boxx
, int boxy
, int boxcx
, int boxcy
, BRUSH
* brush
,
2936 int bgcolour
, int fgcolour
, uint8
* text
, uint8 length
)
2938 /* TODO: use brush appropriately */
2941 int i
, j
, xyoffset
, x1
, y1
;
2944 SET_FOREGROUND(bgcolour
);
2946 /* Sometimes, the boxcx value is something really large, like
2947 32691. This makes XCopyArea fail with Xvnc. The code below
2949 if (boxx
+ boxcx
> This
->width
)
2950 boxcx
= This
->width
- boxx
;
2954 FILL_RECTANGLE_BACKSTORE(boxx
, boxy
, boxcx
, boxcy
);
2956 else if (mixmode
== MIX_OPAQUE
)
2958 FILL_RECTANGLE_BACKSTORE(clipx
, clipy
, clipcx
, clipcy
);
2961 SET_FOREGROUND(fgcolour
);
2962 SET_BACKGROUND(bgcolour
);
2963 XSetFillStyle(This
->display
, This
->xwin
.gc
, FillStippled
);
2965 /* Paint text, character by character */
2966 for (i
= 0; i
< length
;)
2971 /* At least two bytes needs to follow */
2974 warning("Skipping short 0xff command:");
2975 for (j
= 0; j
< length
; j
++)
2976 fprintf(stderr
, "%02x ", text
[j
]);
2977 fprintf(stderr
, "\n");
2981 cache_put_text(This
, text
[i
+ 1], text
, text
[i
+ 2]);
2984 /* this will move pointer from start to first character after FF command */
2990 /* At least one byte needs to follow */
2993 warning("Skipping short 0xfe command:");
2994 for (j
= 0; j
< length
; j
++)
2995 fprintf(stderr
, "%02x ", text
[j
]);
2996 fprintf(stderr
, "\n");
3000 entry
= cache_get_text(This
, text
[i
+ 1]);
3001 if (entry
->data
!= NULL
)
3003 if ((((uint8
*) (entry
->data
))[1] == 0)
3004 && (!(flags
& TEXT2_IMPLICIT_X
)) && (i
+ 2 < length
))
3006 if (flags
& TEXT2_VERTICAL
)
3011 for (j
= 0; j
< entry
->size
; j
++)
3012 DO_GLYPH(((uint8
*) (entry
->data
)), j
);
3019 /* this will move pointer from start to first character after FE command */
3031 XSetFillStyle(This
->display
, This
->xwin
.gc
, FillSolid
);
3033 if (This
->ownbackstore
)
3037 XCopyArea(This
->display
, This
->xwin
.backstore
, This
->wnd
, This
->xwin
.gc
, boxx
,
3038 boxy
, boxcx
, boxcy
, boxx
, boxy
);
3039 ON_ALL_SEAMLESS_WINDOWS(XCopyArea
,
3040 (This
->display
, This
->xwin
.backstore
, sw
->wnd
, This
->xwin
.gc
,
3043 boxx
- sw
->xoffset
, boxy
- sw
->yoffset
));
3047 XCopyArea(This
->display
, This
->xwin
.backstore
, This
->wnd
, This
->xwin
.gc
, clipx
,
3048 clipy
, clipcx
, clipcy
, clipx
, clipy
);
3049 ON_ALL_SEAMLESS_WINDOWS(XCopyArea
,
3050 (This
->display
, This
->xwin
.backstore
, sw
->wnd
, This
->xwin
.gc
,
3052 clipcx
, clipcy
, clipx
- sw
->xoffset
,
3053 clipy
- sw
->yoffset
));
3059 ui_desktop_save(RDPCLIENT
* This
, uint32 offset
, int x
, int y
, int cx
, int cy
)
3064 if (This
->ownbackstore
)
3066 image
= XGetImage(This
->display
, This
->xwin
.backstore
, x
, y
, cx
, cy
, AllPlanes
, ZPixmap
);
3070 pix
= XCreatePixmap(This
->display
, This
->wnd
, cx
, cy
, This
->xwin
.depth
);
3071 XCopyArea(This
->display
, This
->wnd
, pix
, This
->xwin
.gc
, x
, y
, cx
, cy
, 0, 0);
3072 image
= XGetImage(This
->display
, pix
, 0, 0, cx
, cy
, AllPlanes
, ZPixmap
);
3073 XFreePixmap(This
->display
, pix
);
3076 offset
*= This
->xwin
.bpp
/ 8;
3077 cache_put_desktop(This
, offset
, cx
, cy
, image
->bytes_per_line
, This
->xwin
.bpp
/ 8, (uint8
*) image
->data
);
3079 XDestroyImage(image
);
3083 ui_desktop_restore(RDPCLIENT
* This
, uint32 offset
, int x
, int y
, int cx
, int cy
)
3088 offset
*= This
->xwin
.bpp
/ 8;
3089 data
= cache_get_desktop(This
, offset
, cx
, cy
, This
->xwin
.bpp
/ 8);
3093 image
= XCreateImage(This
->display
, This
->xwin
.visual
, This
->xwin
.depth
, ZPixmap
, 0,
3094 (char *) data
, cx
, cy
, BitmapPad(This
->display
), cx
* This
->xwin
.bpp
/ 8);
3096 if (This
->ownbackstore
)
3098 XPutImage(This
->display
, This
->xwin
.backstore
, This
->xwin
.gc
, image
, 0, 0, x
, y
, cx
, cy
);
3099 XCopyArea(This
->display
, This
->xwin
.backstore
, This
->wnd
, This
->xwin
.gc
, x
, y
, cx
, cy
, x
, y
);
3100 ON_ALL_SEAMLESS_WINDOWS(XCopyArea
,
3101 (This
->display
, This
->xwin
.backstore
, sw
->wnd
, This
->xwin
.gc
,
3102 x
, y
, cx
, cy
, x
- sw
->xoffset
, y
- sw
->yoffset
));
3106 XPutImage(This
->display
, This
->wnd
, This
->xwin
.gc
, image
, 0, 0, x
, y
, cx
, cy
);
3107 ON_ALL_SEAMLESS_WINDOWS(XCopyArea
,
3108 (This
->display
, This
->wnd
, sw
->wnd
, This
->xwin
.gc
, x
, y
, cx
, cy
,
3109 x
- sw
->xoffset
, y
- sw
->yoffset
));
3115 /* these do nothing here but are used in uiports */
3117 ui_begin_update(RDPCLIENT
* This
)
3122 ui_end_update(RDPCLIENT
* This
)
3128 ui_seamless_begin(RDPCLIENT
* This
, BOOL hidden
)
3130 if (!This
->seamless_rdp
)
3133 if (This
->xwin
.seamless_started
)
3136 This
->xwin
.seamless_started
= True
;
3137 This
->xwin
.seamless_hidden
= hidden
;
3140 ui_seamless_toggle(This
);
3145 ui_seamless_hide_desktop(RDPCLIENT
* This
)
3147 if (!This
->seamless_rdp
)
3150 if (!This
->xwin
.seamless_started
)
3153 if (This
->xwin
.seamless_active
)
3154 ui_seamless_toggle(This
);
3156 This
->xwin
.seamless_hidden
= True
;
3161 ui_seamless_unhide_desktop(RDPCLIENT
* This
)
3163 if (!This
->seamless_rdp
)
3166 if (!This
->xwin
.seamless_started
)
3169 This
->xwin
.seamless_hidden
= False
;
3171 ui_seamless_toggle(This
);
3176 ui_seamless_toggle(RDPCLIENT
* This
)
3178 if (!This
->seamless_rdp
)
3181 if (!This
->xwin
.seamless_started
)
3184 if (This
->xwin
.seamless_hidden
)
3187 if (This
->xwin
.seamless_active
)
3190 while (This
->xwin
.seamless_windows
)
3192 XDestroyWindow(This
->display
, This
->xwin
.seamless_windows
->wnd
);
3193 sw_remove_window(This
, This
->xwin
.seamless_windows
);
3195 XMapWindow(This
->display
, This
->wnd
);
3200 XUnmapWindow(This
->display
, This
->wnd
);
3201 seamless_send_sync(This
);
3204 This
->xwin
.seamless_active
= !This
->xwin
.seamless_active
;
3209 ui_seamless_create_window(RDPCLIENT
* This
, unsigned long id
, unsigned long group
, unsigned long parent
,
3210 unsigned long flags
)
3213 XSetWindowAttributes attribs
;
3214 XClassHint
*classhints
;
3215 XSizeHints
*sizehints
;
3218 seamless_window
*sw
, *sw_parent
;
3220 if (!This
->xwin
.seamless_active
)
3223 /* Ignore CREATEs for existing windows */
3224 sw
= sw_get_window_by_id(This
, id
);
3228 get_window_attribs(This
, &attribs
);
3229 wnd
= XCreateWindow(This
->display
, RootWindowOfScreen(This
->xwin
.screen
), -1, -1, 1, 1, 0, This
->xwin
.depth
,
3230 InputOutput
, This
->xwin
.visual
,
3231 CWBackPixel
| CWBackingStore
| CWColormap
| CWBorderPixel
, &attribs
);
3233 XStoreName(This
->display
, wnd
, "SeamlessRDP");
3234 ewmh_set_wm_name(This
, wnd
, "SeamlessRDP");
3236 mwm_hide_decorations(This
, wnd
);
3238 classhints
= XAllocClassHint();
3239 if (classhints
!= NULL
)
3241 classhints
->res_name
= "rdesktop";
3242 classhints
->res_class
= "SeamlessRDP";
3243 XSetClassHint(This
->display
, wnd
, classhints
);
3247 /* WM_NORMAL_HINTS */
3248 sizehints
= XAllocSizeHints();
3249 if (sizehints
!= NULL
)
3251 sizehints
->flags
= USPosition
;
3252 XSetWMNormalHints(This
->display
, wnd
, sizehints
);
3256 /* Parent-less transient windows */
3257 if (parent
== 0xFFFFFFFF)
3259 XSetTransientForHint(This
->display
, wnd
, RootWindowOfScreen(This
->xwin
.screen
));
3260 /* Some buggy wm:s (kwin) do not handle the above, so fake it
3261 using some other hints. */
3262 ewmh_set_window_popup(This
, wnd
);
3264 /* Normal transient windows */
3265 else if (parent
!= 0x00000000)
3267 sw_parent
= sw_get_window_by_id(This
, parent
);
3269 XSetTransientForHint(This
->display
, wnd
, sw_parent
->wnd
);
3271 warning("ui_seamless_create_window: No parent window 0x%lx\n", parent
);
3274 if (flags
& SEAMLESSRDP_CREATE_MODAL
)
3276 /* We do this to support buggy wm:s (*cough* metacity *cough*)
3277 somewhat at least */
3278 if (parent
== 0x00000000)
3279 XSetTransientForHint(This
->display
, wnd
, RootWindowOfScreen(This
->xwin
.screen
));
3280 ewmh_set_window_modal(This
, wnd
);
3283 /* FIXME: Support for Input Context:s */
3285 get_input_mask(This
, &input_mask
);
3286 input_mask
|= PropertyChangeMask
;
3288 XSelectInput(This
->display
, wnd
, input_mask
);
3290 /* handle the WM_DELETE_WINDOW protocol. FIXME: When killing a
3291 seamless window, we could try to close the window on the
3292 serverside, instead of terminating rdesktop */
3293 XSetWMProtocols(This
->display
, wnd
, &This
->xwin
.kill_atom
, 1);
3295 sw
= xmalloc(sizeof(seamless_window
));
3299 sw
->group
= sw_find_group(This
, group
, False
);
3300 sw
->group
->refcnt
++;
3305 sw
->state
= SEAMLESSRDP_NOTYETMAPPED
;
3307 sw
->position_timer
= xmalloc(sizeof(struct timeval
));
3308 timerclear(sw
->position_timer
);
3310 sw
->outstanding_position
= False
;
3311 sw
->outpos_serial
= 0;
3312 sw
->outpos_xoffset
= sw
->outpos_yoffset
= 0;
3313 sw
->outpos_width
= sw
->outpos_height
= 0;
3315 sw
->next
= This
->xwin
.seamless_windows
;
3316 This
->xwin
.seamless_windows
= sw
;
3319 wmhints
= XAllocWMHints();
3322 wmhints
->flags
= WindowGroupHint
;
3323 wmhints
->window_group
= sw
->group
->wnd
;
3324 XSetWMHints(This
->display
, sw
->wnd
, wmhints
);
3331 ui_seamless_destroy_window(RDPCLIENT
* This
, unsigned long id
, unsigned long flags
)
3333 seamless_window
*sw
;
3335 if (!This
->xwin
.seamless_active
)
3338 sw
= sw_get_window_by_id(This
, id
);
3341 warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id
);
3345 XDestroyWindow(This
->display
, sw
->wnd
);
3346 sw_remove_window(This
, sw
);
3351 ui_seamless_destroy_group(RDPCLIENT
* This
, unsigned long id
, unsigned long flags
)
3353 seamless_window
*sw
, *sw_next
;
3355 if (!This
->xwin
.seamless_active
)
3358 for (sw
= This
->xwin
.seamless_windows
; sw
; sw
= sw_next
)
3362 if (sw
->group
->id
== id
)
3364 XDestroyWindow(This
->display
, sw
->wnd
);
3365 sw_remove_window(This
, sw
);
3372 ui_seamless_move_window(RDPCLIENT
* This
, unsigned long id
, int x
, int y
, int width
, int height
, unsigned long flags
)
3374 seamless_window
*sw
;
3376 if (!This
->xwin
.seamless_active
)
3379 sw
= sw_get_window_by_id(This
, id
);
3382 warning("ui_seamless_move_window: No information for window 0x%lx\n", id
);
3386 /* We ignore server updates until it has handled our request. */
3387 if (sw
->outstanding_position
)
3390 if (!width
|| !height
)
3391 /* X11 windows must be at least 1x1 */
3397 sw
->height
= height
;
3399 /* If we move the window in a maximized state, then KDE won't
3400 accept restoration */
3403 case SEAMLESSRDP_MINIMIZED
:
3404 case SEAMLESSRDP_MAXIMIZED
:
3408 /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
3409 XMoveResizeWindow(This
->display
, sw
->wnd
, sw
->xoffset
, sw
->yoffset
, sw
->width
, sw
->height
);
3414 ui_seamless_restack_window(RDPCLIENT
* This
, unsigned long id
, unsigned long behind
, unsigned long flags
)
3416 seamless_window
*sw
;
3418 if (!This
->xwin
.seamless_active
)
3421 sw
= sw_get_window_by_id(This
, id
);
3424 warning("ui_seamless_restack_window: No information for window 0x%lx\n", id
);
3430 seamless_window
*sw_behind
;
3433 sw_behind
= sw_get_window_by_id(This
, behind
);
3436 warning("ui_seamless_restack_window: No information for window 0x%lx\n",
3441 wnds
[1] = sw_behind
->wnd
;
3444 XRestackWindows(This
->display
, wnds
, 2);
3448 XRaiseWindow(This
->display
, sw
->wnd
);
3451 sw_restack_window(This
, sw
, behind
);
3456 ui_seamless_settitle(RDPCLIENT
* This
, unsigned long id
, const char *title
, unsigned long flags
)
3458 seamless_window
*sw
;
3460 if (!This
->xwin
.seamless_active
)
3463 sw
= sw_get_window_by_id(This
, id
);
3466 warning("ui_seamless_settitle: No information for window 0x%lx\n", id
);
3470 /* FIXME: Might want to convert the name for non-EWMH WMs */
3471 XStoreName(This
->display
, sw
->wnd
, title
);
3472 ewmh_set_wm_name(This
, sw
->wnd
, title
);
3477 ui_seamless_setstate(RDPCLIENT
* This
, unsigned long id
, unsigned int state
, unsigned long flags
)
3479 seamless_window
*sw
;
3481 if (!This
->xwin
.seamless_active
)
3484 sw
= sw_get_window_by_id(This
, id
);
3487 warning("ui_seamless_setstate: No information for window 0x%lx\n", id
);
3493 case SEAMLESSRDP_NORMAL
:
3494 case SEAMLESSRDP_MAXIMIZED
:
3495 ewmh_change_state(This
, sw
->wnd
, state
);
3496 XMapWindow(This
->display
, sw
->wnd
);
3498 case SEAMLESSRDP_MINIMIZED
:
3499 /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
3500 the Window Manager should probably just ignore the request, since
3501 _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
3502 such as minimization, rather than an independent state." Besides,
3503 XIconifyWindow is easier. */
3504 if (sw
->state
== SEAMLESSRDP_NOTYETMAPPED
)
3507 hints
= XGetWMHints(This
->display
, sw
->wnd
);
3510 hints
->flags
|= StateHint
;
3511 hints
->initial_state
= IconicState
;
3512 XSetWMHints(This
->display
, sw
->wnd
, hints
);
3515 XMapWindow(This
->display
, sw
->wnd
);
3518 XIconifyWindow(This
->display
, sw
->wnd
, DefaultScreen(This
->display
));
3521 warning("SeamlessRDP: Invalid state %d\n", state
);
3530 ui_seamless_syncbegin(RDPCLIENT
* This
, unsigned long flags
)
3532 if (!This
->xwin
.seamless_active
)
3535 /* Destroy all seamless windows */
3536 while (This
->xwin
.seamless_windows
)
3538 XDestroyWindow(This
->display
, This
->xwin
.seamless_windows
->wnd
);
3539 sw_remove_window(This
, This
->xwin
.seamless_windows
);
3545 ui_seamless_ack(RDPCLIENT
* This
, unsigned int serial
)
3547 seamless_window
*sw
;
3548 for (sw
= This
->xwin
.seamless_windows
; sw
; sw
= sw
->next
)
3550 if (sw
->outstanding_position
&& (sw
->outpos_serial
== serial
))
3552 sw
->xoffset
= sw
->outpos_xoffset
;
3553 sw
->yoffset
= sw
->outpos_yoffset
;
3554 sw
->width
= sw
->outpos_width
;
3555 sw
->height
= sw
->outpos_height
;
3556 sw
->outstanding_position
= False
;
3558 /* Do a complete redraw of the window as part of the
3559 completion of the move. This is to remove any
3560 artifacts caused by our lack of synchronization. */
3561 XCopyArea(This
->display
, This
->xwin
.backstore
,
3562 sw
->wnd
, This
->xwin
.gc
,
3563 sw
->xoffset
, sw
->yoffset
, sw
->width
, sw
->height
, 0, 0);