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

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

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

revision 34 by matty, Sat Sep 15 13:03:35 2001 UTC revision 708 by jsorg71, Fri Jun 4 15:01:36 2004 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-2001     Copyright (C) Matthew Chapman 1999-2002
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.
# Line 20  Line 20 
20    
21  #include <X11/Xlib.h>  #include <X11/Xlib.h>
22  #include <X11/Xutil.h>  #include <X11/Xutil.h>
23    #include <unistd.h>
24    #include <sys/time.h>
25  #include <time.h>  #include <time.h>
26  #include <errno.h>  #include <errno.h>
27    #include <strings.h>
28  #include "rdesktop.h"  #include "rdesktop.h"
29    #include "xproto.h"
30    
31  extern int width;  extern int g_width;
32  extern int height;  extern int g_height;
33  extern BOOL sendmotion;  extern BOOL g_sendmotion;
34  extern BOOL fullscreen;  extern BOOL g_fullscreen;
35    extern BOOL g_grab_keyboard;
36  static Display *display;  extern BOOL g_hide_decorations;
37  static int x_socket;  extern char g_title[];
38  static Window wnd;  extern int g_server_bpp;
39  static GC gc;  extern int g_win_button_size;
40  static Visual *visual;  
41  static int depth;  Display *g_display;
42  static int bpp;  Time g_last_gesturetime;
43    static int g_x_socket;
44    static Screen *g_screen;
45    Window g_wnd;
46    extern uint32 g_embed_wnd;
47    BOOL g_enable_compose = False;
48    BOOL g_Unobscured;              /* used for screenblt */
49    static GC g_gc = NULL;
50    static Visual *g_visual;
51    static int g_depth;
52    static int g_bpp;
53    static XIM g_IM;
54    static XIC g_IC;
55    static XModifierKeymap *g_mod_map;
56    static Cursor g_current_cursor;
57    static HCURSOR g_null_cursor = NULL;
58    static Atom g_protocol_atom, g_kill_atom;
59    static BOOL g_focused;
60    static BOOL g_mouse_in_wnd;
61    static BOOL g_arch_match = False;       /* set to True if RGB XServer and little endian */
62    
63  /* endianness */  /* endianness */
64  static BOOL host_be;  static BOOL g_host_be;
65  static BOOL xserver_be;  static BOOL g_xserver_be;
66    static int g_red_shift_r, g_blue_shift_r, g_green_shift_r;
67    static int g_red_shift_l, g_blue_shift_l, g_green_shift_l;
68    
69  /* software backing store */  /* software backing store */
70  static BOOL ownbackstore;  extern BOOL g_ownbackstore;
71  static Pixmap backstore;  static Pixmap g_backstore = 0;
72    
73    /* Moving in single app mode */
74    static BOOL g_moving_wnd;
75    static int g_move_x_offset = 0;
76    static int g_move_y_offset = 0;
77    
78    #ifdef WITH_RDPSND
79    extern int g_dsp_fd;
80    extern BOOL g_dsp_busy;
81    extern BOOL g_rdpsnd;
82    #endif
83    
84    /* MWM decorations */
85    #define MWM_HINTS_DECORATIONS   (1L << 1)
86    #define PROP_MOTIF_WM_HINTS_ELEMENTS    5
87    typedef struct
88    {
89            uint32 flags;
90            uint32 functions;
91            uint32 decorations;
92            sint32 inputMode;
93            uint32 status;
94    }
95    PropMotifWmHints;
96    
97    typedef struct
98    {
99            uint32 red;
100            uint32 green;
101            uint32 blue;
102    }
103    PixelColour;
104    
105    
106  #define FILL_RECTANGLE(x,y,cx,cy)\  #define FILL_RECTANGLE(x,y,cx,cy)\
107  { \  { \
108          XFillRectangle(display, wnd, gc, x, y, cx, cy); \          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \
109          if (ownbackstore) \          if (g_ownbackstore) \
110                  XFillRectangle(display, backstore, gc, x, y, cx, cy); \                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \
111    }
112    
113    #define FILL_RECTANGLE_BACKSTORE(x,y,cx,cy)\
114    { \
115            XFillRectangle(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, cx, cy); \
116  }  }
117    
118  /* colour maps */  /* colour maps */
119  static BOOL owncolmap;  extern BOOL g_owncolmap;
120  static Colormap xcolmap;  static Colormap g_xcolmap;
121  static uint32 white;  static uint32 *g_colmap = NULL;
122  static uint32 *colmap;  
123    #define TRANSLATE(col)          ( g_server_bpp != 8 ? translate_colour(col) : g_owncolmap ? col : g_colmap[col] )
124  #define TRANSLATE(col)          ( owncolmap ? col : translate_colour(colmap[col]) )  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));
125  #define SET_FOREGROUND(col)     XSetForeground(display, gc, TRANSLATE(col));  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));
 #define SET_BACKGROUND(col)     XSetBackground(display, gc, TRANSLATE(col));  
