BRL-CAD
if_X24.c
Go to the documentation of this file.
1 /* I F _ X 2 4 . C
2  * BRL-CAD
3  *
4  * Copyright (c) 1994 Sun Microsystems, Inc. - All Rights Reserved.
5  *
6  * Permission is hereby granted, without written agreement and without
7  * license or royalty fees, to use, copy, modify, and distribute this
8  * software and its documentation for any purpose, provided that the
9  * above copyright notice and the following two paragraphs appear in
10  * all copies of this software.
11  *
12  * IN NO EVENT SHALL SUN MICROSYSTEMS INC. BE LIABLE TO ANY PARTY FOR
13  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING
14  * OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF SUN
15  * MICROSYSTEMS INC. HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16  *
17  * SUN MICROSYSTEMS INC. SPECIFICALLY DISCLAIMS ANY WARRANTIES,
18  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
19  * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER
20  * IS ON AN "AS IS" BASIS, AND SUN MICROSYSTEMS INC. HAS NO OBLIGATION TO
21  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
22  */
23 /** @addtogroup if */
24 /** @{*/
25 /** @file if_X24.c
26  *
27  * X Window System (X11) libfb interface, supporting 24-, 8-, and
28  * 1-bit displays.
29  *
30  */
31 /** @} */
32 
33 #include "common.h"
34 
35 #ifdef IF_X
36 
37 #include <errno.h>
38 #include <stdlib.h>
39 #include <time.h>
40 #include <sys/types.h>
41 #include <string.h>
42 #ifdef HAVE_SYS_TIME_H
43 # include <sys/time.h>
44 #endif
45 #ifdef HAVE_SYS_MMAN_H
46 # include <sys/mman.h>
47 # define CAN_LINGER 1
48 # undef HAVE_SYS_SHM_H /* Don't use both ways, mmap is preferred. */
49 #else
50 # ifdef HAVE_SYS_SHM_H
51 # include <sys/ipc.h>
52 # include <sys/shm.h>
53 # define CAN_LINGER 1
54 # endif
55 #endif
56 
57 #include <X11/X.h>
58 #ifdef HAVE_XOSDEFS_H
59 # include <X11/Xfuncproto.h>
60 # include <X11/Xosdefs.h>
61 #endif
62 #if defined(linux)
63 # undef X_NOT_STDC_ENV
64 # undef X_NOT_POSIX
65 #endif
66 #define class REDEFINE_CLASS_STRING_TO_AVOID_CXX_CONFLICT
67 #include <X11/Xlib.h>
68 #include <X11/Xutil.h>
69 #include <X11/Xatom.h>
70 
71 #include <ctype.h>
72 
73 #include "bu/color.h"
74 #include "bu/file.h"
75 #include "bu/malloc.h"
76 #include "bu/str.h"
77 #include "fb_private.h"
78 #include "fb/fb_X.h"
79 
80 
81 /*
82  * Per window state information.
83  */
84 struct xinfo {
85  Display *xi_dpy; /* Display and Screen(s) info */
86  Window xi_win; /* Window ID */
87  int xi_screen; /* Our screen selection */
88  Visual *xi_visual; /* Our visual selection */
89  XVisualInfo xi_visinfo; /* Visual Info */
90  int xi_depth; /* Depth of our window */
91  GC xi_gc; /* current graphics context */
92  GC xi_cgc; /* graphics context for clipping */
93  Region xi_reg; /* Valid displayed region */
94  int xi_usereg; /* Flag determining whether or not to use regions */
95  Colormap xi_cmap; /* Colormap */
96  XImage *xi_image; /* XImage (size of screen) */
97  Window xi_cwinp; /* Cursor's Parent Window ID */
98  Window xi_cwin; /* Cursor Window ID */
99  unsigned long xi_wp; /* White pixel */
100  unsigned long xi_bp; /* Black pixel */
101 
102  /*
103  * Pixel buffer usage:
104  *
105  * xi_mem is the actual data received from the user. It's stored
106  * in 24-bit RGB format, in image-space coordinates.
107  *
108  * xi_pix is the panned, zoomed, and possibly colormapped output
109  * image. It's stored in whatever X11 format makes sense for our
110  * Visual, in X11-space coordinates. This is the buffer backing
111  * xi_image.
112  *
113  */
114 
115  unsigned char *xi_mem; /* 24-bit backing store */
116  unsigned char *xi_pix; /* X Image buffer */
117 
118 #ifdef HAVE_SYS_SHM_H
119  int xi_shmid; /* Sys V shared mem id */
120 #endif
121 
122  unsigned long xi_mode; /* 0, 1, 2 */
123  unsigned long xi_flags;
124 
125  ColorMap *xi_rgb_cmap; /* User's libfb colormap */
126  unsigned char *xi_redmap; /* Fake colormap for non-DirectColor */
127  unsigned char *xi_blumap; /* Fake colormap for non-DirectColor */
128  unsigned char *xi_grnmap; /* Fake colormap for non-DirectColor */
129 
130  unsigned char *xi_ccredtbl; /* Lookup table for red component */
131  unsigned char *xi_ccgrntbl; /* Lookup table for green component */
132  unsigned char *xi_ccblutbl; /* Lookup table for blue component */
133 
134  unsigned char *xi_andtbl; /* Lookup table for 1-bit dithering */
135  unsigned char *xi_ortbl; /* Lookup table for 1-bit dithering */
136 
137  size_t xi_ncolors; /* Number of colors in colorcube */
138  unsigned int xi_base; /* Base color in colorcube */
139 
140  /* The following values are in Image Pixels */
141 
142  int xi_iwidth; /* Width of user's whole image */
143  int xi_iheight; /* Height of user's whole image */
144 
145  int xi_ilf; /* Image coordinate of LLHC image */
146  int xi_ibt; /* pixel */
147  int xi_irt; /* Image coordinate of URHC image */
148  int xi_itp; /* pixel */
149 
150  /* The following values are in X Pixels */
151 
152  int xi_ilf_w; /* Width of leftmost image pixels */
153  int xi_irt_w; /* Width of rightmost image pixels */
154  int xi_ibt_h; /* Height of bottommost image pixels */
155  int xi_itp_h; /* Height of topmost image pixels */
156 
157  int xi_xwidth; /* Width of X window */
158  int xi_xheight; /* Height of X window */
159 
160  int xi_xlf; /* X-coord of leftmost pixels */
161  int xi_xrt; /* X-coord of rightmost pixels */
162  int xi_xtp; /* Y-coord of topmost pixels */
163  int xi_xbt; /* Y-coord of bottommost pixels */
164 };
165 #define XI(ptr) ((struct xinfo *)((ptr)->u1.p))
166 #define XI_SET(ptr, val) ((ptr)->u1.p) = (char *) val;
167 
168 
169 /* Flags in xi_flags */
170 
171 #define FLG_VMASK 0x07 /* Visual mask */
172  /* Note: values below are in preference order*/
173 #define FLG_VD24 0x01 /* 24-bit DirectColor */
174 #define FLG_VT24 0x02 /* 24-bit TrueColor */
175 #define FLG_VD16 0x03 /* 16-bit DirectColor */
176 #define FLG_VT16 0x04 /* 16-bit TrueColor */
177 #define FLG_VP8 0x05 /* 8-bit PseudoColor */
178 #define FLG_VS8 0x06 /* 8-bit StaticGray */
179 #define FLG_VG8 0x07 /* 8-bit GrayScale */
180 #define FLG_VS1 0x08 /* 1-bit StaticGray */
181 
182 #define FLG_LINCMAP 0x10 /* We're using a linear colormap */
183 #define FLG_XCMAP 0x20 /* The X server can do colormapping for us */
184 #define FLG_INIT 0x40 /* Display is fully initialized */
185 
186 /* Mode flags for open */
187 
188 #define MODE1_MASK (1<<1)
189 #define MODE1_TRANSIENT (0<<1)
190 #define MODE1_LINGERING (1<<1)
191 
192 #define MODEV_MASK (7<<1)
193 
194 #define MODE10_MASK (1<<10)
195 #define MODE10_MALLOC (0<<10)
196 #define MODE10_SHARED (1<<10)
197 
198 #define MODE11_MASK (1<<11)
199 #define MODE11_NORMAL (0<<11)
200 #define MODE11_ZAP (1<<11)
201 
202 static struct modeflags {
203  char c;
204  unsigned long mask;
205  unsigned long value;
206  char *help;
207 } modeflags[] = {
208  { 'l', MODE1_MASK, MODE1_LINGERING,
209  "Lingering window" },
210  { 't', MODE1_MASK, MODE1_TRANSIENT,
211  "Transient window" },
212  { 's', MODE10_MASK, MODE10_SHARED,
213  "Use shared memory backing store" },
214  { 'z', MODE11_MASK, MODE11_ZAP,
215  "Zap (free) shared memory" },
216  { 'D', MODEV_MASK, FLG_VD24 << 1,
217  "Select 24-bit DirectColor display if available" },
218  { 'T', MODEV_MASK, FLG_VT24 << 1,
219  "Select 24-bit TrueColor display if available" },
220  { 'P', MODEV_MASK, FLG_VP8 << 1,
221  "Select 8-bit PseudoColor display if available" },
222  { 'S', MODEV_MASK, FLG_VS8 << 1,
223  "Select 8-bit StaticGray display if available" },
224  { 'G', MODEV_MASK, FLG_VG8 << 1,
225  "Select 8-bit GrayScale display if available" },
226  { 'M', MODEV_MASK, FLG_VS1 << 1,
227  "Select 1-bit StaticGray display if available" },
228  { '\0', 0, 0, "" }
229 };
230 
231 
232 /* Flags for X24_blit's flags argument */
233 
234 #define BLIT_DISP 0x1 /* Write bits to screen */
235 #define BLIT_PZ 0x2 /* This is a pan or zoom */
236 #define BLIT_RESIZE 0x4 /* We just resized (screen empty) */
237 
238 #define BS_NAME "/tmp/X24_fb"
239 
240 /* Elements of 6x9x4 colorcube */
241 
242 static unsigned char reds[] = { 0, 51, 102, 153, 204, 255 };
243 static unsigned char grns[] = { 0, 32, 64, 96, 128, 159, 191, 223, 255 };
244 static unsigned char blus[] = { 0, 85, 170, 255 };
245 
246 /* Dither masks */
247 
248 static float dmsk881[] = {
249  0.705882, 0.956863, 0.235294, 0.486275, 0.737255, 0.988235, 0.203922, 0.454902,
250  0.172549, 0.423529, 0.674510, 0.925490, 0.141176, 0.392157, 0.643137, 0.894118,
251  0.580392, 0.831373, 0.109804, 0.360784, 0.611765, 0.862745, 0.078431, 0.329412,
252  0.047059, 0.298039, 0.549020, 0.800000, 0.015686, 0.266667, 0.517647, 0.768628,
253  0.721569, 0.972549, 0.188235, 0.439216, 0.690196, 0.941177, 0.219608, 0.470588,
254  0.125490, 0.376471, 0.627451, 0.878431, 0.156863, 0.407843, 0.658824, 0.909804,
255  0.596078, 0.847059, 0.062745, 0.313726, 0.564706, 0.815686, 0.094118, 0.345098,
256  0.000000, 0.250980, 0.501961, 0.752941, 0.031373, 0.282353, 0.533333, 0.784314
257 };
258 
259 
260 static float dmsk883[] = {
261  0.784314, 0.533333, 0.282353, 0.031373, 0.752941, 0.501961, 0.250980, 0.000000,
262  0.345098, 0.094118, 0.815686, 0.564706, 0.313726, 0.062745, 0.847059, 0.596078,
263  0.909804, 0.658824, 0.407843, 0.156863, 0.878431, 0.627451, 0.376471, 0.125490,
264  0.470588, 0.219608, 0.941177, 0.690196, 0.439216, 0.188235, 0.972549, 0.721569,
265  0.768628, 0.517647, 0.266667, 0.015686, 0.800000, 0.549020, 0.298039, 0.047059,
266  0.329412, 0.078431, 0.862745, 0.611765, 0.360784, 0.109804, 0.831373, 0.580392,
267  0.894118, 0.643137, 0.392157, 0.141176, 0.925490, 0.674510, 0.423529, 0.172549,
268  0.454902, 0.203922, 0.988235, 0.737255, 0.486275, 0.235294, 0.956863, 0.705882,
269 
270  0.988235, 0.737255, 0.486275, 0.235294, 0.956863, 0.705882, 0.454902, 0.203922,
271  0.392157, 0.141176, 0.925490, 0.674510, 0.423529, 0.172549, 0.894118, 0.643137,
272  0.862745, 0.611765, 0.360784, 0.109804, 0.831373, 0.580392, 0.329412, 0.078431,
273  0.266667, 0.015686, 0.800000, 0.549020, 0.298039, 0.047059, 0.768628, 0.517647,
274  0.941177, 0.690196, 0.439216, 0.188235, 0.972549, 0.721569, 0.470588, 0.219608,
275  0.407843, 0.156863, 0.878431, 0.627451, 0.376471, 0.125490, 0.909804, 0.658824,
276  0.815686, 0.564706, 0.313726, 0.062745, 0.847059, 0.596078, 0.345098, 0.094118,
277  0.282353, 0.031373, 0.752941, 0.501961, 0.250980, 0.000000, 0.784314, 0.533333,
278 
279  0.000000, 0.250980, 0.501961, 0.752941, 0.031373, 0.282353, 0.533333, 0.784314,
280  0.596078, 0.847059, 0.062745, 0.313726, 0.564706, 0.815686, 0.094118, 0.345098,
281  0.125490, 0.376471, 0.627451, 0.878431, 0.156863, 0.407843, 0.658824, 0.909804,
282  0.721569, 0.972549, 0.188235, 0.439216, 0.690196, 0.941177, 0.219608, 0.470588,
283  0.047059, 0.298039, 0.549020, 0.800000, 0.015686, 0.266667, 0.517647, 0.768628,
284  0.580392, 0.831373, 0.109804, 0.360784, 0.611765, 0.862745, 0.078431, 0.329412,
285  0.172549, 0.423529, 0.674510, 0.925490, 0.141176, 0.392157, 0.643137, 0.894118,
286  0.705882, 0.956863, 0.235294, 0.486275, 0.737255, 0.988235, 0.203922, 0.454902
287 };
288 
289 
290 /* Luminance factor tables (filled in in x24_setup()) */
291 
292 static int lumdone = 0; /* Nonzero if tables valid */
293 static unsigned long rlumtbl[256];
294 static unsigned long glumtbl[256];
295 static unsigned long blumtbl[256];
296 
297 /*
298  * A given Display (i.e. Server) can have any number of Screens. Each
299  * Screen can support one or more Visual types.
300  *
301  * unix:0.1.2 => host:display.screen.visual
302  *
303  * Typically the screen and visual default to 0 by being omitted.
304  */
305 HIDDEN void
306 print_display_info(Display *dpy)
307 {
308  int i;
309  int screen;
310  Visual *visual;
311  XVisualInfo *vp;
312  int num;
313  Window win = DefaultRootWindow(dpy);
314  XStandardColormap cmap;
315 
316  printf("Server \"%s\", release %d\n",
317  ServerVendor(dpy), VendorRelease(dpy));
318 
319  /* How many screens? */
320  screen = DefaultScreen(dpy);
321  printf("%d Screen(s), we connected to screen %d\n",
322  ScreenCount(dpy), screen);
323 
324  /* How many visuals? */
325  vp = XGetVisualInfo(dpy, VisualNoMask, NULL, &num);
326  printf("%d Visual(s)\n", num);
327 
328  printf("ImageByteOrder: %s\n",
329  ImageByteOrder(dpy) == MSBFirst ? "MSBFirst" : "LSBFirst");
330  printf("BitmapBitOrder: %s\n",
331  BitmapBitOrder(dpy) == MSBFirst ? "MSBFirst" : "LSBFirst");
332  printf("BitmapUnit: %d\n", BitmapUnit(dpy));
333  printf("BitmapPad: %d\n", BitmapPad(dpy));
334 
335  printf("==== Screen %d ====\n", screen);
336  printf("%d x %d pixels, %d x %d mm, (%.2f x %.2f dpi)\n",
337  DisplayWidth(dpy, screen), DisplayHeight(dpy, screen),
338  DisplayWidthMM(dpy, screen), DisplayHeightMM(dpy, screen),
339  DisplayWidth(dpy, screen)*25.4/DisplayWidthMM(dpy, screen),
340  DisplayHeight(dpy, screen)*25.4/DisplayHeightMM(dpy, screen));
341  printf("%d DisplayPlanes (other Visuals, if any, may vary)\n",
342  DisplayPlanes(dpy, screen));
343  printf("%d DisplayCells\n", DisplayCells(dpy, screen));
344  printf("BlackPixel = %lu\n", BlackPixel(dpy, screen));
345  printf("WhitePixel = %lu\n", WhitePixel(dpy, screen));
346  printf("Save Unders: %s\n",
347  DoesSaveUnders(ScreenOfDisplay(dpy, screen)) ? "True" : "False");
348  i = DoesBackingStore(ScreenOfDisplay(dpy, screen));
349  printf("Backing Store: %s\n", i == WhenMapped ? "WhenMapped" :
350  (i == Always ? "Always" : "NotUseful"));
351  printf("Installed Colormaps: min %d, max %d\n",
352  MinCmapsOfScreen(ScreenOfDisplay(dpy, screen)),
353  MaxCmapsOfScreen(ScreenOfDisplay(dpy, screen)));
354  printf("DefaultColormap: 0x%lx\n", DefaultColormap(dpy, screen));
355 
356 
357  for (i = 0; i < num; i++) {
358 
359  visual = vp[i].visual;
360 
361  printf("---- Visual 0x%lx (%d)----\n", (unsigned long int)visual, i);
362 
363  printf("screen: %d\n", vp[i].screen);
364  printf("depth : %d\n", vp[i].depth);
365 
366  switch (visual->class) {
367  case DirectColor:
368  printf("DirectColor: Alterable RGB maps, pixel RGB subfield indices\n");
369  printf("RGB Masks: 0x%lx 0x%lx 0x%lx\n", visual->red_mask,
370  visual->green_mask, visual->blue_mask);
371  break;
372  case TrueColor:
373  printf("TrueColor: Fixed RGB maps, pixel RGB subfield indices\n");
374  printf("RGB Masks: 0x%lx 0x%lx 0x%lx\n", visual->red_mask,
375  visual->green_mask, visual->blue_mask);
376  break;
377  case PseudoColor:
378  printf("PseudoColor: Alterable RGB maps, single index\n");
379  break;
380  case StaticColor:
381  printf("StaticColor: Fixed RGB maps, single index\n");
382  break;
383  case GrayScale:
384  printf("GrayScale: Alterable map (R=G=B), single index\n");
385  break;
386  case StaticGray:
387  printf("StaticGray: Fixed map (R=G=B), single index\n");
388  break;
389  default:
390  printf("Unknown visual class %d\n",
391  visual->class);
392  break;
393  }
394  printf("Map Entries: %d\n", visual->map_entries);
395  printf("Bits per RGB: %d\n", visual->bits_per_rgb);
396  }
397  XFree((char *) vp);
398 
399 
400  printf("==== Standard Colormaps ====\n");
401  if (XGetStandardColormap(dpy, win, &cmap, XA_RGB_BEST_MAP)) {
402  printf("XA_RGB_BEST_MAP - Yes (0x%lx)\n", cmap.colormap);
403  printf("R[0..%lu] * %lu + G[0..%lu] * %lu + B[0..%lu] * %lu + %lu\n",
404  cmap.red_max, cmap.red_mult, cmap.green_max, cmap.green_mult,
405  cmap.blue_max, cmap.blue_mult, cmap.base_pixel);
406  } else {
407  printf("XA_RGB_BEST_MAP - No\n");
408  }
409  if (XGetStandardColormap(dpy, win, &cmap, XA_RGB_DEFAULT_MAP)) {
410  printf("XA_RGB_DEFAULT_MAP - Yes (0x%lx)\n", cmap.colormap);
411  printf("R[0..%lu] * %lu + G[0..%lu] * %lu + B[0..%lu] * %lu + %lu\n",
412  cmap.red_max, cmap.red_mult, cmap.green_max, cmap.green_mult,
413  cmap.blue_max, cmap.blue_mult, cmap.base_pixel);
414  } else {
415  printf("XA_RGB_DEFAULT_MAP - No\n");
416  }
417  if (XGetStandardColormap(dpy, win, &cmap, XA_RGB_GRAY_MAP)) {
418  printf("XA_RGB_GRAY_MAP - Yes (0x%lx)\n", cmap.colormap);
419  printf("R[0..%lu] * %lu + %lu\n",
420  cmap.red_max, cmap.red_mult, cmap.base_pixel);
421  } else {
422  printf("XA_RGB_GRAY_MAP - No\n");
423  }
424 }
425 
426 
427 /*
428  Create 6x9x4 color cube.
429 */
430 HIDDEN void
431 X24_createColorCube(struct xinfo *xi)
432 {
433  size_t i;
434  int redmul, grnmul;
435  unsigned long pixels[256], pmask[1], pixel[1];
436  XColor colors[256];
437 
438  /*
439  * Color cube is in RGB order
440  */
441  grnmul = sizeof (blus);
442  redmul = sizeof (blus) * sizeof (grns);
443 
444  XAllocColorCells(xi->xi_dpy, xi->xi_cmap, 1, pmask, 0, pixels,
445  xi->xi_base + xi->xi_ncolors);
446 
447  for (pixel[0] = 0; pixel[0] < xi->xi_base; pixel[0]++) {
448  XFreeColors(xi->xi_dpy, xi->xi_cmap, pixel, 1, 0);
449  }
450 
451  /* Fill the colormap and the colorcube */
452  for (i = 0; i < xi->xi_ncolors; i++) {
453  colors[i].red = reds[i / redmul] << 8;
454  colors[i].green = grns[(i % redmul) / grnmul] << 8;
455  colors[i].blue = blus[i % grnmul] << 8;
456  colors[i].flags = DoRed | DoGreen | DoBlue;
457  colors[i].pixel = xi->xi_base + i;
458  }
459 
460  XStoreColors(xi->xi_dpy, xi->xi_cmap, colors, xi->xi_ncolors);
461 }
462 
463 
464 /*
465  Create fast lookup tables for dithering
466 */
467 HIDDEN void
468 X24_createColorTables(struct xinfo *xi)
469 {
470  int i, j;
471  size_t idx;
472  int redmul, grnmul;
473 
474  grnmul = sizeof (blus);
475  redmul = sizeof (blus) * sizeof (grns);
476 
477  xi->xi_ccredtbl = (unsigned char *)malloc(64 * 256);
478  xi->xi_ccgrntbl = (unsigned char *)malloc(64 * 256);
479  xi->xi_ccblutbl = (unsigned char *)malloc(64 * 256);
480 
481  for (i = 0; i < 256; i++) {
482  int redval, grnval, bluval;
483  int redtbl, grntbl, blutbl;
484  int reditbl, grnitbl, bluitbl;
485 
486  idx = i / (256 / (sizeof (reds) - 1));
487  reditbl = redtbl = idx * redmul;
488  if (idx < (sizeof (reds) - 1))
489  reditbl += redmul;
490  redval = reds[idx];
491 
492  idx = i / (256 / (sizeof (grns) - 1));
493  grnitbl = grntbl = idx * grnmul;
494  if (idx < (sizeof (grns) - 1))
495  grnitbl += grnmul;
496  grnval = grns[idx];
497 
498  idx = i / (256 / (sizeof (blus) - 1));
499  bluitbl = blutbl = idx;
500  if (idx < (sizeof (blus) - 1))
501  bluitbl++;
502  bluval = blus[idx];
503 
504  for (j = 0; j < 64; j++) {
505  if (i - redval > (256 / (sizeof (reds) - 1)) * dmsk883[128+j]) {
506  xi->xi_ccredtbl[(i << 6) + j] = reditbl;
507  } else {
508  xi->xi_ccredtbl[(i << 6) + j] = redtbl;
509  }
510 
511  if (i - grnval > (256 / (sizeof (grns) - 1)) * dmsk883[64+j]) {
512  xi->xi_ccgrntbl[(i << 6) + j] = grnitbl;
513  } else {
514  xi->xi_ccgrntbl[(i << 6) + j] = grntbl;
515  }
516 
517  if (i - bluval > (256 / (sizeof (blus) - 1)) * dmsk883[j]) {
518  xi->xi_ccblutbl[(i << 6) + j] = bluitbl;
519  } else {
520  xi->xi_ccblutbl[(i << 6) + j] = blutbl;
521  }
522  }
523  }
524 }
525 
526 
527 HIDDEN int
528 x24_setup(fb *ifp, int width, int height)
529 {
530  struct xinfo *xi = XI(ifp);
531 
532  XGCValues gcv;
533  XSizeHints xsh; /* part of the "standard" props */
534  XWMHints xwmh; /* size guidelines for window mngr */
535  XSetWindowAttributes xswa;
536  XRectangle rect;
537  char *xname;
538 
539  FB_CK_FB(ifp);
540 
541  /* Save these in state structure */
542 
543  xi->xi_xwidth = width;
544  xi->xi_xheight = height;
545 
546  /* Open the display - use the env variable DISPLAY */
547  xname = XDisplayName(NULL);
548  /* Attempt one level of fallback, esp. for fbserv daemon */
549  if (!xname || *xname == '\0') xname = ":0";
550 
551  if ((xi->xi_dpy = XOpenDisplay(xname)) == NULL) {
552  fb_log("if_X: Can't open X display \"%s\"\n", xname);
553  return -1;
554  }
555 
556  /* Use the screen we connected to */
557  xi->xi_screen = DefaultScreen(xi->xi_dpy);
558 
559  /*
560  * Here we try to get the best possible visual that's no better than the
561  * one that the user asked for. Note that each case falls through to
562  * the next.
563  */
564 
565  switch ((xi->xi_mode & MODEV_MASK) >> 1) {
566  default:
567  case FLG_VD24:
568  if (XMatchVisualInfo(xi->xi_dpy, xi->xi_screen, 24, DirectColor,
569  &xi->xi_visinfo)) {
570  xi->xi_flags |= FLG_XCMAP | FLG_VD24;
571  break;
572  }
573  /*FALLTHROUGH*/
574  case FLG_VT24:
575  if (XMatchVisualInfo(xi->xi_dpy, xi->xi_screen, 24, TrueColor,
576  &xi->xi_visinfo)) {
577  xi->xi_flags |= FLG_VT24;
578  break;
579  }
580  /*FALLTHROUGH*/
581  case FLG_VD16:
582  if (XMatchVisualInfo(xi->xi_dpy, xi->xi_screen, 16, DirectColor,
583  &xi->xi_visinfo)) {
584  xi->xi_flags |= FLG_XCMAP | FLG_VD16;
585  break;
586  }
587  /*FALLTHROUGH*/
588  case FLG_VT16:
589  if (XMatchVisualInfo(xi->xi_dpy, xi->xi_screen, 16, TrueColor,
590  &xi->xi_visinfo)) {
591  xi->xi_flags |= FLG_VT16;
592  break;
593  }
594  /*FALLTHROUGH*/
595  case FLG_VP8:
596  if (XMatchVisualInfo(xi->xi_dpy, xi->xi_screen, 8, PseudoColor,
597  &xi->xi_visinfo)) {
598  xi->xi_flags |= FLG_VP8;
599  break;
600  }
601  /*FALLTHROUGH*/
602  case FLG_VS8:
603  if (XMatchVisualInfo(xi->xi_dpy, xi->xi_screen, 8, StaticGray,
604  &xi->xi_visinfo)) {
605  xi->xi_flags |= FLG_VS8;
606  break;
607  }
608  /*FALLTHROUGH*/
609  case FLG_VG8:
610  if (XMatchVisualInfo(xi->xi_dpy, xi->xi_screen, 8, GrayScale,
611  &xi->xi_visinfo)) {
612  xi->xi_flags |= FLG_VG8;
613  break;
614  }
615  /*FALLTHROUGH*/
616  case FLG_VS1:
617  if (XMatchVisualInfo(xi->xi_dpy, xi->xi_screen, 1, StaticGray,
618  &xi->xi_visinfo)) {
619  xi->xi_flags |= FLG_VS1;
620  break;
621  }
622  /*FALLTHROUGH*/
623  fb_log("if_X24: Can't get supported Visual on X display \"%s\"\n",
624  XDisplayName(NULL));
625  print_display_info(xi->xi_dpy);
626  return -1;
627  }
628 
629  xi->xi_visual = xi->xi_visinfo.visual;
630  xi->xi_depth = xi->xi_visinfo.depth;
631 
632  /* Set up colormaps, white/black pixels */
633 
634  switch (xi->xi_flags & FLG_VMASK) {
635  case FLG_VD24:
636  xi->xi_cmap = XCreateColormap(xi->xi_dpy, RootWindow(xi->xi_dpy,
637  xi->xi_screen), xi->xi_visual, AllocAll);
638  xi->xi_wp = 0xFFFFFF;
639  xi->xi_bp = 0x000000;
640  break;
641 
642  case FLG_VT24:
643  /*
644  * We need this colormap, even though we're not really going to
645  * use it, because if we don't specify a colormap when we
646  * create the window (thus getting the default), and the
647  * default visual is not 24-bit, the window create will fail.
648  */
649 
650  xi->xi_cmap = XCreateColormap(xi->xi_dpy, RootWindow(xi->xi_dpy,
651  xi->xi_screen), xi->xi_visual, AllocNone);
652  xi->xi_wp = 0xFFFFFF;
653  xi->xi_bp = 0x000000;
654  break;
655 
656  case FLG_VD16:
657  xi->xi_cmap = XCreateColormap(xi->xi_dpy, RootWindow(xi->xi_dpy,
658  xi->xi_screen), xi->xi_visual, AllocAll);
659  xi->xi_wp = 0xFFFFFF;
660  xi->xi_bp = 0x000000;
661  break;
662 
663  case FLG_VT16:
664  /*
665  * We need this colormap, even though we're not really going to
666  * use it, because if we don't specify a colormap when we
667  * create the window (thus getting the default), and the
668  * default visual is not 24-bit, the window create will fail.
669  */
670 
671  xi->xi_cmap = XCreateColormap(xi->xi_dpy, RootWindow(xi->xi_dpy,
672  xi->xi_screen), xi->xi_visual, AllocNone);
673  xi->xi_wp = 0xFFFFFF;
674  xi->xi_bp = 0x000000;
675  break;
676 
677  case FLG_VP8:
678  {
679  xi->xi_cmap = XCreateColormap(xi->xi_dpy, RootWindow(xi->xi_dpy,
680  xi->xi_screen), xi->xi_visual, AllocNone);
681 
682  xi->xi_ncolors = sizeof (reds) * sizeof (blus) * sizeof (grns);
683  xi->xi_base = 255 - xi->xi_ncolors;
684 
685  /* Create color cube */
686  X24_createColorCube(xi);
687 
688  /* Create fast lookup tables for dithering */
689  X24_createColorTables(xi);
690 
691  /* Do white/black pixels */
692  xi->xi_bp = xi->xi_base;
693  xi->xi_wp = xi->xi_base + xi->xi_ncolors - 1;
694 
695  break;
696  }
697 
698  case FLG_VS8:
699  /*
700  * We need this colormap, even though we're not really going to
701  * use it, because if we don't specify a colormap when we
702  * create the window (thus getting the default), and the
703  * default visual is not 8-bit, the window create will fail.
704  */
705 
706  xi->xi_cmap = XCreateColormap(xi->xi_dpy, RootWindow(xi->xi_dpy,
707  xi->xi_screen), xi->xi_visual, AllocNone);
708  xi->xi_wp = 0xFF;
709  xi->xi_bp = 0x00;
710  break;
711 
712  case FLG_VG8:
713  {
714  /*
715  * We're being a little lazy here by just taking over the
716  * entire colormap and writing a linear ramp to it. If we
717  * didn't take the whole thing we might be able to avoid a
718  * little colormap flashing, but then we'd need separate
719  * display code for GrayScale and StaticGray and I'm just not
720  * sure it's worth it.
721  */
722 
723  int i;
724  XColor colors[256];
725 
726  xi->xi_cmap = XCreateColormap(xi->xi_dpy, RootWindow(xi->xi_dpy,
727  xi->xi_screen), xi->xi_visual, AllocAll);
728 
729  /* Fill the colormap and the colorcube */
730 
731  for (i = 0; i < 255; i++) {
732  colors[i].red = i << 8;
733  colors[i].green = i << 8;
734  colors[i].blue = i << 8;
735  colors[i].flags = DoRed | DoGreen | DoBlue;
736  colors[i].pixel = i;
737  }
738 
739  XStoreColors(xi->xi_dpy, xi->xi_cmap, colors, 256);
740 
741  /* Do white/black pixels */
742 
743  xi->xi_bp = 0x00;
744  xi->xi_wp = 0xFF;
745  break;
746  }
747  case FLG_VS1:
748  {
749  int i, j, x, didx;
750 
751  /*
752  * We need this colormap, even though we're not really going to
753  * use it, because if we don't specify a colormap when we
754  * create the window (thus getting the default), and the
755  * default visual is not 1-bit, the window create will fail.
756  */
757 
758  xi->xi_cmap = XCreateColormap(xi->xi_dpy, RootWindow(xi->xi_dpy,
759  xi->xi_screen), xi->xi_visual, AllocNone);
760 
761  /* Create fast lookup tables for dithering */
762 
763  xi->xi_andtbl = (unsigned char *)malloc(64 * 256);
764  xi->xi_ortbl = (unsigned char *)malloc(64 * 256);
765 
766  for (i = 0; i < 256; i++)
767  for (j = 0; j < 64; j++) {
768  didx = j;
769  x = 7 - (j & 0x7);
770 
771  if (i > (256.0 * dmsk881[didx])) {
772  xi->xi_andtbl[(i << 6) + j] = 0xFF;
773  xi->xi_ortbl[(i << 6) + j] = 1 << x;
774  } else {
775  xi->xi_andtbl[(i << 6) + j] = ~(1 << x);
776  xi->xi_ortbl[(i << 6) + j] = 0;
777  }
778  }
779 
780  xi->xi_wp = 0x0;
781  xi->xi_bp = 0x1;
782  break;
783  }
784  }
785 
786  /* Create fake colormaps if the X server won't do it for us */
787 
788  if (!(xi->xi_flags & FLG_XCMAP)) {
789  xi->xi_redmap = (unsigned char *)malloc(256);
790  xi->xi_grnmap = (unsigned char *)malloc(256);
791  xi->xi_blumap = (unsigned char *)malloc(256);
792 
793  if (!xi->xi_redmap || !xi->xi_grnmap || !xi->xi_blumap) {
794  fb_log("if_X24: Can't allocate colormap memory\n");
795  return -1;
796  }
797  }
798 
799  /*
800  * Fill in XSetWindowAttributes struct for XCreateWindow.
801  */
802  xswa.event_mask = ExposureMask | ButtonPressMask | StructureNotifyMask;
803  xswa.background_pixel = xi->xi_bp;
804  xswa.border_pixel = xi->xi_wp;
805  xswa.bit_gravity = ForgetGravity;
806  xswa.backing_store = Always;
807  xswa.colormap = xi->xi_cmap;
808 
809  xi->xi_win = XCreateWindow(xi->xi_dpy, RootWindow(xi->xi_dpy,
810  xi->xi_screen), 0, 0, width, height, 3, xi->xi_depth,
811  InputOutput, xi->xi_visual, CWEventMask | CWBackPixel |
812  CWBorderPixel | CWBitGravity | CWBackingStore | CWColormap,
813  &xswa);
814  xi->xi_cwinp = xi->xi_win;
815 
816  if (xi->xi_win == 0) {
817  fb_log("if_X: Can't create window\n");
818  return -1;
819  }
820 
821  /* Tell window manager about colormap */
822 
823  XSetWindowColormap(xi->xi_dpy, xi->xi_win, xi->xi_cmap);
824 
825  /*
826  * Fill in XSizeHints struct to inform window
827  * manager about initial size and location.
828  */
829  xsh.flags = PPosition | PSize | PMinSize | PMaxSize;
830  xsh.width = width;
831  xsh.max_width = ifp->if_max_width;
832  xsh.min_width = 0;
833  xsh.height = height;
834  xsh.max_height = ifp->if_max_height;
835  xsh.min_height = 0;
836  xsh.x = xsh.y = 0;
837 
838  /* Set standard properties for Window Managers */
839 
840  XSetStandardProperties(xi->xi_dpy, xi->xi_win,
841  "Frame buffer", /* window name */
842  "Frame buffer", /* icon name */
843  None, /* icon pixmap */
844  NULL, 0, /* command (argv, argc) */
845  &xsh); /* size hints */
846 
847  xwmh.input = False; /* no terminal input? */
848  xwmh.initial_state = NormalState;
849  xwmh.flags = InputHint | StateHint;
850  XSetWMHints(xi->xi_dpy, xi->xi_win, &xwmh);
851 
852  /* Create a Graphics Context for drawing */
853 
854  gcv.foreground = xi->xi_wp;
855  gcv.background = xi->xi_bp;
856  xi->xi_gc = XCreateGC(xi->xi_dpy, xi->xi_win,
857  GCForeground | GCBackground, &gcv);
858 
859  /* Create a Graphics Context for clipping */
860 
861  gcv.foreground = xi->xi_bp;
862  gcv.background = xi->xi_bp;
863  xi->xi_cgc = XCreateGC(xi->xi_dpy, xi->xi_win,
864  GCForeground | GCBackground, &gcv);
865 
866  /* Initialize the valid region */
867  xi->xi_usereg = 1;
868  xi->xi_reg = XCreateRegion();
869  rect.x = 0;
870  rect.y = 0;
871  rect.width = xi->xi_xwidth;
872  rect.height = xi->xi_xheight;
873  XUnionRectWithRegion(&rect, xi->xi_reg, xi->xi_reg);
874 
875  /* Map window to screen */
876 
877  XMapWindow(xi->xi_dpy, xi->xi_win);
878  XFlush(xi->xi_dpy);
879 
880  /* Allocate image buffer, and make our X11 Image */
881 
882  switch (xi->xi_flags & FLG_VMASK) {
883  case FLG_VD24:
884  case FLG_VT24:
885  if ((xi->xi_pix = (unsigned char *) calloc(sizeof(unsigned int),
886  width*height)) == NULL) {
887  fb_log("X24_open: pix32 malloc failed\n");
888  return -1;
889  }
890 
891  xi->xi_image = XCreateImage(xi->xi_dpy,
892  xi->xi_visual, xi->xi_depth, ZPixmap, 0,
893  (char *) xi->xi_pix, width, height,
894  sizeof(unsigned int) * 8, 0);
895  break;
896 
897  case FLG_VD16:
898  case FLG_VT16:
899  if ((xi->xi_pix = (unsigned char *) calloc(2, width*height)) == NULL) {
900  fb_log("X24_open: pix32 malloc failed\n");
901  return -1;
902  }
903 
904  xi->xi_image = XCreateImage(xi->xi_dpy,
905  xi->xi_visual, xi->xi_depth, ZPixmap, 0,
906  (char *) xi->xi_pix, width, height,
907  16, 0);
908  break;
909 
910  case FLG_VP8:
911  case FLG_VS8:
912  case FLG_VG8:
913  if ((xi->xi_pix = (unsigned char *) calloc(sizeof(char),
914  width*height)) == NULL) {
915  fb_log("X24_open: pix8 malloc failed\n");
916  return -1;
917  }
918  memset(xi->xi_pix, xi->xi_bp, width*height);
919 
920  xi->xi_image = XCreateImage(xi->xi_dpy,
921  xi->xi_visual, xi->xi_depth, ZPixmap, 0,
922  (char *) xi->xi_pix, width, height, 8, 0);
923  break;
924 
925  case FLG_VS1:
926  xi->xi_image = XCreateImage(xi->xi_dpy,
927  xi->xi_visual, xi->xi_depth, XYBitmap, 0,
928  NULL, width, height, 32, 0);
929 
930  if ((xi->xi_pix = (unsigned char *) calloc(sizeof(char),
931  xi->xi_image->bytes_per_line * height)) == NULL) {
932  fb_log("X24_open: pix1 malloc failed\n");
933  return -1;
934  }
935  xi->xi_image->data = (char *) xi->xi_pix;
936  xi->xi_image->byte_order = MSBFirst;
937  xi->xi_image->bitmap_bit_order = MSBFirst;
938 
939  memset(xi->xi_pix, 0, xi->xi_image->bytes_per_line *
940  height);
941  break;
942  }
943 
944  /* Calculate luminance tables if we need them */
945 
946  switch (xi->xi_flags & FLG_VMASK) {
947  case FLG_VG8:
948  case FLG_VS1:
949  if (!lumdone) {
950  int i;
951  unsigned long r, g, b;
952 
953  /* This is an integer arithmetic version of YUV to RGB
954  * conversion where we're multiplying by three
955  * coefficients (0.299, 0.587, 0.114) for 24-bit
956  * integers. See http://en.wikipedia.org/wiki/YUV for
957  * more details.
958  *
959  * NOTE: Using an addition method to build up the
960  * luminance ramp instead of multiplication because
961  * it's probably faster and avoids a gcc 4.8.1
962  * aggressive optimization bug.
963  */
964  for (i = r = g = b = 0; i < 256; i++, r += 5016388, g += 9848226, b += 1912603) {
965  rlumtbl[i] = r;
966  glumtbl[i] = g;
967  blumtbl[i] = b;
968  }
969  lumdone = 1;
970  }
971  }
972 
973  return 0;
974 }
975 
976 
977 /*
978  * This routine is called when ever the framebuffer is updated OR when
979  * there is an expose event generated by the X server.
980  *
981  * The X server world is confusing because XDR is NOT done for client
982  * or server, thus leaving each client responsible for getting a X
983  * pixel map prepared in the correct lay out.
984  *
985  * There are something like 18 different visuals and 2 endians that we
986  * need to deal with 1-bit, 2-bit, 4-bit and 8-bit monochrome 8-bit
987  * CLUT, 8-bit True Color, 8-bit Direct Color 15-bit Pseudo Color,
988  * 15-bit True Color, 15-bit Direct color 16-bit Pseudo Color, 16-bit
989  * True Color, 16-bit Direct Color 24-bit Pseudo, True and Direct and
990  * finally 32-bit Pseudo, True and Direct colors.
991  *
992  * For the 1-8 bit case we do some dithering and get an image up as
993  * best we can. for the >8 bit cases we need to do a bit more.
994  *
995  * Our input is always in RGB (24 bit) order in memory so there is
996  * nothing fancy we need to do there.
997  *
998  * For output, the X server tells us, in an opaque object that we are
999  * not suppose to peek into, where the RGB components go in a BIG
1000  * endian bit vector and how many bits per component. Using this
1001  * information we construct masks and shift counts for each component.
1002  * This information is later used to construct a bit vector in a
1003  * register. This register is then clocked out as bytes in the
1004  * correct ordering.
1005  *
1006  * x1, y1->w, h describes a Rectangle of changed bits (image space coord.)
1007  */
1008 HIDDEN void
1009 X24_blit(fb *ifp, int x1, int y1, int w, int h, int flags /* BLIT_xxx flags */)
1010 {
1011  struct xinfo *xi = XI(ifp);
1012 
1013  int x2 = x1 + w - 1; /* Convert to rectangle corners */
1014  int y2 = y1 + h - 1;
1015 
1016  int x1wd, x2wd, y1ht, y2ht;
1017  int x, y;
1018  int ox, oy;
1019  int xdel, ydel;
1020  int xwd, xht;
1021 
1022  /*
1023  * Newish code, discover masks and shifts for each of RGB
1024  *
1025  * The Masks are right justified, we just shift them up 6 bits in
1026  * the long to give us some room on the low end. We'll correct
1027  * this out later.
1028  */
1029  unsigned int a_pixel;
1030 
1031  unsigned long test_mask;
1032  unsigned long a_mask;
1033 
1034  int red_shift, green_shift, blue_shift;
1035  unsigned int mask_red = xi->xi_image->red_mask << 6;
1036  unsigned int mask_green = xi->xi_image->green_mask << 6;
1037  unsigned int mask_blue = xi->xi_image->blue_mask << 6;
1038  size_t i;
1039 
1040  FB_CK_FB(ifp);
1041 
1042  /*
1043  * Now that we know the mask, we shift a bit left, one bit at a
1044  * time until it overlaps the mask. This tells us how far we have
1045  * to shift our pixel to get it under the bit mask.
1046  */
1047  a_mask = mask_red;
1048  test_mask = 1;
1049  for (i=0; i<sizeof(unsigned long)*8;i++) {
1050  if (test_mask & a_mask) break;
1051  test_mask = test_mask << 1;
1052  }
1053  for (;i<sizeof(unsigned long)*8;i++) {
1054  if (!(test_mask & a_mask)) break;
1055  test_mask = test_mask << 1;
1056  }
1057  red_shift = i-8;
1058 
1059  a_mask = mask_green;
1060  test_mask = 1;
1061  for (i=0; i<sizeof(unsigned long)*8;i++) {
1062  if (test_mask & a_mask) break;
1063  test_mask = test_mask << 1;
1064  }
1065  for (;i<sizeof(unsigned long)*8;i++) {
1066  if (!(test_mask & a_mask)) break;
1067  test_mask = test_mask << 1;
1068  }
1069  green_shift = i-8;
1070 
1071  a_mask = mask_blue;
1072  test_mask = 1;
1073  for (i=0; i<sizeof(unsigned long)*8;i++) {
1074  if (test_mask & a_mask) break;
1075  test_mask = test_mask << 1;
1076  }
1077  for (;i<sizeof(unsigned long)*8;i++) {
1078  if (!(test_mask & a_mask)) break;
1079  test_mask =test_mask << 1;
1080  }
1081  blue_shift = i-8;
1082 
1083  /*
1084  * If the changed rectangle is outside the displayed one, there's
1085  * nothing to do
1086  */
1087 
1088  if (x1 > xi->xi_irt ||
1089  x2 < xi->xi_ilf ||
1090  y1 > xi->xi_itp ||
1091  y2 < xi->xi_ibt)
1092  return;
1093 
1094  /*
1095  * Clamp to actual displayed portion of image
1096  */
1097  if (x1 < xi->xi_ilf) x1 = xi->xi_ilf;
1098  if (x2 > xi->xi_irt) x2 = xi->xi_irt;
1099  if (y1 < xi->xi_ibt) y1 = xi->xi_ibt;
1100  if (y2 > xi->xi_itp) y2 = xi->xi_itp;
1101 
1102  /*
1103  * Figure out sizes of outermost image pixels
1104  */
1105  x1wd = (x1 == xi->xi_ilf) ? xi->xi_ilf_w : ifp->if_xzoom;
1106  x2wd = (x2 == xi->xi_irt) ? xi->xi_irt_w : ifp->if_xzoom;
1107  y1ht = (y1 == xi->xi_ibt) ? xi->xi_ibt_h : ifp->if_yzoom;
1108  y2ht = (y2 == xi->xi_itp) ? xi->xi_itp_h : ifp->if_yzoom;
1109 
1110  /* Compute ox: offset from left edge of window to left pixel */
1111 
1112  xdel = x1 - xi->xi_ilf;
1113  if (xdel) {
1114  ox = x1wd + ((xdel - 1) * ifp->if_xzoom) + xi->xi_xlf;
1115  } else {
1116  ox = xi->xi_xlf;
1117  }
1118 
1119 
1120  /* Compute oy: offset from top edge of window to bottom pixel */
1121 
1122  ydel = y1 - xi->xi_ibt;
1123  if (ydel) {
1124  oy = xi->xi_xbt - (y1ht + ((ydel - 1) * ifp->if_yzoom));
1125  } else {
1126  oy = xi->xi_xbt;
1127  }
1128 
1129 
1130  /* Figure out size of changed area on screen in X pixels */
1131 
1132  if (x2 == x1) {
1133  xwd = x1wd;
1134  } else {
1135  xwd = x1wd + x2wd + ifp->if_xzoom * (x2 - x1 - 1);
1136  }
1137 
1138  if (y2 == y1) {
1139  xht = y1ht;
1140  } else {
1141  xht = y1ht + y2ht + ifp->if_yzoom * (y2 - y1 - 1);
1142  }
1143 
1144  /*
1145  * Set pointers to start of source and destination areas; note
1146  * that we're going from lower to higher image coordinates, so
1147  * irgb increases, but since images are in quadrant I and X uses
1148  * quadrant IV, opix _decreases_.
1149  */
1150 
1151  switch (xi->xi_flags & FLG_VMASK) {
1152  case FLG_VD24:
1153  case FLG_VT24:
1154  case FLG_VD16:
1155  case FLG_VT16:
1156  {
1157  unsigned char *irgb;
1158  unsigned char *opix;
1159  unsigned char *red = xi->xi_redmap;
1160  unsigned char *grn = xi->xi_grnmap;
1161  unsigned char *blu = xi->xi_blumap;
1162 
1163  /*
1164  * Calculate the beginning of the line where we are going
1165  * to be outputting pixels.
1166  */
1167  opix = &(xi->xi_pix[oy * xi->xi_image->bytes_per_line]);
1168  /* + ox * (xi->xi_image->bits_per_pixel/8)]); */
1169 
1170  /*
1171  * Our source of pixels in packed RGB order
1172  */
1173  irgb = &(xi->xi_mem[(y1 * xi->xi_iwidth + x1) * sizeof(RGBpixel)]);
1174 
1175  /* General case, zooming in effect */
1176 
1177  for (y = y1; y <= y2; y++) {
1178  unsigned char *line_irgb;
1179  unsigned char *p;
1180 
1181  /* Save pointer to start of line */
1182 
1183  line_irgb = irgb;
1184  p = (unsigned char *)opix;
1185 
1186  /* For the first line, convert/copy pixels */
1187 
1188  for (x = x1; x <= x2; x++) {
1189  int pxwd;
1190 
1191  /* Calculate # pixels needed */
1192  /* See comment above for more info */
1193 
1194  if (x == x1) {
1195  pxwd = x1wd;
1196  } else if (x == x2) {
1197  pxwd = x2wd;
1198  } else {
1199  pxwd = ifp->if_xzoom;
1200  }
1201 
1202  /*
1203  * Construct a pixel with the color components
1204  * in the right places as described by the
1205  * X servers red, green and blue masks.
1206  */
1207  if (xi->xi_flags & (FLG_XCMAP | FLG_LINCMAP)) {
1208  a_pixel = (line_irgb[RED] << red_shift) & mask_red;
1209  a_pixel |= (line_irgb[GRN] << green_shift) & mask_green;
1210  a_pixel |= (line_irgb[BLU] << blue_shift) & mask_blue;
1211  } else {
1212  a_pixel = (red[line_irgb[RED]] << red_shift) & mask_red;
1213  a_pixel |= (grn[line_irgb[GRN]] << green_shift) & mask_green;
1214  a_pixel |= (blu[line_irgb[BLU]] << blue_shift) & mask_blue;
1215  }
1216  /* take out the safety put in above. */
1217  a_pixel = a_pixel >> 6;
1218 
1219  /*
1220  * Now we clock out that pixel according to
1221  * the number of bytes AND the byte ordering
1222  *
1223  * A slightly faster version would unroll
1224  * these loops into a number of different
1225  * loops.
1226  *
1227  * The while loop on the inside causes pixel
1228  * replication for when we are zoomed.
1229  */
1230  if (ImageByteOrder(xi->xi_dpy) == MSBFirst) {
1231  if (xi->xi_image->bits_per_pixel == 16) {
1232  while (pxwd--) {
1233  *p++ = (a_pixel >> 8) & 0xff;
1234  *p++ = a_pixel & 0xff;
1235  }
1236  } else if (xi->xi_image->bits_per_pixel == 24) {
1237  while (pxwd--) {
1238  *p++ = (a_pixel >> 16) & 0xff;
1239  *p++ = (a_pixel >> 8) & 0xff;
1240  *p++ = a_pixel & 0xff;
1241  }
1242  } else if (xi->xi_image->bits_per_pixel == 32) {
1243  while (pxwd--) {
1244  *p++ = (a_pixel >> 24) & 0xff;
1245  *p++ = (a_pixel >> 16) & 0xff;
1246  *p++ = (a_pixel >> 8) & 0xff;
1247  *p++ = a_pixel & 0xff;
1248  }
1249  }
1250 
1251  } else {
1252  /* LSB order */
1253  if (xi->xi_image->bits_per_pixel == 16) {
1254  while (pxwd--) {
1255  *p++ = a_pixel & 0xff;
1256  *p++ = (a_pixel >> 8) & 0xff;
1257  }
1258  } else if (xi->xi_image->bits_per_pixel == 24) {
1259  while (pxwd--) {
1260  *p++ = a_pixel & 0xff;
1261  *p++ = (a_pixel >> 8) & 0xff;
1262  *p++ = (a_pixel >> 16) & 0xff;
1263  }
1264  } else if (xi->xi_image->bits_per_pixel == 32) {
1265  while (pxwd--) {
1266  *p++ = a_pixel & 0xff;
1267  *p++ = (a_pixel >> 8) & 0xff;
1268  *p++ = (a_pixel >> 16) & 0xff;
1269  *p++ = (a_pixel >> 24) & 0xff;
1270  }
1271  }
1272 
1273  }
1274  /*
1275  * Move to the next input line.
1276  */
1277  line_irgb += sizeof (RGBpixel);
1278  }
1279 
1280  /*
1281  * And again, move to the beginning of the next
1282  * line up in the X server.
1283  */
1284  opix -= xi->xi_image->bytes_per_line;
1285 
1286  irgb += xi->xi_iwidth * sizeof(RGBpixel);
1287  }
1288  break;
1289  }
1290 
1291  case FLG_VP8:
1292  {
1293  int dmx = ox & 0x7;
1294  int dmy = (oy & 0x7) << 3;
1295 
1296  unsigned int r, g, b;
1297  unsigned char *red = xi->xi_redmap;
1298  unsigned char *grn = xi->xi_grnmap;
1299  unsigned char *blu = xi->xi_blumap;
1300 
1301  unsigned char *ip = &(xi->xi_mem[(y1 * xi->xi_iwidth + x1) *
1302  sizeof (RGBpixel)]);
1303  unsigned char *op = (unsigned char *) &xi->xi_pix[oy *
1304  xi->xi_xwidth + ox];
1305 
1306 
1307  if (ifp->if_xzoom == 1 && ifp->if_yzoom == 1) {
1308  /* Special case if no zooming */
1309 
1310  int j, k;
1311 
1312  for (j = y2 - y1 + 1; j; j--) {
1313  unsigned char *lip;
1314  unsigned char *lop;
1315 
1316  lip = ip;
1317  lop = op;
1318 
1319  /* For each line, convert/copy pixels */
1320 
1321  if (xi->xi_flags & (FLG_XCMAP | FLG_LINCMAP)) {
1322  for (k = x2 - x1 + 1; k; k--) {
1323  r = lip[RED];
1324  g = lip[GRN];
1325  b = lip[BLU];
1326 
1327  *lop++ = xi->xi_base +
1328  xi->xi_ccredtbl[(r << 6) + dmx + dmy] +
1329  xi->xi_ccgrntbl[(g << 6) + dmx + dmy] +
1330  xi->xi_ccblutbl[(b << 6) + dmx + dmy];
1331 
1332  dmx = (dmx + 1) & 0x7;
1333  lip += sizeof (RGBpixel);
1334  }
1335  } else {
1336  for (k = x2 - x1 + 1; k; k--) {
1337  r = red[lip[RED]];
1338  g = grn[lip[GRN]];
1339  b = blu[lip[BLU]];
1340 
1341  *lop++ = xi->xi_base +
1342  xi->xi_ccredtbl[(r << 6) + dmx + dmy] +
1343  xi->xi_ccgrntbl[(g << 6) + dmx + dmy] +
1344  xi->xi_ccblutbl[(b << 6) + dmx + dmy];
1345 
1346  dmx = (dmx + 1) & 0x7;
1347  lip += sizeof (RGBpixel);
1348  }
1349  }
1350 
1351  ip += xi->xi_iwidth * sizeof (RGBpixel);
1352  op -= xi->xi_image->bytes_per_line;
1353  dmx = ox & 0x7;
1354  dmy = (dmy + 0x38) & 0x38;
1355  }
1356  } else {
1357  /* General case */
1358 
1359  for (y = y1; y <= y2; y++) {
1360  int pyht;
1361  unsigned char *lip;
1362  unsigned char *lop;
1363 
1364  /* Calculate # lines needed */
1365 
1366  if (y == y1)
1367  pyht = y1ht;
1368  else if (y == y2)
1369  pyht = y2ht;
1370  else
1371  pyht = ifp->if_yzoom;
1372 
1373  /* For each line, convert/copy pixels */
1374 
1375  while (pyht--) {
1376  lip = ip;
1377  lop = op;
1378 
1379  if (xi->xi_flags & (FLG_XCMAP | FLG_LINCMAP)) {
1380  for (x = x1; x <= x2; x++) {
1381  int pxwd;
1382 
1383  /* Calculate # pixels needed */
1384 
1385  if (x == x1)
1386  pxwd = x1wd;
1387  else if (x == x2)
1388  pxwd = x2wd;
1389  else
1390  pxwd = ifp->if_xzoom;
1391 
1392  r = lip[RED];
1393  g = lip[GRN];
1394  b = lip[BLU];
1395 
1396  while (pxwd--) {
1397  *lop++ = xi->xi_base +
1398  xi->xi_ccredtbl[(r << 6) + dmx + dmy] +
1399  xi->xi_ccgrntbl[(g << 6) + dmx + dmy] +
1400  xi->xi_ccblutbl[(b << 6) + dmx + dmy];
1401 
1402  dmx = (dmx + 1) & 0x7;
1403  }
1404 
1405  lip += sizeof (RGBpixel);
1406  }
1407  } else {
1408  for (x = x1; x <= x2; x++) {
1409  int pxwd;
1410 
1411  /* Calculate # pixels needed */
1412 
1413  if (x == x1)
1414  pxwd = x1wd;
1415  else if (x == x2)
1416  pxwd = x2wd;
1417  else
1418  pxwd = ifp->if_xzoom;
1419 
1420  r = red[lip[RED]];
1421  g = grn[lip[GRN]];
1422  b = blu[lip[BLU]];
1423 
1424  while (pxwd--) {
1425  *lop++ = xi->xi_base +
1426  xi->xi_ccredtbl[(r << 6) + dmx + dmy] +
1427  xi->xi_ccgrntbl[(g << 6) + dmx + dmy] +
1428  xi->xi_ccblutbl[(b << 6) + dmx + dmy];
1429 
1430  dmx = (dmx + 1) & 0x7;
1431  }
1432 
1433  lip += sizeof (RGBpixel);
1434  }
1435  }
1436 
1437  op -= xi->xi_image->bytes_per_line;
1438  dmx = ox & 0x7;
1439  dmy = (dmy + 0x38) & 0x38;
1440  }
1441  ip += xi->xi_iwidth * sizeof (RGBpixel);
1442  }
1443  }
1444  break;
1445  }
1446 
1447  case FLG_VS8:
1448  case FLG_VG8:
1449  {
1450  unsigned int r, g, b;
1451  unsigned char *red = xi->xi_redmap;
1452  unsigned char *grn = xi->xi_grnmap;
1453  unsigned char *blu = xi->xi_blumap;
1454 
1455  unsigned char *ip = &(xi->xi_mem[(y1 * xi->xi_iwidth + x1) *
1456  sizeof (RGBpixel)]);
1457  unsigned char *op = (unsigned char *) &xi->xi_pix[oy *
1458  xi->xi_xwidth + ox];
1459 
1460  if (ifp->if_xzoom == 1 && ifp->if_yzoom == 1) {
1461  /* Special case if no zooming */
1462 
1463  int j, k;
1464 
1465  for (j = y2 - y1 + 1; j; j--) {
1466  unsigned char *lip;
1467  unsigned char *lop;
1468 
1469  lip = ip;
1470  lop = op;
1471 
1472  /* For each line, convert/copy pixels */
1473 
1474  if (xi->xi_flags & (FLG_XCMAP | FLG_LINCMAP)) {
1475  for (k = x2 - x1 + 1; k; k--) {
1476  r = lip[RED];
1477  g = lip[GRN];
1478  b = lip[BLU];
1479 
1480  *lop++ = (rlumtbl[r] +
1481  glumtbl[g] +
1482  blumtbl[b] +
1483  8388608) >> 24;
1484  lip += sizeof (RGBpixel);
1485  }
1486  } else {
1487  for (k = x2 - x1 + 1; k; k--) {
1488  r = red[lip[RED]];
1489  g = grn[lip[GRN]];
1490  b = blu[lip[BLU]];
1491 
1492  *lop++ = (rlumtbl[r] +
1493  glumtbl[g] +
1494  blumtbl[b] +
1495  8388608) >> 24;
1496  lip += sizeof (RGBpixel);
1497  }
1498  }
1499 
1500  ip += xi->xi_iwidth * sizeof (RGBpixel);
1501  op -= xi->xi_xwidth;
1502  }
1503  } else {
1504  /* General case */
1505 
1506  for (y = y1; y <= y2; y++) {
1507  int pyht;
1508  int copied;
1509  unsigned char *lip;
1510  unsigned char pix, *lop, *prev_line;
1511 
1512  /* Calculate # lines needed */
1513 
1514  if (y == y1)
1515  pyht = y1ht;
1516  else if (y == y2)
1517  pyht = y2ht;
1518  else
1519  pyht = ifp->if_yzoom;
1520 
1521 
1522  /* Save pointer to start of line */
1523 
1524  lip = ip;
1525  prev_line = lop = op;
1526 
1527  /* For the first line, convert/copy pixels */
1528 
1529  if (xi->xi_flags & (FLG_XCMAP | FLG_LINCMAP)) {
1530  for (x = x1; x <= x2; x++) {
1531  int pxwd;
1532 
1533  /* Calculate # pixels needed */
1534 
1535  if (x == x1)
1536  pxwd = x1wd;
1537  else if (x == x2)
1538  pxwd = x2wd;
1539  else
1540  pxwd = ifp->if_xzoom;
1541 
1542  /* Get/convert pixel */
1543 
1544  r = lip[RED];
1545  g = lip[GRN];
1546  b = lip[BLU];
1547 
1548  pix = (rlumtbl[r] +
1549  glumtbl[g] +
1550  blumtbl[b] +
1551  8388608) >> 24;
1552 
1553  lip += sizeof (RGBpixel);
1554 
1555  /* Make as many copies as needed */
1556 
1557  while (pxwd--)
1558  *lop++ = pix;
1559  }
1560  } else {
1561  for (x = x1; x <= x2; x++) {
1562  int pxwd;
1563 
1564  /* Calculate # pixels needed */
1565 
1566  if (x == x1)
1567  pxwd = x1wd;
1568  else if (x == x2)
1569  pxwd = x2wd;
1570  else
1571  pxwd = ifp->if_xzoom;
1572 
1573  /* Get/convert pixel */
1574 
1575  r = red[lip[RED]];
1576  g = grn[lip[GRN]];
1577  b = blu[lip[BLU]];
1578 
1579  pix = (rlumtbl[r] +
1580  glumtbl[g] +
1581  blumtbl[b] +
1582  8388608) >> 24;
1583 
1584  lip += sizeof (RGBpixel);
1585 
1586  /* Make as many copies as needed */
1587 
1588  while (pxwd--)
1589  *lop++ = pix;
1590  }
1591  }
1592 
1593  copied = lop - op;
1594 
1595  ip += xi->xi_iwidth * sizeof (RGBpixel);
1596  op -= xi->xi_xwidth;
1597 
1598  /* Copy remaining output lines from 1st output line */
1599 
1600  pyht--;
1601  while (pyht--) {
1602  memcpy(op, prev_line, copied);
1603  op -= xi->xi_xwidth;
1604  }
1605  }
1606  }
1607  break;
1608  }
1609 
1610  case FLG_VS1:
1611  {
1612  int dmx = ox & 0x7;
1613  int dmy = (oy & 0x7) << 3;
1614 
1615  unsigned int r, g, b;
1616  unsigned char *red = xi->xi_redmap;
1617  unsigned char *grn = xi->xi_grnmap;
1618  unsigned char *blu = xi->xi_blumap;
1619 
1620  unsigned char *ip = &(xi->xi_mem[(y1 * xi->xi_iwidth + x1) *
1621  sizeof (RGBpixel)]);
1622  unsigned char *op = (unsigned char *) &xi->xi_pix[oy *
1623  xi->xi_image->bytes_per_line + ox / 8];
1624 
1625 
1626  if (ifp->if_xzoom == 1 && ifp->if_yzoom == 1) {
1627  /* Special case if no zooming */
1628 
1629  int j, k;
1630 
1631  for (j = y2 - y1 + 1; j; j--) {
1632  unsigned char *lip;
1633  unsigned char *lop;
1634  unsigned char loppix;
1635  unsigned int lum;
1636 
1637  lip = ip;
1638  lop = op;
1639  loppix = *lop;
1640 
1641  /* For each line, convert/copy pixels */
1642 
1643  if (xi->xi_flags & (FLG_XCMAP | FLG_LINCMAP)) {
1644  for (k = x2 - x1 + 1; k; k--) {
1645  r = lip[RED];
1646  g = lip[GRN];
1647  b = lip[BLU];
1648 
1649  lum = (rlumtbl[r] +
1650  glumtbl[g] +
1651  blumtbl[b] +
1652  8388608) >> 24;
1653 
1654  loppix = (loppix &
1655  xi->xi_andtbl[(lum << 6)
1656  + dmx + dmy]) |
1657  xi->xi_ortbl[(lum << 6)
1658  + dmx + dmy];
1659 
1660  dmx = (dmx + 1) & 0x7;
1661  if (!dmx) {
1662  *lop = loppix;
1663  lop++;
1664  }
1665 
1666  lip += sizeof (RGBpixel);
1667  }
1668  } else {
1669  for (k = x2 - x1 + 1; k; k--) {
1670  r = lip[RED];
1671  g = lip[GRN];
1672  b = lip[BLU];
1673 
1674  lum = (rlumtbl[red[r]] +
1675  glumtbl[grn[g]] +
1676  blumtbl[blu[b]] +
1677  8388608) >> 24;
1678 
1679  loppix = (loppix &
1680  xi->xi_andtbl[(lum << 6)
1681  + dmx + dmy]) |
1682  xi->xi_ortbl[(lum << 6)
1683  + dmx + dmy];
1684 
1685  dmx = (dmx + 1) & 0x7;
1686  if (!dmx) {
1687  *lop = loppix;
1688  lop++;
1689  }
1690 
1691  lip += sizeof (RGBpixel);
1692  }
1693  }
1694 
1695  if (dmx)
1696  *lop = loppix;
1697  ip += xi->xi_iwidth * sizeof (RGBpixel);
1698  op -= xi->xi_image->bytes_per_line;
1699  dmx = ox & 0x7;
1700  dmy = (dmy + 0x38) & 0x38;
1701  }
1702  } else {
1703  /* General case */
1704 
1705  for (y = y1; y <= y2; y++) {
1706  int pyht;
1707  unsigned char *lip;
1708  unsigned char *lop;
1709  unsigned char loppix;
1710  unsigned int lum;
1711 
1712  /* Calculate # lines needed */
1713 
1714  if (y == y1)
1715  pyht = y1ht;
1716  else if (y == y2)
1717  pyht = y2ht;
1718  else
1719  pyht = ifp->if_yzoom;
1720 
1721  /* For each line, convert/copy pixels */
1722 
1723  while (pyht--) {
1724  lip = ip;
1725  lop = op;
1726  loppix = *lop;
1727 
1728  if (xi->xi_flags & (FLG_XCMAP | FLG_LINCMAP)) {
1729  for (x = x1; x <= x2; x++) {
1730  int pxwd;
1731 
1732  /* Calculate # pixels needed */
1733 
1734  if (x == x1)
1735  pxwd = x1wd;
1736  else if (x == x2)
1737  pxwd = x2wd;
1738  else
1739  pxwd = ifp->if_xzoom;
1740 
1741  r = lip[RED];
1742  g = lip[GRN];
1743  b = lip[BLU];
1744 
1745  lum = (rlumtbl[r] +
1746  glumtbl[g] +
1747  blumtbl[b] +
1748  8388608) >> 24;
1749 
1750  while (pxwd--) {
1751  loppix = (loppix &
1752  xi->xi_andtbl[(lum << 6)
1753  + dmx + dmy]) |
1754  xi->xi_ortbl[(lum << 6)
1755  + dmx + dmy];
1756 
1757  dmx = (dmx + 1) & 0x7;
1758  if (!dmx) {
1759  *lop = loppix;
1760  lop++;
1761  }
1762  }
1763 
1764  lip += sizeof (RGBpixel);
1765  }
1766  } else {
1767  for (x = x1; x <= x2; x++) {
1768  int pxwd;
1769 
1770  /* Calculate # pixels needed */
1771 
1772  if (x == x1)
1773  pxwd = x1wd;
1774  else if (x == x2)
1775  pxwd = x2wd;
1776  else
1777  pxwd = ifp->if_xzoom;
1778 
1779  r = lip[RED];
1780  g = lip[GRN];
1781  b = lip[BLU];
1782 
1783  lum = (rlumtbl[red[r]] +
1784  glumtbl[grn[g]] +
1785  blumtbl[blu[b]] +
1786  8388608) >> 24;
1787 
1788  while (pxwd--) {
1789  loppix = (loppix &
1790  xi->xi_andtbl[(lum << 6)
1791  + dmx + dmy]) |
1792  xi->xi_ortbl[(lum << 6)
1793  + dmx + dmy];
1794 
1795  dmx = (dmx + 1) & 0x7;
1796  if (!dmx) {
1797  *lop = loppix;
1798  lop++;
1799  }
1800  }
1801 
1802  lip += sizeof (RGBpixel);
1803  }
1804  }
1805 
1806  if (dmx)
1807  *lop = loppix;
1808  op -= xi->xi_image->bytes_per_line;
1809  dmx = ox & 0x7;
1810  dmy = (dmy + 0x38) & 0x38;
1811  }
1812  ip += xi->xi_iwidth * sizeof (RGBpixel);
1813  }
1814  }
1815  break;
1816  }
1817  }
1818 
1819  /* Blit out changed image */
1820 
1821  if (flags & BLIT_DISP) {
1822  XPutImage(xi->xi_dpy, xi->xi_win, xi->xi_gc, xi->xi_image,
1823  ox, oy - xht + 1, ox, oy - xht + 1, xwd, xht);
1824  }
1825 
1826  /* If we changed the valid region, make a new one. */
1827 
1828  if (xi->xi_usereg && (flags & (BLIT_PZ | BLIT_RESIZE))) {
1829  XRectangle rect;
1830  Region Nreg = XCreateRegion();
1831 
1832  rect.x = ox;
1833  rect.y = oy - xht + 1;
1834  rect.width = xwd;
1835  rect.height = xht;
1836  XUnionRectWithRegion(&rect, Nreg, Nreg);
1837 
1838  if (flags & BLIT_PZ) {
1839  /* If we're panning/zooming, clear out old image. */
1840 
1841  Region Creg = XCreateRegion();
1842 
1843  XSubtractRegion(xi->xi_reg, Nreg, Creg);
1844 
1845  if (!XEmptyRegion(Creg)) {
1846  XSetRegion(xi->xi_dpy, xi->xi_cgc, Creg);
1847 
1848  XFillRectangle(xi->xi_dpy, xi->xi_win,
1849  xi->xi_cgc, 0, 0, xi->xi_xwidth,
1850  xi->xi_xheight);
1851  }
1852  XDestroyRegion(Creg);
1853 
1854  }
1855  XDestroyRegion(xi->xi_reg);
1856  xi->xi_reg = Nreg;
1857  }
1858 
1859  if (flags & BLIT_DISP)
1860  XFlush(xi->xi_dpy);
1861 }
1862 
1863 
1864 HIDDEN int
1865 X24_rmap(fb *ifp, ColorMap *cmp)
1866 {
1867  struct xinfo *xi = XI(ifp);
1868  FB_CK_FB(ifp);
1869 
1870  memcpy(cmp, xi->xi_rgb_cmap, sizeof (ColorMap));
1871 
1872  return 0;
1873 }
1874 
1875 
1876 HIDDEN int
1877 X24_wmap(fb *ifp, const ColorMap *cmp)
1878 {
1879  struct xinfo *xi = XI(ifp);
1880  ColorMap *map = xi->xi_rgb_cmap;
1881  int waslincmap;
1882  FB_CK_FB(ifp);
1883 
1884  /* Did we have a linear colormap before this call? */
1885 
1886  waslincmap = xi->xi_flags & FLG_LINCMAP;
1887 
1888  /* Clear linear colormap flag, since it may be changing */
1889 
1890  xi->xi_flags &= ~FLG_LINCMAP;
1891 
1892  /* Copy in or generate colormap */
1893 
1894  if (cmp) {
1895  if (cmp != map)
1896  memcpy(map, cmp, sizeof (ColorMap));
1897  } else {
1898  fb_make_linear_cmap(map);
1899  xi->xi_flags |= FLG_LINCMAP;
1900  }
1901 
1902  /* Decide if this colormap is linear */
1903 
1904  if (!(xi->xi_flags & FLG_LINCMAP)) {
1905  int i;
1906  int nonlin = 0;
1907 
1908  for (i = 0; i < 256; i++)
1909  if (map->cm_red[i] >> 8 != i ||
1910  map->cm_green[i] >> 8 != i ||
1911  map->cm_blue[i] >> 8 != i) {
1912  nonlin = 1;
1913  break;
1914  }
1915 
1916  if (!nonlin)
1917  xi->xi_flags |= FLG_LINCMAP;
1918  }
1919 
1920  /*
1921  * If it was linear before, and they're making it linear again,
1922  * there's nothing to do.
1923  */
1924  if (waslincmap && xi->xi_flags & FLG_LINCMAP)
1925  return 0;
1926 
1927  if (xi->xi_flags & FLG_XCMAP) {
1928  XColor cells[256];
1929  int i;
1930 
1931  /* Copy into the server's colormap. */
1932 
1933  for (i = 0; i < 256; i++) {
1934  cells[i].pixel = (i << 16) | (i << 8) | i;
1935  cells[i].red = map->cm_red[i];
1936  cells[i].green = map->cm_green[i];
1937  cells[i].blue = map->cm_blue[i];
1938  cells[i].flags = DoRed | DoGreen | DoBlue;
1939  }
1940 
1941  XStoreColors(xi->xi_dpy, xi->xi_cmap, cells, 256);
1942  } else {
1943  int i;
1944  unsigned char *red = xi->xi_redmap;
1945  unsigned char *grn = xi->xi_grnmap;
1946  unsigned char *blu = xi->xi_blumap;
1947 
1948  /* Copy into our fake colormap arrays. */
1949 
1950  for (i = 0; i < 256; i++) {
1951  red[i] = map->cm_red[i] >> 8;
1952  grn[i] = map->cm_green[i] >> 8;
1953  blu[i] = map->cm_blue[i] >> 8;
1954  }
1955 
1956  /*
1957  * If we're initialized, redraw the screen to make changes
1958  * take effect.
1959  */
1960 
1961  if (xi->xi_flags & FLG_INIT)
1962  X24_blit(ifp, 0, 0, xi->xi_iwidth, xi->xi_iheight,
1963  BLIT_DISP);
1964  }
1965 
1966  return 0;
1967 }
1968 
1969 
1970 /*
1971  * Allocate backing store for two reasons. First, if we are running on
1972  * a truecolor display then the colormaps are not modifiable and
1973  * colormap ops have to be simulated by manipulating the pixel values.
1974  * Second, X does not provide a means to zoom or pan so zooming and
1975  * panning must also be simulated by manipulating the pixel values.
1976  * In order to preserve the semantics of libfb which say that reads
1977  * will read back the original image, it is necessary to allocate
1978  * backing store. This code tries to allocate a System V shared
1979  * memory segment for backing store. System V shared memory persists
1980  * until explicitly killed, so this also means that under X, the
1981  * previous contents of the frame buffer still exist, and can be
1982  * accessed again, even though the windows are transient, per-process.
1983  */
1984 HIDDEN int
1985 X24_getmem(fb *ifp)
1986 {
1987  struct xinfo *xi = XI(ifp);
1988 
1989  char *mem = NULL;
1990  size_t pixsize;
1991  off_t size;
1992  int isnew = 0;
1993 
1994  FB_CK_FB(ifp);
1995 
1996  pixsize = ifp->if_max_height * ifp->if_max_width * sizeof(RGBpixel);
1997  size = pixsize + sizeof (*xi->xi_rgb_cmap);
1998 
1999  /*
2000  * get shared mem segment, creating it if it does not exist
2001  */
2002  switch (xi->xi_mode & MODE10_MASK) {
2003  case MODE10_SHARED:
2004  {
2005  /* First try to attach to an existing shared memory */
2006 
2007 #ifdef HAVE_SYS_MMAN_H
2008  int fd;
2009 
2010  fd = open(BS_NAME, O_RDWR | O_CREAT | O_BINARY, 0666);
2011  if (fd < 0)
2012  fb_log("X24_getmem: can't create fb file, using private memory instead, errno %d\n", errno);
2013  else if (lseek(fd, size, SEEK_SET) < 0)
2014  fb_log("X24_getmem: can't seek fb file, using private memory instead, errno %d\n", errno);
2015  else if (lseek(fd, 0, SEEK_SET) < 0)
2016  fb_log("X24_getmem: can't seek fb file, using private memory instead, errno %d\n", errno);
2017  else if ((mem = (char *)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == (char *) -1)
2018  fb_log("X24_getmem: can't mmap fb file, using private memory instead, errno %d\n", errno);
2019  else {
2020  close(fd);
2021  break;
2022  }
2023 
2024  /* Change it to local */
2025  xi->xi_mode = (xi->xi_mode & ~MODE10_MASK) | MODE10_MALLOC;
2026 #endif
2027 #ifdef HAVE_SYS_SHM_H
2028  if ((xi->xi_shmid = shmget(SHMEM_KEY, size, 0)) < 0) {
2029  /* No existing one, create a new one */
2030  xi->xi_shmid = shmget(SHMEM_KEY, size, IPC_CREAT|0666);
2031  isnew = 1;
2032  }
2033 
2034  if (xi->xi_shmid < 0) {
2035  fb_log("X24_getmem: can't shmget shared memory, using \
2036 private memory instead, errno %d\n", errno);
2037  } else {
2038  /* Open the segment Read/Write */
2039  if ((mem = (char *)shmat(xi->xi_shmid, 0, 0)) != (char *)-1L)
2040  break;
2041  else
2042  fb_log("X24_getmem: can't shmat shared memory, \
2043 using private memory instead, errno %d\n", errno);
2044  }
2045 
2046  /* Change it to local */
2047  xi->xi_mode = (xi->xi_mode & ~MODE10_MASK) | MODE10_MALLOC;
2048 #endif
2049 
2050 #ifndef CAN_LINGER
2051  /* Change it to local */
2052  xi->xi_mode = (xi->xi_mode & ~MODE10_MASK) | MODE10_MALLOC;
2053 #endif
2054 
2055  /*FALLTHROUGH*/
2056 
2057  }
2058  case MODE10_MALLOC:
2059 
2060  if ((mem = (char *)malloc(size)) == 0) {
2061  fb_log("if_X24: Unable to allocate %d bytes of backing \
2062 store\n Run shell command 'limit datasize unlimited' and try again.\n", size);
2063  return -1;
2064  }
2065  isnew = 1;
2066  break;
2067  }
2068 
2069  xi->xi_rgb_cmap = (ColorMap *) mem;
2070  xi->xi_mem = (unsigned char *) mem + sizeof (*xi->xi_rgb_cmap);
2071 
2072  /* Clear memory frame buffer to black */
2073  if (isnew) {
2074  memset(mem, 0, size);
2075  }
2076 
2077  return isnew;
2078 }
2079 
2080 
2081 HIDDEN void
2082 X24_updstate(fb *ifp)
2083 {
2084  struct xinfo *xi = XI(ifp);
2085 
2086  int xwp, ywp; /* Size of X window in image pixels */
2087  int xrp, yrp; /* Leftover X pixels */
2088 
2089  int tp_h, bt_h; /* Height of top/bottom image pixel slots */
2090  int lf_w, rt_w; /* Width of left/right image pixel slots */
2091 
2092  int want, avail; /* Wanted/available image pixels */
2093 
2094  FB_CK_FB(ifp);
2095 
2096  /*
2097  * Set ?wp to the number of whole zoomed image pixels we could display
2098  * in the X window.
2099  */
2100  xwp = xi->xi_xwidth / ifp->if_xzoom;
2101  ywp = xi->xi_xheight / ifp->if_yzoom;
2102 
2103  /*
2104  * Set ?rp to the number of leftover X pixels we have, after displaying
2105  * wp whole zoomed image pixels.
2106  */
2107  xrp = xi->xi_xwidth % ifp->if_xzoom;
2108  yrp = xi->xi_xheight % ifp->if_yzoom;
2109 
2110  /*
2111  * Force ?wp to be the same as the window width (mod 2). This
2112  * keeps the image from jumping around when using large zoom
2113  * factors.
2114  */
2115 
2116  if (xwp && (xwp ^ xi->xi_xwidth) & 1) {
2117  xwp--;
2118  xrp += ifp->if_xzoom;
2119  }
2120 
2121  if (ywp && (ywp ^ xi->xi_xheight) & 1) {
2122  ywp--;
2123  yrp += ifp->if_yzoom;
2124  }
2125 
2126  /*
2127  * Now we calculate the height/width of the outermost image pixel
2128  * slots. If we've got any leftover X pixels, we'll make
2129  * truncated slots out of them; if not, the outermost ones end up
2130  * full size. We'll adjust ?wp to be the number of full and
2131  * truncated slots available.
2132  */
2133  switch (xrp) {
2134  case 0:
2135  lf_w = ifp->if_xzoom;
2136  rt_w = ifp->if_xzoom;
2137  break;
2138 
2139  case 1:
2140  lf_w = 1;
2141  rt_w = ifp->if_xzoom;
2142  xwp += 1;
2143  break;
2144 
2145  default:
2146  lf_w = xrp / 2;
2147  rt_w = xrp - lf_w;
2148  xwp += 2;
2149  break;
2150  }
2151 
2152  switch (yrp) {
2153  case 0:
2154  tp_h = ifp->if_yzoom;
2155  bt_h = ifp->if_yzoom;
2156  break;
2157 
2158  case 1:
2159  tp_h = 1;
2160  bt_h = ifp->if_yzoom;
2161  ywp += 1;
2162  break;
2163 
2164  default:
2165  tp_h = yrp / 2;
2166  bt_h = yrp - tp_h;
2167  ywp += 2;
2168  break;
2169  }
2170 
2171  /*
2172  * We've now divided our X window up into image pixel slots as
2173  * follows:
2174  *
2175  * - All slots are xzoom by yzoom X pixels in size, except:
2176  * slots in the top row are tp_h X pixels high
2177  * slots in the bottom row are bt_h X pixels high
2178  * slots in the left column are lf_w X pixels wide
2179  * slots in the right column are rt_w X pixels wide
2180  * - The window is xwp by ywp slots in size.
2181  */
2182 
2183  /*
2184  * We can think of xcenter as being "number of pixels we'd like
2185  * displayed on the left half of the screen". We have xwp/2
2186  * pixels available on the left half. We use this information to
2187  * calculate the remaining parameters as noted.
2188  */
2189 
2190  want = ifp->if_xcenter;
2191  avail = xwp/2;
2192  if (want >= avail) {
2193  /*
2194  * Just enough or too many pixels to display. We'll be butted
2195  * up against the left edge, so
2196  * - the leftmost X pixels will have an x coordinate of 0;
2197  * - the leftmost column of image pixels will be as wide as the
2198  * leftmost column of image pixel slots; and
2199  * - the leftmost image pixel displayed will have an x
2200  * coordinate equal to the number of pixels that didn't fit.
2201  */
2202 
2203  xi->xi_xlf = 0;
2204  xi->xi_ilf_w = lf_w;
2205  xi->xi_ilf = want - avail;
2206  } else {
2207  /*
2208  * Not enough image pixels to fill the area. We'll be offset
2209  * from the left edge, so
2210  * - the leftmost X pixels will have an x coordinate equal
2211  * to the number of pixels taken up by the unused image
2212  * pixel slots;
2213  * - the leftmost column of image pixels will be as wide as the
2214  * xzoom width; and
2215  * - the leftmost image pixel displayed will have a zero
2216  * x coordinate.
2217  */
2218 
2219  xi->xi_xlf = lf_w + (avail - want - 1) * ifp->if_xzoom;
2220  xi->xi_ilf_w = ifp->if_xzoom;
2221  xi->xi_ilf = 0;
2222  }
2223 
2224  /* Calculation for bottom edge. */
2225 
2226  want = ifp->if_ycenter;
2227  avail = ywp/2;
2228  if (want >= avail) {
2229  /*
2230  * Just enough or too many pixels to display. We'll be
2231  * butted up against the bottom edge, so
2232  * - the bottommost X pixels will have a y coordinate
2233  * equal to the window height minus 1;
2234  * - the bottommost row of image pixels will be as tall as the
2235  * bottommost row of image pixel slots; and
2236  * - the bottommost image pixel displayed will have a y
2237  * coordinate equal to the number of pixels that didn't fit.
2238  */
2239 
2240  xi->xi_xbt = xi->xi_xheight - 1;
2241  xi->xi_ibt_h = bt_h;
2242  xi->xi_ibt = want - avail;
2243  } else {
2244  /*
2245  * Not enough image pixels to fill the area. We'll be
2246  * offset from the bottom edge, so
2247  * - the bottommost X pixels will have a y coordinate equal
2248  * to the window height, less the space taken up by the
2249  * unused image pixel slots, minus 1;
2250  * - the bottom row of image pixels will be as tall as the
2251  * yzoom width; and
2252  * - the bottommost image pixel displayed will have a zero
2253  * y coordinate.
2254  */
2255 
2256  xi->xi_xbt = xi->xi_xheight - (bt_h + (avail - want - 1) *
2257  ifp->if_yzoom) - 1;
2258  xi->xi_ibt_h = ifp->if_yzoom;
2259  xi->xi_ibt = 0;
2260  }
2261 
2262  /* Calculation for right edge. */
2263 
2264  want = xi->xi_iwidth - ifp->if_xcenter;
2265  avail = xwp - xwp/2;
2266  if (want >= avail) {
2267  /*
2268  * Just enough or too many pixels to display. We'll be
2269  * butted up against the right edge, so
2270  * - the rightmost X pixels will have an x coordinate equal
2271  * to the window width minus 1;
2272  * - the rightmost column of image pixels will be as wide as
2273  * the rightmost column of image pixel slots; and
2274  * - the rightmost image pixel displayed will have an x
2275  * coordinate equal to the center plus the number of pixels
2276  * that fit, minus 1.
2277  */
2278 
2279  xi->xi_xrt = xi->xi_xwidth - 1;
2280  xi->xi_irt_w = rt_w;
2281  xi->xi_irt = ifp->if_xcenter + avail - 1;
2282  } else {
2283  /*
2284  * Not enough image pixels to fill the area. We'll be
2285  * offset from the right edge, so
2286  * - the rightmost X pixels will have an x coordinate equal
2287  * to the window width, less the space taken up by the
2288  * unused image pixel slots, minus 1;
2289  * - the rightmost column of image pixels will be as wide as
2290  * the xzoom width; and
2291  * - the rightmost image pixel displayed will have an x
2292  * coordinate equal to the width of the image minus 1.
2293  */
2294 
2295  xi->xi_xrt = xi->xi_xwidth - (rt_w + (avail - want - 1) *
2296  ifp->if_xzoom) - 1;
2297  xi->xi_irt_w = ifp->if_xzoom;
2298  xi->xi_irt = xi->xi_iwidth - 1;
2299  }
2300 
2301  /* Calculation for top edge. */
2302 
2303  want = xi->xi_iheight - ifp->if_ycenter;
2304  avail = ywp - ywp/2;
2305  if (want >= avail) {
2306  /*
2307  * Just enough or too many pixels to display. We'll be
2308  * butted up against the top edge, so
2309  * - the topmost X pixels will have a y coordinate of 0;
2310  * - the topmost row of image pixels will be as tall as
2311  * the topmost row of image pixel slots; and
2312  * - the topmost image pixel displayed will have a y
2313  * coordinate equal to the center plus the number of pixels
2314  * that fit, minus 1.
2315  */
2316 
2317  xi->xi_xtp = 0;
2318  xi->xi_itp_h = tp_h;
2319  xi->xi_itp = ifp->if_ycenter + avail - 1;
2320  } else {
2321  /*
2322  * Not enough image pixels to fill the area. We'll be
2323  * offset from the top edge, so
2324  * - the topmost X pixels will have a y coordinate equal
2325  * to the space taken up by the unused image pixel slots;
2326  * - the topmost row of image pixels will be as tall as
2327  * the yzoom height; and
2328  * - the topmost image pixel displayed will have a y
2329  * coordinate equal to the height of the image minus 1.
2330  */
2331 
2332  xi->xi_xtp = tp_h + (avail - want - 1) * ifp->if_yzoom;
2333  xi->xi_itp_h = ifp->if_yzoom;
2334  xi->xi_itp = xi->xi_iheight - 1;
2335  }
2336 
2337 }
2338 
2339 
2340 HIDDEN void
2341 X24_zapmem(void)
2342 {
2343 #ifndef HAVE_SYS_MMAN_H
2344  int shmid;
2345  int i;
2346 #endif
2347 
2348 #ifdef HAVE_SYS_MMAN_H
2349  bu_file_delete(BS_NAME);
2350 #endif
2351 #ifdef HAVE_SYS_SHM_H
2352  if ((shmid = shmget(SHMEM_KEY, 0, 0)) < 0) {
2353  fb_log("X24_zapmem shmget failed, errno=%d\n", errno);
2354  return;
2355  }
2356 
2357  i = shmctl(shmid, IPC_RMID, 0);
2358  if (i < 0) {
2359  fb_log("X24_zapmem shmctl failed, errno=%d\n", errno);
2360  return;
2361  }
2362 #endif
2363 #ifdef CAN_LINGER
2364  fb_log("if_X24: shared memory released\n");
2365 #endif
2366  return;
2367 }
2368 
2369 
2370 HIDDEN void
2371 X24_destroy(struct xinfo *xi)
2372 {
2373  if (xi) {
2374  if (xi->xi_rgb_cmap &&
2375  (xi->xi_mode & MODE10_MASK) == MODE10_MALLOC)
2376  free(xi->xi_rgb_cmap);
2377 
2378  if (xi->xi_redmap)
2379  free(xi->xi_redmap);
2380  if (xi->xi_grnmap)
2381  free(xi->xi_grnmap);
2382  if (xi->xi_blumap)
2383  free(xi->xi_blumap);
2384  if (xi->xi_ccredtbl)
2385  free(xi->xi_ccredtbl);
2386  if (xi->xi_ccgrntbl)
2387  free(xi->xi_ccgrntbl);
2388  if (xi->xi_ccblutbl)
2389  free(xi->xi_ccblutbl);
2390  if (xi->xi_andtbl)
2391  free(xi->xi_andtbl);
2392  if (xi->xi_ortbl)
2393  free(xi->xi_ortbl);
2394 
2395  if (xi->xi_dpy) {
2396  if (xi->xi_cgc)
2397  XFreeGC(xi->xi_dpy, xi->xi_cgc);
2398 
2399  if (xi->xi_gc)
2400  XFreeGC(xi->xi_dpy, xi->xi_gc);
2401 
2402  if (xi->xi_image)
2403  XDestroyImage(xi->xi_image);
2404 
2405  if (xi->xi_reg)
2406  XDestroyRegion(xi->xi_reg);
2407 
2408  XCloseDisplay(xi->xi_dpy);
2409  }
2410 
2411  free((char *) xi);
2412  }
2413 }
2414 
2415 
2416 HIDDEN int
2417 X24_open(fb *ifp, const char *file, int width, int height)
2418 {
2419  struct xinfo *xi;
2420 
2421  unsigned long mode; /* local copy */
2422  int getmem_stat;
2423 
2424  FB_CK_FB(ifp);
2425 
2426  /*
2427  * First, attempt to determine operating mode for this open,
2428  * based upon the "unit number" or flags.
2429  * file = "/dev/X###"
2430  */
2431  mode = MODE1_LINGERING;
2432 
2433  if (file != NULL) {
2434  const char *cp;
2435  char modebuf[80];
2436  char *mp;
2437  int alpha;
2438  struct modeflags *mfp;
2439 
2440  if (bu_strncmp(file, ifp->if_name, strlen(ifp->if_name))) {
2441  /* How did this happen?? */
2442  mode = 0;
2443  } else {
2444  /* Parse the options */
2445  alpha = 0;
2446  mp = &modebuf[0];
2447  cp = &file[sizeof("/dev/X")-1];
2448  while (*cp != '\0' && !isspace((int)(*cp))) {
2449  *mp++ = *cp; /* copy it to buffer */
2450  if (isdigit((int)(*cp))) {
2451  cp++;
2452  continue;
2453  }
2454  alpha++;
2455  for (mfp = modeflags; mfp->c != '\0'; mfp++) {
2456  if (mfp->c == *cp) {
2457  mode = (mode&~mfp->mask)|mfp->value;
2458  break;
2459  }
2460  }
2461  if (mfp->c == '\0' && *cp != '-') {
2462  fb_log("if_X24: unknown option '%c' ignored\n", *cp);
2463  }
2464  cp++;
2465  }
2466  *mp = '\0';
2467  if (!alpha)
2468  mode |= atoi(modebuf);
2469  }
2470  }
2471 
2472  /* Just zap the shared memory and exit */
2473  if ((mode & MODE11_MASK) == MODE11_ZAP) {
2474  /* Only task: Attempt to release shared memory segment */
2475  X24_zapmem();
2476  return -1;
2477  }
2478 
2479  if (width <= 0)
2480  width = ifp->if_width;
2481  if (height <= 0)
2482  height = ifp->if_height;
2483  if (width > ifp->if_max_width)
2484  width = ifp->if_max_width;
2485  if (height > ifp->if_max_height)
2486  height = ifp->if_max_height;
2487 
2488  ifp->if_width = width;
2489  ifp->if_height = height;
2490 
2491  ifp->if_xzoom = 1;
2492  ifp->if_yzoom = 1;
2493  ifp->if_xcenter = width/2;
2494  ifp->if_ycenter = height/2;
2495 
2496  /* create a struct of state information */
2497  if ((xi = (struct xinfo *) calloc(1, sizeof(struct xinfo))) == NULL) {
2498  fb_log("X24_open: xinfo malloc failed\n");
2499  return -1;
2500  }
2501  XI_SET(ifp, xi);
2502 
2503  xi->xi_mode = mode;
2504  xi->xi_iwidth = width;
2505  xi->xi_iheight = height;
2506 
2507  /* Allocate backing store (shared memory or local) */
2508 
2509  if ((getmem_stat = X24_getmem(ifp)) == -1) {
2510  X24_destroy(xi);
2511  return -1;
2512  }
2513 
2514  /* Set up an X window, graphics context, etc. */
2515 
2516  if (x24_setup(ifp, width, height) < 0) {
2517  X24_destroy(xi);
2518  return -1;
2519  }
2520 
2521  /* Update state for blits */
2522 
2523  X24_updstate(ifp);
2524 
2525  /* Make the Display connection available for selecting on */
2526  ifp->if_selfd = ConnectionNumber(xi->xi_dpy);
2527 
2528  /* If we already have data, display it */
2529 
2530  if (getmem_stat == 0) {
2531  X24_wmap(ifp, xi->xi_rgb_cmap);
2532  X24_blit(ifp, 0, 0, xi->xi_iwidth, xi->xi_iheight, BLIT_DISP);
2533  } else {
2534  /* Set up default linear colormap */
2535  X24_wmap(ifp, NULL);
2536  }
2537 
2538  /* Mark display ready */
2539 
2540  xi->xi_flags |= FLG_INIT;
2541 
2542 
2543  return 0;
2544 }
2545 
2546 int
2547 X24_configureWindow(fb *ifp, int width, int height)
2548 {
2549  struct xinfo *xi = XI(ifp);
2550  XRectangle rect;
2551 
2552  FB_CK_FB(ifp);
2553 
2554  if (!xi) {
2555  return 1;
2556  }
2557 
2558  if (width == xi->xi_xwidth && height == xi->xi_xheight) {
2559  return 1;
2560  }
2561 
2562  ifp->if_width = ifp->if_max_width = width;
2563  ifp->if_height = ifp->if_max_height = height;
2564 
2565  xi->xi_xwidth = xi->xi_iwidth = width;
2566  xi->xi_xheight = xi->xi_iheight = height;
2567 
2568  ifp->if_xcenter = width/2;
2569  ifp->if_ycenter = height/2;
2570 
2571  /* redo region */
2572  if (xi->xi_usereg) {
2573  XDestroyRegion(xi->xi_reg);
2574  xi->xi_reg = XCreateRegion();
2575  rect.x = 0;
2576  rect.y = 0;
2577  rect.width = xi->xi_xwidth;
2578  rect.height = xi->xi_xheight;
2579  XUnionRectWithRegion(&rect, xi->xi_reg, xi->xi_reg);
2580  }
2581 
2582  X24_updstate(ifp);
2583 
2584  switch (xi->xi_flags & FLG_VMASK) {
2585  case FLG_VD24:
2586  case FLG_VT24:
2587  /* Destroy old image struct and image buffer */
2588  XDestroyImage(xi->xi_image);
2589 
2590  /* Make new buffer and new image */
2591  if ((xi->xi_pix = (unsigned char *)calloc(sizeof(unsigned int),
2592  xi->xi_xwidth*xi->xi_xheight)) == NULL) {
2593  fb_log("X24: pix32 malloc failed in resize!\n");
2594  return 1;
2595  }
2596 
2597  xi->xi_image = XCreateImage(xi->xi_dpy, xi->xi_visual,
2598  xi->xi_depth, ZPixmap, 0, (char *) xi->xi_pix,
2599  xi->xi_xwidth, xi->xi_xheight,
2600  sizeof (unsigned int) * 8, 0);
2601 
2602  break;
2603  case FLG_VD16:
2604  case FLG_VT16:
2605  /* Destroy old image struct and image buffer */
2606  XDestroyImage(xi->xi_image);
2607 
2608  /* Make new buffer and new image */
2609  if ((xi->xi_pix = (unsigned char *)calloc(2, xi->xi_xwidth*xi->xi_xheight)) == NULL) {
2610  fb_log("X24: pix32 malloc failed in resize!\n");
2611  return 1;
2612  }
2613 
2614  xi->xi_image = XCreateImage(xi->xi_dpy, xi->xi_visual,
2615  xi->xi_depth, ZPixmap, 0, (char *) xi->xi_pix,
2616  xi->xi_xwidth, xi->xi_xheight,
2617  16, 0);
2618 
2619  break;
2620  case FLG_VP8:
2621  case FLG_VS8:
2622  case FLG_VG8:
2623  /* Destroy old image struct and image buffers */
2624  XDestroyImage(xi->xi_image);
2625 
2626  /* Make new buffers and new image */
2627  if ((xi->xi_pix = (unsigned char *)calloc(sizeof(char),
2628  xi->xi_xwidth * xi->xi_xheight)) == NULL) {
2629  fb_log("X24: pix8 malloc failed in resize!\n");
2630  return 1;
2631  }
2632 
2633  xi->xi_image = XCreateImage(xi->xi_dpy, xi->xi_visual,
2634  xi->xi_depth, ZPixmap, 0, (char *) xi->xi_pix,
2635  xi->xi_xwidth, xi->xi_xheight, 8, 0);
2636  break;
2637  case FLG_VS1:
2638  /* Destroy old image struct and image buffers */
2639  XDestroyImage(xi->xi_image);
2640 
2641  /* Make new buffers and new image */
2642  xi->xi_image = XCreateImage(xi->xi_dpy,
2643  xi->xi_visual, xi->xi_depth, XYBitmap, 0,
2644  NULL, xi->xi_xwidth, xi->xi_xheight, 32, 0);
2645 
2646  if ((xi->xi_pix = (unsigned char *)calloc(sizeof(char),
2647  xi->xi_image->bytes_per_line * xi->xi_xheight)) == NULL) {
2648  fb_log("X24: pix1 malloc failed in resize!\n");
2649  return 1;
2650  }
2651 
2652  xi->xi_image->data = (char *) xi->xi_pix;
2653  xi->xi_image->byte_order = MSBFirst;
2654  xi->xi_image->bitmap_bit_order = MSBFirst;
2655 
2656  break;
2657  }
2658 
2659  return 0;
2660 
2661 }
2662 
2663 
2664 
2665 int
2666 _X24_open_existing(fb *ifp, Display *dpy, Window win, Window cwinp, Colormap cmap, XVisualInfo *vip, int width, int height, GC gc)
2667 {
2668  struct xinfo *xi;
2669  int getmem_stat;
2670 
2671  ifp->if_width = width;
2672  ifp->if_height = height;
2673 
2674  ifp->if_xzoom = 1;
2675  ifp->if_yzoom = 1;
2676 
2677  ifp->if_xcenter = width/2;
2678  ifp->if_ycenter = height/2;
2679 
2680  /* create a struct of state information */
2681  if ((xi = (struct xinfo *)calloc(1, sizeof(struct xinfo))) == NULL) {
2682  fb_log("X24_open: xinfo malloc failed\n");
2683  return -1;
2684  }
2685  XI_SET(ifp, xi);
2686 
2687  /* X setup */
2688  xi->xi_xwidth = width;
2689  xi->xi_xheight = height;
2690  xi->xi_dpy = dpy;
2691  xi->xi_screen = DefaultScreen(xi->xi_dpy);
2692 
2693  xi->xi_visinfo = *vip; /* struct copy */
2694  xi->xi_visual = vip->visual;
2695  xi->xi_depth = vip->depth;
2696  xi->xi_cmap = cmap;
2697  xi->xi_win = win;
2698  xi->xi_cwinp = cwinp;
2699 
2700  /*XXX For now use same GC for both */
2701  xi->xi_gc = gc;
2702  xi->xi_cgc = gc;
2703 
2704  switch (vip->class) {
2705  case TrueColor:
2706  if (vip->depth >= 24) {
2707  xi->xi_mode = FLG_VT24 << 1;
2708  xi->xi_flags = FLG_VT24;
2709  xi->xi_wp = 0xFFFFFF;
2710  xi->xi_bp = 0x000000;
2711  } else if (vip->depth >= 16) {
2712  xi->xi_mode = FLG_VT16 << 1;
2713  xi->xi_flags = FLG_VT16;
2714  xi->xi_wp = 0xFFFFFF;
2715  xi->xi_bp = 0x000000;
2716  } else {
2717  xi->xi_mode = FLG_VS1 << 1;
2718  xi->xi_flags = FLG_VS1;
2719  xi->xi_wp = 0x0;
2720  xi->xi_bp = 0x1;
2721  }
2722 
2723  break;
2724  case DirectColor:
2725  if (vip->depth >= 24) {
2726  xi->xi_mode = FLG_VD24 << 1;
2727  xi->xi_flags = FLG_VD24 | FLG_XCMAP;
2728  xi->xi_wp = 0xFFFFFF;
2729  xi->xi_bp = 0x000000;
2730  } else if (vip->depth >= 16) {
2731  xi->xi_mode = FLG_VD16 << 1;
2732  xi->xi_flags = FLG_VD16 | FLG_XCMAP;
2733  xi->xi_wp = 0xFFFFFF;
2734  xi->xi_bp = 0x000000;
2735  } else {
2736  xi->xi_mode = FLG_VS1 << 1;
2737  xi->xi_flags = FLG_VS1 | FLG_XCMAP;
2738  xi->xi_wp = 0x0;
2739  xi->xi_bp = 0x1;
2740  }
2741 
2742  break;
2743  case PseudoColor:
2744  if (vip->depth >= 8) {
2745  xi->xi_mode = FLG_VP8 << 1;
2746  xi->xi_flags = FLG_VP8 | FLG_XCMAP;
2747 
2748  xi->xi_ncolors = sizeof (reds) * sizeof (blus) * sizeof (grns);
2749  xi->xi_base = 255 - xi->xi_ncolors;
2750  xi->xi_bp = xi->xi_base;
2751  xi->xi_wp = xi->xi_base + xi->xi_ncolors - 1;
2752 
2753  X24_createColorTables(xi);
2754  } else {
2755  xi->xi_mode = FLG_VS1 << 1;
2756  xi->xi_flags = FLG_VS1 | FLG_XCMAP;
2757  xi->xi_wp = 0x0;
2758  xi->xi_bp = 0x1;
2759  }
2760 
2761  break;
2762  default:
2763  xi->xi_mode = FLG_VS1 << 1;
2764  xi->xi_flags = FLG_VS1 | FLG_XCMAP;
2765  xi->xi_wp = 0x0;
2766  xi->xi_bp = 0x1;
2767 
2768  break;
2769  }
2770 
2771  if (!(xi->xi_flags & FLG_XCMAP)) {
2772  xi->xi_redmap = (unsigned char *)malloc(256);
2773  xi->xi_grnmap = (unsigned char *)malloc(256);
2774  xi->xi_blumap = (unsigned char *)malloc(256);
2775 
2776  if (!xi->xi_redmap || !xi->xi_grnmap || !xi->xi_blumap) {
2777  fb_log("if_X24: Can't allocate colormap memory\n");
2778  return -1;
2779  }
2780  }
2781 
2782  xi->xi_iwidth = width;
2783  xi->xi_iheight = height;
2784 
2785  /* Allocate backing store (shared memory or local) */
2786  if ((getmem_stat = X24_getmem(ifp)) == -1) {
2787  free((char *)xi);
2788  return -1;
2789  }
2790 
2791  /* We're not using Region's */
2792  xi->xi_reg = (Region)0;
2793  xi->xi_usereg = 0;
2794 
2795  /* this will be reallocated in the call to X24_configureWindow */
2796  if ((xi->xi_pix = (unsigned char *) calloc(1, 1)) == NULL) {
2797  fb_log("X24_open: calloc failed\n");
2798  return -1;
2799  }
2800 
2801  /* this will be destroyed in the call to X24_configureWindow */
2802  xi->xi_image = XCreateImage(xi->xi_dpy,
2803  xi->xi_visual, xi->xi_depth, ZPixmap, 0,
2804  (char *) xi->xi_pix, 1, 1, 8, 0);
2805 
2806  /* Update state for blits */
2807  X24_updstate(ifp);
2808 
2809  /* Make the Display connection available for selecting on */
2810  ifp->if_selfd = ConnectionNumber(xi->xi_dpy);
2811 
2812  if (getmem_stat == 0) {
2813  X24_wmap(ifp, xi->xi_rgb_cmap);
2814  X24_blit(ifp, 0, 0, xi->xi_iwidth, xi->xi_iheight, BLIT_DISP);
2815  } else {
2816  /* Set up default linear colormap */
2817  X24_wmap(ifp, NULL);
2818  }
2819 
2820  /* Mark display ready */
2821  xi->xi_flags |= FLG_INIT;
2822 
2823  /* force reconfiguration */
2824  xi->xi_xwidth = 0;
2825  xi->xi_xheight = 0;
2826  X24_configureWindow(ifp, width, height);
2827 
2828  return 0;
2829 }
2830 
2832 X24_get_fbps(uint32_t magic)
2833 {
2834  struct fb_platform_specific *fb_ps = NULL;
2835  struct X24_fb_info *data = NULL;
2836  BU_GET(fb_ps, struct fb_platform_specific);
2837  BU_GET(data, struct X24_fb_info);
2838  fb_ps->magic = magic;
2839  fb_ps->data = data;
2840  return fb_ps;
2841 }
2842 
2843 
2844 HIDDEN void
2845 X24_put_fbps(struct fb_platform_specific *fbps)
2846 {
2847  BU_CKMAG(fbps, FB_X24_MAGIC, "X24 framebuffer");
2848  BU_PUT(fbps->data, struct X24_fb_info);
2849  BU_PUT(fbps, struct fb_platform_specific);
2850  return;
2851 }
2852 
2853 HIDDEN int
2854 X24_open_existing(fb *ifp, int width, int height, struct fb_platform_specific *fb_p)
2855 {
2856  struct X24_fb_info *x24_internal = (struct X24_fb_info *)fb_p->data;
2857  BU_CKMAG(fb_p, FB_X24_MAGIC, "X24 framebuffer");
2858  return _X24_open_existing(ifp, x24_internal->dpy, x24_internal->win,
2859  x24_internal->cwinp, x24_internal->cmap, x24_internal->vip,
2860  width, height, x24_internal->gc);
2861 }
2862 
2863 
2864 static int alive = 1;
2865 
2866 HIDDEN void
2867 X24_handle_event(fb *ifp, XEvent *event)
2868 {
2869  struct xinfo *xi = XI(ifp);
2870  FB_CK_FB(ifp);
2871 
2872  switch ((int)event->type) {
2873  case Expose:
2874  {
2875  XExposeEvent *expose = (XExposeEvent *)event;
2876  int ex1, ey1, ex2, ey2;
2877 
2878  ex1 = expose->x;
2879  ey1 = expose->y;
2880  ex2 = ex1 + expose->width - 1;
2881  ey2 = ey1 + expose->height - 1;
2882 
2883  /* Clip to outline of valid bits in window */
2884  if (ex1 < xi->xi_xlf)
2885  ex1 = xi->xi_xlf;
2886  if (ex2 > xi->xi_xrt)
2887  ex2 = xi->xi_xrt;
2888  if (ey1 < xi->xi_xtp)
2889  ey1 = xi->xi_xtp;
2890  if (ey2 > xi->xi_xbt)
2891  ey2 = xi->xi_xbt;
2892 
2893  if (ex2 >= ex1 && ey2 >= ey1)
2894  XPutImage(xi->xi_dpy, xi->xi_win, xi->xi_gc,
2895  xi->xi_image, ex1, ey1, ex1,
2896  ey1, ex2 - ex1 + 1, ey2 - ey1 + 1);
2897  break;
2898  }
2899  case ButtonPress:
2900  {
2901  int button = (int) event->xbutton.button;
2902 
2903 
2904  if (button == Button1) {
2905  /* Check for single button mouse remap.
2906  * ctrl-1 => 2
2907  * meta-1 => 3
2908  * cmdkey => 3
2909  */
2910  if (event->xbutton.state & ControlMask) {
2911  button = Button2;
2912  } else if (event->xbutton.state & Mod1Mask) {
2913  button = Button3;
2914  } else if (event->xbutton.state & Mod2Mask) {
2915  button = Button3;
2916  }
2917 
2918  }
2919 
2920  switch (button) {
2921  case Button1:
2922  break;
2923  case Button2:
2924  {
2925  int x, sy;
2926  int ix, isy;
2927  unsigned char *cp;
2928 
2929  x = event->xbutton.x;
2930  sy = xi->xi_xheight - event->xbutton.y - 1;
2931 
2932  x -= xi->xi_xlf;
2933  sy -= xi->xi_xheight - xi->xi_xbt - 1;
2934  if (x < 0 || sy < 0) {
2935  fb_log("No RGB (outside image) 1\n");
2936  break;
2937  }
2938 
2939  if (x < xi->xi_ilf_w)
2940  ix = xi->xi_ilf;
2941  else
2942  ix = xi->xi_ilf + (x - xi->xi_ilf_w + ifp->if_xzoom - 1) / ifp->if_xzoom;
2943 
2944  if (sy < xi->xi_ibt_h)
2945  isy = xi->xi_ibt;
2946  else
2947  isy = xi->xi_ibt + (sy - xi->xi_ibt_h + ifp->if_yzoom - 1) / ifp->if_yzoom;
2948 
2949  if (ix >= xi->xi_iwidth || isy >= xi->xi_iheight) {
2950  fb_log("No RGB (outside image) 2\n");
2951  break;
2952  }
2953 
2954  cp = &(xi->xi_mem[(isy*xi->xi_iwidth + ix)*3]);
2955  fb_log("At image (%d, %d), real RGB=(%3d %3d %3d)\n",
2956  ix, isy, cp[RED], cp[GRN], cp[BLU]);
2957 
2958  break;
2959  }
2960  case Button3:
2961  alive = 0;
2962  break;
2963  }
2964  break;
2965  }
2966  case ConfigureNotify:
2967  {
2968  XConfigureEvent *conf = (XConfigureEvent *)event;
2969 
2970  if (conf->width == xi->xi_xwidth &&
2971  conf->height == xi->xi_xheight)
2972  return;
2973 
2974  X24_configureWindow(ifp, conf->width, conf->height);
2975 
2976  /*
2977  * Blit backing store to image buffer (we'll blit to screen
2978  * when we get the expose event)
2979  */
2980  X24_blit(ifp, 0, 0, xi->xi_iwidth, xi->xi_iheight, BLIT_RESIZE);
2981  break;
2982  }
2983  default:
2984  break;
2985  }
2986 
2987  return;
2988 }
2989 
2990 
2991 HIDDEN int
2992 x24_linger(fb *ifp)
2993 {
2994  struct xinfo *xi = XI(ifp);
2995  XEvent event;
2996  FB_CK_FB(ifp);
2997 
2998  if (fork() != 0)
2999  return 1; /* release the parent */
3000 
3001  while (alive) {
3002  XNextEvent(xi->xi_dpy, &event);
3003  X24_handle_event(ifp, &event);
3004  }
3005  return 0;
3006 }
3007 
3008 
3009 HIDDEN int
3010 X24_close(fb *ifp)
3011 {
3012  struct xinfo *xi = XI(ifp);
3013  FB_CK_FB(ifp);
3014 
3015  XFlush(xi->xi_dpy);
3016  if ((xi->xi_mode & MODE1_MASK) == MODE1_LINGERING) {
3017  if (x24_linger(ifp))
3018  return 0; /* parent leaves the display */
3019  }
3020 
3021  X24_destroy(xi);
3022 
3023  return 0;
3024 }
3025 
3026 
3027 int
3028 X24_close_existing(fb *ifp)
3029 {
3030  struct xinfo *xi = XI(ifp);
3031  FB_CK_FB(ifp);
3032 
3033  if (xi->xi_image)
3034  XDestroyImage(xi->xi_image);
3035 
3036  if (xi->xi_reg)
3037  XDestroyRegion(xi->xi_reg);
3038 
3039  if (xi->xi_ccredtbl)
3040  free(xi->xi_ccredtbl);
3041  if (xi->xi_ccgrntbl)
3042  free(xi->xi_ccgrntbl);
3043  if (xi->xi_ccblutbl)
3044  free(xi->xi_ccblutbl);
3045 
3046  free((char *)xi);
3047 
3048  return 0;
3049 }
3050 
3051 
3052 HIDDEN int
3053 X24_clear(fb *ifp, unsigned char *pp)
3054 {
3055  struct xinfo *xi = XI(ifp);
3056 
3057  int red, grn, blu;
3058  int npix;
3059  int n;
3060  unsigned char *cp;
3061 
3062  FB_CK_FB(ifp);
3063 
3064  if (pp == (unsigned char *)NULL) {
3065  red = grn = blu = 0;
3066  } else {
3067  red = pp[RED];
3068  grn = pp[GRN];
3069  blu = pp[BLU];
3070  }
3071 
3072  /* Clear the backing store */
3073  npix = xi->xi_iwidth * xi->xi_xheight;
3074 
3075  if (red == grn && red == blu) {
3076  memset(xi->xi_mem, red, npix*3);
3077  } else {
3078  cp = xi->xi_mem;
3079  n = npix;
3080  while (n--) {
3081  *cp++ = red;
3082  *cp++ = grn;
3083  *cp++ = blu;
3084  }
3085  }
3086 
3087  X24_blit(ifp, 0, 0, xi->xi_iwidth, xi->xi_iheight,
3088  BLIT_DISP | BLIT_PZ);
3089 
3090  return 0;
3091 }
3092 
3093 
3095 X24_read(fb *ifp, int x, int y, unsigned char *pixelp, size_t count)
3096 {
3097  struct xinfo *xi = XI(ifp);
3098  size_t maxcount;
3099  FB_CK_FB(ifp);
3100 
3101  /* check origin bounds */
3102  if (x < 0 || x >= xi->xi_iwidth || y < 0 || y >= xi->xi_iheight)
3103  return -1;
3104 
3105  /* clip read length */
3106  maxcount = xi->xi_iwidth * (xi->xi_iheight - y) - x;
3107  if (count > maxcount)
3108  count = maxcount;
3109 
3110  memcpy(pixelp, &(xi->xi_mem[(y*xi->xi_iwidth+x)*sizeof(RGBpixel)]), count*sizeof(RGBpixel));
3111  return count;
3112 }
3113 
3114 
3116 X24_write(fb *ifp, int x, int y, const unsigned char *pixelp, size_t count)
3117 {
3118  struct xinfo *xi = XI(ifp);
3119  size_t maxcount;
3120 
3121  FB_CK_FB(ifp);
3122 
3123  /* Check origin bounds */
3124  if (x < 0 || x >= xi->xi_iwidth || y < 0 || y >= xi->xi_iheight)
3125  return -1;
3126 
3127  /* Clip write length */
3128  maxcount = xi->xi_iwidth * (xi->xi_iheight - y) - x;
3129  if (count > maxcount)
3130  count = maxcount;
3131 
3132  /* Save it in 24bit backing store */
3133 
3134  memcpy(&(xi->xi_mem[(y*xi->xi_iwidth+x)*sizeof(RGBpixel)]),
3135  pixelp, count*sizeof(RGBpixel));
3136 
3137  /* Get the bits to the screen */
3138 
3139  if (x + count <= (size_t)xi->xi_iwidth) {
3140  X24_blit(ifp, x, y, count, 1, BLIT_DISP);
3141  } else {
3142  size_t ylines;
3143  size_t tcount;
3144 
3145  tcount = count - (xi->xi_iwidth - x);
3146  ylines = 1 + (tcount + xi->xi_iwidth - 1) / xi->xi_iwidth;
3147 
3148  X24_blit(ifp, 0, y, xi->xi_iwidth, ylines, BLIT_DISP);
3149  }
3150 
3151  return count;
3152 }
3153 
3154 
3155 HIDDEN int
3156 X24_view(fb *ifp, int xcenter, int ycenter, int xzoom, int yzoom)
3157 {
3158  struct xinfo *xi = XI(ifp);
3159  FB_CK_FB(ifp);
3160 
3161  /* bypass if no change */
3162  if (ifp->if_xcenter == xcenter && ifp->if_ycenter == ycenter
3163  && ifp->if_xzoom == xcenter && ifp->if_yzoom == ycenter)
3164  return 0;
3165  /* check bounds */
3166  if (xcenter < 0 || xcenter >= xi->xi_iwidth
3167  || ycenter < 0 || ycenter >= xi->xi_iheight)
3168  return -1;
3169  if (xzoom <= 0 || xzoom >= xi->xi_iwidth/2
3170  || yzoom <= 0 || yzoom >= xi->xi_iheight/2)
3171  return -1;
3172 
3173  ifp->if_xcenter = xcenter;
3174  ifp->if_ycenter = ycenter;
3175  ifp->if_xzoom = xzoom;
3176  ifp->if_yzoom = yzoom;
3177 
3178  X24_updstate(ifp);
3179  X24_blit(ifp, 0, 0, xi->xi_iwidth, xi->xi_iheight,
3180  BLIT_DISP | BLIT_PZ);
3181 
3182  return 0;
3183 }
3184 
3185 
3186 HIDDEN int
3187 X24_getview(fb *ifp, int *xcenter, int *ycenter, int *xzoom, int *yzoom)
3188 {
3189 
3190  *xcenter = ifp->if_xcenter;
3191  *ycenter = ifp->if_ycenter;
3192  *xzoom = ifp->if_xzoom;
3193  *yzoom = ifp->if_yzoom;
3194 
3195  return 0;
3196 }
3197 
3198 
3199 /*ARGSUSED*/
3200 HIDDEN int
3201 X24_setcursor(fb *ifp, const unsigned char *UNUSED(bits), int UNUSED(xbits), int UNUSED(ybits), int UNUSED(xorig), int UNUSED(yorig))
3202 {
3203  FB_CK_FB(ifp);
3204 
3205  return 0;
3206 }
3207 
3208 
3209 HIDDEN int
3210 X24_cursor(fb *ifp, int mode, int x, int y)
3211 {
3212  struct xinfo *xi = XI(ifp);
3213 
3214  if (mode) {
3215  register int xx, xy;
3216  register int delta;
3217 
3218  /* If we don't have a cursor, create it */
3219  if (!xi->xi_cwin) {
3220  XSetWindowAttributes xswa;
3221 
3222  xswa.background_pixel = xi->xi_bp;
3223  xswa.border_pixel = xi->xi_wp;
3224  xswa.colormap = xi->xi_cmap;
3225  xswa.save_under = True;
3226 
3227  xi->xi_cwin = XCreateWindow(xi->xi_dpy, xi->xi_cwinp,
3228  0, 0, 4, 4, 2, xi->xi_depth, InputOutput,
3229  xi->xi_visual, CWBackPixel | CWBorderPixel |
3230  CWSaveUnder | CWColormap, &xswa);
3231  }
3232 
3233  delta = ifp->if_width/ifp->if_xzoom/2;
3234  xx = x - (ifp->if_xcenter - delta);
3235  xx *= ifp->if_xzoom;
3236  xx += ifp->if_xzoom/2; /* center cursor */
3237 
3238  delta = ifp->if_height/ifp->if_yzoom/2;
3239  xy = y - (ifp->if_ycenter - delta);
3240  xy *= ifp->if_yzoom;
3241  xy += ifp->if_yzoom/2; /* center cursor */
3242  xy = xi->xi_xheight - xy;
3243 
3244  /* Move cursor into place; make it visible if it isn't */
3245  XMoveWindow(xi->xi_dpy, xi->xi_cwin, xx - 4, xy - 4);
3246 
3247  if (!ifp->if_cursmode)
3248  XMapRaised(xi->xi_dpy, xi->xi_cwin);
3249  } else {
3250  /* If we have a cursor and it's visible, hide it */
3251  if (xi->xi_cwin && ifp->if_cursmode)
3252  XUnmapWindow(xi->xi_dpy, xi->xi_cwin);
3253  }
3254 
3255  /* Without this flush, cursor movement is sluggish */
3256  XFlush(xi->xi_dpy);
3257 
3258  /* Update position of cursor */
3259  ifp->if_cursmode = mode;
3260  ifp->if_xcurs = x;
3261  ifp->if_ycurs = y;
3262 
3263  return 0;
3264 }
3265 
3266 
3267 HIDDEN int
3268 X24_getcursor(fb *ifp, int *mode, int *x, int *y)
3269 {
3270  fb_sim_getcursor(ifp, mode, x, y);
3271 
3272  return 0;
3273 }
3274 
3275 
3276 HIDDEN int
3277 X24_readrect(fb *ifp, int xmin, int ymin, int width, int height, unsigned char *pp)
3278 {
3279  struct xinfo *xi = XI(ifp);
3280  FB_CK_FB(ifp);
3281 
3282  /* Clip arguments */
3283 
3284  if (xmin < 0)
3285  xmin = 0;
3286  if (ymin < 0)
3287  ymin = 0;
3288  if (xmin + width > xi->xi_iwidth)
3289  width = xi->xi_iwidth - xmin;
3290  if (ymin + height > xi->xi_iheight)
3291  height = xi->xi_iheight - ymin;
3292 
3293  /* Do copy to backing store */
3294 
3295  if (xmin == 0 && width == xi->xi_iwidth) {
3296  /* We can do it all in one copy */
3297 
3298  memcpy(pp, &(xi->xi_mem[ymin * xi->xi_iwidth *
3299  sizeof (RGBpixel)]),
3300  width * height * sizeof (RGBpixel));
3301  } else {
3302  /* Need to do individual lines */
3303 
3304  int ht = height;
3305  unsigned char *p = &(xi->xi_mem[(ymin * xi->xi_iwidth + xmin) *
3306  sizeof (RGBpixel)]);
3307 
3308  while (ht--) {
3309  memcpy(pp, p, width * sizeof (RGBpixel));
3310  p += xi->xi_iwidth * sizeof (RGBpixel);
3311  pp += width * sizeof (RGBpixel);
3312  }
3313  }
3314 
3315  return width * height;
3316 }
3317 
3318 
3319 HIDDEN int
3320 X24_writerect(fb *ifp, int xmin, int ymin, int width, int height, const unsigned char *pp)
3321 {
3322  struct xinfo *xi = XI(ifp);
3323  FB_CK_FB(ifp);
3324 
3325  /* Clip arguments */
3326 
3327  if (xmin < 0)
3328  xmin = 0;
3329  if (ymin < 0)
3330  ymin = 0;
3331  if (xmin + width > xi->xi_iwidth)
3332  width = xi->xi_iwidth - xmin;
3333  if (ymin + height > xi->xi_iheight)
3334  height = xi->xi_iheight - ymin;
3335 
3336  /* Do copy to backing store */
3337 
3338  if (xmin == 0 && width == xi->xi_iwidth) {
3339  /* We can do it all in one copy */
3340 
3341  memcpy(&(xi->xi_mem[ymin * xi->xi_iwidth * sizeof (RGBpixel)]),
3342  pp, width * height * sizeof (RGBpixel));
3343  } else {
3344  /* Need to do individual lines */
3345 
3346  int ht = height;
3347  unsigned char *p = &(xi->xi_mem[(ymin * xi->xi_iwidth + xmin) *
3348  sizeof (RGBpixel)]);
3349 
3350  while (ht--) {
3351  memcpy(p, pp, width * sizeof (RGBpixel));
3352  p += xi->xi_iwidth * sizeof (RGBpixel);
3353  pp += width * sizeof (RGBpixel);
3354  }
3355  }
3356 
3357  /* Flush to screen */
3358 
3359  X24_blit(ifp, xmin, ymin, width, height, BLIT_DISP);
3360 
3361  return width * height;
3362 }
3363 
3364 
3365 HIDDEN int
3366 X24_poll(fb *ifp)
3367 {
3368  struct xinfo *xi = XI(ifp);
3369  XEvent event;
3370 
3371  FB_CK_FB(ifp);
3372 
3373  /* Check for and dispatch event */
3374  while (XCheckMaskEvent(xi->xi_dpy, ~NoEventMask, &event))
3375  X24_handle_event(ifp, &event);
3376 
3377  return 0;
3378 }
3379 
3380 
3381 HIDDEN int
3382 X24_flush(fb *ifp)
3383 {
3384  struct xinfo *xi = XI(ifp);
3385  FB_CK_FB(ifp);
3386 
3387  XFlush(xi->xi_dpy);
3388  return 0;
3389 }
3390 
3391 
3392 HIDDEN int
3393 X24_free(fb *ifp)
3394 {
3395  FB_CK_FB(ifp);
3396 
3397  return 0;
3398 }
3399 
3400 
3401 HIDDEN int
3402 X24_help(fb *ifp)
3403 {
3404  struct xinfo *xi = XI(ifp);
3405  struct modeflags *mfp;
3406  FB_CK_FB(ifp);
3407 
3408  fb_log("Description: %s\n", X24_interface.if_type);
3409  fb_log("Device: %s\n", ifp->if_name);
3410  fb_log("Max width/height: %d %d\n",
3411  X24_interface.if_max_width,
3412  X24_interface.if_max_height);
3413  fb_log("Default width/height: %d %d\n",
3414  X24_interface.if_width,
3415  X24_interface.if_height);
3416  fb_log("Usage: /dev/X[options]\n");
3417  for (mfp = modeflags; mfp->c != '\0'; mfp++) {
3418  fb_log(" %c %s\n", mfp->c, mfp->help);
3419  }
3420 
3421  fb_log("\nCurrent internal state:\n");
3422  fb_log(" xi_depth=%d\n", xi->xi_depth);
3423  fb_log(" xi_mode=%lu\n", xi->xi_mode);
3424  fb_log(" xi_flags=%lu\n", xi->xi_flags);
3425  fb_log(" xi_xwidth=%d\n", xi->xi_xwidth);
3426  fb_log(" xi_xheight=%d\n", xi->xi_xheight);
3427 
3428  fb_log("X11 Visual:\n");
3429  fb_log(" class=%d\n", xi->xi_visinfo.class);
3430 
3431  switch (xi->xi_visinfo.class) {
3432  case DirectColor:
3433  fb_log("\tDirectColor: Alterable RGB maps, pixel RGB subfield indices\n");
3434  fb_log("\tRGB Masks: 0x%lu 0x%lu 0x%lu\n", xi->xi_visinfo.red_mask,
3435  xi->xi_visinfo.green_mask, xi->xi_visinfo.blue_mask);
3436  break;
3437  case TrueColor:
3438  fb_log("\tTrueColor: Fixed RGB maps, pixel RGB subfield indices\n");
3439  fb_log("\tRGB Masks: 0x%lu 0x%lu 0x%lu\n", xi->xi_visinfo.red_mask,
3440  xi->xi_visinfo.green_mask, xi->xi_visinfo.blue_mask);
3441  break;
3442  case PseudoColor:
3443  fb_log("\tPseudoColor: Alterable RGB maps, single index\n");
3444  break;
3445  case StaticColor:
3446  fb_log("\tStaticColor: Fixed RGB maps, single index\n");
3447  break;
3448  case GrayScale:
3449  fb_log("\tGrayScale: Alterable map (R=G=B), single index\n");
3450  break;
3451  case StaticGray:
3452  fb_log("\tStaticGray: Fixed map (R=G=B), single index\n");
3453  break;
3454  default:
3455  fb_log("\tUnknown visual class %d\n", xi->xi_visinfo.class);
3456  break;
3457  }
3458  fb_log("\tColormap Size: %d\n", xi->xi_visinfo.colormap_size);
3459  fb_log("\tBits per RGB: %d\n", xi->xi_visinfo.bits_per_rgb);
3460  fb_log("\tscreen: %d\n", xi->xi_visinfo.screen);
3461  fb_log("\tdepth (total bits per pixel): %d\n", xi->xi_visinfo.depth);
3462  if (xi->xi_visinfo.depth < 24)
3463  fb_log("\tWARNING: unable to obtain full 24-bits of color, image will be quantized.\n");
3464 
3465  return 0;
3466 }
3467 
3468 
3469 int
3470 X24_refresh(fb *ifp, int x, int y, int w, int h)
3471 {
3472  if (w < 0) {
3473  w = -w;
3474  x -= w;
3475  }
3476 
3477  if (h < 0) {
3478  h = -h;
3479  y -= h;
3480  }
3481 
3482  X24_blit(ifp, x, y, w, h, BLIT_DISP);
3483 
3484  return 0;
3485 }
3486 
3487 
3488 /* This is the ONLY thing that we normally "export" */
3489 fb X24_interface = {
3490  0, /* magic number slot */
3491  FB_X24_MAGIC,
3492  X24_open, /* open device */
3493  X24_open_existing, /* existing device_open */
3494  X24_close_existing, /* existing device_close */
3495  X24_get_fbps, /* get platform specific memory */
3496  X24_put_fbps, /* free platform specific memory */
3497  X24_close, /* close device */
3498  X24_clear, /* clear device */
3499  X24_read, /* read pixels */
3500  X24_write, /* write pixels */
3501  X24_rmap, /* read colormap */
3502  X24_wmap, /* write colormap */
3503  X24_view, /* set view */
3504  X24_getview, /* get view */
3505  X24_setcursor, /* define cursor */
3506  X24_cursor, /* set cursor */
3507  X24_getcursor, /* get cursor */
3508  X24_readrect, /* read rectangle */
3509  X24_writerect, /* write rectangle */
3512  X24_configureWindow,
3513  X24_refresh,
3514  X24_poll, /* process events */
3515  X24_flush, /* flush output */
3516  X24_free, /* free resources */
3517  X24_help, /* help message */
3518  "24 bit X Window System (X11)", /* device description */
3519  2048, /* max width */
3520  2048, /* max height */
3521  "/dev/X", /* short device name */
3522  512, /* default/current width */
3523  512, /* default/current height */
3524  -1, /* select file desc */
3525  -1, /* file descriptor */
3526  1, 1, /* zoom */
3527  256, 256, /* window center */
3528  0, 0, 0, /* cursor */
3529  PIXEL_NULL, /* page_base */
3530  PIXEL_NULL, /* page_curp */
3531  PIXEL_NULL, /* page_endp */
3532  -1, /* page_no */
3533  0, /* page_dirty */
3534  0L, /* page_curpos */
3535  0L, /* page_pixels */
3536  0, /* debug */
3537  60000000, /* refresh rate - from fbserv, which had 60 seconds as a default (not sure why) */
3538  {0}, /* u1 */
3539  {0}, /* u2 */
3540  {0}, /* u3 */
3541  {0}, /* u4 */
3542  {0}, /* u5 */
3543  {0} /* u6 */
3544 };
3545 
3546 /* Because class is actually used to access a struct
3547  * entry in this file, preserve our redefinition
3548  * of class for the benefit of avoiding C++ name
3549  * collisions until the end of this file */
3550 #undef class
3551 
3552 #else
3553 
3554 /* quell empty-compilation unit warnings */
3555 static const int unused = 0;
3556 
3557 #endif /* IF_X */
3558 
3559 /*
3560  * Local Variables:
3561  * mode: C
3562  * tab-width: 8
3563  * indent-tabs-mode: t
3564  * c-file-style: "stroustrup"
3565  * End:
3566  * ex: shiftwidth=4 tabstop=8
3567  */
ptrdiff_t ssize_t
Definition: common.h:119
unsigned char RGBpixel[3]
Definition: fb.h:73
#define SHMEM_KEY
Definition: fb_private.h:65
void fb_log(const char *fmt,...) _BU_ATTR_PRINTF12
Definition: fb_log.c:42
void * data
Definition: fb.h:176
unsigned short cm_green[256]
Definition: fb.h:84
#define BU_CKMAG(_ptr, _magic, _str)
Definition: magic.h:233
#define FLG_INIT
Definition: if_qt.cpp:114
void fb_make_linear_cmap(ColorMap *cmap)
#define RED
Definition: color.h:39
#define PIXEL_NULL
Definition: fb.h:89
long Display
Definition: dm_xvars.h:49
int if_xzoom
zoom factors
Definition: fb_private.h:120
Header file for the BRL-CAD common definitions.
int fb_sim_bwreadrect(fb *ifp, int xmin, int ymin, int _width, int _height, unsigned char *pp)
Definition: fb_rect.c:102
int if_max_width
max device width
Definition: fb_private.h:111
#define BLU
Definition: color.h:41
ustring width
#define HIDDEN
Definition: common.h:86
int if_ycenter
Definition: fb_private.h:123
#define MODE10_SHARED
Definition: if_qt.cpp:125
#define SEEK_SET
Definition: db_open.c:52
if(share_geom)
Definition: nmg_mod.c:3829
#define FLG_LINCMAP
Definition: if_qt.cpp:113
int bu_strncmp(const char *string1, const char *string2, size_t n)
Definition: str.c:191
COMPLEX data[64]
Definition: fftest.c:34
void * memset(void *s, int c, size_t n)
int if_selfd
select(fd) for input events if >= 0
Definition: fb_private.h:117
#define FB_CK_FB(_p)
Definition: fb.h:100
int fb_sim_getcursor(fb *ifp, int *mode, int *x, int *y)
Definition: fb_util.c:96
long Colormap
Definition: dm_xvars.h:51
#define BU_GET(_ptr, _type)
Definition: malloc.h:201
unsigned short cm_red[256]
Definition: fb.h:83
int if_max_height
max device height
Definition: fb_private.h:112
int fb_sim_bwwriterect(fb *ifp, int xmin, int ymin, int _width, int _height, const unsigned char *pp)
Definition: fb_rect.c:132
oldeumate l2 magic
Definition: nmg_mod.c:3843
#define UNUSED(parameter)
Definition: common.h:239
#define BU_PUT(_ptr, _type)
Definition: malloc.h:215
long Window
Definition: dm_xvars.h:50
#define MODE10_MALLOC
Definition: if_qt.cpp:124
ustring alpha
#define MODE11_MASK
Definition: if_qt.cpp:127
Definition: fb.h:82
#define MODE1_MASK
Definition: if_qt.cpp:117
uint32_t magic
Definition: fb.h:176
int if_cursmode
cursor on/off
Definition: fb_private.h:124
#define MODE10_MASK
Definition: if_qt.cpp:123
#define FB_X24_MAGIC
Definition: magic.h:183
#define MODE1_TRANSIENT
Definition: if_qt.cpp:118
#define MODE1_LINGERING
Definition: if_qt.cpp:119
int if_xcurs
cursor position
Definition: fb_private.h:125
A frame-buffer IO structure.
Definition: fb_private.h:80
int if_width
current values
Definition: fb_private.h:115
unsigned short cm_blue[256]
Definition: fb.h:85
#define GRN
Definition: color.h:40
#define MODEV_MASK
Definition: if_qt.cpp:121
HIDDEN const point_t delta
Definition: sh_prj.c:618
char * if_name
what the user called it
Definition: fb_private.h:114
#define MODE11_ZAP
Definition: if_qt.cpp:129
int if_xcenter
pan position
Definition: fb_private.h:122
int bu_file_delete(const char *path)
Definition: file.c:278