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

Legend:
Removed from v.28  
changed lines
  Added in v.415

  ViewVC Help
Powered by ViewVC 1.1.26