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

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

  ViewVC Help
Powered by ViewVC 1.1.26