126    
127  static int rop2_map[] = {  static int rop2_map[] = {
128          GXclear,                /* 0 */          GXclear,                /* 0 */
# Line 81  static int rop2_map[] = { Line 143  static int rop2_map[] = {
143          GXset                   /* 1 */          GXset                   /* 1 */
144  };  };
145    
146  #define SET_FUNCTION(rop2)      { if (rop2 != ROP2_COPY) XSetFunction(display, gc, rop2_map[rop2]); }  #define SET_FUNCTION(rop2)      { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, rop2_map[rop2]); }
147  #define RESET_FUNCTION(rop2)    { if (rop2 != ROP2_COPY) XSetFunction(display, gc, GXcopy); }  #define RESET_FUNCTION(rop2)    { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, GXcopy); }
148    
149  static void  static void
150  translate8(uint8 *data, uint8 *out, uint8 *end)  mwm_hide_decorations(void)
151    {
152            PropMotifWmHints motif_hints;
153            Atom hintsatom;
154    
155            /* setup the property */
156            motif_hints.flags = MWM_HINTS_DECORATIONS;
157            motif_hints.decorations = 0;
158    
159            /* get the atom for the property */
160            hintsatom = XInternAtom(g_display, "_MOTIF_WM_HINTS", False);
161            if (!hintsatom)
162            {
163                    warning("Failed to get atom _MOTIF_WM_HINTS: probably your window manager does not support MWM hints\n");
164                    return;
165            }
166    
167            XChangeProperty(g_display, g_wnd, hintsatom, hintsatom, 32, PropModeReplace,
168                            (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
169    }
170    
171    static PixelColour
172    split_colour15(uint32 colour)
173    {
174            PixelColour rv;
175            rv.red = ((colour >> 7) & 0xf8) | ((colour >> 12) & 0x7);
176            rv.green = ((colour >> 2) & 0xf8) | ((colour >> 8) & 0x7);
177            rv.blue = ((colour << 3) & 0xf8) | ((colour >> 2) & 0x7);
178            return rv;
179    }
180    
181    static PixelColour
182    split_colour16(uint32 colour)
183    {
184            PixelColour rv;
185            rv.red = ((colour >> 8) & 0xf8) | ((colour >> 13) & 0x7);
186            rv.green = ((colour >> 3) & 0xfc) | ((colour >> 9) & 0x3);
187            rv.blue = ((colour << 3) & 0xf8) | ((colour >> 2) & 0x7);
188            return rv;
189    }
190    
191    static PixelColour
192    split_colour24(uint32 colour)
193    {
194            PixelColour rv;
195            rv.blue = (colour & 0xff0000) >> 16;
196            rv.green = (colour & 0x00ff00) >> 8;
197            rv.red = (colour & 0x0000ff);
198            return rv;
199    }
200    
201    static uint32
202    make_colour(PixelColour pc)
203    {
204            return (((pc.red >> g_red_shift_r) << g_red_shift_l)
205                    | ((pc.green >> g_green_shift_r) << g_green_shift_l)
206                    | ((pc.blue >> g_blue_shift_r) << g_blue_shift_l));
207    }
208    
209    #define BSWAP16(x) { x = (((x & 0xff) << 8) | (x >> 8)); }
210    #define BSWAP24(x) { x = (((x & 0xff) << 16) | (x >> 16) | (x & 0xff00)); }
211    #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \
212                            x = (x << 16) | (x >> 16); }
213    
214    static uint32
215    translate_colour(uint32 colour)
216    {
217            PixelColour pc;
218            switch (g_server_bpp)
219            {
220                    case 15:
221                            pc = split_colour15(colour);
222                            break;
223                    case 16:
224                            pc = split_colour16(colour);
225                            break;
226                    case 24:
227                            pc = split_colour24(colour);
228                            break;
229            }
230            return make_colour(pc);
231    }
232    
233    #define UNROLL8(stm) { stm stm stm stm stm stm stm stm }
234    #define REPEAT(stm) \
235    { \
236            while (out <= end - 8 * 4) \
237                    UNROLL8(stm) \
238            while (out < end) \
239                    { stm } \
240    }
241    
242    static void
243    translate8to8(uint8 * data, uint8 * out, uint8 * end)
244  {  {
245          while (out < end)          while (out < end)
246                  *(out++) = (uint8)colmap[*(data++)];                  *(out++) = (uint8) g_colmap[*(data++)];
247  }  }
248    
249  static void  static void
250  translate16(uint8 *data, uint16 *out, uint16 *end)  translate8to16(uint8 * data, uint8 * out, uint8 * end)
251    {
252            uint16 value;
253    
254            if (g_arch_match)
255                    REPEAT(*((uint16 *) out) = g_colmap[*(data++)];
256                           out += 2;)
257            else
258    if (g_xserver_be)
259  {  {
260          while (out < end)          while (out < end)
261                  *(out++) = (uint16)colmap[*(data++)];          {
262                    value = (uint16) g_colmap[*(data++)];
263                    *(out++) = value >> 8;
264                    *(out++) = value;
265            }
266    }
267    else
268    {
269            while (out < end)
270            {
271                    value = (uint16) g_colmap[*(data++)];
272                    *(out++) = value;
273                    *(out++) = value >> 8;
274            }
275    }
276  }  }
277    
278  /* little endian - conversion happens when colourmap is built */  /* little endian - conversion happens when colourmap is built */
279  static void  static void
280  translate24(uint8 *data, uint8 *out, uint8 *end)  translate8to24(uint8 * data, uint8 * out, uint8 * end)
281  {  {
282          uint32 value;          uint32 value;
283    
284            if (g_xserver_be)
285            {
286                    while (out < end)
287                    {
288                            value = g_colmap[*(data++)];
289                            *(out++) = value >> 16;
290                            *(out++) = value >> 8;
291                            *(out++) = value;
292                    }
293            }
294            else
295            {
296                    while (out < end)
297                    {
298                            value = g_colmap[*(data++)];
299                            *(out++) = value;
300                            *(out++) = value >> 8;
301                            *(out++) = value >> 16;
302                    }
303            }
304    }
305    
306    static void
307    translate8to32(uint8 * data, uint8 * out, uint8 * end)
308    {
309            uint32 value;
310    
311            if (g_arch_match)
312                    REPEAT(*((uint32 *) out) = g_colmap[*(data++)];
313                           out += 4;)
314            else
315    if (g_xserver_be)
316    {
317          while (out < end)          while (out < end)
318          {          {
319                  value = colmap[*(data++)];                  value = g_colmap[*(data++)];
320                    *(out++) = value >> 24;
321                    *(out++) = value >> 16;
322                    *(out++) = value >> 8;
323                    *(out++) = value;
324            }
325    }
326    else
327    {
328            while (out < end)
329            {
330                    value = g_colmap[*(data++)];
331                  *(out++) = value;                  *(out++) = value;
332                  *(out++) = value >> 8;                  *(out++) = value >> 8;
333                  *(out++) = value >> 16;                  *(out++) = value >> 16;
334                    *(out++) = value >> 24;
335          }          }
336  }  }
337    }
338    
339  static void  static void
340  translate32(uint8 *data, uint32 *out, uint32 *end)  translate15to16(uint16 * data, uint8 * out, uint8 * end)
341  {  {
342            uint16 pixel;
343            uint16 value;
344    
345          while (out < end)          while (out < end)
346                  *(out++) = colmap[*(data++)];          {
347                    pixel = *(data++);
348    
349                    if (g_host_be)
350                    {
351                            BSWAP16(pixel);
352                    }
353    
354                    value = make_colour(split_colour15(pixel));
355    
356                    if (g_xserver_be)
357                    {
358                            *(out++) = value >> 8;
359                            *(out++) = value;
360                    }
361                    else
362                    {
363                            *(out++) = value;
364                            *(out++) = value >> 8;
365                    }
366            }
367  }  }
368    
369  static uint8 *  static void
370  translate_image(int width, int height, uint8 *data)  translate15to24(uint16 * data, uint8 * out, uint8 * end)
371  {  {
372          int size = width * height * bpp/8;          uint32 value;
373          uint8 *out = xmalloc(size);          uint16 pixel;
         uint8 *end = out + size;  
374    
375          switch (bpp)          while (out < end)
376          {          {
377                  case 8:                  pixel = *(data++);
                         translate8(data, out, end);  
                         break;  
378    
379                  case 16:                  if (g_host_be)
380                          translate16(data, (uint16 *)out, (uint16 *)end);                  {
381                          break;                          BSWAP16(pixel);
382                    }
383    
384                  case 24:                  value = make_colour(split_colour15(pixel));
385                          translate24(data, out, end);                  if (g_xserver_be)
386                          break;                  {
387                            *(out++) = value >> 16;
388                            *(out++) = value >> 8;
389                            *(out++) = value;
390                    }
391                    else
392                    {
393                            *(out++) = value;
394                            *(out++) = value >> 8;
395                            *(out++) = value >> 16;
396                    }
397            }
398    }
399    
400                  case 32:  static void
401                          translate32(data, (uint32 *)out, (uint32 *)end);  translate15to32(uint16 * data, uint8 * out, uint8 * end)
402                          break;  {
403            uint16 pixel;
404            uint32 value;
405    
406            while (out < end)
407            {
408                    pixel = *(data++);
409    
410                    if (g_host_be)
411                    {
412                            BSWAP16(pixel);
413                    }
414    
415                    value = make_colour(split_colour15(pixel));
416    
417                    if (g_xserver_be)
418                    {
419                            *(out++) = value >> 24;
420                            *(out++) = value >> 16;
421                            *(out++) = value >> 8;
422                            *(out++) = value;
423                    }
424                    else
425                    {
426                            *(out++) = value;
427                            *(out++) = value >> 8;
428                            *(out++) = value >> 16;
429                            *(out++) = value >> 24;
430                    }
431          }          }
432    }
433    
434          return out;  static void
435    translate16to16(uint16 * data, uint8 * out, uint8 * end)
436    {
437            uint16 pixel;
438            uint16 value;
439    
440            while (out < end)
441            {
442                    pixel = *(data++);
443    
444                    if (g_host_be)
445                    {
446                            BSWAP16(pixel);
447                    }
448    
449                    value = make_colour(split_colour16(pixel));
450    
451                    if (g_xserver_be)
452                    {
453                            *(out++) = value >> 8;
454                            *(out++) = value;
455                    }
456                    else
457                    {
458                            *(out++) = value;
459                            *(out++) = value >> 8;
460                    }
461            }
462  }  }
463    
464  #define BSWAP16(x) x = (((x & 0xff) << 8) | (x >> 8));  static void
465  #define BSWAP24(x) x = (((x & 0xff) << 16) | (x >> 16) | ((x >> 8) & 0xff00));  translate16to24(uint16 * data, uint8 * out, uint8 * end)
466  #define BSWAP32(x) x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \  {
467                     x = (x << 16) | (x >> 16);          uint32 value;
468            uint16 pixel;
469    
470  static uint32          while (out < end)
471  translate_colour(uint32 colour)          {
472                    pixel = *(data++);
473    
474                    if (g_host_be)
475                    {
476                            BSWAP16(pixel);
477                    }
478    
479                    value = make_colour(split_colour16(pixel));
480    
481                    if (g_xserver_be)
482                    {
483                            *(out++) = value >> 16;
484                            *(out++) = value >> 8;
485                            *(out++) = value;
486                    }
487                    else
488                    {
489                            *(out++) = value;
490                            *(out++) = value >> 8;
491                            *(out++) = value >> 16;
492                    }
493            }
494    }
495    
496    static void
497    translate16to32(uint16 * data, uint8 * out, uint8 * end)
498  {  {
499          switch (bpp)          uint16 pixel;
500            uint32 value;
501    
502            while (out < end)
503          {          {
504                  case 16:                  pixel = *(data++);
505                          if (host_be != xserver_be)  
506                                  BSWAP16(colour);                  if (g_host_be)
507                          break;                  {
508                            BSWAP16(pixel);
509                    }
510    
511                    value = make_colour(split_colour16(pixel));
512    
513                    if (g_xserver_be)
514                    {
515                            *(out++) = value >> 24;
516                            *(out++) = value >> 16;
517                            *(out++) = value >> 8;
518                            *(out++) = value;
519                    }
520                    else
521                    {
522                            *(out++) = value;
523                            *(out++) = value >> 8;
524                            *(out++) = value >> 16;
525                            *(out++) = value >> 24;
526                    }
527            }
528    }
529    
530    static void
531    translate24to16(uint8 * data, uint8 * out, uint8 * end)
532    {
533            uint32 pixel = 0;
534            uint16 value;
535            while (out < end)
536            {
537                    pixel = *(data++) << 16;
538                    pixel |= *(data++) << 8;
539                    pixel |= *(data++);
540    
541                    value = (uint16) make_colour(split_colour24(pixel));
542    
543                    if (g_xserver_be)
544                    {
545                            *(out++) = value >> 8;
546                            *(out++) = value;
547                    }
548                    else
549                    {
550                            *(out++) = value;
551                            *(out++) = value >> 8;
552                    }
553            }
554    }
555    
556    static void
557    translate24to24(uint8 * data, uint8 * out, uint8 * end)
558    {
559            uint32 pixel;
560            uint32 value;
561    
562            while (out < end)
563            {
564                    pixel = *(data++) << 16;
565                    pixel |= *(data++) << 8;
566                    pixel |= *(data++);
567    
568                    value = make_colour(split_colour24(pixel));
569    
570                    if (g_xserver_be)
571                    {
572                            *(out++) = value >> 16;
573                            *(out++) = value >> 8;
574                            *(out++) = value;
575                    }
576                    else
577                    {
578                            *(out++) = value;
579                            *(out++) = value >> 8;
580                            *(out++) = value >> 16;
581                    }
582            }
583    }
584    
585    static void
586    translate24to32(uint8 * data, uint8 * out, uint8 * end)
587    {
588            uint32 pixel;
589            uint32 value;
590    
591            while (out < end)
592            {
593                    pixel = *(data++) << 16;
594                    pixel |= *(data++) << 8;
595                    pixel |= *(data++);
596    
597                    value = make_colour(split_colour24(pixel));
598    
599                    if (g_xserver_be)
600                    {
601                            *(out++) = value >> 24;
602                            *(out++) = value >> 16;
603                            *(out++) = value >> 8;
604                            *(out++) = value;
605                    }
606                    else
607                    {
608                            *(out++) = value;
609                            *(out++) = value >> 8;
610                            *(out++) = value >> 16;
611                            *(out++) = value >> 24;
612                    }
613            }
614    }
615    
616    static uint8 *
617    translate_image(int width, int height, uint8 * data)
618    {
619            int size;
620            uint8 *out;
621            uint8 *end;
622    
623            /* if server and xserver bpp match, */
624            /* and arch(endian) matches, no need to translate */
625            /* just return data */
626            if (g_arch_match)
627            {
628                    if (g_depth == 15 && g_server_bpp == 15)
629                            return data;
630                    if (g_depth == 16 && g_server_bpp == 16)
631                            return data;
632            }
633    
634            size = width * height * (g_bpp / 8);
635            out = (uint8 *) xmalloc(size);
636            end = out + size;
637    
638            switch (g_server_bpp)
639            {
640                  case 24:                  case 24:
641                          if (xserver_be)                          switch (g_bpp)
642                                  BSWAP24(colour);                          {
643                                    case 32:
644                                            translate24to32(data, out, end);
645                                            break;
646                                    case 24:
647                                            translate24to24(data, out, end);
648                                            break;
649                                    case 16:
650                                            translate24to16(data, out, end);
651                                            break;
652                            }
653                          break;                          break;
654                    case 16:
655                  case 32:                          switch (g_bpp)
656                          if (host_be != xserver_be)                          {
657                                  BSWAP32(colour);                                  case 32:
658                                            translate16to32((uint16 *) data, out, end);
659                                            break;
660                                    case 24:
661                                            translate16to24((uint16 *) data, out, end);
662                                            break;
663                                    case 16:
664                                            translate16to16((uint16 *) data, out, end);
665                                            break;
666                            }
667                            break;
668                    case 15:
669                            switch (g_bpp)
670                            {
671                                    case 32:
672                                            translate15to32((uint16 *) data, out, end);
673                                            break;
674                                    case 24:
675                                            translate15to24((uint16 *) data, out, end);
676                                            break;
677                                    case 16:
678                                            translate15to16((uint16 *) data, out, end);
679                                            break;
680                            }
681                            break;
682                    case 8:
683                            switch (g_bpp)
684                            {
685                                    case 8:
686                                            translate8to8(data, out, end);
687                                            break;
688                                    case 16:
689                                            translate8to16(data, out, end);
690                                            break;
691                                    case 24:
692                                            translate8to24(data, out, end);
693                                            break;
694                                    case 32:
695                                            translate8to32(data, out, end);
696                                            break;
697                            }
698                          break;                          break;
699          }          }
700            return out;
701    }
702    
703    BOOL
704    get_key_state(unsigned int state, uint32 keysym)
705    {
706            int modifierpos, key, keysymMask = 0;
707            int offset;
708    
709            KeyCode keycode = XKeysymToKeycode(g_display, keysym);
710    
711            if (keycode == NoSymbol)
712                    return False;
713    
714          return colour;          for (modifierpos = 0; modifierpos < 8; modifierpos++)
715            {
716                    offset = g_mod_map->max_keypermod * modifierpos;
717    
718                    for (key = 0; key < g_mod_map->max_keypermod; key++)
719                    {
720                            if (g_mod_map->modifiermap[offset + key] == keycode)
721                                    keysymMask |= 1 << modifierpos;
722                    }
723            }
724    
725            return (state & keysymMask) ? True : False;
726    }
727    
728    static void
729    calculate_shifts(uint32 mask, int *shift_r, int *shift_l)
730    {
731            *shift_l = ffs(mask) - 1;
732            mask >>= *shift_l;
733            *shift_r = 8 - ffs(mask & ~(mask >> 1));
734  }  }
735    
736  BOOL  BOOL
737  ui_create_window(char *title)  ui_init(void)
738  {  {
739          XSetWindowAttributes attribs;          XVisualInfo vi;
         XClassHint *classhints;  
         XSizeHints *sizehints;  
         unsigned long input_mask;  
740          XPixmapFormatValues *pfm;          XPixmapFormatValues *pfm;
         Screen *screen;  
741          uint16 test;          uint16 test;
742          int i;          int i, screen_num, nvisuals;
743            XVisualInfo *vmatches = NULL;
744            XVisualInfo template;
745            Bool TrueColorVisual = False;
746    
747          display = XOpenDisplay(NULL);          g_display = XOpenDisplay(NULL);
748          if (display == NULL)          if (g_display == NULL)
749          {          {
750                  error("Failed to open display\n");                  error("Failed to open display: %s\n", XDisplayName(NULL));
751                  return False;                  return False;
752          }          }
753    
754          x_socket = ConnectionNumber(display);          screen_num = DefaultScreen(g_display);
755          screen = DefaultScreenOfDisplay(display);          g_x_socket = ConnectionNumber(g_display);
756          visual = DefaultVisualOfScreen(screen);          g_screen = ScreenOfDisplay(g_display, screen_num);
757          depth = DefaultDepthOfScreen(screen);          g_depth = DefaultDepthOfScreen(g_screen);
758    
759            /* Search for best TrueColor depth */
760            template.class = TrueColor;
761            vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &nvisuals);
762    
763            nvisuals--;
764            while (nvisuals >= 0)
765            {
766                    if ((vmatches + nvisuals)->depth > g_depth)
767                    {
768                            g_depth = (vmatches + nvisuals)->depth;
769                    }
770                    nvisuals--;
771                    TrueColorVisual = True;
772            }
773    
774            test = 1;
775            g_host_be = !(BOOL) (*(uint8 *) (&test));
776            g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
777    
778            if ((g_server_bpp == 8) && ((!TrueColorVisual) || (g_depth <= 8)))
779            {
780                    /* we use a colourmap, so the default visual should do */
781                    g_visual = DefaultVisualOfScreen(g_screen);
782                    g_depth = DefaultDepthOfScreen(g_screen);
783    
784          pfm = XListPixmapFormats(display, &i);                  /* Do not allocate colours on a TrueColor visual */
785                    if (g_visual->class == TrueColor)
786                    {
787                            g_owncolmap = False;
788                    }
789            }
790            else
791            {
792                    /* need a truecolour visual */
793                    if (!XMatchVisualInfo(g_display, screen_num, g_depth, TrueColor, &vi))
794                    {
795                            error("The display does not support true colour - high colour support unavailable.\n");
796                            return False;
797                    }
798    
799                    g_visual = vi.visual;
800                    g_owncolmap = False;
801                    calculate_shifts(vi.red_mask, &g_red_shift_r, &g_red_shift_l);
802                    calculate_shifts(vi.blue_mask, &g_blue_shift_r, &g_blue_shift_l);
803                    calculate_shifts(vi.green_mask, &g_green_shift_r, &g_green_shift_l);
804    
805                    /* if RGB video and averything is little endian */
806                    if (vi.red_mask > vi.green_mask && vi.green_mask > vi.blue_mask)
807                            if (!g_xserver_be && !g_host_be)
808                                    g_arch_match = True;
809            }
810    
811            pfm = XListPixmapFormats(g_display, &i);
812          if (pfm != NULL)          if (pfm != NULL)
813          {          {
814                  /* Use maximum bpp for this depth - this is generally                  /* Use maximum bpp for this depth - this is generally
815                     desirable, e.g. 24 bits->32 bits. */                     desirable, e.g. 24 bits->32 bits. */
816                  while (i--)                  while (i--)
817                  {                  {
818                          if ((pfm[i].depth == depth)                          if ((pfm[i].depth == g_depth) && (pfm[i].bits_per_pixel > g_bpp))
                             && (pfm[i].bits_per_pixel > bpp))  
819                          {                          {
820                                  bpp = pfm[i].bits_per_pixel;                                  g_bpp = pfm[i].bits_per_pixel;
821                          }                          }
822                  }                  }
823                  XFree(pfm);                  XFree(pfm);
824          }          }
825    
826          if (bpp < 8)          if (g_bpp < 8)
827          {          {
828                  error("Less than 8 bpp not currently supported.\n");                  error("Less than 8 bpp not currently supported.\n");
829                  XCloseDisplay(display);                  XCloseDisplay(g_display);
830                  return False;                  return False;
831          }          }
832    
833          if (depth <= 8)          if (!g_owncolmap)
834                  owncolmap = True;          {
835          else                  g_xcolmap =
836                  xcolmap = DefaultColormapOfScreen(screen);                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,
837                                            AllocNone);
838          test = 1;                  if (g_depth <= 8)
839          host_be = !(BOOL)(*(uint8 *)(&test));                          warning("Screen depth is 8 bits or lower: you may want to use -C for a private colourmap\n");
840          xserver_be = (ImageByteOrder(display) == MSBFirst);          }
   
         white = WhitePixelOfScreen(screen);  
         attribs.background_pixel = BlackPixelOfScreen(screen);  
         attribs.backing_store = DoesBackingStore(screen);  
