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

Diff of /sourceforge.net/branches/seamlessrdp-branch/rdesktop/xwin.c

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

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

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

  ViewVC Help
Powered by ViewVC 1.1.26