/[rdesktop]/sourceforge.net/trunk/rdesktop/xwin.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /sourceforge.net/trunk/rdesktop/xwin.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 208 by matthewc, Fri Sep 27 01:04:34 2002 UTC revision 1057 by astrand, Tue Mar 7 08:17:40 2006 UTC
# Line 1  Line 1 
1  /*  /* -*- c-basic-offset: 8 -*-
2     rdesktop: A Remote Desktop Protocol client.     rdesktop: A Remote Desktop Protocol client.
3     User interface services - X Window System     User interface services - X Window System
4     Copyright (C) Matthew Chapman 1999-2002     Copyright (C) Matthew Chapman 1999-2005
5    
6     This program is free software; you can redistribute it and/or modify     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     it under the terms of the GNU General Public License as published by
# Line 20  Line 20 
20    
21  #include <X11/Xlib.h>  #include <X11/Xlib.h>
22  #include <X11/Xutil.h>  #include <X11/Xutil.h>
23    #include <unistd.h>
24    #include <sys/time.h>
25  #include <time.h>  #include <time.h>
26  #include <errno.h>  #include <errno.h>
27    #include <strings.h>
28  #include "rdesktop.h"  #include "rdesktop.h"
29    #include "xproto.h"
30    
31  extern int width;  extern int g_width;
32  extern int height;  extern int g_height;
33  extern BOOL sendmotion;  extern int g_xpos;
34  extern BOOL fullscreen;  extern int g_ypos;
35  extern BOOL grab_keyboard;  extern int g_pos;
36  extern char title[];  extern BOOL g_sendmotion;
37  BOOL enable_compose = False;  extern BOOL g_fullscreen;
38    extern BOOL g_grab_keyboard;
39  Display *display;  extern BOOL g_hide_decorations;
40  static int x_socket;  extern char g_title[];
41  static Screen *screen;  /* Color depth of the RDP session.
42  static Window wnd;     As of RDP 5.1, it may be 8, 15, 16 or 24. */
43  static GC gc;  extern int g_server_depth;
44  static Visual *visual;  extern int g_win_button_size;
45  static int depth;  
46  static int bpp;  Display *g_display;
47  static XIM IM;  Time g_last_gesturetime;
48  static XIC IC;  static int g_x_socket;
49  static XModifierKeymap *mod_map;  static Screen *g_screen;
50  static Cursor current_cursor;  Window g_wnd;
51    extern uint32 g_embed_wnd;
52    BOOL g_enable_compose = False;
53    BOOL g_Unobscured;              /* used for screenblt */
54    static GC g_gc = NULL;
55    static GC g_create_bitmap_gc = NULL;
56    static GC g_create_glyph_gc = NULL;
57    static Visual *g_visual;
58    /* Color depth of the X11 visual of our window (e.g. 24 for True Color R8G8B visual).
59       This may be 32 for R8G8B8 visuals, and then the rest of the bits are undefined
60       as far as we're concerned. */
61    static int g_depth;
62    /* Bits-per-Pixel of the pixmaps we'll be using to draw on our window.
63       This may be larger than g_depth, in which case some of the bits would
64       be kept solely for alignment (e.g. 32bpp pixmaps on a 24bpp visual). */
65    static int g_bpp;
66    static XIM g_IM;
67    static XIC g_IC;
68    static XModifierKeymap *g_mod_map;
69    static Cursor g_current_cursor;
70    static HCURSOR g_null_cursor = NULL;
71    static Atom g_protocol_atom, g_kill_atom;
72    static BOOL g_focused;
73    static BOOL g_mouse_in_wnd;
74    /* Indicates that:
75       1) visual has 15, 16 or 24 depth and the same color channel masks
76          as its RDP equivalent (implies X server is LE),
77       2) host is LE
78       This will trigger an optimization whose real value is questionable.
79    */
80    static BOOL g_compatible_arch;
81    /* Indicates whether RDP's bitmaps and our XImages have the same
82       binary format. If so, we can avoid an expensive translation.
83       Note that this can be true when g_compatible_arch is false,
84       e.g.:
85      
86         RDP(LE) <-> host(BE) <-> X-Server(LE)
87        
88       ('host' is the machine running rdesktop; the host simply memcpy's
89        so its endianess doesn't matter)
90     */
91    static BOOL g_no_translate_image = False;
92    
93  /* endianness */  /* endianness */
94  static BOOL host_be;  static BOOL g_host_be;
95  static BOOL xserver_be;  static BOOL g_xserver_be;
96    static int g_red_shift_r, g_blue_shift_r, g_green_shift_r;
97    static int g_red_shift_l, g_blue_shift_l, g_green_shift_l;
98    
99  /* software backing store */  /* software backing store */
100  static BOOL ownbackstore;  extern BOOL g_ownbackstore;
101  static Pixmap backstore;  static Pixmap g_backstore = 0;
102    
103    /* Moving in single app mode */
104    static BOOL g_moving_wnd;
105    static int g_move_x_offset = 0;
106    static int g_move_y_offset = 0;
107    static BOOL g_using_full_workarea = False;
108    
109    #ifdef WITH_RDPSND
110    extern int g_dsp_fd;
111    extern BOOL g_dsp_busy;
112    extern BOOL g_rdpsnd;
113    #endif
114    
115    /* MWM decorations */
116    #define MWM_HINTS_DECORATIONS   (1L << 1)
117    #define PROP_MOTIF_WM_HINTS_ELEMENTS    5
118    typedef struct
119    {
120            unsigned long flags;
121            unsigned long functions;
122            unsigned long decorations;
123            long inputMode;
124            unsigned long status;
125    }
126    PropMotifWmHints;
127    
128    typedef struct
129    {
130            uint32 red;
131            uint32 green;
132            uint32 blue;
133    }
134    PixelColour;
135    
136    
137  #define FILL_RECTANGLE(x,y,cx,cy)\  #define FILL_RECTANGLE(x,y,cx,cy)\
138  { \  { \
139          XFillRectangle(display, wnd, gc, x, y, cx, cy); \          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \
140          if (ownbackstore) \          if (g_ownbackstore) \
141                  XFillRectangle(display, backstore, gc, x, y, cx, cy); \                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \
142  }  }
143    
144  /* colour maps */  #define FILL_RECTANGLE_BACKSTORE(x,y,cx,cy)\
145  static Colormap xcolmap;  { \
146  static uint32 *colmap;          XFillRectangle(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, cx, cy); \
147    }
148    
149    #define FILL_POLYGON(p,np)\
150    { \
151            XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \
152            if (g_ownbackstore) \
153                    XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \
154    }
155    
156    #define DRAW_ELLIPSE(x,y,cx,cy,m)\
157    { \
158            switch (m) \
159            { \
160                    case 0: /* Outline */ \
161                            XDrawArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \
162                            if (g_ownbackstore) \
163                                    XDrawArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
164                            break; \
165                    case 1: /* Filled */ \
166                            XFillArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \
167                            if (g_ownbackstore) \
168                                    XFillArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
169                            break; \
170            } \
171    }
172    
173  #define SET_FOREGROUND(col)     XSetForeground(display, gc, translate_colour(colmap[col]));  /* colour maps */
174  #define SET_BACKGROUND(col)     XSetBackground(display, gc, translate_colour(colmap[col]));  extern BOOL g_owncolmap;
175    static Colormap g_xcolmap;
176    static uint32 *g_colmap = NULL;
177    
178    #define TRANSLATE(col)          ( g_server_depth != 8 ? translate_colour(col) : g_owncolmap ? col : g_colmap[col] )
179    #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));
180    #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));
181    
182  static int rop2_map[] = {  static int rop2_map[] = {
183          GXclear,                /* 0 */          GXclear,                /* 0 */
# Line 86  static int rop2_map[] = { Line 198  static int rop2_map[] = {
198          GXset                   /* 1 */          GXset                   /* 1 */
199  };  };
200    
201  #define SET_FUNCTION(rop2)      { if (rop2 != ROP2_COPY) XSetFunction(display, gc, rop2_map[rop2]); }  #define SET_FUNCTION(rop2)      { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, rop2_map[rop2]); }
202  #define RESET_FUNCTION(rop2)    { if (rop2 != ROP2_COPY) XSetFunction(display, gc, GXcopy); }  #define RESET_FUNCTION(rop2)    { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, GXcopy); }
203    
204  static void  static void
205  translate8(uint8 * data, uint8 * out, uint8 * end)  mwm_hide_decorations(void)
206  {  {
207          while (out < end)          PropMotifWmHints motif_hints;
208                  *(out++) = (uint8) colmap[*(data++)];          Atom hintsatom;
209    
210            /* setup the property */
211            motif_hints.flags = MWM_HINTS_DECORATIONS;
212            motif_hints.decorations = 0;
213    
214            /* get the atom for the property */
215            hintsatom = XInternAtom(g_display, "_MOTIF_WM_HINTS", False);
216            if (!hintsatom)
217            {
218                    warning("Failed to get atom _MOTIF_WM_HINTS: probably your window manager does not support MWM hints\n");
219                    return;
220            }
221    
222            XChangeProperty(g_display, g_wnd, hintsatom, hintsatom, 32, PropModeReplace,
223                            (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
224  }  }
225    
226    #define SPLITCOLOUR15(colour, rv) \
227    { \
228            rv.red = ((colour >> 7) & 0xf8) | ((colour >> 12) & 0x7); \
229            rv.green = ((colour >> 2) & 0xf8) | ((colour >> 8) & 0x7); \
230            rv.blue = ((colour << 3) & 0xf8) | ((colour >> 2) & 0x7); \
231    }
232    
233    #define SPLITCOLOUR16(colour, rv) \
234    { \
235            rv.red = ((colour >> 8) & 0xf8) | ((colour >> 13) & 0x7); \
236            rv.green = ((colour >> 3) & 0xfc) | ((colour >> 9) & 0x3); \
237            rv.blue = ((colour << 3) & 0xf8) | ((colour >> 2) & 0x7); \
238    } \
239    
240    #define SPLITCOLOUR24(colour, rv) \
241    { \
242            rv.blue = (colour & 0xff0000) >> 16; \
243            rv.green = (colour & 0x00ff00) >> 8; \
244            rv.red = (colour & 0x0000ff); \
245    }
246    
247    #define MAKECOLOUR(pc) \
248            ((pc.red >> g_red_shift_r) << g_red_shift_l) \
249                    | ((pc.green >> g_green_shift_r) << g_green_shift_l) \
250                    | ((pc.blue >> g_blue_shift_r) << g_blue_shift_l) \
251    
252    #define BSWAP16(x) { x = (((x & 0xff) << 8) | (x >> 8)); }
253    #define BSWAP24(x) { x = (((x & 0xff) << 16) | (x >> 16) | (x & 0xff00)); }
254    #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \
255                            x = (x << 16) | (x >> 16); }
256    
257    /* The following macros output the same octet sequences
258       on both BE and LE hosts: */
259    
260    #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }
261    #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
262    #define BOUT32(o, x) { *(o++) = x >> 24; *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
263    #define LOUT16(o, x) { *(o++) = x; *(o++) = x >> 8; }
264    #define LOUT24(o, x) { *(o++) = x; *(o++) = x >> 8; *(o++) = x >> 16; }
265    #define LOUT32(o, x) { *(o++) = x; *(o++) = x >> 8; *(o++) = x >> 16; *(o++) = x >> 24; }
266    
267    static uint32
268    translate_colour(uint32 colour)
269    {
270            PixelColour pc;
271            switch (g_server_depth)
272            {
273                    case 15:
274                            SPLITCOLOUR15(colour, pc);
275                            break;
276                    case 16:
277                            SPLITCOLOUR16(colour, pc);
278                            break;
279                    case 24:
280                            SPLITCOLOUR24(colour, pc);
281                            break;
282                    default:
283                            /* Avoid warning */
284                            pc.red = 0;
285                            pc.green = 0;
286                            pc.blue = 0;
287                            break;
288            }
289            return MAKECOLOUR(pc);
290    }
291    
292    /* indent is confused by UNROLL8 */
293    /* *INDENT-OFF* */
294    
295    /* repeat and unroll, similar to bitmap.c */
296    /* potentialy any of the following translate */
297    /* functions can use repeat but just doing */
298    /* the most common ones */
299    
300    #define UNROLL8(stm) { stm stm stm stm stm stm stm stm }
301    /* 2 byte output repeat */
302    #define REPEAT2(stm) \
303    { \
304            while (out <= end - 8 * 2) \
305                    UNROLL8(stm) \
306            while (out < end) \
307                    { stm } \
308    }
309    /* 3 byte output repeat */
310    #define REPEAT3(stm) \
311    { \
312            while (out <= end - 8 * 3) \
313                    UNROLL8(stm) \
314            while (out < end) \
315                    { stm } \
316    }
317    /* 4 byte output repeat */
318    #define REPEAT4(stm) \
319    { \
320            while (out <= end - 8 * 4) \
321                    UNROLL8(stm) \
322            while (out < end) \
323                    { stm } \
324    }
325    /* *INDENT-ON* */
326    
327  static void  static void
328  translate16(uint8 * data, uint16 * out, uint16 * end)  translate8to8(const uint8 * data, uint8 * out, uint8 * end)
329  {  {
330          while (out < end)          while (out < end)
331                  *(out++) = (uint16) colmap[*(data++)];                  *(out++) = (uint8) g_colmap[*(data++)];
332    }
333    
334    static void
335    translate8to16(const uint8 * data, uint8 * out, uint8 * end)
336    {
337            uint16 value;
338    
339            if (g_compatible_arch)
340            {
341                    /* *INDENT-OFF* */
342                    REPEAT2
343                    (
344                            *((uint16 *) out) = g_colmap[*(data++)];
345                            out += 2;
346                    )
347                    /* *INDENT-ON* */
348            }
349            else if (g_xserver_be)
350            {
351                    while (out < end)
352                    {
353                            value = (uint16) g_colmap[*(data++)];
354                            BOUT16(out, value);
355                    }
356            }
357            else
358            {
359                    while (out < end)
360                    {
361                            value = (uint16) g_colmap[*(data++)];
362                            LOUT16(out, value);
363                    }
364            }
365  }  }
366    
367  /* little endian - conversion happens when colourmap is built */  /* little endian - conversion happens when colourmap is built */
368  static void  static void
369  translate24(uint8 * data, uint8 * out, uint8 * end)  translate8to24(const uint8 * data, uint8 * out, uint8 * end)
370  {  {
371          uint32 value;          uint32 value;
372    
373          while (out < end)          if (g_compatible_arch)
374            {
375                    while (out < end)
376                    {
377                            value = g_colmap[*(data++)];
378                            BOUT24(out, value);
379                    }
380            }
381            else
382          {          {
383                  value = colmap[*(data++)];                  while (out < end)
384                  *(out++) = value;                  {
385                  *(out++) = value >> 8;                          value = g_colmap[*(data++)];
386                  *(out++) = value >> 16;                          LOUT24(out, value);
387                    }
388          }          }
389  }  }
390    
391  static void  static void
392  translate32(uint8 * data, uint32 * out, uint32 * end)  translate8to32(const uint8 * data, uint8 * out, uint8 * end)
393  {  {
394          while (out < end)          uint32 value;
395                  *(out++) = colmap[*(data++)];  
396            if (g_compatible_arch)
397            {
398                    /* *INDENT-OFF* */
399                    REPEAT4
400                    (
401                            *((uint32 *) out) = g_colmap[*(data++)];
402                            out += 4;
403                    )
404                    /* *INDENT-ON* */
405            }
406            else if (g_xserver_be)
407            {
408                    while (out < end)
409                    {
410                            value = g_colmap[*(data++)];
411                            BOUT32(out, value);
412                    }
413            }
414            else
415            {
416                    while (out < end)
417                    {
418                            value = g_colmap[*(data++)];
419                            LOUT32(out, value);
420                    }
421            }
422  }  }
423    
424  static uint8 *  static void
425  translate_image(int width, int height, uint8 * data)  translate15to16(const uint16 * data, uint8 * out, uint8 * end)
426  {  {
427          int size = width * height * bpp / 8;          uint16 pixel;
428          uint8 *out = xmalloc(size);          uint16 value;
429          uint8 *end = out + size;          PixelColour pc;
430    
431          switch (bpp)          if (g_xserver_be)
432          {          {
433                  case 8:                  while (out < end)
434                          translate8(data, out, end);                  {
435                          break;                          pixel = *(data++);
436                            if (g_host_be)
437                            {
438                                    BSWAP16(pixel);
439                            }
440                            SPLITCOLOUR15(pixel, pc);
441                            value = MAKECOLOUR(pc);
442                            BOUT16(out, value);
443                    }
444            }
445            else
446            {
447                    while (out < end)
448                    {
449                            pixel = *(data++);
450                            if (g_host_be)
451                            {
452                                    BSWAP16(pixel);
453                            }
454                            SPLITCOLOUR15(pixel, pc);
455                            value = MAKECOLOUR(pc);
456                            LOUT16(out, value);
457                    }
458            }
459    }
460    
461                  case 16:  static void
462                          translate16(data, (uint16 *) out, (uint16 *) end);  translate15to24(const uint16 * data, uint8 * out, uint8 * end)
463                          break;  {
464            uint32 value;
465            uint16 pixel;
466            PixelColour pc;
467    
468                  case 24:          if (g_compatible_arch)
469                          translate24(data, out, end);          {
470                          break;                  /* *INDENT-OFF* */
471                    REPEAT3
472                    (
473                            pixel = *(data++);
474                            SPLITCOLOUR15(pixel, pc);
475                            *(out++) = pc.blue;
476                            *(out++) = pc.green;
477                            *(out++) = pc.red;
478                    )
479                    /* *INDENT-ON* */
480            }
481            else if (g_xserver_be)
482            {
483                    while (out < end)
484                    {
485                            pixel = *(data++);
486                            if (g_host_be)
487                            {
488                                    BSWAP16(pixel);
489                            }
490                            SPLITCOLOUR15(pixel, pc);
491                            value = MAKECOLOUR(pc);
492                            BOUT24(out, value);
493                    }
494            }
495            else
496            {
497                    while (out < end)
498                    {
499                            pixel = *(data++);
500                            if (g_host_be)
501                            {
502                                    BSWAP16(pixel);
503                            }
504                            SPLITCOLOUR15(pixel, pc);
505                            value = MAKECOLOUR(pc);
506                            LOUT24(out, value);
507                    }
508            }
509    }
510    
511                  case 32:  static void
512                          translate32(data, (uint32 *) out, (uint32 *) end);  translate15to32(const uint16 * data, uint8 * out, uint8 * end)
513                          break;  {
514            uint16 pixel;
515            uint32 value;
516            PixelColour pc;
517    
518            if (g_compatible_arch)
519            {
520                    /* *INDENT-OFF* */
521                    REPEAT4
522                    (
523                            pixel = *(data++);
524                            SPLITCOLOUR15(pixel, pc);
525                            *(out++) = pc.blue;
526                            *(out++) = pc.green;
527                            *(out++) = pc.red;
528                            *(out++) = 0;
529                    )
530                    /* *INDENT-ON* */
531            }
532            else if (g_xserver_be)
533            {
534                    while (out < end)
535                    {
536                            pixel = *(data++);
537                            if (g_host_be)
538                            {
539                                    BSWAP16(pixel);
540                            }
541                            SPLITCOLOUR15(pixel, pc);
542                            value = MAKECOLOUR(pc);
543                            BOUT32(out, value);
544                    }
545          }          }
546            else
547            {
548                    while (out < end)
549                    {
550                            pixel = *(data++);
551                            if (g_host_be)
552                            {
553                                    BSWAP16(pixel);
554                            }
555                            SPLITCOLOUR15(pixel, pc);
556                            value = MAKECOLOUR(pc);
557                            LOUT32(out, value);
558                    }
559            }
560    }
561    
562          return out;  static void
563    translate16to16(const uint16 * data, uint8 * out, uint8 * end)
564    {
565            uint16 pixel;
566            uint16 value;
567            PixelColour pc;
568    
569            if (g_xserver_be)
570            {
571                    if (g_host_be)
572                    {
573                            while (out < end)
574                            {
575                                    pixel = *(data++);
576                                    BSWAP16(pixel);
577                                    SPLITCOLOUR16(pixel, pc);
578                                    value = MAKECOLOUR(pc);
579                                    BOUT16(out, value);
580                            }
581                    }
582                    else
583                    {
584                            while (out < end)
585                            {
586                                    pixel = *(data++);
587                                    SPLITCOLOUR16(pixel, pc);
588                                    value = MAKECOLOUR(pc);
589                                    BOUT16(out, value);
590                            }
591                    }
592            }
593            else
594            {
595                    if (g_host_be)
596                    {
597                            while (out < end)
598                            {
599                                    pixel = *(data++);
600                                    BSWAP16(pixel);
601                                    SPLITCOLOUR16(pixel, pc);
602                                    value = MAKECOLOUR(pc);
603                                    LOUT16(out, value);
604                            }
605                    }
606                    else
607                    {
608                            while (out < end)
609                            {
610                                    pixel = *(data++);
611                                    SPLITCOLOUR16(pixel, pc);
612                                    value = MAKECOLOUR(pc);
613                                    LOUT16(out, value);
614                            }
615                    }
616            }
617  }  }
618    
619  #define BSWAP16(x) { x = (((x & 0xff) << 8) | (x >> 8)); }  static void
620  #define BSWAP24(x) { x = (((x & 0xff) << 16) | (x >> 16) | ((x >> 8) & 0xff00)); }  translate16to24(const uint16 * data, uint8 * out, uint8 * end)
621  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \  {
622                          x = (x << 16) | (x >> 16); }          uint32 value;
623            uint16 pixel;
624            PixelColour pc;
625    
626  static uint32          if (g_compatible_arch)
627  translate_colour(uint32 colour)          {
628                    /* *INDENT-OFF* */
629                    REPEAT3
630                    (
631                            pixel = *(data++);
632                            SPLITCOLOUR16(pixel, pc);
633                            *(out++) = pc.blue;
634                            *(out++) = pc.green;
635                            *(out++) = pc.red;
636                    )
637                    /* *INDENT-ON* */
638            }
639            else if (g_xserver_be)
640            {
641                    if (g_host_be)
642                    {
643                            while (out < end)
644                            {
645                                    pixel = *(data++);
646                                    BSWAP16(pixel);
647                                    SPLITCOLOUR16(pixel, pc);
648                                    value = MAKECOLOUR(pc);
649                                    BOUT24(out, value);
650                            }
651                    }
652                    else
653                    {
654                            while (out < end)
655                            {
656                                    pixel = *(data++);
657                                    SPLITCOLOUR16(pixel, pc);
658                                    value = MAKECOLOUR(pc);
659                                    BOUT24(out, value);
660                            }
661                    }
662            }
663            else
664            {
665                    if (g_host_be)
666                    {
667                            while (out < end)
668                            {
669                                    pixel = *(data++);
670                                    BSWAP16(pixel);
671                                    SPLITCOLOUR16(pixel, pc);
672                                    value = MAKECOLOUR(pc);
673                                    LOUT24(out, value);
674                            }
675                    }
676                    else
677                    {
678                            while (out < end)
679                            {
680                                    pixel = *(data++);
681                                    SPLITCOLOUR16(pixel, pc);
682                                    value = MAKECOLOUR(pc);
683                                    LOUT24(out, value);
684                            }
685                    }
686            }
687    }
688    
689    static void
690    translate16to32(const uint16 * data, uint8 * out, uint8 * end)
691  {  {
692          switch (bpp)          uint16 pixel;
693            uint32 value;
694            PixelColour pc;
695    
696            if (g_compatible_arch)
697          {          {
698                  case 16:                  /* *INDENT-OFF* */
699                          if (host_be != xserver_be)                  REPEAT4
700                                  BSWAP16(colour);                  (
701                          break;                          pixel = *(data++);
702                            SPLITCOLOUR16(pixel, pc);
703                            *(out++) = pc.blue;
704                            *(out++) = pc.green;
705                            *(out++) = pc.red;
706                            *(out++) = 0;
707                    )
708                    /* *INDENT-ON* */
709            }
710            else if (g_xserver_be)
711            {
712                    if (g_host_be)
713                    {
714                            while (out < end)
715                            {
716                                    pixel = *(data++);
717                                    BSWAP16(pixel);
718                                    SPLITCOLOUR16(pixel, pc);
719                                    value = MAKECOLOUR(pc);
720                                    BOUT32(out, value);
721                            }
722                    }
723                    else
724                    {
725                            while (out < end)
726                            {
727                                    pixel = *(data++);
728                                    SPLITCOLOUR16(pixel, pc);
729                                    value = MAKECOLOUR(pc);
730                                    BOUT32(out, value);
731                            }
732                    }
733            }
734            else
735            {
736                    if (g_host_be)
737                    {
738                            while (out < end)
739                            {
740                                    pixel = *(data++);
741                                    BSWAP16(pixel);
742                                    SPLITCOLOUR16(pixel, pc);
743                                    value = MAKECOLOUR(pc);
744                                    LOUT32(out, value);
745                            }
746                    }
747                    else
748                    {
749                            while (out < end)
750                            {
751                                    pixel = *(data++);
752                                    SPLITCOLOUR16(pixel, pc);
753                                    value = MAKECOLOUR(pc);
754                                    LOUT32(out, value);
755                            }
756                    }
757            }
758    }
759    
760    static void
761    translate24to16(const uint8 * data, uint8 * out, uint8 * end)
762    {
763            uint32 pixel = 0;
764            uint16 value;
765            PixelColour pc;
766    
767            while (out < end)
768            {
769                    pixel = *(data++) << 16;
770                    pixel |= *(data++) << 8;
771                    pixel |= *(data++);
772                    SPLITCOLOUR24(pixel, pc);
773                    value = MAKECOLOUR(pc);
774                    if (g_xserver_be)
775                    {
776                            BOUT16(out, value);
777                    }
778                    else
779                    {
780                            LOUT16(out, value);
781                    }
782            }
783    }
784    
785    static void
786    translate24to24(const uint8 * data, uint8 * out, uint8 * end)
787    {
788            uint32 pixel;
789            uint32 value;
790            PixelColour pc;
791    
792            if (g_xserver_be)
793            {
794                    while (out < end)
795                    {
796                            pixel = *(data++) << 16;
797                            pixel |= *(data++) << 8;
798                            pixel |= *(data++);
799                            SPLITCOLOUR24(pixel, pc);
800                            value = MAKECOLOUR(pc);
801                            BOUT24(out, value);
802                    }
803            }
804            else
805            {
806                    while (out < end)
807                    {
808                            pixel = *(data++) << 16;
809                            pixel |= *(data++) << 8;
810                            pixel |= *(data++);
811                            SPLITCOLOUR24(pixel, pc);
812                            value = MAKECOLOUR(pc);
813                            LOUT24(out, value);
814                    }
815            }
816    }
817    
818    static void
819    translate24to32(const uint8 * data, uint8 * out, uint8 * end)
820    {
821            uint32 pixel;
822            uint32 value;
823            PixelColour pc;
824    
825            if (g_compatible_arch)
826            {
827                    /* *INDENT-OFF* */
828    #ifdef NEED_ALIGN
829                    REPEAT4
830                    (
831                            *(out++) = *(data++);
832                            *(out++) = *(data++);
833                            *(out++) = *(data++);
834                            *(out++) = 0;
835                    )
836    #else
837                    REPEAT4
838                    (
839                     /* Only read 3 bytes. Reading 4 bytes means reading beyond buffer. */
840                     *((uint32 *) out) = *((uint16 *) data) + (*((uint8 *) data + 2) << 16);
841                     out += 4;
842                     data += 3;
843                    )
844    #endif
845                    /* *INDENT-ON* */
846            }
847            else if (g_xserver_be)
848            {
849                    while (out < end)
850                    {
851                            pixel = *(data++) << 16;
852                            pixel |= *(data++) << 8;
853                            pixel |= *(data++);
854                            SPLITCOLOUR24(pixel, pc);
855                            value = MAKECOLOUR(pc);
856                            BOUT32(out, value);
857                    }
858            }
859            else
860            {
861                    while (out < end)
862                    {
863                            pixel = *(data++) << 16;
864                            pixel |= *(data++) << 8;
865                            pixel |= *(data++);
866                            SPLITCOLOUR24(pixel, pc);
867                            value = MAKECOLOUR(pc);
868                            LOUT32(out, value);
869                    }
870            }
871    }
872    
873    static uint8 *
874    translate_image(int width, int height, uint8 * data)
875    {
876            int size;
877            uint8 *out;
878            uint8 *end;
879    
880            /*
881               If RDP depth and X Visual depths match,
882               and arch(endian) matches, no need to translate:
883               just return data.
884               Note: select_visual should've already ensured g_no_translate
885               is only set for compatible depths, but the RDP depth might've
886               changed during connection negotiations.
887             */
888            if (g_no_translate_image)
889            {
890                    if ((g_depth == 15 && g_server_depth == 15) ||
891                        (g_depth == 16 && g_server_depth == 16) ||
892                        (g_depth == 24 && g_server_depth == 24))
893                            return data;
894            }
895    
896            size = width * height * (g_bpp / 8);
897            out = (uint8 *) xmalloc(size);
898            end = out + size;
899    
900            switch (g_server_depth)
901            {
902                  case 24:                  case 24:
903                          if (xserver_be)                          switch (g_bpp)
904                                  BSWAP24(colour);                          {
905                                    case 32:
906                                            translate24to32(data, out, end);
907                                            break;
908                                    case 24:
909                                            translate24to24(data, out, end);
910                                            break;
911                                    case 16:
912                                            translate24to16(data, out, end);
913                                            break;
914                            }
915                          break;                          break;
916                    case 16:
917                  case 32:                          switch (g_bpp)
918                          if (host_be != xserver_be)                          {
919                                  BSWAP32(colour);                                  case 32:
920                                            translate16to32((uint16 *) data, out, end);
921                                            break;
922                                    case 24:
923                                            translate16to24((uint16 *) data, out, end);
924                                            break;
925                                    case 16:
926                                            translate16to16((uint16 *) data, out, end);
927                                            break;
928                            }
929                            break;
930                    case 15:
931                            switch (g_bpp)
932                            {
933                                    case 32:
934                                            translate15to32((uint16 *) data, out, end);
935                                            break;
936                                    case 24:
937                                            translate15to24((uint16 *) data, out, end);
938                                            break;
939                                    case 16:
940                                            translate15to16((uint16 *) data, out, end);
941                                            break;
942                            }
943                            break;
944                    case 8:
945                            switch (g_bpp)
946                            {
947                                    case 8:
948                                            translate8to8(data, out, end);
949                                            break;
950                                    case 16:
951                                            translate8to16(data, out, end);
952                                            break;
953                                    case 24:
954                                            translate8to24(data, out, end);
955                                            break;
956                                    case 32:
957                                            translate8to32(data, out, end);
958                                            break;
959                            }
960                          break;                          break;
961          }          }
962            return out;
         return colour;  
963  }  }
964    
965  BOOL  BOOL
966  get_key_state(uint32 keysym, unsigned int state)  get_key_state(unsigned int state, uint32 keysym)
967  {  {
968          int modifierpos, key, keysymMask = 0;          int modifierpos, key, keysymMask = 0;
969          int offset;          int offset;
970    
971          KeyCode keycode = XKeysymToKeycode(display, keysym);          KeyCode keycode = XKeysymToKeycode(g_display, keysym);
972    
973          if (keycode == NoSymbol)          if (keycode == NoSymbol)
974                  return False;                  return False;
975    
976          for (modifierpos = 0; modifierpos < 8; modifierpos++)          for (modifierpos = 0; modifierpos < 8; modifierpos++)
977          {          {
978                  offset = mod_map->max_keypermod * modifierpos;                  offset = g_mod_map->max_keypermod * modifierpos;
979    
980                  for (key = 0; key < mod_map->max_keypermod; key++)                  for (key = 0; key < g_mod_map->max_keypermod; key++)
981                  {                  {
982                          if (mod_map->modifiermap[offset + key] == keycode)                          if (g_mod_map->modifiermap[offset + key] == keycode)
983                                  keysymMask |= 1 << modifierpos;                                  keysymMask |= 1 << modifierpos;
984                  }                  }
985          }          }
# Line 208  get_key_state(uint32 keysym, unsigned in Line 987  get_key_state(uint32 keysym, unsigned in
987          return (state & keysymMask) ? True : False;          return (state & keysymMask) ? True : False;
988  }  }
989    
990  BOOL  static void
991  ui_init(void)  calculate_shifts(uint32 mask, int *shift_r, int *shift_l)
992    {
993            *shift_l = ffs(mask) - 1;
994            mask >>= *shift_l;
995            *shift_r = 8 - ffs(mask & ~(mask >> 1));
996    }
997    
998    /* Given a mask of a colour channel (e.g. XVisualInfo.red_mask),
999       calculates the bits-per-pixel of this channel (a.k.a. colour weight).
1000     */
1001    static unsigned
1002    calculate_mask_weight(uint32 mask)
1003    {
1004            unsigned weight = 0;
1005            do
1006            {
1007                    weight += (mask & 1);
1008            }
1009            while (mask >>= 1);
1010            return weight;
1011    }
1012    
1013    static BOOL
1014    select_visual()
1015  {  {
1016          XPixmapFormatValues *pfm;          XPixmapFormatValues *pfm;
1017          uint16 test;          int pixmap_formats_count, visuals_count;
1018            XVisualInfo *vmatches = NULL;
1019            XVisualInfo template;
1020          int i;          int i;
1021            unsigned red_weight, blue_weight, green_weight;
1022    
1023          display = XOpenDisplay(NULL);          red_weight = blue_weight = green_weight = 0;
1024          if (display == NULL)  
1025            pfm = XListPixmapFormats(g_display, &pixmap_formats_count);
1026            if (pfm == NULL)
1027          {          {
1028                  error("Failed to open display\n");                  error("Unable to get list of pixmap formats from display.\n");
1029                    XCloseDisplay(g_display);
1030                  return False;                  return False;
1031          }          }
1032    
1033          x_socket = ConnectionNumber(display);          /* Search for best TrueColor visual */
1034          screen = DefaultScreenOfDisplay(display);          template.class = TrueColor;
1035          visual = DefaultVisualOfScreen(screen);          vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &visuals_count);
1036          depth = DefaultDepthOfScreen(screen);          g_visual = NULL;
1037            g_no_translate_image = False;
1038            g_compatible_arch = False;
1039            if (vmatches != NULL)
1040            {
1041                    for (i = 0; i < visuals_count; ++i)
1042                    {
1043                            XVisualInfo *visual_info = &vmatches[i];
1044    
1045                            /* Try to find a no-translation visual that'll
1046                               allow us to use RDP bitmaps directly as ZPixmaps. */
1047                            if (!g_xserver_be && (((visual_info->depth == 15) &&
1048                                                   /* R5G5B5 */
1049                                                   (visual_info->red_mask == 0x7c00) &&
1050                                                   (visual_info->green_mask == 0x3e0) &&
1051                                                   (visual_info->blue_mask == 0x1f)) ||
1052                                                  ((visual_info->depth == 16) &&
1053                                                   /* R5G6B5 */
1054                                                   (visual_info->red_mask == 0xf800) &&
1055                                                   (visual_info->green_mask == 0x7e0) &&
1056                                                   (visual_info->blue_mask == 0x1f)) ||
1057                                                  ((visual_info->depth == 24) &&
1058                                                   /* R8G8B8 */
1059                                                   (visual_info->red_mask == 0xff0000) &&
1060                                                   (visual_info->green_mask == 0xff00) &&
1061                                                   (visual_info->blue_mask == 0xff))))
1062                            {
1063                                    g_visual = visual_info->visual;
1064                                    g_depth = visual_info->depth;
1065                                    g_compatible_arch = !g_host_be;
1066                                    g_no_translate_image = (visual_info->depth == g_server_depth);
1067                                    if (g_no_translate_image)
1068                                            /* We found the best visual */
1069                                            break;
1070                            }
1071                            else
1072                            {
1073                                    g_compatible_arch = False;
1074                            }
1075    
1076                            if (visual_info->depth > 24)
1077                            {
1078                                    /* Avoid 32-bit visuals and likes like the plague.
1079                                       They're either untested or proven to work bad
1080                                       (e.g. nvidia's Composite 32-bit visual).
1081                                       Most implementation offer a 24-bit visual anyway. */
1082                                    continue;
1083                            }
1084    
1085                            /* Only care for visuals, for whose BPPs (not depths!)
1086                               we have a translateXtoY function. */
1087                            BOOL can_translate_to_bpp = False;
1088                            int j;
1089                            for (j = 0; j < pixmap_formats_count; ++j)
1090                            {
1091                                    if (pfm[j].depth == visual_info->depth)
1092                                    {
1093                                            if ((pfm[j].bits_per_pixel == 16) ||
1094                                                (pfm[j].bits_per_pixel == 24) ||
1095                                                (pfm[j].bits_per_pixel == 32))
1096                                            {
1097                                                    can_translate_to_bpp = True;
1098                                            }
1099                                            break;
1100                                    }
1101                            }
1102    
1103                            /* Prefer formats which have the most colour depth.
1104                               We're being truly aristocratic here, minding each
1105                               weight on its own. */
1106                            if (can_translate_to_bpp)
1107                            {
1108                                    unsigned vis_red_weight =
1109                                            calculate_mask_weight(visual_info->red_mask);
1110                                    unsigned vis_green_weight =
1111                                            calculate_mask_weight(visual_info->green_mask);
1112                                    unsigned vis_blue_weight =
1113                                            calculate_mask_weight(visual_info->blue_mask);
1114                                    if ((vis_red_weight >= red_weight)
1115                                        && (vis_green_weight >= green_weight)
1116                                        && (vis_blue_weight >= blue_weight))
1117                                    {
1118                                            red_weight = vis_red_weight;
1119                                            green_weight = vis_green_weight;
1120                                            blue_weight = vis_blue_weight;
1121                                            g_visual = visual_info->visual;
1122                                            g_depth = visual_info->depth;
1123                                    }
1124                            }
1125                    }
1126                    XFree(vmatches);
1127            }
1128    
1129            if (g_visual != NULL)
1130            {
1131                    g_owncolmap = False;
1132                    calculate_shifts(g_visual->red_mask, &g_red_shift_r, &g_red_shift_l);
1133                    calculate_shifts(g_visual->green_mask, &g_green_shift_r, &g_green_shift_l);
1134                    calculate_shifts(g_visual->blue_mask, &g_blue_shift_r, &g_blue_shift_l);
1135            }
1136            else
1137            {
1138                    template.class = PseudoColor;
1139                    template.depth = 8;
1140                    template.colormap_size = 256;
1141                    vmatches =
1142                            XGetVisualInfo(g_display,
1143                                           VisualClassMask | VisualDepthMask | VisualColormapSizeMask,
1144                                           &template, &visuals_count);
1145                    if (vmatches == NULL)
1146                    {
1147                            error("No usable TrueColor or PseudoColor visuals on this display.\n");
1148                            XCloseDisplay(g_display);
1149                            XFree(pfm);
1150                            return False;
1151                    }
1152    
1153          pfm = XListPixmapFormats(display, &i);                  /* we use a colourmap, so the default visual should do */
1154          if (pfm != NULL)                  g_owncolmap = True;
1155                    g_visual = vmatches[0].visual;
1156                    g_depth = vmatches[0].depth;
1157            }
1158    
1159            g_bpp = 0;
1160            for (i = 0; i < pixmap_formats_count; ++i)
1161          {          {
1162                  /* Use maximum bpp for this depth - this is generally                  XPixmapFormatValues *pf = &pfm[i];
1163                     desirable, e.g. 24 bits->32 bits. */                  if (pf->depth == g_depth)
                 while (i--)  
1164                  {                  {
1165                          if ((pfm[i].depth == depth) && (pfm[i].bits_per_pixel > bpp))                          g_bpp = pf->bits_per_pixel;
1166    
1167                            if (g_no_translate_image)
1168                          {                          {
1169                                  bpp = pfm[i].bits_per_pixel;                                  switch (g_server_depth)
1170                                    {
1171                                            case 15:
1172                                            case 16:
1173                                                    if (g_bpp != 16)
1174                                                            g_no_translate_image = False;
1175                                                    break;
1176                                            case 24:
1177                                                    /* Yes, this will force image translation
1178                                                       on most modern servers which use 32 bits
1179                                                       for R8G8B8. */
1180                                                    if (g_bpp != 24)
1181                                                            g_no_translate_image = False;
1182                                                    break;
1183                                            default:
1184                                                    g_no_translate_image = False;
1185                                                    break;
1186                                    }
1187                          }                          }
1188    
1189                            /* Pixmap formats list is a depth-to-bpp mapping --
1190                               there's just a single entry for every depth,
1191                               so we can safely break here */
1192                            break;
1193                  }                  }
                 XFree(pfm);  
1194          }          }
1195            XFree(pfm);
1196            pfm = NULL;
1197            return True;
1198    }
1199    
1200          if (bpp < 8)  BOOL
1201    ui_init(void)
1202    {
1203            int screen_num;
1204    
1205            g_display = XOpenDisplay(NULL);
1206            if (g_display == NULL)
1207          {          {
1208                  error("Less than 8 bpp not currently supported.\n");                  error("Failed to open display: %s\n", XDisplayName(NULL));
                 XCloseDisplay(display);  
1209                  return False;                  return False;
1210          }          }
1211    
1212          xcolmap = DefaultColormapOfScreen(screen);          {
1213          gc = XCreateGC(display, RootWindowOfScreen(screen), 0, NULL);                  uint16 endianess_test = 1;
1214                    g_host_be = !(BOOL) (*(uint8 *) (&endianess_test));
1215            }
1216    
1217          if (DoesBackingStore(screen) != Always)          g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1218                  ownbackstore = True;          screen_num = DefaultScreen(g_display);
1219            g_x_socket = ConnectionNumber(g_display);
1220            g_screen = ScreenOfDisplay(g_display, screen_num);
1221            g_depth = DefaultDepthOfScreen(g_screen);
1222    
1223          test = 1;          if (!select_visual())
1224          host_be = !(BOOL) (*(uint8 *) (&test));                  return False;
         xserver_be = (ImageByteOrder(display) == MSBFirst);  
1225    
1226          if (fullscreen)          if (g_no_translate_image)
1227          {          {
1228                  width = WidthOfScreen(screen);                  DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
                 height = HeightOfScreen(screen);  
1229          }          }
1230    
1231          /* make sure width is a multiple of 4 */          if (g_server_depth > g_bpp)
1232          width = (width + 3) & ~3;          {
1233                    warning("Remote desktop colour depth %d higher than display colour depth %d.\n",
1234                            g_server_depth, g_bpp);
1235            }
1236    
1237            DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n",
1238                   g_server_depth, g_depth, g_bpp, g_xserver_be, g_host_be));
1239    
1240          if (ownbackstore)          if (!g_owncolmap)
1241          {          {
1242                  backstore =                  g_xcolmap =
1243                          XCreatePixmap(display, RootWindowOfScreen(screen), width, height, depth);                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,
1244                                            AllocNone);
1245                    if (g_depth <= 8)
1246                            warning("Display colour depth is %d bit: you may want to use -C for a private colourmap.\n", g_depth);
1247            }
1248    
1249                  /* clear to prevent rubbish being exposed at startup */          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1250                  XSetForeground(display, gc, BlackPixelOfScreen(screen));          {
1251                  XFillRectangle(display, backstore, gc, 0, 0, width, height);                  warning("External BackingStore not available. Using internal.\n");
1252                    g_ownbackstore = True;
1253            }
1254    
1255            /*
1256             * Determine desktop size
1257             */
1258            if (g_fullscreen)
1259            {
1260                    g_width = WidthOfScreen(g_screen);
1261                    g_height = HeightOfScreen(g_screen);
1262                    g_using_full_workarea = True;
1263            }
1264            else if (g_width < 0)
1265            {
1266                    /* Percent of screen */
1267                    if (-g_width >= 100)
1268                            g_using_full_workarea = True;
1269                    g_height = HeightOfScreen(g_screen) * (-g_width) / 100;
1270                    g_width = WidthOfScreen(g_screen) * (-g_width) / 100;
1271            }
1272            else if (g_width == 0)
1273            {
1274                    /* Fetch geometry from _NET_WORKAREA */
1275                    uint32 x, y, cx, cy;
1276                    if (get_current_workarea(&x, &y, &cx, &cy) == 0)
1277                    {
1278                            g_width = cx;
1279                            g_height = cy;
1280                            g_using_full_workarea = True;
1281                    }
1282                    else
1283                    {
1284                            warning("Failed to get workarea: probably your window manager does not support extended hints\n");
1285                            g_width = WidthOfScreen(g_screen);
1286                            g_height = HeightOfScreen(g_screen);
1287                    }
1288          }          }
1289    
1290          mod_map = XGetModifierMapping(display);          /* make sure width is a multiple of 4 */
1291            g_width = (g_width + 3) & ~3;
1292    
1293          if (enable_compose)          g_mod_map = XGetModifierMapping(g_display);
                 IM = XOpenIM(display, NULL, NULL, NULL);  