841    
842          if (attribs.backing_store == NotUseful)          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
843                  ownbackstore = True;          {
844                    warning("External BackingStore not available, using internal\n");
845                    g_ownbackstore = True;
846            }
847    
848          if (fullscreen)          /*
849             * Determine desktop size
850             */
851            if (g_fullscreen)
852          {          {
853                  attribs.override_redirect = True;                  g_width = WidthOfScreen(g_screen);
854                  width = WidthOfScreen(screen);                  g_height = HeightOfScreen(g_screen);
                 height = HeightOfScreen(screen);  
855          }          }
856          else          else if (g_width < 0)
857            {
858                    /* Percent of screen */
859                    g_height = HeightOfScreen(g_screen) * (-g_width) / 100;
860                    g_width = WidthOfScreen(g_screen) * (-g_width) / 100;
861            }
862            else if (g_width == 0)
863          {          {
864                  attribs.override_redirect = False;                  /* Fetch geometry from _NET_WORKAREA */
865                    uint32 x, y, cx, cy;
866    
867                    if (get_current_workarea(&x, &y, &cx, &cy) == 0)
868                    {
869                            g_width = cx;
870                            g_height = cy;
871                    }
872                    else
873                    {
874                            warning("Failed to get workarea: probably your window manager does not support extended hints\n");
875                            g_width = 800;
876                            g_height = 600;
877                    }
878          }          }
879    
880          width = (width + 3) & ~3; /* make width a multiple of 32 bits */          /* make sure width is a multiple of 4 */
881            g_width = (g_width + 3) & ~3;
882    
883            g_mod_map = XGetModifierMapping(g_display);
884    
885            xkeymap_init();
886    
887            if (g_enable_compose)
888                    g_IM = XOpenIM(g_display, NULL, NULL, NULL);
889    
890            xclip_init();
891    
892            DEBUG_RDP5(("server bpp %d client bpp %d depth %d\n", g_server_bpp, g_bpp, g_depth));
893    
894            return True;
895    }
896    
897    void
898    ui_deinit(void)
899    {
900            if (g_IM != NULL)
901                    XCloseIM(g_IM);
902    
903            if (g_null_cursor != NULL)
904                    ui_destroy_cursor(g_null_cursor);
905    
906            XFreeModifiermap(g_mod_map);
907    
908            if (g_ownbackstore)
909                    XFreePixmap(g_display, g_backstore);
910    
911            XFreeGC(g_display, g_gc);
912            XCloseDisplay(g_display);
913            g_display = NULL;
914    }
915    
916    BOOL
917    ui_create_window(void)
918    {
919            uint8 null_pointer_mask[1] = { 0x80 };
920            uint8 null_pointer_data[4] = { 0x00, 0x00, 0x00, 0x00 };
921            XSetWindowAttributes attribs;
922            XClassHint *classhints;
923            XSizeHints *sizehints;
924            int wndwidth, wndheight;
925            long input_mask, ic_input_mask;
926            XEvent xevent;
927    
928            wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
929            wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
930    
931            attribs.background_pixel = BlackPixelOfScreen(g_screen);
932            attribs.border_pixel = WhitePixelOfScreen(g_screen);
933            attribs.backing_store = g_ownbackstore ? NotUseful : Always;
934            attribs.override_redirect = g_fullscreen;
935            attribs.colormap = g_xcolmap;
936    
937            g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), 0, 0, wndwidth, wndheight,
938                                  0, g_depth, InputOutput, g_visual,
939                                  CWBackPixel | CWBackingStore | CWOverrideRedirect |
940                                  CWColormap | CWBorderPixel, &attribs);
941    
942            if (g_gc == NULL)
943                    g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
944    
945            if ((g_ownbackstore) && (g_backstore == 0))
946            {
947                    g_backstore = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
948    
949                    /* clear to prevent rubbish being exposed at startup */
950                    XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
951                    XFillRectangle(g_display, g_backstore, g_gc, 0, 0, g_width, g_height);
952            }
953    
954          wnd = XCreateWindow(display, RootWindowOfScreen(screen),          XStoreName(g_display, g_wnd, g_title);
                             0, 0, width, height, 0, CopyFromParent,  
                             InputOutput, CopyFromParent,  
                             CWBackingStore | CWBackPixel | CWOverrideRedirect,  
                             &attribs);  
