/[rdesktop]/sourceforge.net/branches/seamlessrdp-branch/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/branches/seamlessrdp-branch/rdesktop/xwin.c

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

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

Legend:
Removed from v.9  
changed lines
  Added in v.949

  ViewVC Help
Powered by ViewVC 1.1.26