1294    
1295          xkeymap_init();          xkeymap_init();
1296    
1297            if (g_enable_compose)
1298                    g_IM = XOpenIM(g_display, NULL, NULL, NULL);
1299    
1300            xclip_init();
1301    
1302            DEBUG_RDP5(("server bpp %d client bpp %d depth %d\n", g_server_depth, g_bpp, g_depth));
1303    
1304          return True;          return True;
1305  }  }
1306    
1307  void  void
1308  ui_deinit(void)  ui_deinit(void)
1309  {  {
1310          if (IM != NULL)          if (g_IM != NULL)
1311                  XCloseIM(IM);                  XCloseIM(g_IM);
1312    
1313          XFreeModifiermap(mod_map);          if (g_null_cursor != NULL)
1314                    ui_destroy_cursor(g_null_cursor);
1315    
1316          if (ownbackstore)          XFreeModifiermap(g_mod_map);
                 XFreePixmap(display, backstore);  
1317    
1318          XFreeGC(display, gc);          if (g_ownbackstore)
1319          XCloseDisplay(display);                  XFreePixmap(g_display, g_backstore);
1320          display = NULL;  
1321            XFreeGC(g_display, g_gc);
1322            XCloseDisplay(g_display);
1323            g_display = NULL;
1324  }  }
1325    
1326  BOOL  BOOL
1327  ui_create_window(void)  ui_create_window(void)
1328  {  {
1329            uint8 null_pointer_mask[1] = { 0x80 };
1330            uint8 null_pointer_data[24] = { 0x00 };
1331    
1332          XSetWindowAttributes attribs;          XSetWindowAttributes attribs;
1333          XClassHint *classhints;          XClassHint *classhints;
1334          XSizeHints *sizehints;          XSizeHints *sizehints;
# Line 313  ui_create_window(void) Line 1336  ui_create_window(void)
1336          long input_mask, ic_input_mask;          long input_mask, ic_input_mask;
1337          XEvent xevent;          XEvent xevent;
1338    
1339          wndwidth = fullscreen ? WidthOfScreen(screen) : width;          wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
1340          wndheight = fullscreen ? HeightOfScreen(screen) : height;          wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
1341    
1342          attribs.background_pixel = BlackPixelOfScreen(screen);          /* Handle -x-y portion of geometry string */
1343          attribs.backing_store = ownbackstore ? NotUseful : Always;          if (g_xpos < 0 || (g_xpos == 0 && (g_pos & 2)))
1344          attribs.override_redirect = fullscreen;                  g_xpos = WidthOfScreen(g_screen) + g_xpos - g_width;
1345            if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
1346          wnd = XCreateWindow(display, RootWindowOfScreen(screen), 0, 0, wndwidth, wndheight,                  g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
1347                              0, CopyFromParent, InputOutput, CopyFromParent,  
1348                              CWBackPixel | CWBackingStore | CWOverrideRedirect, &attribs);          attribs.background_pixel = BlackPixelOfScreen(g_screen);
1349            attribs.border_pixel = WhitePixelOfScreen(g_screen);
1350            attribs.backing_store = g_ownbackstore ? NotUseful : Always;
1351            attribs.override_redirect = g_fullscreen;
1352            attribs.colormap = g_xcolmap;
1353    
1354            g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, wndwidth,
1355                                  wndheight, 0, g_depth, InputOutput, g_visual,
1356                                  CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
1357                                  CWBorderPixel, &attribs);
1358    
1359            if (g_gc == NULL)
1360                    g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1361    
1362          XStoreName(display, wnd, title);          if (g_create_bitmap_gc == NULL)
1363                    g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1364    
1365            if ((g_ownbackstore) && (g_backstore == 0))
1366            {
1367                    g_backstore = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1368    
1369                    /* clear to prevent rubbish being exposed at startup */
1370                    XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
1371                    XFillRectangle(g_display, g_backstore, g_gc, 0, 0, g_width, g_height);
1372            }
1373    
1374            XStoreName(g_display, g_wnd, g_title);
1375    
1376            if (g_hide_decorations)
1377                    mwm_hide_decorations();
1378    
1379          classhints = XAllocClassHint();          classhints = XAllocClassHint();
1380          if (classhints != NULL)          if (classhints != NULL)
1381          {          {
1382                  classhints->res_name = classhints->res_class = "rdesktop";                  classhints->res_name = classhints->res_class = "rdesktop";
1383                  XSetClassHint(display, wnd, classhints);                  XSetClassHint(g_display, g_wnd, classhints);
1384                  XFree(classhints);                  XFree(classhints);
1385          }          }
1386    
# Line 338  ui_create_window(void) Line 1388  ui_create_window(void)
1388          if (sizehints)          if (sizehints)
1389          {          {
1390                  sizehints->flags = PMinSize | PMaxSize;                  sizehints->flags = PMinSize | PMaxSize;
1391                  sizehints->min_width = sizehints->max_width = width;                  if (g_pos)
1392                  sizehints->min_height = sizehints->max_height = height;                          sizehints->flags |= PPosition;
1393                  XSetWMNormalHints(display, wnd, sizehints);                  sizehints->min_width = sizehints->max_width = g_width;
1394                    sizehints->min_height = sizehints->max_height = g_height;
1395                    XSetWMNormalHints(g_display, g_wnd, sizehints);
1396                  XFree(sizehints);                  XFree(sizehints);
1397          }          }
1398    
1399            if (g_embed_wnd)
1400            {
1401                    XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
1402            }
1403    
1404          input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |          input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1405                  VisibilityChangeMask | FocusChangeMask;                  VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1406    
1407          if (sendmotion)          if (g_sendmotion)
1408                  input_mask |= PointerMotionMask;                  input_mask |= PointerMotionMask;
1409          if (ownbackstore)          if (g_ownbackstore)
1410                  input_mask |= ExposureMask;                  input_mask |= ExposureMask;
1411            if (g_fullscreen || g_grab_keyboard)
1412                    input_mask |= EnterWindowMask;
1413            if (g_grab_keyboard)
1414                    input_mask |= LeaveWindowMask;
1415    
1416          if (IM != NULL)          if (g_IM != NULL)
1417          {          {
1418                  IC = XCreateIC(IM, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing),                  g_IC = XCreateIC(g_IM, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing),
1419                                 XNClientWindow, wnd, XNFocusWindow, wnd, NULL);                                   XNClientWindow, g_wnd, XNFocusWindow, g_wnd, NULL);
1420    
1421                  if ((IC != NULL)                  if ((g_IC != NULL)
1422                      && (XGetICValues(IC, XNFilterEvents, &ic_input_mask, NULL) == NULL))                      && (XGetICValues(g_IC, XNFilterEvents, &ic_input_mask, NULL) == NULL))
1423                          input_mask |= ic_input_mask;                          input_mask |= ic_input_mask;
1424          }          }
1425    
1426          XSelectInput(display, wnd, input_mask);          XSelectInput(g_display, g_wnd, input_mask);
1427          XMapWindow(display, wnd);          XMapWindow(g_display, g_wnd);
1428    
1429          /* wait for VisibilityNotify */          /* wait for VisibilityNotify */
1430          do          do
1431          {          {
1432                  XMaskEvent(display, VisibilityChangeMask, &xevent);                  XMaskEvent(g_display, VisibilityChangeMask, &xevent);
1433          }          }
1434          while (xevent.type != VisibilityNotify);          while (xevent.type != VisibilityNotify);
1435            g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
1436    
1437            g_focused = False;
1438            g_mouse_in_wnd = False;
1439    
1440          if (fullscreen)          /* handle the WM_DELETE_WINDOW protocol */
1441                  XSetInputFocus(display, wnd, RevertToPointerRoot, CurrentTime);          g_protocol_atom = XInternAtom(g_display, "WM_PROTOCOLS", True);
1442            g_kill_atom = XInternAtom(g_display, "WM_DELETE_WINDOW", True);
1443            XSetWMProtocols(g_display, g_wnd, &g_kill_atom, 1);
1444    
1445            /* create invisible 1x1 cursor to be used as null cursor */
1446            if (g_null_cursor == NULL)
1447                    g_null_cursor = ui_create_cursor(0, 0, 1, 1, null_pointer_mask, null_pointer_data);
1448    
1449          return True;          return True;
1450  }  }
1451    
1452  void  void
1453    ui_resize_window()
1454    {
1455            XSizeHints *sizehints;
1456            Pixmap bs;
1457    
1458            sizehints = XAllocSizeHints();
1459            if (sizehints)
1460            {
1461                    sizehints->flags = PMinSize | PMaxSize;
1462                    sizehints->min_width = sizehints->max_width = g_width;
1463                    sizehints->min_height = sizehints->max_height = g_height;
1464                    XSetWMNormalHints(g_display, g_wnd, sizehints);
1465                    XFree(sizehints);
1466            }
1467    
1468            if (!(g_fullscreen || g_embed_wnd))
1469            {
1470                    XResizeWindow(g_display, g_wnd, g_width, g_height);
1471            }
1472    
1473            /* create new backstore pixmap */
1474            if (g_backstore != 0)
1475            {
1476                    bs = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1477                    XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
1478                    XFillRectangle(g_display, bs, g_gc, 0, 0, g_width, g_height);
1479                    XCopyArea(g_display, g_backstore, bs, g_gc, 0, 0, g_width, g_height, 0, 0);
1480                    XFreePixmap(g_display, g_backstore);
1481                    g_backstore = bs;
1482            }
1483    }
1484    
1485    void
1486  ui_destroy_window(void)  ui_destroy_window(void)
1487  {  {
1488          if (IC != NULL)          if (g_IC != NULL)
1489                  XDestroyIC(IC);                  XDestroyIC(g_IC);
1490    
1491          XDestroyWindow(display, wnd);          XDestroyWindow(g_display, g_wnd);
1492  }  }
1493    
1494  void  void
# Line 392  xwin_toggle_fullscreen(void) Line 1496  xwin_toggle_fullscreen(void)
1496  {  {
1497          Pixmap contents = 0;          Pixmap contents = 0;
1498    
1499          if (!ownbackstore)          if (!g_ownbackstore)
1500          {          {
1501                  /* need to save contents of window */                  /* need to save contents of window */
1502                  contents = XCreatePixmap(display, wnd, width, height, depth);                  contents = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1503                  XCopyArea(display, wnd, contents, gc, 0, 0, width, height, 0, 0);                  XCopyArea(g_display, g_wnd, contents, g_gc, 0, 0, g_width, g_height, 0, 0);
1504          }          }
1505    
1506          ui_destroy_window();          ui_destroy_window();
1507          fullscreen = !fullscreen;          g_fullscreen = !g_fullscreen;
1508          ui_create_window();          ui_create_window();
1509    
1510          XDefineCursor(display, wnd, current_cursor);          XDefineCursor(g_display, g_wnd, g_current_cursor);
1511    
1512          if (!ownbackstore)          if (!g_ownbackstore)
1513          {          {
1514                  XCopyArea(display, contents, wnd, gc, 0, 0, width, height, 0, 0);                  XCopyArea(g_display, contents, g_wnd, g_gc, 0, 0, g_width, g_height, 0, 0);
1515                  XFreePixmap(display, contents);                  XFreePixmap(g_display, contents);
1516          }          }
1517  }  }
1518    
 /* Process all events in Xlib queue */  