955    
956          XStoreName(display, wnd, title);          if (g_hide_decorations)
957                    mwm_hide_decorations();
958    
959          classhints = XAllocClassHint();          classhints = XAllocClassHint();
960          if (classhints != NULL)          if (classhints != NULL)
961          {          {
962                  classhints->res_name = classhints->res_class = "rdesktop";                  classhints->res_name = classhints->res_class = "rdesktop";
963                  XSetClassHint(display, wnd, classhints);                  XSetClassHint(g_display, g_wnd, classhints);
964                  XFree(classhints);                  XFree(classhints);
965          }          }
966    
# Line 274  ui_create_window(char *title) Line 968  ui_create_window(char *title)
968          if (sizehints)          if (sizehints)
969          {          {
970                  sizehints->flags = PMinSize | PMaxSize;                  sizehints->flags = PMinSize | PMaxSize;
971                  sizehints->min_width = sizehints->max_width = width;                  sizehints->min_width = sizehints->max_width = g_width;
972                  sizehints->min_height = sizehints->max_height = height;                  sizehints->min_height = sizehints->max_height = g_height;
973                  XSetWMNormalHints(display, wnd, sizehints);                  XSetWMNormalHints(g_display, g_wnd, sizehints);
974                  XFree(sizehints);                  XFree(sizehints);
975          }          }
976    
977          input_mask = KeyPressMask | KeyReleaseMask          if (g_embed_wnd)
978                          | ButtonPressMask | ButtonReleaseMask          {
979                          | EnterWindowMask | LeaveWindowMask;                  XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
980            }
981    
982          if (sendmotion)          input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
983                  input_mask |= PointerMotionMask;                  VisibilityChangeMask | FocusChangeMask;
984    
985          if (ownbackstore)          if (g_sendmotion)
986                    input_mask |= PointerMotionMask;
987            if (g_ownbackstore)
988                  input_mask |= ExposureMask;                  input_mask |= ExposureMask;
989            if (g_fullscreen || g_grab_keyboard)
990                    input_mask |= EnterWindowMask;
991            if (g_grab_keyboard)
992                    input_mask |= LeaveWindowMask;
993    
994            if (g_IM != NULL)
995            {
996                    g_IC = XCreateIC(g_IM, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing),
997                                     XNClientWindow, g_wnd, XNFocusWindow, g_wnd, NULL);
998    
999                    if ((g_IC != NULL)
1000                        && (XGetICValues(g_IC, XNFilterEvents, &ic_input_mask, NULL) == NULL))
1001                            input_mask |= ic_input_mask;
1002            }
1003    
1004            XSelectInput(g_display, g_wnd, input_mask);
1005            XMapWindow(g_display, g_wnd);
1006    
1007          XSelectInput(display, wnd, input_mask);          /* wait for VisibilityNotify */
1008          gc = XCreateGC(display, wnd, 0, NULL);          do
1009            {
1010                    XMaskEvent(g_display, VisibilityChangeMask, &xevent);
1011            }
1012            while (xevent.type != VisibilityNotify);
1013            g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
1014    
1015            g_focused = False;
1016            g_mouse_in_wnd = False;
1017    
1018          if (ownbackstore)          /* handle the WM_DELETE_WINDOW protocol */
1019                  backstore = XCreatePixmap(display, wnd, width, height, depth);          g_protocol_atom = XInternAtom(g_display, "WM_PROTOCOLS", True);
1020            g_kill_atom = XInternAtom(g_display, "WM_DELETE_WINDOW", True);
1021            XSetWMProtocols(g_display, g_wnd, &g_kill_atom, 1);
1022    
1023            /* create invisible 1x1 cursor to be used as null cursor */
1024            if (g_null_cursor == NULL)
1025                    g_null_cursor = ui_create_cursor(0, 0, 1, 1, null_pointer_mask, null_pointer_data);
1026    
         XMapWindow(display, wnd);  
