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

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

  ViewVC Help
Powered by ViewVC 1.1.26