/[rdesktop]/jpeg/rdesktop/trunk/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 /jpeg/rdesktop/trunk/xwin.c

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

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

Legend:
Removed from v.7  
changed lines
  Added in v.1042

  ViewVC Help
Powered by ViewVC 1.1.26