1027          return True;          return True;
1028  }  }
1029    
1030  void  void
1031  ui_destroy_window()  ui_resize_window()
1032  {  {
1033          if (ownbackstore)          XSizeHints *sizehints;
1034                  XFreePixmap(display, backstore);          Pixmap bs;
1035    
1036          XFreeGC(display, gc);          sizehints = XAllocSizeHints();
1037          XDestroyWindow(display, wnd);          if (sizehints)
1038          XCloseDisplay(display);          {
1039          display = NULL;                  sizehints->flags = PMinSize | PMaxSize;
1040  }                  sizehints->min_width = sizehints->max_width = g_width;
1041                    sizehints->min_height = sizehints->max_height = g_height;
1042  static uint8                  XSetWMNormalHints(g_display, g_wnd, sizehints);
1043  xwin_translate_key(unsigned long key)                  XFree(sizehints);
 {  
         DEBUG(("KEY(code=0x%lx)\n", key));  
   
         if ((key > 8) && (key <= 0x60))  
                 return (key - 8);  
   
         switch (key)  
         {  
                 case 0x61:      /* home */  
                         return 0x47 | 0x80;  
                 case 0x62:      /* up arrow */  
                         return 0x48 | 0x80;  
                 case 0x63:      /* page up */  
                         return 0x49 | 0x80;  
                 case 0x64:      /* left arrow */  
                         return 0x4b | 0x80;  
                 case 0x66:      /* right arrow */  
                         return 0x4d | 0x80;  
                 case 0x67:      /* end */  
                         return 0x4f | 0x80;  
                 case 0x68:      /* down arrow */  
                         return 0x50 | 0x80;  
                 case 0x69:      /* page down */  
                         return 0x51 | 0x80;  
                 case 0x6a:      /* insert */  
                         return 0x52 | 0x80;  
                 case 0x6b:      /* delete */  
                         return 0x53 | 0x80;  
                 case 0x6c:      /* keypad enter */  
                         return 0x1c | 0x80;  
                 case 0x6d:      /* right ctrl */  
                         return 0x1d | 0x80;  
                 case 0x6f:      /* ctrl - print screen */  
                         return 0x37 | 0x80;  
                 case 0x70:      /* keypad '/' */  
                         return 0x35 | 0x80;  
                 case 0x71:      /* right alt */  
                         return 0x38 | 0x80;  
                 case 0x72:      /* ctrl break */  
                         return 0x46 | 0x80;  
                 case 0x73:      /* left window key */  
                         return 0xff;    /* real scancode is 5b */  
                 case 0x74:      /* right window key */  
                         return 0xff;    /* real scancode is 5c */  
                 case 0x75:      /* menu key */  
                         return 0x5d | 0x80;  
         }  
   
         return 0;  
 }  
   
 static uint16  
 xwin_translate_mouse(unsigned long button)  
 {  
         switch (button)  
         {  
                 case Button1:   /* left */  
                         return MOUSE_FLAG_BUTTON1;  
                 case Button2:   /* middle */  
                         return MOUSE_FLAG_BUTTON3;  
                 case Button3:   /* right */  
                         return MOUSE_FLAG_BUTTON2;  
1044          }          }
1045    
1046          return 0;          if (!(g_fullscreen || g_embed_wnd))
1047            {
1048                    XResizeWindow(g_display, g_wnd, g_width, g_height);
1049            }
1050    
1051            /* create new backstore pixmap */
1052            if (g_backstore != 0)
1053            {
1054                    bs = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1055                    XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
1056                    XFillRectangle(g_display, bs, g_gc, 0, 0, g_width, g_height);
1057                    XCopyArea(g_display, g_backstore, bs, g_gc, 0, 0, g_width, g_height, 0, 0);
1058                    XFreePixmap(g_display, g_backstore);
1059                    g_backstore = bs;
1060            }
1061  }  }
1062    
1063  static void  void
1064  xwin_process_events()  ui_destroy_window(void)
1065  {  {
1066          XEvent event;          if (g_IC != NULL)
1067          uint8 scancode;                  XDestroyIC(g_IC);
         uint16 button;  
         uint32 ev_time;  
1068    
1069          if (display == NULL)          XDestroyWindow(g_display, g_wnd);
1070                  return;  }
1071    
1072    void
1073    xwin_toggle_fullscreen(void)
1074    {
1075            Pixmap contents = 0;
1076    
1077            if (!g_ownbackstore)
1078            {
1079                    /* need to save contents of window */
1080                    contents = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1081                    XCopyArea(g_display, g_wnd, contents, g_gc, 0, 0, g_width, g_height, 0, 0);
1082            }
1083    
1084          while (XCheckWindowEvent(display, wnd, ~0, &event))          ui_destroy_window();
1085            g_fullscreen = !g_fullscreen;
1086            ui_create_window();
1087    
1088            XDefineCursor(g_display, g_wnd, g_current_cursor);
1089    
1090            if (!g_ownbackstore)
1091            {
1092                    XCopyArea(g_display, contents, g_wnd, g_gc, 0, 0, g_width, g_height, 0, 0);
1093                    XFreePixmap(g_display, contents);
1094            }
1095    }
1096    
1097    /* Process all events in Xlib queue
1098       Returns 0 after user quit, 1 otherwise */
1099    static int
1100    xwin_process_events(void)
1101    {
1102            XEvent xevent;
1103            KeySym keysym;
1104            uint16 button, flags;
1105            uint32 ev_time;
1106            key_translation tr;
1107            char str[256];
1108            Status status;
1109    
1110            while (XPending(g_display) > 0)
1111          {          {
1112                  ev_time = time(NULL);                  XNextEvent(g_display, &xevent);
1113    
1114                  switch (event.type)                  if ((g_IC != NULL) && (XFilterEvent(&xevent, None) == True))
1115                  {                  {
1116                            DEBUG_KBD(("Filtering event\n"));
1117                            continue;
1118                    }
1119    
1120                    flags = 0;
1121    
1122                    switch (xevent.type)
1123                    {
1124                            case VisibilityNotify:
1125                                    g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
1126                                    break;
1127                            case ClientMessage:
1128                                    /* the window manager told us to quit */
1129                                    if ((xevent.xclient.message_type == g_protocol_atom)
1130                                        && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))
1131                                            /* Quit */
1132                                            return 0;
1133                                    break;
1134    
1135                          case KeyPress:                          case KeyPress:
1136                                  scancode = xwin_translate_key(event.xkey.keycode);                                  g_last_gesturetime = xevent.xkey.time;
1137                                  if (scancode == 0)                                  if (g_IC != NULL)
1138                                            /* Multi_key compatible version */
1139                                    {
1140                                            XmbLookupString(g_IC,
1141                                                            &xevent.xkey, str, sizeof(str), &keysym,
1142                                                            &status);
1143                                            if (!((status == XLookupKeySym) || (status == XLookupBoth)))
1144                                            {
1145                                                    error("XmbLookupString failed with status 0x%x\n",
1146                                                          status);
1147                                                    break;
1148                                            }
1149                                    }
1150                                    else
1151                                    {
1152                                            /* Plain old XLookupString */
1153                                            DEBUG_KBD(("\nNo input context, using XLookupString\n"));
1154                                            XLookupString((XKeyEvent *) & xevent,
1155                                                          str, sizeof(str), &keysym, NULL);
1156                                    }
1157    
1158                                    DEBUG_KBD(("KeyPress for (keysym 0x%lx, %s)\n", keysym,
1159                                               get_ksname(keysym)));
1160    
1161                                    ev_time = time(NULL);
1162                                    if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
1163                                          break;                                          break;
1164    
1165                                  rdp_send_input(ev_time, RDP_INPUT_SCANCODE, 0,                                  tr = xkeymap_translate_key(keysym,
1166                                                 scancode, 0);                                                             xevent.xkey.keycode, xevent.xkey.state);
1167    
1168                                    if (tr.scancode == 0)
1169                                            break;
1170    
1171                                    save_remote_modifiers(tr.scancode);
1172                                    ensure_remote_modifiers(ev_time, tr);
1173                                    rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);
1174                                    restore_remote_modifiers(ev_time, tr.scancode);
1175    
1176                                  break;                                  break;
1177    
1178                          case KeyRelease:                          case KeyRelease:
1179                                  scancode = xwin_translate_key(event.xkey.keycode);                                  g_last_gesturetime = xevent.xkey.time;
1180                                  if (scancode == 0)                                  XLookupString((XKeyEvent *) & xevent, str,
1181                                                  sizeof(str), &keysym, NULL);
1182    
1183                                    DEBUG_KBD(("\nKeyRelease for (keysym 0x%lx, %s)\n", keysym,
1184                                               get_ksname(keysym)));
1185    
1186                                    ev_time = time(NULL);
1187                                    if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
1188                                          break;                                          break;
1189    
1190                                  rdp_send_input(ev_time, RDP_INPUT_SCANCODE,                                  tr = xkeymap_translate_key(keysym,
1191                                                 KBD_FLAG_DOWN | KBD_FLAG_UP,                                                             xevent.xkey.keycode, xevent.xkey.state);
                                                scancode, 0);  
                                 break;  
1192    
1193                          case ButtonPress:                                  if (tr.scancode == 0)
                                 button = xwin_translate_mouse(event.xbutton.button);  
                                 if (button == 0)  
1194                                          break;                                          break;
1195    
1196                                  rdp_send_input(ev_time, RDP_INPUT_MOUSE,                                  rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);
                                                button | MOUSE_FLAG_DOWN,  
                                                event.xbutton.x,  
                                                event.xbutton.y);  
1197                                  break;                                  break;
1198    
1199                            case ButtonPress:
1200                                    flags = MOUSE_FLAG_DOWN;
1201                                    /* fall through */
1202    
1203                          case ButtonRelease:                          case ButtonRelease:
1204                                  button = xwin_translate_mouse(event.xbutton.button);                                  g_last_gesturetime = xevent.xbutton.time;
1205                                    button = xkeymap_translate_button(xevent.xbutton.button);
1206                                  if (button == 0)                                  if (button == 0)
1207                                          break;                                          break;
1208    
1209                                  rdp_send_input(ev_time, RDP_INPUT_MOUSE,                                  /* If win_button_size is nonzero, enable single app mode */
1210                                                 button,                                  if (xevent.xbutton.y < g_win_button_size)
1211                                                 event.xbutton.x,                                  {
1212                                                 event.xbutton.y);                                          /* Stop moving window when button is released, regardless of cursor position */
1213                                            if (g_moving_wnd && (xevent.type == ButtonRelease))
1214                                                    g_moving_wnd = False;
1215    
1216                                            /*  Check from right to left: */
1217    
1218                                            if (xevent.xbutton.x >= g_width - g_win_button_size)
1219                                            {
1220                                                    /* The close button, continue */
1221                                                    ;
1222                                            }
1223                                            else if (xevent.xbutton.x >=
1224                                                     g_width - g_win_button_size * 2)
1225                                            {
1226                                                    /* The maximize/restore button. Do not send to
1227                                                       server.  It might be a good idea to change the
1228                                                       cursor or give some other visible indication
1229                                                       that rdesktop inhibited this click */
1230                                                    break;
1231                                            }
1232                                            else if (xevent.xbutton.x >=
1233                                                     g_width - g_win_button_size * 3)
1234                                            {
1235                                                    /* The minimize button. Iconify window. */
1236                                                    XIconifyWindow(g_display, g_wnd,
1237                                                                   DefaultScreen(g_display));
1238                                                    break;
1239                                            }
1240                                            else if (xevent.xbutton.x <= g_win_button_size)
1241                                            {
1242                                                    /* The system menu. Ignore. */
1243                                                    break;
1244                                            }
1245                                            else
1246                                            {
1247                                                    /* The title bar. */
1248                                                    if ((xevent.type == ButtonPress) && !g_fullscreen
1249                                                        && g_hide_decorations)
1250                                                    {
1251                                                            g_moving_wnd = True;
1252                                                            g_move_x_offset = xevent.xbutton.x;
1253                                                            g_move_y_offset = xevent.xbutton.y;
1254                                                    }
1255                                                    break;
1256    
1257                                            }
1258                                    }
1259    
1260                                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1261                                                   flags | button, xevent.xbutton.x, xevent.xbutton.y);
1262                                  break;                                  break;
1263    
1264                          case MotionNotify:                          case MotionNotify:
1265                                  rdp_send_input(ev_time, RDP_INPUT_MOUSE,                                  if (g_moving_wnd)
1266                                                 MOUSE_FLAG_MOVE,                                  {
1267                                                 event.xmotion.x,                                          XMoveWindow(g_display, g_wnd,
1268                                                 event.xmotion.y);                                                      xevent.xmotion.x_root - g_move_x_offset,
1269                                                        xevent.xmotion.y_root - g_move_y_offset);
1270                                            break;
1271                                    }
1272    
1273                                    if (g_fullscreen && !g_focused)
1274                                            XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1275                                                           CurrentTime);
1276                                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1277                                                   MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);
1278                                    break;
1279    
1280                            case FocusIn:
1281                                    if (xevent.xfocus.mode == NotifyGrab)
1282                                            break;
1283                                    g_focused = True;
1284                                    reset_modifier_keys();
1285                                    if (g_grab_keyboard && g_mouse_in_wnd)
1286                                            XGrabKeyboard(g_display, g_wnd, True,
1287                                                          GrabModeAsync, GrabModeAsync, CurrentTime);
1288                                    break;
1289    
1290                            case FocusOut:
1291                                    if (xevent.xfocus.mode == NotifyUngrab)
1292                                            break;
1293                                    g_focused = False;
1294                                    if (xevent.xfocus.mode == NotifyWhileGrabbed)
1295                                            XUngrabKeyboard(g_display, CurrentTime);
1296                                  break;                                  break;
1297    
1298                          case EnterNotify:                          case EnterNotify:
1299                                  XGrabKeyboard(display, wnd, True, GrabModeAsync,                                  /* we only register for this event when in fullscreen mode */
1300                                                GrabModeAsync, CurrentTime);                                  /* or grab_keyboard */
1301                                    g_mouse_in_wnd = True;
1302                                    if (g_fullscreen)
1303                                    {
1304                                            XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1305                                                           CurrentTime);
1306                                            break;
1307                                    }
1308                                    if (g_focused)
1309                                            XGrabKeyboard(g_display, g_wnd, True,
1310                                                          GrabModeAsync, GrabModeAsync, CurrentTime);
1311                                  break;                                  break;
1312    
1313                          case LeaveNotify:                          case LeaveNotify:
1314                                  XUngrabKeyboard(display, CurrentTime);                                  /* we only register for this event when grab_keyboard */
1315                                    g_mouse_in_wnd = False;
1316                                    XUngrabKeyboard(g_display, CurrentTime);
1317                                  break;                                  break;
1318    
1319                          case Expose:                          case Expose:
1320                                  XCopyArea(display, backstore, wnd, gc,                                  XCopyArea(g_display, g_backstore, g_wnd, g_gc,
1321                                            event.xexpose.x, event.xexpose.y,                                            xevent.xexpose.x, xevent.xexpose.y,
1322                                            event.xexpose.width, event.xexpose.height,                                            xevent.xexpose.width,
1323                                            event.xexpose.x, event.xexpose.y);                                            xevent.xexpose.height,
1324                                              xevent.xexpose.x, xevent.xexpose.y);
1325                                    break;
1326    
1327                            case MappingNotify:
1328                                    /* Refresh keyboard mapping if it has changed. This is important for
1329                                       Xvnc, since it allocates keycodes dynamically */
1330                                    if (xevent.xmapping.request == MappingKeyboard
1331                                        || xevent.xmapping.request == MappingModifier)
1332                                            XRefreshKeyboardMapping(&xevent.xmapping);
1333    
1334                                    if (xevent.xmapping.request == MappingModifier)
1335                                    {
1336                                            XFreeModifiermap(g_mod_map);
1337                                            g_mod_map = XGetModifierMapping(g_display);
1338                                    }
1339                                    break;
1340    
1341                                    /* clipboard stuff */
1342                            case SelectionNotify:
1343                                    xclip_handle_SelectionNotify(&xevent.xselection);
1344                                    break;
1345                            case SelectionRequest:
1346                                    xclip_handle_SelectionRequest(&xevent.xselectionrequest);
1347                                    break;
1348                            case SelectionClear:
1349                                    xclip_handle_SelectionClear();
1350                                    break;
1351                            case PropertyNotify:
1352                                    xclip_handle_PropertyNotify(&xevent.xproperty);
1353                                  break;                                  break;
1354                  }                  }
1355          }          }
1356            /* Keep going */
1357            return 1;
1358  }  }
1359    
1360  void  /* Returns 0 after user quit, 1 otherwise */
1361    int
1362  ui_select(int rdp_socket)  ui_select(int rdp_socket)
1363  {  {
1364          int n = (rdp_socket > x_socket) ? rdp_socket+1 : x_socket+1;          int n;
1365          fd_set rfds;          fd_set rfds, wfds;
1366            struct timeval tv;
1367          XFlush(display);          BOOL s_timeout = False;
   
         FD_ZERO(&rfds);  
1368    
1369          while (True)          while (True)
1370          {          {
1371                    n = (rdp_socket > g_x_socket) ? rdp_socket : g_x_socket;
1372                    /* Process any events already waiting */
1373                    if (!xwin_process_events())
1374                            /* User quit */
1375                            return 0;
1376    
1377                  FD_ZERO(&rfds);                  FD_ZERO(&rfds);
1378                    FD_ZERO(&wfds);
1379                  FD_SET(rdp_socket, &rfds);                  FD_SET(rdp_socket, &rfds);
1380                  FD_SET(x_socket, &rfds);                  FD_SET(g_x_socket, &rfds);
1381    
1382    #ifdef WITH_RDPSND
1383                    /* FIXME: there should be an API for registering fds */
1384                    if (g_dsp_busy)
1385                    {
1386                            FD_SET(g_dsp_fd, &wfds);
1387                            n = (g_dsp_fd > n) ? g_dsp_fd : n;
1388                    }
1389    #endif
1390                    /* default timeout */
1391                    tv.tv_sec = 60;
1392                    tv.tv_usec = 0;
1393    
1394                    /* add redirection handles */
1395                    rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
1396    
1397                    n++;
1398    
1399                  switch (select(n, &rfds, NULL, NULL, NULL))                  switch (select(n, &rfds, &wfds, NULL, &tv))
1400                  {                  {
1401                          case -1:                          case -1:
1402                                  error("select: %s\n", strerror(errno));                                  error("select: %s\n", strerror(errno));
1403    
1404                          case 0:                          case 0:
1405                                    /* TODO: if tv.tv_sec just times out
1406                                     * we will segfault.
1407                                     * FIXME:
1408                                     */
1409                                    //s_timeout = True;
1410                                    //rdpdr_check_fds(&rfds, &wfds, (BOOL) True);
1411                                  continue;                                  continue;
1412                  }                  }
1413    
1414                  if (FD_ISSET(x_socket, &rfds))                  rdpdr_check_fds(&rfds, &wfds, (BOOL) False);
                         xwin_process_events();  
1415    
1416                  if (FD_ISSET(rdp_socket, &rfds))                  if (FD_ISSET(rdp_socket, &rfds))
1417                          return;                          return 1;
1418    
1419    #ifdef WITH_RDPSND
1420                    if (g_dsp_busy && FD_ISSET(g_dsp_fd, &wfds))
1421                            wave_out_play();
1422    #endif
1423          }          }
1424  }  }
1425    
1426  void  void
1427  ui_move_pointer(int x, int y)  ui_move_pointer(int x, int y)
1428  {  {
1429          XWarpPointer(display, wnd, wnd, 0, 0, 0, 0, x, y);          XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y);
1430  }  }
1431    
1432  HBITMAP  HBITMAP
1433  ui_create_bitmap(int width, int height, uint8 *data)  ui_create_bitmap(int width, int height, uint8 * data)
1434  {  {
1435          XImage *image;          XImage *image;
1436          Pixmap bitmap;          Pixmap bitmap;
1437          uint8 *tdata;          uint8 *tdata;
1438            int bitmap_pad;
1439    
1440          tdata = (owncolmap ? data : translate_image(width, height, data));          if (g_server_bpp == 8)
1441          bitmap = XCreatePixmap(display, wnd, width, height, depth);          {
1442          image = XCreateImage(display, visual, depth, ZPixmap,                  bitmap_pad = 8;
1443                               0, tdata, width, height, 8, 0);          }
1444            else
1445            {
1446                    bitmap_pad = g_bpp;
1447    
1448          XPutImage(display, bitmap, gc, image, 0, 0, 0, 0, width, height);                  if (g_bpp == 24)
1449                            bitmap_pad = 32;
1450            }
1451    
1452            tdata = (g_owncolmap ? data : translate_image(width, height, data));
1453            bitmap = XCreatePixmap(g_display, g_wnd, width, height, g_depth);
1454            image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1455                                 (char *) tdata, width, height, bitmap_pad, 0);
1456    
1457            XPutImage(g_display, bitmap, g_gc, image, 0, 0, 0, 0, width, height);
1458    
1459          XFree(image);          XFree(image);
1460          if (!owncolmap)          if (tdata != data)
1461                  xfree(tdata);                  xfree(tdata);
1462          return (HBITMAP) bitmap;          return (HBITMAP) bitmap;
1463  }  }
1464    
1465  void  void
1466  ui_paint_bitmap(int x, int y, int cx, int cy,  ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data)
                 int width, int height, uint8 *data)  
