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

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

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

revision 7 by matty, Fri Jul 7 09:40:03 2000 UTC revision 517 by matthewc, Tue Oct 28 03:30:51 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          display = XOpenDisplay(NULL);  BOOL
643          if (display == NULL)  get_key_state(unsigned int state, uint32 keysym)
644                  return NULL;  {
645            int modifierpos, key, keysymMask = 0;
646            int offset;
647    
648          black = BlackPixel(display, DefaultScreen(display));          KeyCode keycode = XKeysymToKeycode(g_display, keysym);
         window = XCreateSimpleWindow(display, DefaultRootWindow(display),  
                                 0, 0, width, height, 0, black, black);  
649    
650          XMapWindow(display, window);          if (keycode == NoSymbol)
651          XSync(display, True);                  return False;
652    
653          gc = XCreateGC(display, window, 0, NULL);          for (modifierpos = 0; modifierpos < 8; modifierpos++)
654            {
655                    offset = g_mod_map->max_keypermod * modifierpos;
656    
657          wnd = xmalloc(sizeof(struct window));                  for (key = 0; key < g_mod_map->max_keypermod; key++)
658          wnd->display = display;                  {
659          wnd->wnd = window;                          if (g_mod_map->modifiermap[offset + key] == keycode)
660          wnd->gc = gc;                                  keysymMask |= 1 << modifierpos;
661          wnd->visual = DefaultVisual(wnd->display, DefaultScreen(wnd->display));                  }
662            }
663    
664          return wnd;          return (state & keysymMask) ? True : False;
665  }  }
666    
667  void ui_destroy_window(HWINDOW wnd)  BOOL
668    ui_init(void)
669  {  {
670          XFreeGC(wnd->display, wnd->gc);          XPixmapFormatValues *pfm;
671          XDestroyWindow(wnd->display, wnd->wnd);          uint16 test;
672          XCloseDisplay(wnd->display);          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            /* private colour map code only works for 8 bpp */
709            if (g_owncolmap && (g_bpp > 8))
710                    g_owncolmap = False;
711    
712            if (!g_owncolmap)
713            {
714                    g_xcolmap = DefaultColormapOfScreen(g_screen);
715                    if (g_depth <= 8)
716                            warning("Screen depth is 8 bits or lower: you may want to use -C for a private colourmap\n");
717            }
718    
719            g_gc = XCreateGC(g_display, RootWindowOfScreen(g_screen), 0, NULL);
720    
721            if (DoesBackingStore(g_screen) != Always)
722                    g_ownbackstore = True;
723    
724            test = 1;
725            g_host_be = !(BOOL) (*(uint8 *) (&test));
726            g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
727    
728            /*
729             * Determine desktop size
730             */
731            if (g_width < 0)
732            {
733                    /* Percent of screen */
734                    g_height = HeightOfScreen(g_screen) * (-g_width) / 100;
735                    g_width = WidthOfScreen(g_screen) * (-g_width) / 100;
736            }
737            else if (g_width == 0)
738            {
739                    /* Fetch geometry from _NET_WORKAREA */
740                    uint32 x, y, cx, cy;
741    
742                    if (get_current_workarea(&x, &y, &cx, &cy) == 0)
743                    {
744                            g_width = cx;
745                            g_height = cy;
746                    }
747                    else
748                    {
749                            warning("Failed to get workarea: probably your window manager does not support extended hints\n");
750                            g_width = 800;
751                            g_height = 600;
752                    }
753            }
754            else if (g_fullscreen)
755            {
756                    g_width = WidthOfScreen(g_screen);
757                    g_height = HeightOfScreen(g_screen);
758            }
759    
760            /* make sure width is a multiple of 4 */
761            g_width = (g_width + 3) & ~3;
762    
763            if (g_ownbackstore)
764            {
765                    g_backstore =
766                            XCreatePixmap(g_display, RootWindowOfScreen(g_screen), g_width, g_height,
767                                          g_depth);
768    
769                    /* clear to prevent rubbish being exposed at startup */
770                    XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
771                    XFillRectangle(g_display, g_backstore, g_gc, 0, 0, g_width, g_height);
772            }
773    
774            g_mod_map = XGetModifierMapping(g_display);
775    
776            xkeymap_init();
777    
778            if (g_enable_compose)
779                    g_IM = XOpenIM(g_display, NULL, NULL, NULL);
780    
781            xclip_init();
782    
783            /* todo take this out when high colour is done */
784            printf("server bpp %d client bpp %d depth %d\n", g_server_bpp, g_bpp, g_depth);
785    
786            return True;
787  }  }
788    
789  HBITMAP ui_create_bitmap(HWINDOW wnd, int width, int height, uint8 *data)  void
790    ui_deinit(void)
791    {
792            if (g_IM != NULL)
793                    XCloseIM(g_IM);
794    
795            XFreeModifiermap(g_mod_map);
796    
797            if (g_ownbackstore)
798                    XFreePixmap(g_display, g_backstore);
799    
800            XFreeGC(g_display, g_gc);
801            XCloseDisplay(g_display);
802            g_display = NULL;
803    }
804    
805    #define NULL_POINTER_MASK       "\x80"
806    #define NULL_POINTER_DATA       "\x0\x0\x0"
807            
808    BOOL
809    ui_create_window(void)
810    {
811            XSetWindowAttributes attribs;
812            XClassHint *classhints;
813            XSizeHints *sizehints;
814            int wndwidth, wndheight;
815            long input_mask, ic_input_mask;
816            XEvent xevent;
817    
818            wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
819            wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
820    
821            attribs.background_pixel = BlackPixelOfScreen(g_screen);
822            attribs.backing_store = g_ownbackstore ? NotUseful : Always;
823            attribs.override_redirect = g_fullscreen;
824    
825            g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), 0, 0, wndwidth, wndheight,
826                                  0, CopyFromParent, InputOutput, CopyFromParent,
827                                  CWBackPixel | CWBackingStore | CWOverrideRedirect, &attribs);
828    
829            XStoreName(g_display, g_wnd, g_title);
830    
831            if (g_hide_decorations)
832                    mwm_hide_decorations();
833    
834            classhints = XAllocClassHint();
835            if (classhints != NULL)
836            {
837                    classhints->res_name = classhints->res_class = "rdesktop";
838                    XSetClassHint(g_display, g_wnd, classhints);
839                    XFree(classhints);
840            }
841    
842            sizehints = XAllocSizeHints();
843            if (sizehints)
844            {
845                    sizehints->flags = PMinSize | PMaxSize;
846                    sizehints->min_width = sizehints->max_width = g_width;
847                    sizehints->min_height = sizehints->max_height = g_height;
848                    XSetWMNormalHints(g_display, g_wnd, sizehints);
849                    XFree(sizehints);
850            }
851    
852            input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
853                    VisibilityChangeMask | FocusChangeMask;
854    
855            if (g_sendmotion)
856                    input_mask |= PointerMotionMask;
857            if (g_ownbackstore)
858                    input_mask |= ExposureMask;
859            if (g_fullscreen || g_grab_keyboard)
860                    input_mask |= EnterWindowMask;
861            if (g_grab_keyboard)
862                    input_mask |= LeaveWindowMask;
863    
864            if (g_IM != NULL)
865            {
866                    g_IC = XCreateIC(g_IM, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing),
867                                     XNClientWindow, g_wnd, XNFocusWindow, g_wnd, NULL);
868    
869                    if ((g_IC != NULL)
870                        && (XGetICValues(g_IC, XNFilterEvents, &ic_input_mask, NULL) == NULL))
871                            input_mask |= ic_input_mask;
872            }
873    
874            XSelectInput(g_display, g_wnd, input_mask);
875            XMapWindow(g_display, g_wnd);
876    
877            /* wait for VisibilityNotify */
878            do
879            {
880                    XMaskEvent(g_display, VisibilityChangeMask, &xevent);
881            }
882            while (xevent.type != VisibilityNotify);
883    
884            g_focused = False;
885            g_mouse_in_wnd = False;
886    
887            /* handle the WM_DELETE_WINDOW protocol */
888            g_protocol_atom = XInternAtom(g_display, "WM_PROTOCOLS", True);
889            g_kill_atom = XInternAtom(g_display, "WM_DELETE_WINDOW", True);
890            XSetWMProtocols(g_display, g_wnd, &g_kill_atom, 1);
891    
892            /* create invisible 1x1 cursor to be used as null cursor */
893            g_null_cursor = ui_create_cursor(0, 0, 1, 1, NULL_POINTER_MASK, NULL_POINTER_DATA);
894    
895            return True;
896    }
897    
898    void
899    ui_destroy_window(void)
900    {
901            ui_destroy_cursor(g_null_cursor);
902            
903            if (g_IC != NULL)
904                    XDestroyIC(g_IC);
905    
906            XDestroyWindow(g_display, g_wnd);
907    }
908    
909    void
910    xwin_toggle_fullscreen(void)
911    {
912            Pixmap contents = 0;
913    
914            if (!g_ownbackstore)
915            {
916                    /* need to save contents of window */
917                    contents = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
918                    XCopyArea(g_display, g_wnd, contents, g_gc, 0, 0, g_width, g_height, 0, 0);
919            }
920    
921            ui_destroy_window();
922            g_fullscreen = !g_fullscreen;
923            ui_create_window();
924    
925            XDefineCursor(g_display, g_wnd, g_current_cursor);
926    
927            if (!g_ownbackstore)
928            {
929                    XCopyArea(g_display, contents, g_wnd, g_gc, 0, 0, g_width, g_height, 0, 0);
930                    XFreePixmap(g_display, contents);
931            }
932    }
933    
934    /* Process all events in Xlib queue
935       Returns 0 after user quit, 1 otherwise */
936    static int
937    xwin_process_events(void)
938    {
939            XEvent xevent;
940            KeySym keysym;
941            uint16 button, flags;
942            uint32 ev_time;
943            key_translation tr;
944            char str[256];
945            Status status;
946            unsigned int state;
947            Window wdummy;
948            int dummy;
949    
950            while (XPending(g_display) > 0)
951            {
952                    XNextEvent(g_display, &xevent);
953    
954                    if ((g_IC != NULL) && (XFilterEvent(&xevent, None) == True))
955                    {
956                            DEBUG_KBD(("Filtering event\n"));
957                            continue;
958                    }
959    
960                    flags = 0;
961    
962                    switch (xevent.type)
963                    {
964                            case ClientMessage:
965                                    /* the window manager told us to quit */
966                                    if ((xevent.xclient.message_type == g_protocol_atom)
967                                        && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))
968                                            /* Quit */
969                                            return 0;
970                                    break;
971    
972                            case KeyPress:
973                                    g_last_gesturetime = xevent.xkey.time;
974                                    if (g_IC != NULL)
975                                            /* Multi_key compatible version */
976                                    {
977                                            XmbLookupString(g_IC,
978                                                            &xevent.xkey, str, sizeof(str), &keysym,
979                                                            &status);
980                                            if (!((status == XLookupKeySym) || (status == XLookupBoth)))
981                                            {
982                                                    error("XmbLookupString failed with status 0x%x\n",
983                                                          status);
984                                                    break;
985                                            }
986                                    }
987                                    else
988                                    {
989                                            /* Plain old XLookupString */
990                                            DEBUG_KBD(("\nNo input context, using XLookupString\n"));
991                                            XLookupString((XKeyEvent *) & xevent,
992                                                          str, sizeof(str), &keysym, NULL);
993                                    }
994    
995                                    DEBUG_KBD(("KeyPress for (keysym 0x%lx, %s)\n", keysym,
996                                               get_ksname(keysym)));
997    
998                                    ev_time = time(NULL);
999                                    if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
1000                                            break;
1001    
1002                                    tr = xkeymap_translate_key(keysym,
1003                                                               xevent.xkey.keycode, xevent.xkey.state);
1004    
1005                                    if (tr.scancode == 0)
1006                                            break;
1007    
1008                                    save_remote_modifiers(tr.scancode);
1009                                    ensure_remote_modifiers(ev_time, tr);
1010                                    rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);
1011                                    restore_remote_modifiers(ev_time, tr.scancode);
1012    
1013                                    break;
1014    
1015                            case KeyRelease:
1016                                    g_last_gesturetime = xevent.xkey.time;
1017                                    XLookupString((XKeyEvent *) & xevent, str,
1018                                                  sizeof(str), &keysym, NULL);
1019    
1020                                    DEBUG_KBD(("\nKeyRelease for (keysym 0x%lx, %s)\n", keysym,
1021                                               get_ksname(keysym)));
1022    
1023                                    ev_time = time(NULL);
1024                                    if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
1025                                            break;
1026    
1027                                    tr = xkeymap_translate_key(keysym,
1028                                                               xevent.xkey.keycode, xevent.xkey.state);
1029    
1030                                    if (tr.scancode == 0)
1031                                            break;
1032    
1033                                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);
1034                                    break;
1035    
1036                            case ButtonPress:
1037                                    flags = MOUSE_FLAG_DOWN;
1038                                    /* fall through */
1039    
1040                            case ButtonRelease:
1041                                    g_last_gesturetime = xevent.xbutton.time;
1042                                    button = xkeymap_translate_button(xevent.xbutton.button);
1043                                    if (button == 0)
1044                                            break;
1045    
1046                                    /* If win_button_size is nonzero, enable single app mode */
1047                                    if (xevent.xbutton.y < g_win_button_size)
1048                                    {
1049                                            /* Stop moving window when button is released, regardless of cursor position */
1050                                            if (g_moving_wnd && (xevent.type == ButtonRelease))
1051                                                    g_moving_wnd = False;
1052    
1053                                            /*  Check from right to left: */
1054    
1055                                            if (xevent.xbutton.x >= g_width - g_win_button_size)
1056                                            {
1057                                                    /* The close button, continue */
1058                                                    ;
1059                                            }
1060                                            else if (xevent.xbutton.x >=
1061                                                     g_width - g_win_button_size * 2)
1062                                            {
1063                                                    /* The maximize/restore button. Do not send to
1064                                                       server.  It might be a good idea to change the
1065                                                       cursor or give some other visible indication
1066                                                       that rdesktop inhibited this click */
1067                                                    break;
1068                                            }
1069                                            else if (xevent.xbutton.x >=
1070                                                     g_width - g_win_button_size * 3)
1071                                            {
1072                                                    /* The minimize button. Iconify window. */
1073                                                    XIconifyWindow(g_display, g_wnd,
1074                                                                   DefaultScreen(g_display));
1075                                                    break;
1076                                            }
1077                                            else if (xevent.xbutton.x <= g_win_button_size)
1078                                            {
1079                                                    /* The system menu. Ignore. */
1080                                                    break;
1081                                            }
1082                                            else
1083                                            {
1084                                                    /* The title bar. */
1085                                                    if ((xevent.type == ButtonPress) && !g_fullscreen
1086                                                        && g_hide_decorations)
1087                                                    {
1088                                                            g_moving_wnd = True;
1089                                                            g_move_x_offset = xevent.xbutton.x;
1090                                                            g_move_y_offset = xevent.xbutton.y;
1091                                                    }
1092                                                    break;
1093    
1094                                            }
1095                                    }
1096    
1097                                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1098                                                   flags | button, xevent.xbutton.x, xevent.xbutton.y);
1099                                    break;
1100    
1101                            case MotionNotify:
1102                                    if (g_moving_wnd)
1103                                    {
1104                                            XMoveWindow(g_display, g_wnd,
1105                                                        xevent.xmotion.x_root - g_move_x_offset,
1106                                                        xevent.xmotion.y_root - g_move_y_offset);
1107                                            break;
1108                                    }
1109    
1110                                    if (g_fullscreen && !g_focused)
1111                                            XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1112                                                           CurrentTime);
1113                                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1114                                                   MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);
1115                                    break;
1116    
1117                            case FocusIn:
1118                                    if (xevent.xfocus.mode == NotifyGrab)
1119                                            break;
1120                                    g_focused = True;
1121                                    XQueryPointer(g_display, g_wnd, &wdummy, &wdummy, &dummy, &dummy,
1122                                                  &dummy, &dummy, &state);
1123                                    reset_modifier_keys(state);
1124                                    if (g_grab_keyboard && g_mouse_in_wnd)
1125                                            XGrabKeyboard(g_display, g_wnd, True,
1126                                                          GrabModeAsync, GrabModeAsync, CurrentTime);
1127                                    break;
1128    
1129                            case FocusOut:
1130                                    if (xevent.xfocus.mode == NotifyUngrab)
1131                                            break;
1132                                    g_focused = False;
1133                                    if (xevent.xfocus.mode == NotifyWhileGrabbed)
1134                                            XUngrabKeyboard(g_display, CurrentTime);
1135                                    break;
1136    
1137                            case EnterNotify:
1138                                    /* we only register for this event when in fullscreen mode */
1139                                    /* or grab_keyboard */
1140                                    g_mouse_in_wnd = True;
1141                                    if (g_fullscreen)
1142                                    {
1143                                            XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1144                                                           CurrentTime);
1145                                            break;
1146                                    }
1147                                    if (g_focused)
1148                                            XGrabKeyboard(g_display, g_wnd, True,
1149                                                          GrabModeAsync, GrabModeAsync, CurrentTime);
1150                                    break;
1151    
1152                            case LeaveNotify:
1153                                    /* we only register for this event when grab_keyboard */
1154                                    g_mouse_in_wnd = False;
1155                                    XUngrabKeyboard(g_display, CurrentTime);
1156                                    break;
1157    
1158                            case Expose:
1159                                    XCopyArea(g_display, g_backstore, g_wnd, g_gc,
1160                                              xevent.xexpose.x, xevent.xexpose.y,
1161                                              xevent.xexpose.width,
1162                                              xevent.xexpose.height,
1163                                              xevent.xexpose.x, xevent.xexpose.y);
1164                                    break;
1165    
1166                            case MappingNotify:
1167                                    /* Refresh keyboard mapping if it has changed. This is important for
1168                                       Xvnc, since it allocates keycodes dynamically */
1169                                    if (xevent.xmapping.request == MappingKeyboard
1170                                        || xevent.xmapping.request == MappingModifier)
1171                                            XRefreshKeyboardMapping(&xevent.xmapping);
1172    
1173                                    if (xevent.xmapping.request == MappingModifier)
1174                                    {
1175                                            XFreeModifiermap(g_mod_map);
1176                                            g_mod_map = XGetModifierMapping(g_display);
1177                                    }
1178                                    break;
1179    
1180                                    /* clipboard stuff */
1181                            case SelectionNotify:
1182                                    xclip_handle_SelectionNotify(&xevent.xselection);
1183                                    break;
1184                            case SelectionRequest:
1185                                    xclip_handle_SelectionRequest(&xevent.xselectionrequest);
1186                                    break;
1187                            case SelectionClear:
1188                                    xclip_handle_SelectionClear();
1189                                    break;
1190                            case PropertyNotify:
1191                                    xclip_handle_PropertyNotify(&xevent.xproperty);
1192                                    break;
1193                    }
1194            }
1195            /* Keep going */
1196            return 1;
1197    }
1198    
1199    /* Returns 0 after user quit, 1 otherwise */
1200    int
1201    ui_select(int rdp_socket)
1202    {
1203            int n = (rdp_socket > g_x_socket) ? rdp_socket + 1 : g_x_socket + 1;
1204            fd_set rfds, wfds;
1205    
1206            while (True)
1207            {
1208                    /* Process any events already waiting */
1209                    if (!xwin_process_events())
1210                            /* User quit */
1211                            return 0;
1212    
1213                    FD_ZERO(&rfds);
1214                    FD_ZERO(&wfds);
1215                    FD_SET(rdp_socket, &rfds);
1216                    FD_SET(g_x_socket, &rfds);
1217    
1218    #ifdef WITH_RDPSND
1219                    /* FIXME: there should be an API for registering fds */
1220                    if (g_dsp_busy)
1221                    {
1222                            FD_SET(g_dsp_fd, &wfds);
1223                            n = (g_dsp_fd + 1 > n) ? g_dsp_fd + 1 : n;
1224                    }
1225    #endif
1226    
1227                    switch (select(n, &rfds, &wfds, NULL, NULL))
1228                    {
1229                            case -1:
1230                                    error("select: %s\n", strerror(errno));
1231    
1232                            case 0:
1233                                    continue;
1234                    }
1235    
1236                    if (FD_ISSET(rdp_socket, &rfds))
1237                            return 1;
1238    
1239    #ifdef WITH_RDPSND
1240                    if (g_dsp_busy && FD_ISSET(g_dsp_fd, &wfds))
1241                            wave_out_play();
1242    #endif
1243            }
1244    }
1245    
1246    void
1247    ui_move_pointer(int x, int y)
1248    {
1249            XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y);
1250    }
1251    
1252    HBITMAP
1253    ui_create_bitmap(int width, int height, uint8 * data)
1254  {  {
1255          XImage *image;          XImage *image;
1256            Pixmap bitmap;
1257            uint8 *tdata;
1258    
1259          image = XCreateImage(wnd->display, wnd->visual, 8, ZPixmap, 0,          tdata = (g_owncolmap ? data : translate_image(width, height, data));
1260                                  data, width, height, 32, width);          bitmap = XCreatePixmap(g_display, g_wnd, width, height, g_depth);
1261            image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1262                                 (char *) tdata, width, height, g_server_bpp == 8 ? 8 : g_bpp, 0);
1263    
1264            XPutImage(g_display, bitmap, g_gc, image, 0, 0, 0, 0, width, height);
1265    
1266            XFree(image);
1267            if (!g_owncolmap)
1268                    xfree(tdata);
1269            return (HBITMAP) bitmap;
1270    }
1271    
1272    void
1273    ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data)
1274    {
1275            XImage *image;
1276            uint8 *tdata;
1277            tdata = (g_owncolmap ? data : translate_image(width, height, data));
1278            image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1279                                 (char *) tdata, width, height, g_server_bpp == 8 ? 8 : g_bpp, 0);
1280    
1281            if (g_ownbackstore)
1282            {
1283                    XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
1284                    XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
1285            }
1286            else
1287            {
1288                    XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
1289            }
1290    
1291          return (HBITMAP)image;          XFree(image);
1292            if (!g_owncolmap)
1293                    xfree(tdata);
1294  }  }
1295    
1296  void ui_destroy_bitmap(HWINDOW wnd, HBITMAP bmp)  void
1297    ui_destroy_bitmap(HBITMAP bmp)
1298  {  {
1299          XDestroyImage((XImage *)bmp);          XFreePixmap(g_display, (Pixmap) bmp);
1300  }  }
1301    
1302  void ui_paint_bitmap(HWINDOW wnd, HBITMAP bmp, int x, int y)  HGLYPH
1303    ui_create_glyph(int width, int height, uint8 * data)
1304  {  {
1305          XImage *image = (XImage *)bmp;          XImage *image;
1306            Pixmap bitmap;
1307            int scanline;
1308            GC gc;
1309    
1310          XPutImage(wnd->display, wnd->wnd, wnd->gc, image,          scanline = (width + 7) / 8;
                         0, 0, x, y, image->width, image->height);  
1311    
1312          XSync(wnd->display, True);          bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
1313            gc = XCreateGC(g_display, bitmap, 0, NULL);
1314    
1315            image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
1316                                 width, height, 8, scanline);
1317            image->byte_order = MSBFirst;
1318            image->bitmap_bit_order = MSBFirst;
1319            XInitImage(image);
1320    
1321            XPutImage(g_display, bitmap, gc, image, 0, 0, 0, 0, width, height);
1322    
1323            XFree(image);
1324            XFreeGC(g_display, gc);
1325            return (HGLYPH) bitmap;
1326  }  }
1327    
1328  HCOLORMAP ui_create_colormap(HWINDOW wnd, COLORMAP *colors)  void
1329    ui_destroy_glyph(HGLYPH glyph)
1330  {  {
1331          COLORENTRY *entry;          XFreePixmap(g_display, (Pixmap) glyph);
1332          XColor *xcolors, *xentry;  }
         Colormap map;  
         int i, ncolors = colors->ncolors;  
1333    
1334          xcolors = malloc(sizeof(XColor) * ncolors);  HCURSOR
1335          for (i = 0; i < ncolors; i++)  ui_create_cursor(unsigned int x, unsigned int y, int width, int height,
1336                     uint8 * andmask, uint8 * xormask)
1337    {
1338            HGLYPH maskglyph, cursorglyph;
1339            XColor bg, fg;
1340            Cursor xcursor;
1341            uint8 *cursor, *pcursor;
1342            uint8 *mask, *pmask;
1343            uint8 nextbit;
1344            int scanline, offset;
1345            int i, j;
1346    
1347            scanline = (width + 7) / 8;
1348            offset = scanline * height;
1349    
1350            cursor = (uint8 *) xmalloc(offset);
1351            memset(cursor, 0, offset);
1352    
1353            mask = (uint8 *) xmalloc(offset);
1354            memset(mask, 0, offset);
1355    
1356            /* approximate AND and XOR masks with a monochrome X pointer */
1357            for (i = 0; i < height; i++)
1358          {          {
1359                  entry = &colors->colors[i];                  offset -= scanline;
1360                  xentry = &xcolors[i];                  pcursor = &cursor[offset];
1361                    pmask = &mask[offset];
1362    
1363                    for (j = 0; j < scanline; j++)
1364                    {
1365                            for (nextbit = 0x80; nextbit != 0; nextbit >>= 1)
1366                            {
1367                                    if (xormask[0] || xormask[1] || xormask[2])
1368                                    {
1369                                            *pcursor |= (~(*andmask) & nextbit);
1370                                            *pmask |= nextbit;
1371                                    }
1372                                    else
1373                                    {
1374                                            *pcursor |= ((*andmask) & nextbit);
1375                                            *pmask |= (~(*andmask) & nextbit);
1376                                    }
1377    
1378                                    xormask += 3;
1379                            }
1380    
1381                            andmask++;
1382                            pcursor++;
1383                            pmask++;
1384                    }
1385            }
1386    
1387            fg.red = fg.blue = fg.green = 0xffff;
1388            bg.red = bg.blue = bg.green = 0x0000;
1389            fg.flags = bg.flags = DoRed | DoBlue | DoGreen;
1390    
1391            cursorglyph = ui_create_glyph(width, height, cursor);
1392            maskglyph = ui_create_glyph(width, height, mask);
1393    
1394            xcursor =
1395                    XCreatePixmapCursor(g_display, (Pixmap) cursorglyph,
1396                                        (Pixmap) maskglyph, &fg, &bg, x, y);
1397    
1398            ui_destroy_glyph(maskglyph);
1399            ui_destroy_glyph(cursorglyph);
1400            xfree(mask);
1401            xfree(cursor);
1402            return (HCURSOR) xcursor;
1403    }
1404    
1405    void
1406    ui_set_cursor(HCURSOR cursor)
1407    {
1408            g_current_cursor = (Cursor) cursor;
1409            XDefineCursor(g_display, g_wnd, g_current_cursor);
1410    }
1411    
1412    void
1413    ui_destroy_cursor(HCURSOR cursor)
1414    {
1415            XFreeCursor(g_display, (Cursor) cursor);
1416    }
1417    
1418    void
1419    ui_set_null_cursor(void)
1420    {
1421            ui_set_cursor(g_null_cursor);
1422    }
1423    
1424    #define MAKE_XCOLOR(xc,c) \
1425                    (xc)->red   = ((c)->red   << 8) | (c)->red; \
1426                    (xc)->green = ((c)->green << 8) | (c)->green; \
1427                    (xc)->blue  = ((c)->blue  << 8) | (c)->blue; \
1428                    (xc)->flags = DoRed | DoGreen | DoBlue;
1429    
1430                  xentry->pixel = i;  
1431                  xentry->red = entry->red << 8;  HCOLOURMAP
1432                  xentry->blue = entry->blue << 8;  ui_create_colourmap(COLOURMAP * colours)
1433                  xentry->green = entry->green << 8;  {
1434                  xentry->flags = DoRed | DoBlue | DoGreen;          COLOURENTRY *entry;
1435            int i, ncolours = colours->ncolours;
1436            if (!g_owncolmap)
1437            {
1438                    uint32 *map = (uint32 *) xmalloc(sizeof(*g_colmap) * ncolours);
1439                    XColor xentry;
1440                    XColor xc_cache[256];
1441                    uint32 colour;
1442                    int colLookup = 256;
1443                    for (i = 0; i < ncolours; i++)
1444                    {
1445                            entry = &colours->colours[i];
1446                            MAKE_XCOLOR(&xentry, entry);
1447    
1448                            if (XAllocColor(g_display, g_xcolmap, &xentry) == 0)
1449                            {
1450                                    /* Allocation failed, find closest match. */
1451                                    int j = 256;
1452                                    int nMinDist = 3 * 256 * 256;
1453                                    long nDist = nMinDist;
1454    
1455                                    /* only get the colors once */
1456                                    while (colLookup--)
1457                                    {
1458                                            xc_cache[colLookup].pixel = colLookup;
1459                                            xc_cache[colLookup].red = xc_cache[colLookup].green =
1460                                                    xc_cache[colLookup].blue = 0;
1461                                            xc_cache[colLookup].flags = 0;
1462                                            XQueryColor(g_display,
1463                                                        DefaultColormap(g_display,
1464                                                                        DefaultScreen(g_display)),
1465                                                        &xc_cache[colLookup]);
1466                                    }
1467                                    colLookup = 0;
1468    
1469                                    /* approximate the pixel */
1470                                    while (j--)
1471                                    {
1472                                            if (xc_cache[j].flags)
1473                                            {
1474                                                    nDist = ((long) (xc_cache[j].red >> 8) -
1475                                                             (long) (xentry.red >> 8)) *
1476                                                            ((long) (xc_cache[j].red >> 8) -
1477                                                             (long) (xentry.red >> 8)) +
1478                                                            ((long) (xc_cache[j].green >> 8) -
1479                                                             (long) (xentry.green >> 8)) *
1480                                                            ((long) (xc_cache[j].green >> 8) -
1481                                                             (long) (xentry.green >> 8)) +
1482                                                            ((long) (xc_cache[j].blue >> 8) -
1483                                                             (long) (xentry.blue >> 8)) *
1484                                                            ((long) (xc_cache[j].blue >> 8) -
1485                                                             (long) (xentry.blue >> 8));
1486                                            }
1487                                            if (nDist < nMinDist)
1488                                            {
1489                                                    nMinDist = nDist;
1490                                                    xentry.pixel = j;
1491                                            }
1492                                    }
1493                            }
1494                            colour = xentry.pixel;
1495    
1496                            /* update our cache */
1497                            if (xentry.pixel < 256)
1498                            {
1499                                    xc_cache[xentry.pixel].red = xentry.red;
1500                                    xc_cache[xentry.pixel].green = xentry.green;
1501                                    xc_cache[xentry.pixel].blue = xentry.blue;
1502    
1503                            }
1504    
1505    
1506                            /* byte swap here to make translate_image faster */
1507                            map[i] = translate_colour(colour);
1508                    }
1509                    return map;
1510            }
1511            else
1512            {
1513                    XColor *xcolours, *xentry;
1514                    Colormap map;
1515    
1516                    xcolours = (XColor *) xmalloc(sizeof(XColor) * ncolours);
1517                    for (i = 0; i < ncolours; i++)
1518                    {
1519                            entry = &colours->colours[i];
1520                            xentry = &xcolours[i];
1521                            xentry->pixel = i;
1522                            MAKE_XCOLOR(xentry, entry);
1523                    }
1524    
1525                    map = XCreateColormap(g_display, g_wnd, g_visual, AllocAll);
1526                    XStoreColors(g_display, map, xcolours, ncolours);
1527    
1528                    xfree(xcolours);
1529                    return (HCOLOURMAP) map;
1530            }
1531    }
1532    
1533    void
1534    ui_destroy_colourmap(HCOLOURMAP map)
1535    {
1536            if (!g_owncolmap)
1537                    xfree(map);
1538            else
1539                    XFreeColormap(g_display, (Colormap) map);
1540    }
1541    
1542    void
1543    ui_set_colourmap(HCOLOURMAP map)
1544    {
1545            if (!g_owncolmap)
1546            {
1547                    if (g_colmap)
1548                            xfree(g_colmap);
1549    
1550                    g_colmap = (uint32 *) map;
1551          }          }
1552            else
1553                    XSetWindowColormap(g_display, g_wnd, (Colormap) map);
1554    }
1555    
1556    void
1557    ui_set_clip(int x, int y, int cx, int cy)
1558    {
1559            XRectangle rect;
1560    
1561            rect.x = x;
1562            rect.y = y;
1563            rect.width = cx;
1564            rect.height = cy;
1565            XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);
1566    }
1567    
1568          map = XCreateColormap(wnd->display, wnd->wnd, wnd->visual, AllocAll);  void
1569          XStoreColors(wnd->display, map, xcolors, ncolors);  ui_reset_clip(void)
1570    {
1571            XRectangle rect;
1572    
1573            rect.x = 0;
1574            rect.y = 0;
1575            rect.width = g_width;
1576            rect.height = g_height;
1577            XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);
1578    }
1579    
1580    void
1581    ui_bell(void)
1582    {
1583            XBell(g_display, 0);
1584    }
1585    
1586    void
1587    ui_destblt(uint8 opcode,
1588               /* dest */ int x, int y, int cx, int cy)
1589    {
1590            SET_FUNCTION(opcode);
1591            FILL_RECTANGLE(x, y, cx, cy);
1592            RESET_FUNCTION(opcode);
1593    }
1594    
1595    static uint8 hatch_patterns[] = {
1596            0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, /* 0 - bsHorizontal */
1597            0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 1 - bsVertical */
1598            0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, /* 2 - bsFDiagonal */
1599            0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, /* 3 - bsBDiagonal */
1600            0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, /* 4 - bsCross */
1601            0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81  /* 5 - bsDiagCross */
1602    };
1603    
1604    void
1605    ui_patblt(uint8 opcode,
1606              /* dest */ int x, int y, int cx, int cy,
1607              /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
1608    {
1609            Pixmap fill;
1610            uint8 i, ipattern[8];
1611    
1612          free(xcolors);          SET_FUNCTION(opcode);
1613          return (HCOLORMAP)map;  
1614            switch (brush->style)
1615            {
1616                    case 0: /* Solid */
1617                            SET_FOREGROUND(fgcolour);
1618                            FILL_RECTANGLE(x, y, cx, cy);
1619                            break;
1620    
1621                    case 2: /* Hatch */
1622                            fill = (Pixmap) ui_create_glyph(8, 8,
1623                                                            hatch_patterns + brush->pattern[0] * 8);
1624                            SET_FOREGROUND(fgcolour);
1625                            SET_BACKGROUND(bgcolour);
1626                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
1627                            XSetStipple(g_display, g_gc, fill);
1628                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
1629                            FILL_RECTANGLE(x, y, cx, cy);
1630                            XSetFillStyle(g_display, g_gc, FillSolid);
1631                            XSetTSOrigin(g_display, g_gc, 0, 0);
1632                            ui_destroy_glyph((HGLYPH) fill);
1633                            break;
1634    
1635                    case 3: /* Pattern */
1636                            for (i = 0; i != 8; i++)
1637                                    ipattern[7 - i] = brush->pattern[i];
1638                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
1639    
1640                            SET_FOREGROUND(bgcolour);
1641                            SET_BACKGROUND(fgcolour);
1642                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
1643                            XSetStipple(g_display, g_gc, fill);
1644                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
1645    
1646                            FILL_RECTANGLE(x, y, cx, cy);
1647    
1648                            XSetFillStyle(g_display, g_gc, FillSolid);
1649                            XSetTSOrigin(g_display, g_gc, 0, 0);
1650                            ui_destroy_glyph((HGLYPH) fill);
1651                            break;
1652    
1653                    default:
1654                            unimpl("brush %d\n", brush->style);
1655            }
1656    
1657            RESET_FUNCTION(opcode);
1658  }  }
1659    
1660  void ui_destroy_colormap(HWINDOW wnd, HCOLORMAP map)  void
1661    ui_screenblt(uint8 opcode,
1662                 /* dest */ int x, int y, int cx, int cy,
1663                 /* src */ int srcx, int srcy)
1664  {  {
1665          XFreeColormap(wnd->display, (Colormap)map);          SET_FUNCTION(opcode);
1666            XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
1667            if (g_ownbackstore)
1668                    XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
1669            RESET_FUNCTION(opcode);
1670  }  }
1671    
1672  void ui_set_colormap(HWINDOW wnd, HCOLORMAP map)  void
1673    ui_memblt(uint8 opcode,
1674              /* dest */ int x, int y, int cx, int cy,
1675              /* src */ HBITMAP src, int srcx, int srcy)
1676  {  {
1677          XSetWindowColormap(wnd->display, wnd->wnd, (Colormap)map);          SET_FUNCTION(opcode);
1678            XCopyArea(g_display, (Pixmap) src, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
1679            if (g_ownbackstore)
1680                    XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
1681            RESET_FUNCTION(opcode);
1682  }  }
1683    
1684  void ui_draw_rectangle(HWINDOW wnd, int x, int y, int width, int height)  void
1685    ui_triblt(uint8 opcode,
1686              /* dest */ int x, int y, int cx, int cy,
1687              /* src */ HBITMAP src, int srcx, int srcy,
1688              /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
1689  {  {
1690          static int white = 0;          /* This is potentially difficult to do in general. Until someone
1691               comes up with a more efficient way of doing it I am using cases. */
1692    
1693          XSetForeground(wnd->display, wnd->gc, white);          switch (opcode)
1694          XFillRectangle(wnd->display, wnd->wnd, wnd->gc, x, y, width, height);          {
1695                    case 0x69:      /* PDSxxn */
1696                            ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);
1697                            ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1698                            break;
1699    
1700                    case 0xb8:      /* PSDPxax */
1701                            ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1702                            ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);
1703                            ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1704                            break;
1705    
1706                    case 0xc0:      /* PSa */
1707                            ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
1708                            ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour, fgcolour);
1709                            break;
1710    
1711                    default:
1712                            unimpl("triblt 0x%x\n", opcode);
1713                            ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
1714            }
1715    }
1716    
1717          white++;  void
1718    ui_line(uint8 opcode,
1719            /* dest */ int startx, int starty, int endx, int endy,
1720            /* pen */ PEN * pen)
1721    {
1722            SET_FUNCTION(opcode);
1723            SET_FOREGROUND(pen->colour);
1724            XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
1725            if (g_ownbackstore)
1726                    XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
1727            RESET_FUNCTION(opcode);
1728  }  }
1729    
1730  void ui_move_pointer(HWINDOW wnd, int x, int y)  void
1731    ui_rect(
1732                   /* dest */ int x, int y, int cx, int cy,
1733                   /* brush */ int colour)
1734  {  {
1735          XWarpPointer(wnd->display, wnd->wnd, wnd->wnd, 0, 0, 0, 0, x, y);          SET_FOREGROUND(colour);
1736            FILL_RECTANGLE(x, y, cx, cy);
1737    }
1738    
1739    /* warning, this function only draws on wnd or backstore, not both */
1740    void
1741    ui_draw_glyph(int mixmode,
1742                  /* dest */ int x, int y, int cx, int cy,
1743                  /* src */ HGLYPH glyph, int srcx, int srcy,
1744                  int bgcolour, int fgcolour)
1745    {
1746            SET_FOREGROUND(fgcolour);
1747            SET_BACKGROUND(bgcolour);
1748    
1749            XSetFillStyle(g_display, g_gc,
1750                          (mixmode == MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled);
1751            XSetStipple(g_display, g_gc, (Pixmap) glyph);
1752            XSetTSOrigin(g_display, g_gc, x, y);
1753    
1754            FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
1755    
1756            XSetFillStyle(g_display, g_gc, FillSolid);
1757    }
1758    
1759    #define DO_GLYPH(ttext,idx) \
1760    {\
1761      glyph = cache_get_font (font, ttext[idx]);\
1762      if (!(flags & TEXT2_IMPLICIT_X))\
1763        {\
1764          xyoffset = ttext[++idx];\
1765          if ((xyoffset & 0x80))\
1766            {\
1767              if (flags & TEXT2_VERTICAL) \
1768                y += ttext[idx+1] | (ttext[idx+2] << 8);\
1769              else\
1770                x += ttext[idx+1] | (ttext[idx+2] << 8);\
1771              idx += 2;\
1772            }\
1773          else\
1774            {\
1775              if (flags & TEXT2_VERTICAL) \
1776                y += xyoffset;\
1777              else\
1778                x += xyoffset;\
1779            }\
1780        }\
1781      if (glyph != NULL)\
1782        {\
1783          ui_draw_glyph (mixmode, x + glyph->offset,\
1784                         y + glyph->baseline,\
1785                         glyph->width, glyph->height,\
1786                         glyph->pixmap, 0, 0, bgcolour, fgcolour);\
1787          if (flags & TEXT2_IMPLICIT_X)\
1788            x += glyph->width;\
1789        }\
1790    }
1791    
1792    void
1793    ui_draw_text(uint8 font, uint8 flags, int mixmode, int x, int y,
1794                 int clipx, int clipy, int clipcx, int clipcy,
1795                 int boxx, int boxy, int boxcx, int boxcy, int bgcolour,
1796                 int fgcolour, uint8 * text, uint8 length)
1797    {
1798            FONTGLYPH *glyph;
1799            int i, j, xyoffset;
1800            DATABLOB *entry;
1801    
1802            SET_FOREGROUND(bgcolour);
1803    
1804            if (boxcx > 1)
1805            {
1806                    FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);
1807            }
1808            else if (mixmode == MIX_OPAQUE)
1809            {
1810                    FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);
1811            }
1812    
1813            /* Paint text, character by character */
1814            for (i = 0; i < length;)
1815            {
1816                    switch (text[i])
1817                    {
1818                            case 0xff:
1819                                    if (i + 2 < length)
1820                                            cache_put_text(text[i + 1], text, text[i + 2]);
1821                                    else
1822                                    {
1823                                            error("this shouldn't be happening\n");
1824                                            exit(1);
1825                                    }
1826                                    /* this will move pointer from start to first character after FF command */
1827                                    length -= i + 3;
1828                                    text = &(text[i + 3]);
1829                                    i = 0;
1830                                    break;
1831    
1832                            case 0xfe:
1833                                    entry = cache_get_text(text[i + 1]);
1834                                    if (entry != NULL)
1835                                    {
1836                                            if ((((uint8 *) (entry->data))[1] ==
1837                                                 0) && (!(flags & TEXT2_IMPLICIT_X)))
1838                                            {
1839                                                    if (flags & TEXT2_VERTICAL)
1840                                                            y += text[i + 2];
1841                                                    else
1842                                                            x += text[i + 2];
1843                                            }
1844                                            for (j = 0; j < entry->size; j++)
1845                                                    DO_GLYPH(((uint8 *) (entry->data)), j);
1846                                    }
1847                                    if (i + 2 < length)
1848                                            i += 3;
1849                                    else
1850                                            i += 2;
1851                                    length -= i;
1852                                    /* this will move pointer from start to first character after FE command */
1853                                    text = &(text[i]);
1854                                    i = 0;
1855                                    break;
1856    
1857                            default:
1858                                    DO_GLYPH(text, i);
1859                                    i++;
1860                                    break;
1861                    }
1862            }
1863            if (g_ownbackstore)
1864            {
1865                    if (boxcx > 1)
1866                            XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
1867                                      boxy, boxcx, boxcy, boxx, boxy);
1868                    else
1869                            XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
1870                                      clipy, clipcx, clipcy, clipx, clipy);
1871            }
1872    }
1873    
1874    void
1875    ui_desktop_save(uint32 offset, int x, int y, int cx, int cy)
1876    {
1877            Pixmap pix;
1878            XImage *image;
1879    
1880            if (g_ownbackstore)
1881            {
1882                    image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
1883            }
1884            else
1885            {
1886                    pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);
1887                    XCopyArea(g_display, g_wnd, pix, g_gc, x, y, cx, cy, 0, 0);
1888                    image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
1889                    XFreePixmap(g_display, pix);
1890            }
1891    
1892            offset *= g_bpp / 8;
1893            cache_put_desktop(offset, cx, cy, image->bytes_per_line, g_bpp / 8, (uint8 *) image->data);
1894    
1895            XDestroyImage(image);
1896    }
1897    
1898    void
1899    ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy)
1900    {
1901            XImage *image;
1902            uint8 *data;
1903    
1904            offset *= g_bpp / 8;
1905            data = cache_get_desktop(offset, cx, cy, g_bpp / 8);
1906            if (data == NULL)
1907                    return;
1908    
1909            image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1910                                 (char *) data, cx, cy, BitmapPad(g_display), cx * g_bpp / 8);
1911    
1912            if (g_ownbackstore)
1913            {
1914                    XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
1915                    XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
1916            }
1917            else
1918            {
1919                    XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
1920            }
1921    
1922            XFree(image);
1923  }  }

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

  ViewVC Help
Powered by ViewVC 1.1.26