1519  static void  static void
1520    handle_button_event(XEvent xevent, BOOL down)
1521    {
1522            uint16 button, flags = 0;
1523            g_last_gesturetime = xevent.xbutton.time;
1524            button = xkeymap_translate_button(xevent.xbutton.button);
1525            if (button == 0)
1526                    return;
1527    
1528            if (down)
1529                    flags = MOUSE_FLAG_DOWN;
1530    
1531            /* Stop moving window when button is released, regardless of cursor position */
1532            if (g_moving_wnd && (xevent.type == ButtonRelease))
1533                    g_moving_wnd = False;
1534    
1535            /* If win_button_size is nonzero, enable single app mode */
1536            if (xevent.xbutton.y < g_win_button_size)
1537            {
1538                    /*  Check from right to left: */
1539                    if (xevent.xbutton.x >= g_width - g_win_button_size)
1540                    {
1541                            /* The close button, continue */
1542                            ;
1543                    }
1544                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 2)
1545                    {
1546                            /* The maximize/restore button. Do not send to
1547                               server.  It might be a good idea to change the
1548                               cursor or give some other visible indication
1549                               that rdesktop inhibited this click */
1550                            if (xevent.type == ButtonPress)
1551                                    return;
1552                    }
1553                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 3)
1554                    {
1555                            /* The minimize button. Iconify window. */
1556                            if (xevent.type == ButtonRelease)
1557                            {
1558                                    /* Release the mouse button outside the minimize button, to prevent the
1559                                       actual minimazation to happen */
1560                                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE, button, 1, 1);
1561                                    XIconifyWindow(g_display, g_wnd, DefaultScreen(g_display));
1562                                    return;
1563                            }
1564                    }
1565                    else if (xevent.xbutton.x <= g_win_button_size)
1566                    {
1567                            /* The system menu. Ignore. */
1568                            if (xevent.type == ButtonPress)
1569                                    return;
1570                    }
1571                    else
1572                    {
1573                            /* The title bar. */
1574                            if (xevent.type == ButtonPress)
1575                            {
1576                                    if (!g_fullscreen && g_hide_decorations && !g_using_full_workarea)
1577                                    {
1578                                            g_moving_wnd = True;
1579                                            g_move_x_offset = xevent.xbutton.x;
1580                                            g_move_y_offset = xevent.xbutton.y;
1581                                    }
1582                                    return;
1583                            }
1584                    }
1585            }
1586    
1587            rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1588                           flags | button, xevent.xbutton.x, xevent.xbutton.y);
1589    }
1590    
1591    /* Process events in Xlib queue
1592       Returns 0 after user quit, 1 otherwise */
1593    static int
1594  xwin_process_events(void)  xwin_process_events(void)
1595  {  {
1596          XEvent xevent;          XEvent xevent;
1597          KeySym keysym;          KeySym keysym;
         uint16 button, flags;  
1598          uint32 ev_time;          uint32 ev_time;
         key_translation tr;  
1599          char str[256];          char str[256];
1600          Status status;          Status status;
1601          unsigned int state;          int events = 0;
         Window wdummy;  
         int dummy;  
1602    
1603          while (XPending(display) > 0)          while ((XPending(g_display) > 0) && events++ < 20)
1604          {          {
1605                  XNextEvent(display, &xevent);                  XNextEvent(g_display, &xevent);
1606    
1607                  if ((IC != NULL) && (XFilterEvent(&xevent, None) == True))                  if ((g_IC != NULL) && (XFilterEvent(&xevent, None) == True))
1608                  {                  {
1609                          DEBUG_KBD(("Filtering event\n"));                          DEBUG_KBD(("Filtering event\n"));
1610                          continue;                          continue;
1611                  }                  }
1612    
                 flags = 0;  
   
1613                  switch (xevent.type)                  switch (xevent.type)
1614                  {                  {
1615                            case VisibilityNotify:
1616                                    g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
1617                                    break;
1618                            case ClientMessage:
1619                                    /* the window manager told us to quit */
1620                                    if ((xevent.xclient.message_type == g_protocol_atom)
1621                                        && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))
1622                                            /* Quit */
1623                                            return 0;
1624                                    break;
1625    
1626                          case KeyPress:                          case KeyPress:
1627                                  if (IC != NULL)                                  g_last_gesturetime = xevent.xkey.time;
1628                                    if (g_IC != NULL)
1629                                          /* Multi_key compatible version */                                          /* Multi_key compatible version */
1630                                  {                                  {
1631                                          XmbLookupString(IC,                                          XmbLookupString(g_IC,
1632                                                          (XKeyPressedEvent *) &                                                          &xevent.xkey, str, sizeof(str), &keysym,
1633                                                          xevent, str, sizeof(str), &keysym, &status);                                                          &status);
1634                                          if (!((status == XLookupKeySym) || (status == XLookupBoth)))                                          if (!((status == XLookupKeySym) || (status == XLookupBoth)))
1635                                          {                                          {
1636                                                  error("XmbLookupString failed with status 0x%x\n",                                                  error("XmbLookupString failed with status 0x%x\n",
# Line 463  xwin_process_events(void) Line 1646  xwin_process_events(void)
1646                                                        str, sizeof(str), &keysym, NULL);                                                        str, sizeof(str), &keysym, NULL);
1647                                  }                                  }
1648    
1649                                  DEBUG_KBD(("KeyPress for (keysym 0x%lx, %s)\n", keysym, get_ksname(keysym)));                                  DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym,
1650                                               get_ksname(keysym)));
1651    
1652                                  ev_time = time(NULL);                                  ev_time = time(NULL);
1653                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
1654                                          break;                                          break;
1655    
1656                                  tr = xkeymap_translate_key(keysym,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
1657                                                             xevent.xkey.keycode, xevent.xkey.state);                                                    ev_time, True, 0);
   
                                 if (tr.scancode == 0)  
                                         break;  
   
                                 ensure_remote_modifiers(ev_time, tr);  
   
                                 rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);  
1658                                  break;                                  break;
1659    
1660                          case KeyRelease:                          case KeyRelease:
1661                                    g_last_gesturetime = xevent.xkey.time;
1662                                  XLookupString((XKeyEvent *) & xevent, str,                                  XLookupString((XKeyEvent *) & xevent, str,
1663                                                sizeof(str), &keysym, NULL);                                                sizeof(str), &keysym, NULL);
1664    
1665                                  DEBUG_KBD(("\nKeyRelease for (keysym 0x%lx, %s)\n", keysym,                                  DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym,
1666                                             get_ksname(keysym)));                                             get_ksname(keysym)));
1667    
1668                                  ev_time = time(NULL);                                  ev_time = time(NULL);
1669                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
1670                                          break;                                          break;
1671    
1672                                  tr = xkeymap_translate_key(keysym,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
1673                                                             xevent.xkey.keycode, xevent.xkey.state);                                                    ev_time, False, 0);
   
                                 if (tr.scancode == 0)  
                                         break;  
   
                                 rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);  