1467  {  {
1468          XImage *image;          XImage *image;
1469          uint8 *tdata;          uint8 *tdata;
1470            int bitmap_pad;
1471    
1472            if (g_server_bpp == 8)
1473            {
1474                    bitmap_pad = 8;
1475            }
1476            else
1477            {
1478                    bitmap_pad = g_bpp;
1479    
1480          tdata = (owncolmap ? data : translate_image(width, height, data));                  if (g_bpp == 24)
1481          image = XCreateImage(display, visual, depth, ZPixmap,                          bitmap_pad = 32;
1482                               0, tdata, width, height, 8, 0);          }
1483    
1484          if (ownbackstore)          tdata = (g_owncolmap ? data : translate_image(width, height, data));
1485            image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1486                                 (char *) tdata, width, height, bitmap_pad, 0);
1487    
1488            if (g_ownbackstore)
1489          {          {
1490                  XPutImage(display, backstore, gc, image, 0, 0, x, y, cx, cy);                  XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
1491                  XCopyArea(display, backstore, wnd, gc, x, y, cx, cy, x, y);                  XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
1492          }          }
1493          else          else
1494          {          {
1495                  XPutImage(display, wnd, gc, image, 0, 0, x, y, cx, cy);                  XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
1496          }          }
1497    
1498          XFree(image);          XFree(image);
1499          if (!owncolmap)          if (tdata != data)
1500                  xfree(tdata);                  xfree(tdata);
1501  }  }
1502    
1503  void  void
1504  ui_destroy_bitmap(HBITMAP bmp)  ui_destroy_bitmap(HBITMAP bmp)
1505  {  {
1506          XFreePixmap(display, (Pixmap)bmp);          XFreePixmap(g_display, (Pixmap) bmp);
1507  }  }
1508    
1509  HGLYPH  HGLYPH
1510  ui_create_glyph(int width, int height, uint8 *data)  ui_create_glyph(int width, int height, uint8 * data)
1511  {  {
1512          XImage *image;          XImage *image;
1513          Pixmap bitmap;          Pixmap bitmap;
# Line 566  ui_create_glyph(int width, int height, u Line 1516  ui_create_glyph(int width, int height, u
1516    
1517          scanline = (width + 7) / 8;          scanline = (width + 7) / 8;
1518    
1519          bitmap = XCreatePixmap(display, wnd, width, height, 1);          bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
1520          gc = XCreateGC(display, bitmap, 0, NULL);          gc = XCreateGC(g_display, bitmap, 0, NULL);
1521    
1522          image = XCreateImage(display, visual, 1, ZPixmap, 0,          image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
1523                               data, width, height, 8, scanline);                               width, height, 8, scanline);
1524          image->byte_order = MSBFirst;          image->byte_order = MSBFirst;
1525          image->bitmap_bit_order = MSBFirst;          image->bitmap_bit_order = MSBFirst;
1526          XInitImage(image);          XInitImage(image);
1527    
1528          XPutImage(display, bitmap, gc, image, 0, 0, 0, 0, width, height);          XPutImage(g_display, bitmap, gc, image, 0, 0, 0, 0, width, height);
1529    
1530          XFree(image);          XFree(image);
1531          XFreeGC(display, gc);          XFreeGC(g_display, gc);
1532          return (HGLYPH)bitmap;          return (HGLYPH) bitmap;
1533  }  }
1534    
1535  void  void
1536  ui_destroy_glyph(HGLYPH glyph)  ui_destroy_glyph(HGLYPH glyph)
1537  {  {
1538          XFreePixmap(display, (Pixmap)glyph);          XFreePixmap(g_display, (Pixmap) glyph);
1539  }  }
1540    
1541  HCURSOR  HCURSOR
1542  ui_create_cursor(unsigned int x, unsigned int y, int width,  ui_create_cursor(unsigned int x, unsigned int y, int width, int height,
1543                   int height, uint8 *andmask, uint8 *xormask)                   uint8 * andmask, uint8 * xormask)
1544  {  {
1545          HGLYPH maskglyph, cursorglyph;          HGLYPH maskglyph, cursorglyph;
1546          XColor bg, fg;          XColor bg, fg;
# Line 604  ui_create_cursor(unsigned int x, unsigne Line 1554  ui_create_cursor(unsigned int x, unsigne
1554          scanline = (width + 7) / 8;          scanline = (width + 7) / 8;
1555          offset = scanline * height;          offset = scanline * height;
1556    
1557          cursor = xmalloc(offset);          cursor = (uint8 *) xmalloc(offset);
1558          memset(cursor, 0, offset);          memset(cursor, 0, offset);
1559    
1560          mask = xmalloc(offset);          mask = (uint8 *) xmalloc(offset);
1561          memset(mask, 0, offset);          memset(mask, 0, offset);
1562    
1563          /* approximate AND and XOR masks with a monochrome X pointer */          /* approximate AND and XOR masks with a monochrome X pointer */
# Line 647  ui_create_cursor(unsigned int x, unsigne Line 1597  ui_create_cursor(unsigned int x, unsigne
1597    
1598          cursorglyph = ui_create_glyph(width, height, cursor);          cursorglyph = ui_create_glyph(width, height, cursor);
1599          maskglyph = ui_create_glyph(width, height, mask);          maskglyph = ui_create_glyph(width, height, mask);
1600            
1601          xcursor = XCreatePixmapCursor(display, (Pixmap)cursorglyph,          xcursor =
1602                                  (Pixmap)maskglyph, &fg, &bg, x, y);                  XCreatePixmapCursor(g_display, (Pixmap) cursorglyph,
1603                                        (Pixmap) maskglyph, &fg, &bg, x, y);
1604    
1605          ui_destroy_glyph(maskglyph);          ui_destroy_glyph(maskglyph);
1606          ui_destroy_glyph(cursorglyph);          ui_destroy_glyph(cursorglyph);
1607          xfree(mask);          xfree(mask);
1608          xfree(cursor);          xfree(cursor);
1609          return (HCURSOR)xcursor;          return (HCURSOR) xcursor;
1610  }  }
1611    
1612  void  void
1613  ui_set_cursor(HCURSOR cursor)  ui_set_cursor(HCURSOR cursor)
1614  {  {
1615          XDefineCursor(display, wnd, (Cursor)cursor);          g_current_cursor = (Cursor) cursor;
1616            XDefineCursor(g_display, g_wnd, g_current_cursor);
1617  }  }
1618    
1619  void  void
1620  ui_destroy_cursor(HCURSOR cursor)  ui_destroy_cursor(HCURSOR cursor)
1621  {  {
1622          XFreeCursor(display, (Cursor)cursor);          XFreeCursor(g_display, (Cursor) cursor);
1623    }
1624    
1625    void
1626    ui_set_null_cursor(void)
1627    {
1628            ui_set_cursor(g_null_cursor);
1629  }  }
1630    
1631  #define MAKE_XCOLOR(xc,c) \  #define MAKE_XCOLOR(xc,c) \
# Line 676  ui_destroy_cursor(HCURSOR cursor) Line 1634  ui_destroy_cursor(HCURSOR cursor)
1634                  (xc)->blue  = ((c)->blue  << 8) | (c)->blue; \                  (xc)->blue  = ((c)->blue  << 8) | (c)->blue; \
1635                  (xc)->flags = DoRed | DoGreen | DoBlue;                  (xc)->flags = DoRed | DoGreen | DoBlue;
1636    
1637    
1638  HCOLOURMAP  HCOLOURMAP
1639  ui_create_colourmap(COLOURMAP *colours)  ui_create_colourmap(COLOURMAP * colours)
1640  {  {
1641          COLOURENTRY *entry;          COLOURENTRY *entry;
1642          int i, ncolours = colours->ncolours;          int i, ncolours = colours->ncolours;
1643            if (!g_owncolmap)
         if (owncolmap)  
1644          {          {
1645                  XColor *xcolours, *xentry;                  uint32 *map = (uint32 *) xmalloc(sizeof(*g_colmap) * ncolours);
1646                  Colormap map;                  XColor xentry;
1647                    XColor xc_cache[256];
1648                  xcolours = xmalloc(sizeof(XColor) * ncolours);                  uint32 colour;
1649                    int colLookup = 256;
1650                  for (i = 0; i < ncolours; i++)                  for (i = 0; i < ncolours; i++)
1651                  {                  {
1652                          entry = &colours->colours[i];                          entry = &colours->colours[i];
1653                          xentry = &xcolours[i];                          MAKE_XCOLOR(&xentry, entry);
                         xentry->pixel = i;  
                         MAKE_XCOLOR(xentry, entry);  
                 }  
1654    
1655                  map = XCreateColormap(display, wnd, visual, AllocAll);                          if (XAllocColor(g_display, g_xcolmap, &xentry) == 0)
1656                  XStoreColors(display, map, xcolours, ncolours);                          {
1657                                    /* Allocation failed, find closest match. */
1658                                    int j = 256;
1659                                    int nMinDist = 3 * 256 * 256;
1660                                    long nDist = nMinDist;
1661    
1662                  xfree(xcolours);                                  /* only get the colors once */
1663                  return (HCOLOURMAP)map;                                  while (colLookup--)
1664                                    {
1665                                            xc_cache[colLookup].pixel = colLookup;
1666                                            xc_cache[colLookup].red = xc_cache[colLookup].green =
1667                                                    xc_cache[colLookup].blue = 0;
1668                                            xc_cache[colLookup].flags = 0;
1669                                            XQueryColor(g_display,
1670                                                        DefaultColormap(g_display,
1671                                                                        DefaultScreen(g_display)),
1672                                                        &xc_cache[colLookup]);
1673                                    }
1674                                    colLookup = 0;
1675    
1676                                    /* approximate the pixel */
1677                                    while (j--)
1678                                    {
1679                                            if (xc_cache[j].flags)
1680                                            {
1681                                                    nDist = ((long) (xc_cache[j].red >> 8) -
1682                                                             (long) (xentry.red >> 8)) *
1683                                                            ((long) (xc_cache[j].red >> 8) -
1684                                                             (long) (xentry.red >> 8)) +
1685                                                            ((long) (xc_cache[j].green >> 8) -
1686                                                             (long) (xentry.green >> 8)) *
1687                                                            ((long) (xc_cache[j].green >> 8) -
1688                                                             (long) (xentry.green >> 8)) +
1689                                                            ((long) (xc_cache[j].blue >> 8) -
1690                                                             (long) (xentry.blue >> 8)) *
1691                                                            ((long) (xc_cache[j].blue >> 8) -
1692                                                             (long) (xentry.blue >> 8));
1693                                            }
1694                                            if (nDist < nMinDist)
1695                                            {
1696                                                    nMinDist = nDist;
1697                                                    xentry.pixel = j;
1698                                            }
1699                                    }
1700                            }
1701                            colour = xentry.pixel;
1702    
1703                            /* update our cache */
1704                            if (xentry.pixel < 256)
1705                            {
1706                                    xc_cache[xentry.pixel].red = xentry.red;
1707                                    xc_cache[xentry.pixel].green = xentry.green;
1708                                    xc_cache[xentry.pixel].blue = xentry.blue;
1709    
1710                            }
1711    
1712                            map[i] = colour;
1713                    }
1714                    return map;
1715          }          }
1716          else          else
1717          {          {
1718                  uint32 *map = xmalloc(sizeof(*colmap) * ncolours);                  XColor *xcolours, *xentry;
1719                  XColor xentry;                  Colormap map;
                 uint32 colour;  
1720    
1721                    xcolours = (XColor *) xmalloc(sizeof(XColor) * ncolours);
1722                  for (i = 0; i < ncolours; i++)                  for (i = 0; i < ncolours; i++)
1723                  {                  {
1724                          entry = &colours->colours[i];                          entry = &colours->colours[i];
1725                          MAKE_XCOLOR(&xentry, entry);                          xentry = &xcolours[i];
1726                            xentry->pixel = i;
1727                          if (XAllocColor(display, xcolmap, &xentry) != 0)                          MAKE_XCOLOR(xentry, entry);
                                 colour = xentry.pixel;  
                         else  
                                 colour = white;  
   
                         /* byte swap here to make translate_image faster */  
                         map[i] = translate_colour(colour);  
1728                  }                  }
1729    
1730                  return map;                  map = XCreateColormap(g_display, g_wnd, g_visual, AllocAll);
1731                    XStoreColors(g_display, map, xcolours, ncolours);
1732    
1733                    xfree(xcolours);
1734                    return (HCOLOURMAP) map;
1735          }          }
1736  }  }
1737    
1738  void  void
1739  ui_destroy_colourmap(HCOLOURMAP map)  ui_destroy_colourmap(HCOLOURMAP map)
1740  {  {
1741          if (owncolmap)          if (!g_owncolmap)
                 XFreeColormap(display, (Colormap)map);  
         else  
1742                  xfree(map);                  xfree(map);
1743            else
1744                    XFreeColormap(g_display, (Colormap) map);
1745  }  }
1746    
1747  void  void
1748  ui_set_colourmap(HCOLOURMAP map)  ui_set_colourmap(HCOLOURMAP map)
1749  {  {
1750          if (owncolmap)          if (!g_owncolmap)
1751                  XSetWindowColormap(display, wnd, (Colormap)map);          {
1752                    if (g_colmap)
1753                            xfree(g_colmap);
1754    
1755                    g_colmap = (uint32 *) map;
1756            }
1757          else          else
1758                  colmap = map;                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);
1759  }  }
1760    
1761  void  void
# Line 753  ui_set_clip(int x, int y, int cx, int cy Line 1767  ui_set_clip(int x, int y, int cx, int cy
1767          rect.y = y;          rect.y = y;
1768          rect.width = cx;          rect.width = cx;
1769          rect.height = cy;          rect.height = cy;
1770          XSetClipRectangles(display, gc, 0, 0, &rect, 1, YXBanded);          XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);
1771  }  }
1772    
1773  void  void
1774  ui_reset_clip()  ui_reset_clip(void)
1775  {  {
1776          XRectangle rect;          XRectangle rect;
1777    
1778          rect.x = 0;          rect.x = 0;
1779          rect.y = 0;          rect.y = 0;
1780          rect.width = width;          rect.width = g_width;
1781          rect.height = height;          rect.height = g_height;
1782          XSetClipRectangles(display, gc, 0, 0, &rect, 1, YXBanded);          XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);
1783  }  }
1784    
1785  void  void
1786  ui_bell()  ui_bell(void)
1787  {  {
1788          XBell(display, 0);          XBell(g_display, 0);
1789  }  }
1790    
1791  void  void
# Line 783  ui_destblt(uint8 opcode, Line 1797  ui_destblt(uint8 opcode,
1797          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
1798  }  }
1799    
1800    static uint8 hatch_patterns[] = {
1801            0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, /* 0 - bsHorizontal */
1802            0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 1 - bsVertical */
1803            0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, /* 2 - bsFDiagonal */
1804            0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, /* 3 - bsBDiagonal */
1805            0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, /* 4 - bsCross */
1806            0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81  /* 5 - bsDiagCross */
1807    };
1808    
1809  void  void
1810  ui_patblt(uint8 opcode,  ui_patblt(uint8 opcode,
1811            /* dest */ int x, int y, int cx, int cy,            /* dest */ int x, int y, int cx, int cy,
1812            /* brush */ BRUSH *brush, int bgcolour, int fgcolour)            /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
1813  {  {
1814          Pixmap fill;          Pixmap fill;
1815            uint8 i, ipattern[8];
1816    
1817          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
1818    
# Line 796  ui_patblt(uint8 opcode, Line 1820  ui_patblt(uint8 opcode,
1820          {          {
1821                  case 0: /* Solid */                  case 0: /* Solid */
1822                          SET_FOREGROUND(fgcolour);                          SET_FOREGROUND(fgcolour);
1823                          FILL_RECTANGLE(x, y, cx, cy);                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
1824                          break;                          break;
1825    
1826                  case 3: /* Pattern */                  case 2: /* Hatch */
1827                          fill = (Pixmap)ui_create_glyph(8, 8, brush->pattern);                          fill = (Pixmap) ui_create_glyph(8, 8,
1828                                                            hatch_patterns + brush->pattern[0] * 8);
1829                            SET_FOREGROUND(fgcolour);
1830                            SET_BACKGROUND(bgcolour);
1831                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
1832                            XSetStipple(g_display, g_gc, fill);
1833                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
1834                            FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
1835                            XSetFillStyle(g_display, g_gc, FillSolid);
1836                            XSetTSOrigin(g_display, g_gc, 0, 0);
1837                            ui_destroy_glyph((HGLYPH) fill);
1838                            break;
1839    
1840                    case 3: /* Pattern */
1841                            for (i = 0; i != 8; i++)
1842                                    ipattern[7 - i] = brush->pattern[i];
1843                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
1844                          SET_FOREGROUND(bgcolour);                          SET_FOREGROUND(bgcolour);
1845                          SET_BACKGROUND(fgcolour);                          SET_BACKGROUND(fgcolour);
1846                          XSetFillStyle(display, gc, FillOpaqueStippled);                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
1847                          XSetStipple(display, gc, fill);                          XSetStipple(g_display, g_gc, fill);
1848                          XSetTSOrigin(display, gc, brush->xorigin, brush->yorigin);                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
1849                            FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
1850                          FILL_RECTANGLE(x, y, cx, cy);                          XSetFillStyle(g_display, g_gc, FillSolid);
1851                            XSetTSOrigin(g_display, g_gc, 0, 0);
1852                          XSetFillStyle(display, gc, FillSolid);                          ui_destroy_glyph((HGLYPH) fill);
                         ui_destroy_glyph((HGLYPH)fill);  
1853                          break;                          break;
1854    
1855                  default:                  default:
# Line 819  ui_patblt(uint8 opcode, Line 1857  ui_patblt(uint8 opcode,
1857          }          }
1858    
1859          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
1860    
1861            if (g_ownbackstore)
1862                    XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
1863  }  }
1864    
1865  void  void
# Line 827  ui_screenblt(uint8 opcode, Line 1868  ui_screenblt(uint8 opcode,
1868               /* src */ int srcx, int srcy)               /* src */ int srcx, int srcy)
1869  {  {
1870          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
1871          XCopyArea(display, wnd, wnd, gc, srcx, srcy, cx, cy, x, y);          if (g_ownbackstore)
1872          if (ownbackstore)          {
1873                  XCopyArea(display, backstore, backstore, gc, srcx, srcy,                  if (g_Unobscured)
1874                            cx, cy, x, y);                  {
1875                            XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
1876                            XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x,
1877                                      y);
1878                    }
1879                    else
1880                    {
1881                            XCopyArea(g_display, g_backstore, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
1882                            XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x,
1883                                      y);
1884                    }
1885            }
1886            else
1887            {
1888                    XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
1889            }
1890          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
1891  }  }
1892    
# Line 840  ui_memblt(uint8 opcode, Line 1896  ui_memblt(uint8 opcode,
1896            /* src */ HBITMAP src, int srcx, int srcy)            /* src */ HBITMAP src, int srcx, int srcy)
1897  {  {
1898          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
1899          XCopyArea(display, (Pixmap)src, wnd, gc, srcx, srcy, cx, cy, x, y);          XCopyArea(g_display, (Pixmap) src, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
1900          if (ownbackstore)          if (g_ownbackstore)
1901                  XCopyArea(display, (Pixmap)src, backstore, gc, srcx, srcy,                  XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
                           cx, cy, x, y);  
1902          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
1903  }  }
1904    
# Line 851  void Line 1906  void
1906  ui_triblt(uint8 opcode,  ui_triblt(uint8 opcode,
1907            /* dest */ int x, int y, int cx, int cy,            /* dest */ int x, int y, int cx, int cy,
1908            /* src */ HBITMAP src, int srcx, int srcy,            /* src */ HBITMAP src, int srcx, int srcy,
1909            /* brush */ BRUSH *brush, int bgcolour, int fgcolour)            /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
1910  {  {
1911          /* This is potentially difficult to do in general. Until someone          /* This is potentially difficult to do in general. Until someone
1912             comes up with a more efficient way of doing it I am using cases. */             comes up with a more efficient way of doing it I am using cases. */
# Line 860  ui_triblt(uint8 opcode, Line 1915  ui_triblt(uint8 opcode,
1915          {          {
1916                  case 0x69:      /* PDSxxn */                  case 0x69:      /* PDSxxn */
1917                          ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);                          ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);
1918                          ui_patblt(ROP2_NXOR, x, y, cx, cy,                          ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour, fgcolour);
                                   brush, bgcolour, fgcolour);  
1919                          break;                          break;
1920    
1921                  case 0xb8:      /* PSDPxax */                  case 0xb8:      /* PSDPxax */
1922                          ui_patblt(ROP2_XOR, x, y, cx, cy,                          ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
                                   brush, bgcolour, fgcolour);  
1923                          ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);                          ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);
1924                          ui_patblt(ROP2_XOR, x, y, cx, cy,                          ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
                                   brush, bgcolour, fgcolour);  
1925                          break;                          break;
1926    
1927                  case 0xc0:      /* PSa */                  case 0xc0:      /* PSa */
1928                          ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);                          ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
1929                          ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour,                          ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour, fgcolour);
                                   fgcolour);  
