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

Diff of /jpeg/rdesktop/trunk/xwin.c

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

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

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

  ViewVC Help
Powered by ViewVC 1.1.26