1674                                  break;                                  break;
1675    
1676                          case ButtonPress:                          case ButtonPress:
1677                                  flags = MOUSE_FLAG_DOWN;                                  handle_button_event(xevent, True);
1678                                  /* fall through */                                  break;
1679    
1680                          case ButtonRelease:                          case ButtonRelease:
1681                                  button = xkeymap_translate_button(xevent.xbutton.button);                                  handle_button_event(xevent, False);
                                 if (button == 0)  
                                         break;  
   
                                 rdp_send_input(time(NULL), RDP_INPUT_MOUSE,  
                                                flags | button, xevent.xbutton.x, xevent.xbutton.y);  
1682                                  break;                                  break;
1683    
1684                          case MotionNotify:                          case MotionNotify:
1685                                    if (g_moving_wnd)
1686                                    {
1687                                            XMoveWindow(g_display, g_wnd,
1688                                                        xevent.xmotion.x_root - g_move_x_offset,
1689                                                        xevent.xmotion.y_root - g_move_y_offset);
1690                                            break;
1691                                    }
1692    
1693                                    if (g_fullscreen && !g_focused)
1694                                            XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1695                                                           CurrentTime);
1696                                  rdp_send_input(time(NULL), RDP_INPUT_MOUSE,                                  rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1697                                                 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);                                                 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);
1698                                  break;                                  break;
1699    
1700                          case FocusIn:                          case FocusIn:
1701                                  XQueryPointer(display, wnd, &wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state);                                  if (xevent.xfocus.mode == NotifyGrab)
1702                                  reset_modifier_keys(state);                                          break;
1703                                  if (grab_keyboard)                                  g_focused = True;
1704                                          XGrabKeyboard(display, wnd, True,                                  reset_modifier_keys();
1705                                    if (g_grab_keyboard && g_mouse_in_wnd)
1706                                            XGrabKeyboard(g_display, g_wnd, True,
1707                                                        GrabModeAsync, GrabModeAsync, CurrentTime);                                                        GrabModeAsync, GrabModeAsync, CurrentTime);
1708                                  break;                                  break;
1709    
1710                          case FocusOut:                          case FocusOut:
1711                                    if (xevent.xfocus.mode == NotifyUngrab)
1712                                            break;
1713                                    g_focused = False;
1714                                  if (xevent.xfocus.mode == NotifyWhileGrabbed)                                  if (xevent.xfocus.mode == NotifyWhileGrabbed)
1715                                          XUngrabKeyboard(display, CurrentTime);                                          XUngrabKeyboard(g_display, CurrentTime);
1716                                    break;
1717    
1718                            case EnterNotify:
1719                                    /* we only register for this event when in fullscreen mode */
1720                                    /* or grab_keyboard */
1721                                    g_mouse_in_wnd = True;
1722                                    if (g_fullscreen)
1723                                    {
1724                                            XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1725                                                           CurrentTime);
1726                                            break;
1727                                    }
1728                                    if (g_focused)
1729                                            XGrabKeyboard(g_display, g_wnd, True,
1730                                                          GrabModeAsync, GrabModeAsync, CurrentTime);
1731                                    break;
1732    
1733                            case LeaveNotify:
1734                                    /* we only register for this event when grab_keyboard */
1735                                    g_mouse_in_wnd = False;
1736                                    XUngrabKeyboard(g_display, CurrentTime);
1737                                  break;                                  break;
1738    
1739                          case Expose:                          case Expose:
1740                                  XCopyArea(display, backstore, wnd, gc,                                  XCopyArea(g_display, g_backstore, g_wnd, g_gc,
1741                                            xevent.xexpose.x, xevent.xexpose.y,                                            xevent.xexpose.x, xevent.xexpose.y,
1742                                            xevent.xexpose.width,                                            xevent.xexpose.width,
1743                                            xevent.xexpose.height,                                            xevent.xexpose.height,
# Line 548  xwin_process_events(void) Line 1753  xwin_process_events(void)
1753    
1754                                  if (xevent.xmapping.request == MappingModifier)                                  if (xevent.xmapping.request == MappingModifier)
1755                                  {                                  {
1756                                          XFreeModifiermap(mod_map);                                          XFreeModifiermap(g_mod_map);
1757                                          mod_map = XGetModifierMapping(display);                                          g_mod_map = XGetModifierMapping(g_display);
1758                                  }                                  }
1759                                  break;                                  break;
1760    
1761                                    /* clipboard stuff */
1762                            case SelectionNotify:
1763                                    xclip_handle_SelectionNotify(&xevent.xselection);
1764                                    break;
1765                            case SelectionRequest:
1766                                    xclip_handle_SelectionRequest(&xevent.xselectionrequest);
1767                                    break;
1768                            case SelectionClear:
1769                                    xclip_handle_SelectionClear();
1770                                    break;
1771                            case PropertyNotify:
1772                                    xclip_handle_PropertyNotify(&xevent.xproperty);
1773                                    break;
1774                            case MapNotify:
1775                                    rdp_send_client_window_status(1);
1776                                    break;
1777                            case UnmapNotify:
1778                                    rdp_send_client_window_status(0);
1779                                    break;
1780                  }                  }
1781          }          }
1782            /* Keep going */
1783            return 1;
1784  }  }
1785    
1786  void  /* Returns 0 after user quit, 1 otherwise */
1787    int
1788  ui_select(int rdp_socket)  ui_select(int rdp_socket)
1789  {  {
1790          int n = (rdp_socket > x_socket) ? rdp_socket + 1 : x_socket + 1;          int n;
1791          fd_set rfds;          fd_set rfds, wfds;
1792            struct timeval tv;
1793          FD_ZERO(&rfds);          BOOL s_timeout = False;
1794    
1795          while (True)          while (True)
1796          {          {
1797                    n = (rdp_socket > g_x_socket) ? rdp_socket : g_x_socket;
1798                  /* Process any events already waiting */                  /* Process any events already waiting */
1799                  xwin_process_events();                  if (!xwin_process_events())
1800                            /* User quit */
1801                            return 0;
1802    
1803                  FD_ZERO(&rfds);                  FD_ZERO(&rfds);
1804                    FD_ZERO(&wfds);
1805                  FD_SET(rdp_socket, &rfds);                  FD_SET(rdp_socket, &rfds);
1806                  FD_SET(x_socket, &rfds);                  FD_SET(g_x_socket, &rfds);
1807    
1808    #ifdef WITH_RDPSND
1809                    /* FIXME: there should be an API for registering fds */
1810                    if (g_dsp_busy)
1811                    {
1812                            FD_SET(g_dsp_fd, &wfds);
1813                            n = (g_dsp_fd > n) ? g_dsp_fd : n;
1814                    }
1815    #endif
1816                    /* default timeout */
1817                    tv.tv_sec = 60;
1818                    tv.tv_usec = 0;
1819    
1820                    /* add redirection handles */
1821                    rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
1822    
1823                    n++;
1824    
1825                  switch (select(n, &rfds, NULL, NULL, NULL))                  switch (select(n, &rfds, &wfds, NULL, &tv))
1826                  {                  {
1827                          case -1:                          case -1:
1828                                  error("select: %s\n", strerror(errno));                                  error("select: %s\n", strerror(errno));
1829    
1830                          case 0:                          case 0:
1831                                    /* Abort serial read calls */
1832                                    if (s_timeout)
1833                                            rdpdr_check_fds(&rfds, &wfds, (BOOL) True);
1834                                  continue;                                  continue;
1835                  }                  }
1836    
1837                    rdpdr_check_fds(&rfds, &wfds, (BOOL) False);
1838    
1839                  if (FD_ISSET(rdp_socket, &rfds))                  if (FD_ISSET(rdp_socket, &rfds))
1840                          return;                          return 1;
1841    
1842    #ifdef WITH_RDPSND
1843                    if (g_dsp_busy && FD_ISSET(g_dsp_fd, &wfds))
1844                            wave_out_play();
1845    #endif
1846          }          }
1847  }  }
1848    
1849  void  void
1850  ui_move_pointer(int x, int y)  ui_move_pointer(int x, int y)
1851  {  {
1852          XWarpPointer(display, wnd, wnd, 0, 0, 0, 0, x, y);          XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y);
1853  }  }
1854    
1855  HBITMAP  HBITMAP
# Line 600  ui_create_bitmap(int width, int height, Line 1858  ui_create_bitmap(int width, int height,
1858          XImage *image;          XImage *image;
1859          Pixmap bitmap;          Pixmap bitmap;
1860          uint8 *tdata;          uint8 *tdata;
1861            int bitmap_pad;
1862    
1863          tdata = translate_image(width, height, data);          if (g_server_depth == 8)
1864          bitmap = XCreatePixmap(display, wnd, width, height, depth);          {
1865          image = XCreateImage(display, visual, depth, ZPixmap, 0,                  bitmap_pad = 8;
1866                               (char *) tdata, width, height, 8, 0);          }
1867            else
1868            {
1869                    bitmap_pad = g_bpp;
1870    
1871          XPutImage(display, bitmap, gc, image, 0, 0, 0, 0, width, height);                  if (g_bpp == 24)
1872                            bitmap_pad = 32;
1873            }
1874    
1875            tdata = (g_owncolmap ? data : translate_image(width, height, data));
1876            bitmap = XCreatePixmap(g_display, g_wnd, width, height, g_depth);
1877            image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1878                                 (char *) tdata, width, height, bitmap_pad, 0);
1879    
1880            XPutImage(g_display, bitmap, g_create_bitmap_gc, image, 0, 0, 0, 0, width, height);
1881    
1882          XFree(image);          XFree(image);
1883          xfree(tdata);          if (tdata != data)
1884                    xfree(tdata);
1885          return (HBITMAP) bitmap;          return (HBITMAP) bitmap;
1886  }  }
1887    
# Line 618  ui_paint_bitmap(int x, int y, int cx, in Line 1890  ui_paint_bitmap(int x, int y, int cx, in
1890  {  {
1891          XImage *image;          XImage *image;
1892          uint8 *tdata;          uint8 *tdata;
1893            int bitmap_pad;
1894    
1895            if (g_server_depth == 8)
1896            {
1897                    bitmap_pad = 8;
1898            }
1899            else
1900            {
1901                    bitmap_pad = g_bpp;
1902    
1903          tdata = translate_image(width, height, data);                  if (g_bpp == 24)
1904          image = XCreateImage(display, visual, depth, ZPixmap, 0,                          bitmap_pad = 32;
1905                               (char *) tdata, width, height, 8, 0);          }
1906    
1907            tdata = (g_owncolmap ? data : translate_image(width, height, data));
1908            image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1909                                 (char *) tdata, width, height, bitmap_pad, 0);
1910    
1911          if (ownbackstore)          if (g_ownbackstore)
1912          {          {
1913                  XPutImage(display, backstore, gc, image, 0, 0, x, y, cx, cy);                  XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
1914                  XCopyArea(display, backstore, wnd, gc, x, y, cx, cy, x, y);                  XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
1915          }          }
1916          else          else
1917          {          {
1918                  XPutImage(display, wnd, gc, image, 0, 0, x, y, cx, cy);                  XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
1919          }          }
1920    
1921          XFree(image);          XFree(image);
1922          xfree(tdata);          if (tdata != data)
1923                    xfree(tdata);
1924  }  }
1925    
1926  void  void
1927  ui_destroy_bitmap(HBITMAP bmp)  ui_destroy_bitmap(HBITMAP bmp)
1928  {  {
1929          XFreePixmap(display, (Pixmap) bmp);          XFreePixmap(g_display, (Pixmap) bmp);
1930  }  }
1931    
1932  HGLYPH  HGLYPH
# Line 649  ui_create_glyph(int width, int height, u Line 1935  ui_create_glyph(int width, int height, u
1935          XImage *image;          XImage *image;
1936          Pixmap bitmap;          Pixmap bitmap;
1937          int scanline;          int scanline;
         GC gc;  