1930                          break;                          break;
1931    
1932                  default:                  default:
# Line 887  ui_triblt(uint8 opcode, Line 1938  ui_triblt(uint8 opcode,
1938  void  void
1939  ui_line(uint8 opcode,  ui_line(uint8 opcode,
1940          /* dest */ int startx, int starty, int endx, int endy,          /* dest */ int startx, int starty, int endx, int endy,
1941          /* pen */ PEN *pen)          /* pen */ PEN * pen)
1942  {  {
1943          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
1944          SET_FOREGROUND(pen->colour);          SET_FOREGROUND(pen->colour);
1945          XDrawLine(display, wnd, gc, startx, starty, endx, endy);          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
1946          if (ownbackstore)          if (g_ownbackstore)
1947                  XDrawLine(display, backstore, gc, startx, starty, endx, endy);                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
1948          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
1949  }  }
1950    
# Line 906  ui_rect( Line 1957  ui_rect(
1957          FILL_RECTANGLE(x, y, cx, cy);          FILL_RECTANGLE(x, y, cx, cy);
1958  }  }
1959    
1960    /* warning, this function only draws on wnd or backstore, not both */
1961  void  void
1962  ui_draw_glyph(int mixmode,  ui_draw_glyph(int mixmode,
1963                /* dest */ int x, int y, int cx, int cy,                /* dest */ int x, int y, int cx, int cy,
1964                /* src */ HGLYPH glyph, int srcx, int srcy, int bgcolour,                /* src */ HGLYPH glyph, int srcx, int srcy,
1965                int fgcolour)                int bgcolour, int fgcolour)
1966  {  {
1967          SET_FOREGROUND(fgcolour);          SET_FOREGROUND(fgcolour);
1968          SET_BACKGROUND(bgcolour);          SET_BACKGROUND(bgcolour);
1969    
1970          XSetFillStyle(display, gc, (mixmode == MIX_TRANSPARENT)          XSetFillStyle(g_display, g_gc,
1971                        ? FillStippled : FillOpaqueStippled);                        (mixmode == MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled);
1972          XSetStipple(display, gc, (Pixmap)glyph);          XSetStipple(g_display, g_gc, (Pixmap) glyph);
1973          XSetTSOrigin(display, gc, x, y);          XSetTSOrigin(g_display, g_gc, x, y);
1974    
1975          FILL_RECTANGLE(x, y, cx, cy);          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
1976    
1977          XSetFillStyle(display, gc, FillSolid);          XSetFillStyle(g_display, g_gc, FillSolid);
1978    }
1979    
1980    #define DO_GLYPH(ttext,idx) \
1981    {\
1982      glyph = cache_get_font (font, ttext[idx]);\
1983      if (!(flags & TEXT2_IMPLICIT_X))\
1984      {\
1985        xyoffset = ttext[++idx];\
1986        if ((xyoffset & 0x80))\
1987        {\
1988          if (flags & TEXT2_VERTICAL)\
1989            y += ttext[idx+1] | (ttext[idx+2] << 8);\
1990          else\
1991            x += ttext[idx+1] | (ttext[idx+2] << 8);\
1992          idx += 2;\
1993        }\
1994        else\
1995        {\
1996          if (flags & TEXT2_VERTICAL)\
1997            y += xyoffset;\
1998          else\
1999            x += xyoffset;\
2000        }\
2001      }\
2002      if (glyph != NULL)\
2003      {\
2004        x1 = x + glyph->offset;\
2005        y1 = y + glyph->baseline;\
2006        XSetStipple(g_display, g_gc, (Pixmap) glyph->pixmap);\
2007        XSetTSOrigin(g_display, g_gc, x1, y1);\
2008        FILL_RECTANGLE_BACKSTORE(x1, y1, glyph->width, glyph->height);\
2009        if (flags & TEXT2_IMPLICIT_X)\
2010          x += glyph->width;\
2011      }\
2012  }  }
2013    
2014  void  void
2015  ui_draw_text(uint8 font, uint8 flags, int mixmode, int x, int y,  ui_draw_text(uint8 font, uint8 flags, int mixmode, int x, int y,
2016               int clipx, int clipy, int clipcx, int clipcy,               int clipx, int clipy, int clipcx, int clipcy,
2017               int boxx, int boxy, int boxcx, int boxcy,               int boxx, int boxy, int boxcx, int boxcy, int bgcolour,
2018               int bgcolour, int fgcolour, uint8 *text, uint8 length)               int fgcolour, uint8 * text, uint8 length)
2019  {  {
2020          FONTGLYPH *glyph;          FONTGLYPH *glyph;
2021          int i, offset;          int i, j, xyoffset, x1, y1;
2022            DATABLOB *entry;
2023    
2024          SET_FOREGROUND(bgcolour);          SET_FOREGROUND(bgcolour);
2025    
2026            /* Sometimes, the boxcx value is something really large, like
2027               32691. This makes XCopyArea fail with Xvnc. The code below
2028               is a quick fix. */
2029            if (boxx + boxcx > g_width)
2030                    boxcx = g_width - boxx;
2031    
2032          if (boxcx > 1)          if (boxcx > 1)
2033          {          {
2034                  FILL_RECTANGLE(boxx, boxy, boxcx, boxcy);                  FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);
2035          }          }
2036          else if (mixmode == MIX_OPAQUE)          else if (mixmode == MIX_OPAQUE)
2037          {          {
2038                  FILL_RECTANGLE(clipx, clipy, clipcx, clipcy);                  FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);
2039          }          }
2040    
2041            SET_FOREGROUND(fgcolour);
2042            SET_BACKGROUND(bgcolour);
2043            XSetFillStyle(g_display, g_gc, FillStippled);
2044    
2045          /* Paint text, character by character */          /* Paint text, character by character */
2046          for (i = 0; i < length; i++)          for (i = 0; i < length;)
2047          {          {
2048                  glyph = cache_get_font(font, text[i]);                  switch (text[i])
   
                 if (!(flags & TEXT2_IMPLICIT_X))  
2049                  {                  {
2050                          offset = text[++i];                          case 0xff:
2051                          if (offset & 0x80)                                  if (i + 2 < length)
2052                                  offset = ((offset & 0x7f) << 8) | text[++i];                                          cache_put_text(text[i + 1], text, text[i + 2]);
2053                                    else
2054                                    {
2055                                            error("this shouldn't be happening\n");
2056                                            exit(1);
2057                                    }
2058                                    /* this will move pointer from start to first character after FF command */
2059                                    length -= i + 3;
2060                                    text = &(text[i + 3]);
2061                                    i = 0;
2062                                    break;
2063    
2064                          if (flags & TEXT2_VERTICAL)                          case 0xfe:
2065                                  y += offset;                                  entry = cache_get_text(text[i + 1]);
2066                          else                                  if (entry != NULL)
2067                                  x += offset;                                  {
2068                                            if ((((uint8 *) (entry->data))[1] ==
2069                                                 0) && (!(flags & TEXT2_IMPLICIT_X)))
2070                                            {
2071                                                    if (flags & TEXT2_VERTICAL)
2072                                                            y += text[i + 2];
2073                                                    else
2074                                                            x += text[i + 2];
2075                                            }
2076                                            for (j = 0; j < entry->size; j++)
2077                                                    DO_GLYPH(((uint8 *) (entry->data)), j);
2078                                    }
2079                                    if (i + 2 < length)
2080                                            i += 3;
2081                                    else
2082                                            i += 2;
2083                                    length -= i;
2084                                    /* this will move pointer from start to first character after FE command */
2085                                    text = &(text[i]);
2086                                    i = 0;
2087                                    break;
2088    
2089                            default:
2090                                    DO_GLYPH(text, i);
2091                                    i++;
2092                                    break;
2093                  }                  }
2094            }
2095    
2096                  if (glyph != NULL)          XSetFillStyle(g_display, g_gc, FillSolid);
                 {  
                         ui_draw_glyph(mixmode, x + (short) glyph->offset,  
                                       y + (short) glyph->baseline,  
                                       glyph->width, glyph->height,  
                                       glyph->pixmap, 0, 0,  
                                       bgcolour, fgcolour);  
2097    
2098                          if (flags & TEXT2_IMPLICIT_X)          if (g_ownbackstore)
2099                                  x += glyph->width;          {
2100                  }                  if (boxcx > 1)
2101                            XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
2102                                      boxy, boxcx, boxcy, boxx, boxy);
2103                    else
2104                            XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
2105                                      clipy, clipcx, clipcy, clipx, clipy);
2106          }          }
2107  }  }
2108    
# Line 982  ui_desktop_save(uint32 offset, int x, in Line 2112  ui_desktop_save(uint32 offset, int x, in
2112          Pixmap pix;          Pixmap pix;
2113          XImage *image;          XImage *image;
2114    
2115          if (ownbackstore)          if (g_ownbackstore)
2116          {          {
2117                  image = XGetImage(display, backstore, x, y, cx, cy, AllPlanes,                  image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
                                   ZPixmap);  
2118          }          }
2119          else          else
2120          {          {
2121                  pix = XCreatePixmap(display, wnd, cx, cy, depth);                  pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);
2122                  XCopyArea(display, wnd, pix, gc, x, y, cx, cy, 0, 0);                  XCopyArea(g_display, g_wnd, pix, g_gc, x, y, cx, cy, 0, 0);
2123                  image = XGetImage(display, pix, 0, 0, cx, cy, AllPlanes,                  image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
2124                                    ZPixmap);                  XFreePixmap(g_display, pix);
                 XFreePixmap(display, pix);  
2125          }          }
2126    
2127          offset *= bpp/8;          offset *= g_bpp / 8;
2128          cache_put_desktop(offset, cx, cy, image->bytes_per_line,          cache_put_desktop(offset, cx, cy, image->bytes_per_line, g_bpp / 8, (uint8 *) image->data);
                           bpp/8, image->data);  
2129    
2130          XDestroyImage(image);          XDestroyImage(image);
2131  }  }
# Line 1009  ui_desktop_restore(uint32 offset, int x, Line 2136  ui_desktop_restore(uint32 offset, int x,
2136          XImage *image;          XImage *image;
2137          uint8 *data;          uint8 *data;
2138    
2139          offset *= bpp/8;          offset *= g_bpp / 8;
2140          data = cache_get_desktop(offset, cx, cy, bpp/8);          data = cache_get_desktop(offset, cx, cy, g_bpp / 8);
2141          if (data == NULL)          if (data == NULL)
2142                  return;                  return;
2143    
2144          image = XCreateImage(display, visual, depth, ZPixmap,          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2145                               0, data, cx, cy, BitmapPad(display),                               (char *) data, cx, cy, BitmapPad(g_display), cx * g_bpp / 8);
                              cx * bpp/8);  
2146    
2147          if (ownbackstore)          if (g_ownbackstore)
2148          {          {
2149                  XPutImage(display, backstore, gc, image, 0, 0, x, y, cx, cy);                  XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
2150                  XCopyArea(display, backstore, wnd, gc, x, y, cx, cy, x, y);                  XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2151          }          }
2152          else          else
2153          {          {
2154                  XPutImage(display, wnd, gc, image, 0, 0, x, y, cx, cy);                  XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
2155          }          }
2156    
2157          XFree(image);          XFree(image);

Legend:
Removed from v.34  
changed lines
  Added in v.708

  ViewVC Help
Powered by ViewVC 1.1.26