1938    
1939          scanline = (width + 7) / 8;          scanline = (width + 7) / 8;
1940    
1941          bitmap = XCreatePixmap(display, wnd, width, height, 1);          bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
1942          gc = XCreateGC(display, bitmap, 0, NULL);          if (g_create_glyph_gc == 0)
1943                    g_create_glyph_gc = XCreateGC(g_display, bitmap, 0, NULL);
1944    
1945          image = XCreateImage(display, visual, 1, ZPixmap, 0, (char *) data,          image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
1946                               width, height, 8, scanline);                               width, height, 8, scanline);
1947          image->byte_order = MSBFirst;          image->byte_order = MSBFirst;
1948          image->bitmap_bit_order = MSBFirst;          image->bitmap_bit_order = MSBFirst;
1949          XInitImage(image);          XInitImage(image);
1950    
1951          XPutImage(display, bitmap, gc, image, 0, 0, 0, 0, width, height);          XPutImage(g_display, bitmap, g_create_glyph_gc, image, 0, 0, 0, 0, width, height);
1952    
1953          XFree(image);          XFree(image);
         XFreeGC(display, gc);  
1954          return (HGLYPH) bitmap;          return (HGLYPH) bitmap;
1955  }  }
1956    
1957  void  void
1958  ui_destroy_glyph(HGLYPH glyph)  ui_destroy_glyph(HGLYPH glyph)
1959  {  {
1960          XFreePixmap(display, (Pixmap) glyph);          XFreePixmap(g_display, (Pixmap) glyph);
1961  }  }
1962    
1963  HCURSOR  HCURSOR
# Line 691  ui_create_cursor(unsigned int x, unsigne Line 1976  ui_create_cursor(unsigned int x, unsigne
1976          scanline = (width + 7) / 8;          scanline = (width + 7) / 8;
1977          offset = scanline * height;          offset = scanline * height;
1978    
1979          cursor = xmalloc(offset);          cursor = (uint8 *) xmalloc(offset);
1980          memset(cursor, 0, offset);          memset(cursor, 0, offset);
1981    
1982          mask = xmalloc(offset);          mask = (uint8 *) xmalloc(offset);
1983          memset(mask, 0, offset);          memset(mask, 0, offset);
1984    
1985          /* approximate AND and XOR masks with a monochrome X pointer */          /* approximate AND and XOR masks with a monochrome X pointer */
# Line 736  ui_create_cursor(unsigned int x, unsigne Line 2021  ui_create_cursor(unsigned int x, unsigne
2021          maskglyph = ui_create_glyph(width, height, mask);          maskglyph = ui_create_glyph(width, height, mask);
2022    
2023          xcursor =          xcursor =
2024                  XCreatePixmapCursor(display, (Pixmap) cursorglyph,                  XCreatePixmapCursor(g_display, (Pixmap) cursorglyph,
2025                                      (Pixmap) maskglyph, &fg, &bg, x, y);                                      (Pixmap) maskglyph, &fg, &bg, x, y);
2026    
2027          ui_destroy_glyph(maskglyph);          ui_destroy_glyph(maskglyph);
# Line 749  ui_create_cursor(unsigned int x, unsigne Line 2034  ui_create_cursor(unsigned int x, unsigne
2034  void  void
2035  ui_set_cursor(HCURSOR cursor)  ui_set_cursor(HCURSOR cursor)
2036  {  {
2037          current_cursor = (Cursor) cursor;          g_current_cursor = (Cursor) cursor;
2038          XDefineCursor(display, wnd, current_cursor);          XDefineCursor(g_display, g_wnd, g_current_cursor);
2039  }  }
2040    
2041  void  void
2042  ui_destroy_cursor(HCURSOR cursor)  ui_destroy_cursor(HCURSOR cursor)
2043  {  {
2044          XFreeCursor(display, (Cursor) cursor);          XFreeCursor(g_display, (Cursor) cursor);
2045    }
2046    
2047    void
2048    ui_set_null_cursor(void)
2049    {
2050            ui_set_cursor(g_null_cursor);
2051  }  }
2052    
2053  #define MAKE_XCOLOR(xc,c) \  #define MAKE_XCOLOR(xc,c) \
# Line 765  ui_destroy_cursor(HCURSOR cursor) Line 2056  ui_destroy_cursor(HCURSOR cursor)
2056                  (xc)->blue  = ((c)->blue  << 8) | (c)->blue; \                  (xc)->blue  = ((c)->blue  << 8) | (c)->blue; \
2057                  (xc)->flags = DoRed | DoGreen | DoBlue;                  (xc)->flags = DoRed | DoGreen | DoBlue;
2058    
2059    
2060  HCOLOURMAP  HCOLOURMAP
2061  ui_create_colourmap(COLOURMAP * colours)  ui_create_colourmap(COLOURMAP * colours)
2062  {  {
2063          COLOURENTRY *entry;          COLOURENTRY *entry;
2064          int i, ncolours = colours->ncolours;          int i, ncolours = colours->ncolours;
2065          uint32 *map = xmalloc(sizeof(*colmap) * ncolours);          if (!g_owncolmap)
2066          XColor xentry;          {
2067          XColor xc_cache[256];                  uint32 *map = (uint32 *) xmalloc(sizeof(*g_colmap) * ncolours);
2068          uint32 colour;                  XColor xentry;
2069          int colLookup = 256;                  XColor xc_cache[256];
2070          for (i = 0; i < ncolours; i++)                  uint32 colour;
2071          {                  int colLookup = 256;
2072                  entry = &colours->colours[i];                  for (i = 0; i < ncolours; i++)
2073                  MAKE_XCOLOR(&xentry, entry);                  {
2074                            entry = &colours->colours[i];
2075                  if (XAllocColor(display, xcolmap, &xentry) == 0)                          MAKE_XCOLOR(&xentry, entry);
                 {  
                         /* Allocation failed, find closest match. */  
                         int j = 256;  
                         int nMinDist = 3 * 256 * 256;  
                         long nDist = nMinDist;  
   
                         /* only get the colors once */  
                         while (colLookup--)  
                         {  
                                 xc_cache[colLookup].pixel = colLookup;  
                                 xc_cache[colLookup].red = xc_cache[colLookup].green =  
                                         xc_cache[colLookup].blue = 0;  
                                 xc_cache[colLookup].flags = 0;  
                                 XQueryColor(display,  
                                             DefaultColormap(display, DefaultScreen(display)),  
                                             &xc_cache[colLookup]);  
                         }  
                         colLookup = 0;  
2076    
2077                          /* approximate the pixel */                          if (XAllocColor(g_display, g_xcolmap, &xentry) == 0)
                         while (j--)  
2078                          {                          {
2079                                  if (xc_cache[j].flags)                                  /* Allocation failed, find closest match. */
2080                                    int j = 256;
2081                                    int nMinDist = 3 * 256 * 256;
2082                                    long nDist = nMinDist;
2083    
2084                                    /* only get the colors once */
2085                                    while (colLookup--)
2086                                  {                                  {
2087                                          nDist = ((long) (xc_cache[j].red >> 8) -                                          xc_cache[colLookup].pixel = colLookup;
2088                                                   (long) (xentry.red >> 8)) *                                          xc_cache[colLookup].red = xc_cache[colLookup].green =
2089                                                  ((long) (xc_cache[j].red >> 8) -                                                  xc_cache[colLookup].blue = 0;
2090                                                   (long) (xentry.red >> 8)) +                                          xc_cache[colLookup].flags = 0;
2091                                                  ((long) (xc_cache[j].green >> 8) -                                          XQueryColor(g_display,
2092                                                   (long) (xentry.green >> 8)) *                                                      DefaultColormap(g_display,
2093                                                  ((long) (xc_cache[j].green >> 8) -                                                                      DefaultScreen(g_display)),
2094                                                   (long) (xentry.green >> 8)) +                                                      &xc_cache[colLookup]);
                                                 ((long) (xc_cache[j].blue >> 8) -  
                                                  (long) (xentry.blue >> 8)) *  
                                                 ((long) (xc_cache[j].blue >> 8) -  
                                                  (long) (xentry.blue >> 8));  
2095                                  }                                  }
2096                                  if (nDist < nMinDist)                                  colLookup = 0;
2097    
2098                                    /* approximate the pixel */
2099                                    while (j--)
2100                                  {                                  {
2101                                          nMinDist = nDist;                                          if (xc_cache[j].flags)
2102                                          xentry.pixel = j;                                          {
2103                                                    nDist = ((long) (xc_cache[j].red >> 8) -
2104                                                             (long) (xentry.red >> 8)) *
2105                                                            ((long) (xc_cache[j].red >> 8) -
2106                                                             (long) (xentry.red >> 8)) +
2107                                                            ((long) (xc_cache[j].green >> 8) -
2108                                                             (long) (xentry.green >> 8)) *
2109                                                            ((long) (xc_cache[j].green >> 8) -
2110                                                             (long) (xentry.green >> 8)) +
2111                                                            ((long) (xc_cache[j].blue >> 8) -
2112                                                             (long) (xentry.blue >> 8)) *
2113                                                            ((long) (xc_cache[j].blue >> 8) -
2114                                                             (long) (xentry.blue >> 8));
2115                                            }
2116                                            if (nDist < nMinDist)
2117                                            {
2118                                                    nMinDist = nDist;
2119                                                    xentry.pixel = j;
2120                                            }
2121                                  }                                  }
2122                          }                          }
2123                            colour = xentry.pixel;
2124    
2125                            /* update our cache */
2126                            if (xentry.pixel < 256)
2127                            {
2128                                    xc_cache[xentry.pixel].red = xentry.red;
2129                                    xc_cache[xentry.pixel].green = xentry.green;
2130                                    xc_cache[xentry.pixel].blue = xentry.blue;
2131    
2132                            }
2133    
2134                            map[i] = colour;
2135                  }                  }
2136                  colour = xentry.pixel;                  return map;
2137            }
2138            else
2139            {
2140                    XColor *xcolours, *xentry;
2141                    Colormap map;
2142    
2143                  /* update our cache */                  xcolours = (XColor *) xmalloc(sizeof(XColor) * ncolours);
2144                  if (xentry.pixel < 256)                  for (i = 0; i < ncolours; i++)
2145                  {                  {
2146                          xc_cache[xentry.pixel].red = xentry.red;                          entry = &colours->colours[i];
2147                          xc_cache[xentry.pixel].green = xentry.green;                          xentry = &xcolours[i];
2148                          xc_cache[xentry.pixel].blue = xentry.blue;                          xentry->pixel = i;
2149                            MAKE_XCOLOR(xentry, entry);
2150                  }                  }
2151    
2152                    map = XCreateColormap(g_display, g_wnd, g_visual, AllocAll);
2153                    XStoreColors(g_display, map, xcolours, ncolours);
2154    
2155                  /* byte swap here to make translate_image faster */                  xfree(xcolours);
2156                  map[i] = translate_colour(colour);                  return (HCOLOURMAP) map;
2157          }          }
   
         return map;  
2158  }  }
2159    
2160  void  void
2161  ui_destroy_colourmap(HCOLOURMAP map)  ui_destroy_colourmap(HCOLOURMAP map)
2162  {  {
2163          xfree(map);          if (!g_owncolmap)
2164                    xfree(map);
2165            else
2166                    XFreeColormap(g_display, (Colormap) map);
2167  }  }
2168    
2169  void  void
2170  ui_set_colourmap(HCOLOURMAP map)  ui_set_colourmap(HCOLOURMAP map)
2171  {  {
2172          colmap = map;          if (!g_owncolmap)
2173            {
2174                    if (g_colmap)
2175                            xfree(g_colmap);
2176    
2177                    g_colmap = (uint32 *) map;
2178            }
2179            else
2180                    XSetWindowColormap(g_display, g_wnd, (Colormap) map);
2181  }  }
2182    
2183  void  void
# Line 865  ui_set_clip(int x, int y, int cx, int cy Line 2189  ui_set_clip(int x, int y, int cx, int cy
2189          rect.y = y;          rect.y = y;
2190          rect.width = cx;          rect.width = cx;
2191          rect.height = cy;          rect.height = cy;
2192          XSetClipRectangles(display, gc, 0, 0, &rect, 1, YXBanded);          XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);
2193  }  }
2194    
2195  void  void
# Line 875  ui_reset_clip(void) Line 2199  ui_reset_clip(void)
2199    
2200          rect.x = 0;          rect.x = 0;
2201          rect.y = 0;          rect.y = 0;
2202          rect.width = width;          rect.width = g_width;
2203          rect.height = height;          rect.height = g_height;
2204          XSetClipRectangles(display, gc, 0, 0, &rect, 1, YXBanded);          XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);
2205  }  }
2206    
2207  void  void
2208  ui_bell(void)  ui_bell(void)
2209  {  {
2210          XBell(display, 0);          XBell(g_display, 0);
2211  }  }
2212    
2213  void  void
# Line 895  ui_destblt(uint8 opcode, Line 2219  ui_destblt(uint8 opcode,
2219          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2220  }  }
2221    
2222    static uint8 hatch_patterns[] = {
2223            0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, /* 0 - bsHorizontal */
2224            0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 1 - bsVertical */
2225            0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, /* 2 - bsFDiagonal */
2226            0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, /* 3 - bsBDiagonal */
2227            0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, /* 4 - bsCross */
2228            0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81  /* 5 - bsDiagCross */
2229    };
2230    
2231  void  void
2232  ui_patblt(uint8 opcode,  ui_patblt(uint8 opcode,
2233            /* dest */ int x, int y, int cx, int cy,            /* dest */ int x, int y, int cx, int cy,
# Line 909  ui_patblt(uint8 opcode, Line 2242  ui_patblt(uint8 opcode,
2242          {          {
2243                  case 0: /* Solid */                  case 0: /* Solid */
2244                          SET_FOREGROUND(fgcolour);                          SET_FOREGROUND(fgcolour);
2245                          FILL_RECTANGLE(x, y, cx, cy);                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2246                            break;
2247    
2248                    case 2: /* Hatch */
2249                            fill = (Pixmap) ui_create_glyph(8, 8,
2250                                                            hatch_patterns + brush->pattern[0] * 8);
2251                            SET_FOREGROUND(fgcolour);
2252                            SET_BACKGROUND(bgcolour);
2253                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2254                            XSetStipple(g_display, g_gc, fill);
2255                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2256                            FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2257                            XSetFillStyle(g_display, g_gc, FillSolid);
2258                            XSetTSOrigin(g_display, g_gc, 0, 0);
2259                            ui_destroy_glyph((HGLYPH) fill);
2260                          break;                          break;
2261    
2262                  case 3: /* Pattern */                  case 3: /* Pattern */
2263                          for (i = 0; i != 8; i++)                          for (i = 0; i != 8; i++)
2264                                  ipattern[7 - i] = brush->pattern[i];                                  ipattern[7 - i] = brush->pattern[i];
2265                          fill = (Pixmap) ui_create_glyph(8, 8, ipattern);                          fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
   
2266                          SET_FOREGROUND(bgcolour);                          SET_FOREGROUND(bgcolour);
2267                          SET_BACKGROUND(fgcolour);                          SET_BACKGROUND(fgcolour);
2268                          XSetFillStyle(display, gc, FillOpaqueStippled);                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2269                          XSetStipple(display, gc, fill);                          XSetStipple(g_display, g_gc, fill);
2270                          XSetTSOrigin(display, gc, brush->xorigin, brush->yorigin);                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2271                            FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2272                          FILL_RECTANGLE(x, y, cx, cy);                          XSetFillStyle(g_display, g_gc, FillSolid);
2273                            XSetTSOrigin(g_display, g_gc, 0, 0);
                         XSetFillStyle(display, gc, FillSolid);  
                         XSetTSOrigin(display, gc, 0, 0);  
2274                          ui_destroy_glyph((HGLYPH) fill);                          ui_destroy_glyph((HGLYPH) fill);
2275                          break;                          break;
2276    
# Line 935  ui_patblt(uint8 opcode, Line 2279  ui_patblt(uint8 opcode,
2279          }          }
2280    
2281          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2282    
2283            if (g_ownbackstore)
2284                    XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2285  }  }
2286    
2287  void  void
# Line 943  ui_screenblt(uint8 opcode, Line 2290  ui_screenblt(uint8 opcode,
2290               /* src */ int srcx, int srcy)               /* src */ int srcx, int srcy)
2291  {  {
2292          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2293          XCopyArea(display, wnd, wnd, gc, srcx, srcy, cx, cy, x, y);          if (g_ownbackstore)
2294          if (ownbackstore)          {
2295                  XCopyArea(display, backstore, backstore, gc, srcx, srcy, cx, cy, x, y);                  if (g_Unobscured)
2296                    {
2297                            XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2298                            XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x,
2299                                      y);
2300                    }
2301                    else
2302                    {
2303                            XCopyArea(g_display, g_backstore, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2304                            XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x,
2305                                      y);
2306                    }
2307            }
2308            else
2309            {
2310                    XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2311            }
2312          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2313  }  }
2314    
# Line 955  ui_memblt(uint8 opcode, Line 2318  ui_memblt(uint8 opcode,
2318            /* src */ HBITMAP src, int srcx, int srcy)            /* src */ HBITMAP src, int srcx, int srcy)
2319  {  {
2320          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2321          XCopyArea(display, (Pixmap) src, wnd, gc, srcx, srcy, cx, cy, x, y);          XCopyArea(g_display, (Pixmap) src, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2322          if (ownbackstore)          if (g_ownbackstore)
2323                  XCopyArea(display, (Pixmap) src, backstore, gc, srcx, srcy, cx, cy, x, y);                  XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
2324          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2325  }  }
2326    
# Line 1001  ui_line(uint8 opcode, Line 2364  ui_line(uint8 opcode,
2364  {  {
2365          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2366          SET_FOREGROUND(pen->colour);          SET_FOREGROUND(pen->colour);
2367          XDrawLine(display, wnd, gc, startx, starty, endx, endy);          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
2368          if (ownbackstore)          if (g_ownbackstore)
2369                  XDrawLine(display, backstore, gc, startx, starty, endx, endy);                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
2370          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2371  }  }
2372    
# Line 1017  ui_rect( Line 2380  ui_rect(
2380  }  }
2381    
2382  void  void
2383    ui_polygon(uint8 opcode,
2384               /* mode */ uint8 fillmode,
2385               /* dest */ POINT * point, int npoints,
2386               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2387    {
2388            uint8 style, i, ipattern[8];
2389            Pixmap fill;
2390    
2391            SET_FUNCTION(opcode);
2392    
2393            switch (fillmode)
2394            {
2395                    case ALTERNATE:
2396                            XSetFillRule(g_display, g_gc, EvenOddRule);
2397                            break;
2398                    case WINDING:
2399                            XSetFillRule(g_display, g_gc, WindingRule);
2400                            break;
2401                    default:
2402                            unimpl("fill mode %d\n", fillmode);
2403            }
2404    
2405            if (brush)
2406                    style = brush->style;
2407            else
2408                    style = 0;
2409    
2410            switch (style)
2411            {
2412                    case 0: /* Solid */
2413                            SET_FOREGROUND(fgcolour);
2414                            FILL_POLYGON((XPoint *) point, npoints);
2415                            break;
2416    
2417                    case 2: /* Hatch */
2418                            fill = (Pixmap) ui_create_glyph(8, 8,
2419                                                            hatch_patterns + brush->pattern[0] * 8);
2420                            SET_FOREGROUND(fgcolour);
2421                            SET_BACKGROUND(bgcolour);
2422                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2423                            XSetStipple(g_display, g_gc, fill);
2424                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2425                            FILL_POLYGON((XPoint *) point, npoints);
2426                            XSetFillStyle(g_display, g_gc, FillSolid);
2427                            XSetTSOrigin(g_display, g_gc, 0, 0);
2428                            ui_destroy_glyph((HGLYPH) fill);
2429                            break;
2430    
2431                    case 3: /* Pattern */
2432                            for (i = 0; i != 8; i++)
2433                                    ipattern[7 - i] = brush->pattern[i];
2434                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2435                            SET_FOREGROUND(bgcolour);
2436                            SET_BACKGROUND(fgcolour);
2437                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2438                            XSetStipple(g_display, g_gc, fill);
2439                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2440                            FILL_POLYGON((XPoint *) point, npoints);
2441                            XSetFillStyle(g_display, g_gc, FillSolid);
2442                            XSetTSOrigin(g_display, g_gc, 0, 0);
2443                            ui_destroy_glyph((HGLYPH) fill);
2444                            break;
2445    
2446                    default:
2447                            unimpl("brush %d\n", brush->style);
2448            }
2449    
2450            RESET_FUNCTION(opcode);
2451    }
2452    
2453    void
2454    ui_polyline(uint8 opcode,
2455                /* dest */ POINT * points, int npoints,
2456                /* pen */ PEN * pen)
2457    {
2458            /* TODO: set join style */
2459            SET_FUNCTION(opcode);
2460            SET_FOREGROUND(pen->colour);
2461            XDrawLines(g_display, g_wnd, g_gc, (XPoint *) points, npoints, CoordModePrevious);
2462            if (g_ownbackstore)
2463                    XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
2464                               CoordModePrevious);
2465            RESET_FUNCTION(opcode);
2466    }
2467    
2468    void
2469    ui_ellipse(uint8 opcode,
2470               /* mode */ uint8 fillmode,
2471               /* dest */ int x, int y, int cx, int cy,
2472               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2473    {
2474            uint8 style, i, ipattern[8];
2475            Pixmap fill;
2476    
2477            SET_FUNCTION(opcode);
2478    
2479            if (brush)
2480                    style = brush->style;
2481            else
2482                    style = 0;
2483    
2484            switch (style)
2485            {
2486                    case 0: /* Solid */
2487                            SET_FOREGROUND(fgcolour);
2488                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2489                            break;
2490    
2491                    case 2: /* Hatch */
2492                            fill = (Pixmap) ui_create_glyph(8, 8,
2493                                                            hatch_patterns + brush->pattern[0] * 8);
2494                            SET_FOREGROUND(fgcolour);
2495                            SET_BACKGROUND(bgcolour);
2496                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2497                            XSetStipple(g_display, g_gc, fill);
2498                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2499                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2500                            XSetFillStyle(g_display, g_gc, FillSolid);
2501                            XSetTSOrigin(g_display, g_gc, 0, 0);
2502                            ui_destroy_glyph((HGLYPH) fill);
2503                            break;
2504    
2505                    case 3: /* Pattern */
2506                            for (i = 0; i != 8; i++)
2507                                    ipattern[7 - i] = brush->pattern[i];
2508                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2509                            SET_FOREGROUND(bgcolour);
2510                            SET_BACKGROUND(fgcolour);
2511                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2512                            XSetStipple(g_display, g_gc, fill);
2513                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2514                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2515                            XSetFillStyle(g_display, g_gc, FillSolid);
2516                            XSetTSOrigin(g_display, g_gc, 0, 0);
2517                            ui_destroy_glyph((HGLYPH) fill);
2518                            break;
2519    
2520                    default:
2521                            unimpl("brush %d\n", brush->style);
2522            }
2523    
2524            RESET_FUNCTION(opcode);
2525    }
2526    
2527    /* warning, this function only draws on wnd or backstore, not both */
2528    void
2529  ui_draw_glyph(int mixmode,  ui_draw_glyph(int mixmode,
2530                /* dest */ int x, int y, int cx, int cy,                /* dest */ int x, int y, int cx, int cy,
2531                /* src */ HGLYPH glyph, int srcx, int srcy,                /* src */ HGLYPH glyph, int srcx, int srcy,
# Line 1025  ui_draw_glyph(int mixmode, Line 2534  ui_draw_glyph(int mixmode,
2534          SET_FOREGROUND(fgcolour);          SET_FOREGROUND(fgcolour);
2535          SET_BACKGROUND(bgcolour);          SET_BACKGROUND(bgcolour);
2536    
2537          XSetFillStyle(display, gc,          XSetFillStyle(g_display, g_gc,
2538                        (mixmode == MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled);                        (mixmode == MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled);
2539          XSetStipple(display, gc, (Pixmap) glyph);          XSetStipple(g_display, g_gc, (Pixmap) glyph);
2540          XSetTSOrigin(display, gc, x, y);          XSetTSOrigin(g_display, g_gc, x, y);
2541    
2542          FILL_RECTANGLE(x, y, cx, cy);          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2543    
2544          XSetFillStyle(display, gc, FillSolid);          XSetFillStyle(g_display, g_gc, FillSolid);
2545  }  }
2546    
2547  #define DO_GLYPH(ttext,idx) \  #define DO_GLYPH(ttext,idx) \
2548  {\  {\
2549    glyph = cache_get_font (font, ttext[idx]);\    glyph = cache_get_font (font, ttext[idx]);\
2550    if (!(flags & TEXT2_IMPLICIT_X))\    if (!(flags & TEXT2_IMPLICIT_X))\
2551      {\
2552        xyoffset = ttext[++idx];\
2553        if ((xyoffset & 0x80))\
2554      {\      {\
2555        xyoffset = ttext[++idx];\        if (flags & TEXT2_VERTICAL)\
2556        if ((xyoffset & 0x80))\          y += ttext[idx+1] | (ttext[idx+2] << 8);\
         {\  
           if (flags & TEXT2_VERTICAL) \  
             y += ttext[idx+1] | (ttext[idx+2] << 8);\  
           else\  
             x += ttext[idx+1] | (ttext[idx+2] << 8);\  
           idx += 2;\  
         }\  
2557        else\        else\
2558          {\          x += ttext[idx+1] | (ttext[idx+2] << 8);\
2559            if (flags & TEXT2_VERTICAL) \        idx += 2;\
             y += xyoffset;\  
           else\  
             x += xyoffset;\  
         }\  
2560      }\      }\
2561    if (glyph != NULL)\      else\
2562      {\      {\
2563        ui_draw_glyph (mixmode, x + (short) glyph->offset,\        if (flags & TEXT2_VERTICAL)\
2564                       y + (short) glyph->baseline,\          y += xyoffset;\
2565                       glyph->width, glyph->height,\        else\
2566                       glyph->pixmap, 0, 0, bgcolour, fgcolour);\          x += xyoffset;\
       if (flags & TEXT2_IMPLICIT_X)\  
         x += glyph->width;\  
2567      }\      }\
2568      }\
2569      if (glyph != NULL)\
2570      {\
2571        x1 = x + glyph->offset;\
2572        y1 = y + glyph->baseline;\
2573        XSetStipple(g_display, g_gc, (Pixmap) glyph->pixmap);\
2574        XSetTSOrigin(g_display, g_gc, x1, y1);\
2575        FILL_RECTANGLE_BACKSTORE(x1, y1, glyph->width, glyph->height);\
2576        if (flags & TEXT2_IMPLICIT_X)\
2577          x += glyph->width;\
2578      }\
2579  }  }
2580    
2581  void  void
2582  ui_draw_text(uint8 font, uint8 flags, int mixmode, int x, int y,  ui_draw_text(uint8 font, uint8 flags, uint8 opcode, int mixmode, int x, int y,
2583               int clipx, int clipy, int clipcx, int clipcy,               int clipx, int clipy, int clipcx, int clipcy,
2584               int boxx, int boxy, int boxcx, int boxcy, int bgcolour,               int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush,
2585               int fgcolour, uint8 * text, uint8 length)               int bgcolour, int fgcolour, uint8 * text, uint8 length)
2586  {  {
2587            /* TODO: use brush appropriately */
2588    
2589          FONTGLYPH *glyph;          FONTGLYPH *glyph;
2590          int i, j, xyoffset;          int i, j, xyoffset, x1, y1;
2591          DATABLOB *entry;          DATABLOB *entry;
2592    
2593          SET_FOREGROUND(bgcolour);          SET_FOREGROUND(bgcolour);
2594    
2595            /* Sometimes, the boxcx value is something really large, like
2596               32691. This makes XCopyArea fail with Xvnc. The code below
2597               is a quick fix. */
2598            if (boxx + boxcx > g_width)
2599                    boxcx = g_width - boxx;
2600    
2601          if (boxcx > 1)          if (boxcx > 1)
2602          {          {
2603                  FILL_RECTANGLE(boxx, boxy, boxcx, boxcy);                  FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);
2604          }          }
2605          else if (mixmode == MIX_OPAQUE)          else if (mixmode == MIX_OPAQUE)
2606          {          {
2607                  FILL_RECTANGLE(clipx, clipy, clipcx, clipcy);                  FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);
2608          }          }
2609    
2610            SET_FOREGROUND(fgcolour);
2611            SET_BACKGROUND(bgcolour);
2612            XSetFillStyle(g_display, g_gc, FillStippled);
2613    
2614          /* Paint text, character by character */          /* Paint text, character by character */
2615          for (i = 0; i < length;)          for (i = 0; i < length;)
2616          {          {
2617                  switch (text[i])                  switch (text[i])
2618                  {                  {
2619                          case 0xff:                          case 0xff:
2620                                  if (i + 2 < length)                                  /* At least two bytes needs to follow */
2621                                          cache_put_text(text[i + 1], text, text[i + 2]);                                  if (i + 3 > length)
                                 else  
2622                                  {                                  {
2623                                          error("this shouldn't be happening\n");                                          warning("Skipping short 0xff command:");
2624                                            for (j = 0; j < length; j++)
2625                                                    fprintf(stderr, "%02x ", text[j]);
2626                                            fprintf(stderr, "\n");
2627                                            i = length = 0;
2628                                          break;                                          break;
2629                                  }                                  }
2630                                    cache_put_text(text[i + 1], text, text[i + 2]);
2631                                    i += 3;
2632                                    length -= i;
2633                                  /* this will move pointer from start to first character after FF command */                                  /* this will move pointer from start to first character after FF command */
2634                                  length -= i + 3;                                  text = &(text[i]);
                                 text = &(text[i + 3]);  
2635                                  i = 0;                                  i = 0;
2636                                  break;                                  break;
2637    
2638                          case 0xfe:                          case 0xfe:
2639                                    /* At least one byte needs to follow */
2640                                    if (i + 2 > length)
2641                                    {
2642                                            warning("Skipping short 0xfe command:");
2643                                            for (j = 0; j < length; j++)
2644                                                    fprintf(stderr, "%02x ", text[j]);
2645                                            fprintf(stderr, "\n");
2646                                            i = length = 0;
2647                                            break;
2648                                    }
2649                                  entry = cache_get_text(text[i + 1]);                                  entry = cache_get_text(text[i + 1]);
2650                                  if (entry != NULL)                                  if (entry->data != NULL)
2651                                  {                                  {
2652                                          if ((((uint8 *) (entry->data))[1] ==                                          if ((((uint8 *) (entry->data))[1] == 0)
2653                                               0) && (!(flags & TEXT2_IMPLICIT_X)))                                              && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
2654                                          {                                          {
2655                                                  if (flags & TEXT2_VERTICAL)                                                  if (flags & TEXT2_VERTICAL)
2656                                                          y += text[i + 2];                                                          y += text[i + 2];
2657                                                  else                                                  else
2658                                                          x += text[i + 2];                                                          x += text[i + 2];
2659                                          }                                          }
                                         if (i + 2 < length)  
                                                 i += 3;  
                                         else  
                                                 i += 2;  
                                         length -= i;  
                                         /* this will move pointer from start to first character after FE command */  
                                         text = &(text[i]);  
                                         i = 0;  
2660                                          for (j = 0; j < entry->size; j++)                                          for (j = 0; j < entry->size; j++)
2661                                                  DO_GLYPH(((uint8 *) (entry->data)), j);                                                  DO_GLYPH(((uint8 *) (entry->data)), j);
2662                                  }                                  }
2663                                    if (i + 2 < length)
2664                                            i += 3;
2665                                    else
2666                                            i += 2;
2667                                    length -= i;
2668                                    /* this will move pointer from start to first character after FE command */
2669                                    text = &(text[i]);
2670                                    i = 0;
2671                                  break;                                  break;
2672    
2673                          default:                          default:
# Line 1140  ui_draw_text(uint8 font, uint8 flags, in Line 2677  ui_draw_text(uint8 font, uint8 flags, in
2677                  }                  }
2678          }          }
2679    
2680            XSetFillStyle(g_display, g_gc, FillSolid);
2681    
2682            if (g_ownbackstore)
2683            {
2684                    if (boxcx > 1)
2685                            XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
2686                                      boxy, boxcx, boxcy, boxx, boxy);
2687                    else
2688                            XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
2689                                      clipy, clipcx, clipcy, clipx, clipy);
2690            }
2691  }  }
2692    
2693  void  void
# Line 1149  ui_desktop_save(uint32 offset, int x, in Line 2696  ui_desktop_save(uint32 offset, int x, in
2696          Pixmap pix;          Pixmap pix;
2697          XImage *image;          XImage *image;
2698    
2699          if (ownbackstore)          if (g_ownbackstore)
2700          {          {
2701                  image = XGetImage(display, backstore, x, y, cx, cy, AllPlanes, ZPixmap);                  image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
2702          }          }
2703          else          else
2704          {          {
2705                  pix = XCreatePixmap(display, wnd, cx, cy, depth);                  pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);
2706                  XCopyArea(display, wnd, pix, gc, x, y, cx, cy, 0, 0);                  XCopyArea(g_display, g_wnd, pix, g_gc, x, y, cx, cy, 0, 0);
2707                  image = XGetImage(display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);                  image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
2708                  XFreePixmap(display, pix);                  XFreePixmap(g_display, pix);
2709          }          }
2710    
2711          offset *= bpp / 8;          offset *= g_bpp / 8;
2712          cache_put_desktop(offset, cx, cy, image->bytes_per_line, bpp / 8, (uint8 *) image->data);          cache_put_desktop(offset, cx, cy, image->bytes_per_line, g_bpp / 8, (uint8 *) image->data);
2713    
2714          XDestroyImage(image);          XDestroyImage(image);
2715  }  }
# Line 1173  ui_desktop_restore(uint32 offset, int x, Line 2720  ui_desktop_restore(uint32 offset, int x,
2720          XImage *image;          XImage *image;
2721          uint8 *data;          uint8 *data;
2722    
2723          offset *= bpp / 8;          offset *= g_bpp / 8;
2724          data = cache_get_desktop(offset, cx, cy, bpp / 8);          data = cache_get_desktop(offset, cx, cy, g_bpp / 8);
2725          if (data == NULL)          if (data == NULL)
2726                  return;                  return;
2727    
2728          image = XCreateImage(display, visual, depth, ZPixmap, 0,          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2729                               (char *) data, cx, cy, BitmapPad(display), cx * bpp / 8);                               (char *) data, cx, cy, BitmapPad(g_display), cx * g_bpp / 8);
2730    
2731          if (ownbackstore)          if (g_ownbackstore)
2732          {          {
2733                  XPutImage(display, backstore, gc, image, 0, 0, x, y, cx, cy);                  XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
2734                  XCopyArea(display, backstore, wnd, gc, x, y, cx, cy, x, y);                  XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2735          }          }
2736          else          else
2737          {          {
2738                  XPutImage(display, wnd, gc, image, 0, 0, x, y, cx, cy);                  XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
2739          }          }
2740    
2741          XFree(image);          XFree(image);
2742  }  }
2743    
2744    /* these do nothing here but are used in uiports */
2745    void
2746    ui_begin_update(void)
2747    {
2748    }
2749    
2750    void
2751    ui_end_update(void)
2752    {
2753    }

Legend:
Removed from v.208  
changed lines
  Added in v.1057

  ViewVC Help
Powered by ViewVC 1.1.26