source: abuse/branches/pd/imlib/port/x11/video.c @ 528

Last change on this file since 528 was 49, checked in by Sam Hocevar, 15 years ago
  • Imported original public domain release, for future reference.
  • Property svn:keywords set to Id
File size: 21.2 KB
Line 
1#include <X11/Xlib.h>
2#include <X11/Xutil.h>
3#include <X11/keysym.h>
4
5#ifndef NO_XSHM
6#include <sys/ipc.h>
7#include <sys/shm.h>
8#include <X11/extensions/XShm.h>
9#include <signal.h>
10#endif
11
12
13#include <string.h>
14#ifdef _AIX
15#include <strings.h>
16//#include <X11/AIX.h>
17//#include <X11/extensions/Xdfb.h>
18#endif
19
20#include "filter.hpp"
21#include "globals.hpp"
22#include "system.h"
23#include "video.hpp"
24#include "dos.h"
25#include "xinclude.h"
26#include "macs.hpp"
27#include "bitmap.h"
28#include "image.hpp"
29#include "jmalloc.hpp"
30
31unsigned char current_background;
32extern unsigned int xres,yres;
33extern palette *lastl;
34int X_xoff,Y_yoff,vmode;
35image *screen;
36char display_name[120];
37
38Window root;
39Display *display;
40int screen_num;
41Screen *screen_ptr;
42unsigned border_width,depth;
43Colormap XCMap;
44Window mainwin;
45GC gc;
46XFontStruct *font_info;
47XVisualInfo *my_visual;
48Visual *X_visual;
49
50int pixel_scale=1;
51
52uchar last_load_palette[256*4];  // store word alligned for faster access
53
54static int fullscreen=0;
55static int dfb=0;
56
57
58// ========================================================================
59// makes a null cursor
60// ========================================================================
61
62static Cursor CreateNullCursor(Display *display, Window root)
63{
64    Pixmap cursormask;
65    XGCValues xgc;
66    GC gc;
67    XColor dummycolour;
68    Cursor cursor;
69
70    cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
71    xgc.function = GXclear;
72    gc =  XCreateGC(display, cursormask, GCFunction, &xgc);
73    XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
74    dummycolour.pixel = 0;
75    dummycolour.red = 0;
76    dummycolour.flags = 04;
77    cursor = XCreatePixmapCursor(display, cursormask, cursormask,
78          &dummycolour,&dummycolour, 0,0);
79    XFreePixmap(display,cursormask);
80    XFreeGC(display,gc);
81    return cursor;
82}
83
84
85
86#ifndef NO_XSHM
87// ************** SHM Vars *******************
88int shm_base,shm_error_base,shm_finish_event,doShm=0;
89
90
91struct event_node
92{
93  XEvent report; 
94  event_node *next; 
95} ;
96
97
98void wait_shm_finish()
99{
100  event_node *en,*first=NULL;
101  while (1)
102  {
103    en=(event_node *)jmalloc(sizeof(event_node),"shm_wait : event");
104    XNextEvent(display, &en->report);
105
106    // if this is the finishing event, put all the stored events back
107    // on the que
108#ifndef NO_XSHM
109    if (en->report.type==shm_base+ShmCompletion)
110    {
111      jfree(en);
112     
113      while (first)
114      {
115        XPutBackEvent(display,&first->report);
116        en=first;
117        first=first->next;
118        jfree(en);     
119      }
120      return ;     
121    } else // put the event on the que to be puback
122#endif
123    {
124      en->next=first;     // put the back in reverse order
125      first=en;
126    }   
127  }
128}
129
130   
131#endif
132
133
134int get_vmode()
135{ return vmode; }
136
137void getGC(Window win, GC *gc, XFontStruct *font_info)
138{
139  XGCValues values;
140  *gc=XCreateGC(display,win,0,&values);
141  XSetFont(display, *gc, font_info->fid);
142  XSetForeground(display, *gc, BlackPixel(display,screen_num));
143  XSetLineAttributes(display, *gc, 1, LineSolid, CapRound, JoinRound);
144}
145
146
147class XImage_Info             // stored in the extended desciptor
148{
149public :
150 
151#ifndef NO_XSHM
152  XShmSegmentInfo X_shminfo;   
153#endif
154  XImage *XImg;
155} ;
156
157
158void image::make_page(short width, short height, unsigned char *page_buffer)
159{
160  XImage_Info *xi; 
161  if (special && !special->static_mem)
162  {
163    xi=new XImage_Info;
164    special->extended_descriptor=(void *)xi;   
165#ifndef NO_XSHM
166    if (doShm)
167    {
168      width=(width+3)&(0xffffffff-3);
169      // create the image
170      xi->XImg = XShmCreateImage(display,
171                                 X_visual,
172                                 my_visual->depth,
173                                 ZPixmap,
174                                 0,
175                                 &xi->X_shminfo,
176                                 width*pixel_scale,
177                                 height*pixel_scale);
178
179          w = width = xi->XImg->bytes_per_line / pixel_scale;
180
181      // create the shared memory segment
182      xi->X_shminfo.shmid = shmget (IPC_PRIVATE,
183                width*height*pixel_scale*pixel_scale, IPC_CREAT | 0777);
184      ERROR(xi->X_shminfo.shmid>=0,"shmget() failed, go figure");
185
186      xi->X_shminfo.readOnly=False;
187
188      // attach to the shared memory segment to us
189      xi->XImg->data = xi->X_shminfo.shmaddr =
190                (char *) shmat(xi->X_shminfo.shmid, 0, 0);
191      ERROR(xi->XImg->data,"shmat() failed, go figure");
192
193      // get the X server to attach to it to the X server
194      ERROR(XShmAttach(display, &xi->X_shminfo),"XShmAttach() failed, go figure");
195      XSync(display,False); // make sure segment gets attached
196      ERROR(shmctl(xi->X_shminfo.shmid,IPC_RMID,NULL)==0,"shmctl failed, why?");
197
198          if (pixel_scale == 1)
199            data=(unsigned char *) (xi->XImg->data);
200          else
201            data=(unsigned char *) jmalloc(width*height, "unscaled image");
202    } else
203#endif
204    {
205      width=(width+3)&(0xffffffff-3);       
206      if (!page_buffer)
207        page_buffer=
208                        (unsigned char *)jmalloc(width*height*pixel_scale*pixel_scale,
209                        "image::data");
210     
211      xi->XImg = XCreateImage(  display,
212                                X_visual,
213                                my_visual->depth,
214                                ZPixmap,
215                                0,
216                                (char *)page_buffer,
217                                width*pixel_scale,
218                                height*pixel_scale,
219                                32,
220                                0 );
221      ERROR(xi->XImg,"XCreateImage failed");
222
223          w = width = xi->XImg->bytes_per_line / pixel_scale;
224
225          if (pixel_scale == 1)
226            data=(unsigned char *) (xi->XImg->data);
227          else
228            data=(unsigned char *) jmalloc(width*height, "unscaled image");
229    }   
230  }
231  else
232  {
233    if (!page_buffer)
234      data=(unsigned char *)jmalloc(width*height,"image::data");
235    else data=page_buffer;
236  }
237
238  if (special)
239    special->resize(width,height);
240
241}
242
243void image::delete_page()
244{
245  XImage_Info *xi; 
246  if (special && !special->static_mem && special->extended_descriptor)
247  {   
248    xi=(XImage_Info *)special->extended_descriptor;   
249#ifndef NO_XSHM
250    if (doShm)
251    {   
252      XFlush(display);
253      XSync(display,False);  // maker sure anything with this image is drawn!
254
255      // Dettach the memory from the server
256      ERROR(XShmDetach(display, &xi->X_shminfo),"XShmDetach() failed, go figure");
257
258      XSync(display,False);  // maker sure server detached
259
260      // detach the memory from us, it will be deleted!
261      ERROR(shmdt(xi->X_shminfo.shmaddr)>=0,"shmdt failed, oops");
262
263      xi->XImg->data=NULL;  // tell X not to try to free the memory, cause we already did.
264
265      XDestroyImage(xi->XImg);   
266
267      if (pixel_scale > 1)
268        jfree(data);
269
270    } else
271#endif
272    {
273      if (!special->static_mem)
274        jfree(xi->XImg->data);
275      xi->XImg->data=NULL;                  // make sure X doesn't try to free static memory
276      XDestroyImage(xi->XImg);   
277
278      if (pixel_scale > 1)
279        jfree(data);
280    }
281    delete xi;
282  }
283  else if (!special)
284    jfree(data);     
285}
286
287
288#ifndef NO_XSHM
289#ifdef __sgi
290void clean_shm(...)
291#else
292void clean_shm(int why)      // on exit, delete all images, so shm get de-allocated.
293#endif
294{
295  while (image_list.first())
296  {
297    image *i=(image *)image_list.first();
298    delete i;
299  }
300}
301#endif
302
303void set_mode(int mode, int argc, char **argv)
304{
305  unsigned char *page;
306  vmode=mode;
307  XVisualInfo vis_info;
308  int items,i;
309  XEvent report;
310  XWMHints *wm_hints;
311  XClassHint *class_hints;
312  XTextProperty winName,iconName;
313  XSizeHints *size_hints;
314  char *win_name=argv[0],        // name the window and the icon the executable name
315       *icon_name=argv[0];
316  Pixmap icon_pixmap;
317 
318  // get the default display name from the enviroment variable DISPLAY
319  char *ds_name=getenv("DISPLAY");
320  if (!ds_name) ds_name="unix:0.0";
321  strcpy(display_name,ds_name);
322 
323  int suppress_shm=0;
324
325  // check for command line display name
326  for (i=1;i<argc;i++)
327  {
328    if (!strcasecmp(argv[i],"-display") || !strcasecmp(argv[i],"-disp"))
329    {
330      i++;     
331      strcpy(display_name,argv[i]); 
332    }   
333    else if (!strcasecmp(argv[i],"-noshm"))
334      suppress_shm=1;
335    else if (!strcasecmp(argv[i],"-pixel_scale"))
336      pixel_scale=atoi(argv[i+1]);
337    else if (!strcasecmp(argv[i],"-fullscreen"))
338                {
339      fullscreen=1;
340                        pixel_scale=2;
341                }
342    else if (!strcasecmp(argv[i],"-dfb"))
343                {
344      fullscreen=1;
345                        pixel_scale=2;
346                        dfb = 1;
347                }
348  }
349   
350  display=XOpenDisplay(display_name); 
351  if (!display)
352  {
353    printf("Cound not connect to X server named '%s'\n",display_name);
354    exit(1);
355  }
356
357#ifndef NO_XSHM
358  // check for the MITSHM extension
359  int major_op;
360 
361  if (suppress_shm)
362    doShm=0;
363  else
364    doShm = XQueryExtension(display,"MIT-SHM",&major_op,&shm_base,&shm_error_base);
365
366  // make sure it's a local connection
367  if (doShm)
368  {   
369    char *d = display_name;
370    while (*d && (*d != ':')) d++;
371    if (*d) *d = 0;
372    if (strcasecmp(display_name, "unix") && display_name[0]!=0)
373      doShm = 0;   
374  }
375
376  if (doShm)
377  {
378    printf("Using MITSHM extension!\n");
379    int sigs[29]={SIGHUP,SIGINT,SIGQUIT,SIGILL,SIGTRAP,
380                SIGABRT,SIGIOT,SIGBUS,SIGFPE,SIGKILL,
381                SIGUSR1,SIGSEGV,SIGUSR2,SIGPIPE,SIGALRM,
382                SIGTERM,SIGCHLD,SIGCONT,SIGSTOP,
383                SIGTSTP,SIGTTIN,SIGTTOU,SIGIO,
384                SIGURG,SIGXCPU,SIGXFSZ,SIGVTALRM,SIGPROF,
385                SIGWINCH};
386
387    for (int i=0;i<29;i++)
388      signal(sigs[i],clean_shm);
389  }
390#endif
391  depth=8;
392  screen_num = DefaultScreen(display);
393  screen_ptr = DefaultScreenOfDisplay(display);
394  ERROR(XGetGeometry(display,RootWindow(display,screen_num), &root,
395        &X_xoff,&Y_yoff,&xres,&yres,&border_width,&depth),
396        "can't get root window attributes");
397
398  {
399    vis_info.c_class=PseudoColor;       
400    vis_info.depth=8;
401    my_visual=XGetVisualInfo(display,VisualClassMask | VisualDepthMask, &vis_info,&items);
402
403    if (items>0)
404    {
405      int rc;
406
407      X_visual=my_visual->visual;
408      vmode=XWINDOWS_256;
409
410      rc=XMatchVisualInfo(display, screen_num, 8, PseudoColor, &vis_info);
411      ERROR(rc, "What the hell? Non-8 bit Psuedo color..\n");
412      X_visual = my_visual->visual = vis_info.visual;
413      //    ERROR(my_visual->depth==8,"What the hell? Non-8 bit Psuedo color..\n");
414      printf("Using 8 bit Psuedo color\n");
415    }
416    else
417    {
418      printf("X windows screen type not supported\n");
419      exit(0);
420    }
421  }
422
423  xres=320; yres=200;
424  for (i=1;i<argc;i++)
425  { if (!strcmp(argv[i],"-size"))
426    { i++; if (!sscanf(argv[i],"%d",&xres)) xres=320;
427      i++; if (!sscanf(argv[i],"%d",&yres)) yres=200;
428    }
429  }
430
431
432  Colormap tmpcmap;
433 
434  tmpcmap = XCreateColormap(display, XRootWindow(display,
435                                                my_visual->screen), X_visual, AllocNone);
436
437  int attribmask = CWColormap | CWBorderPixel;
438  XSetWindowAttributes attribs;
439  attribs.border_pixel = 0;
440  attribs.colormap = tmpcmap;
441 
442  mainwin=XCreateWindow(display,
443                        XRootWindow(display,my_visual->screen),
444                        0,0,fullscreen ? 640 : (xres*pixel_scale), fullscreen ? 480 : (yres*pixel_scale),
445                        0,
446                        my_visual->depth,
447                        InputOutput,
448                        X_visual,
449                        attribmask,
450                        &attribs);
451  xres--; yres--;
452
453
454  icon_pixmap=XCreateBitmapFromData(display,mainwin,bitmap_bits,
455        bitmap_width, bitmap_height);
456  ERROR((size_hints=XAllocSizeHints()),"memory allocation error");
457  ERROR((wm_hints=XAllocWMHints()),"memory allocation error");
458  ERROR((class_hints=XAllocClassHint()),"memory allocation error");
459
460  int lock=0;
461  for (i=1;i<argc;i++)
462    if (!strcmp(argv[i],"-lock_size"))
463     lock=1;
464
465/*
466  if (lock)
467  {
468    size_hints->flags=PPosition | PSize | PMinSize | PMaxSize;
469    size_hints->min_width  = (xres+1)*pixel_scale;
470    size_hints->min_height = (yres+1)*pixel_scale;
471    size_hints->max_width  = (xres+1)*pixel_scale;
472    size_hints->max_height = (yres+1)*pixel_scale;
473  }
474  else
475  {
476*/
477//    size_hints->flags=PPosition | PSize | PMinSize;
478    size_hints->flags=PMinSize | PMaxSize;
479    size_hints->min_width  = (xres+1)*pixel_scale;
480    size_hints->min_height = (yres+1)*pixel_scale;
481    size_hints->max_width  = (xres+1)*pixel_scale;
482    size_hints->max_height = (yres+1)*pixel_scale;
483// }
484
485
486  ERROR(XStringListToTextProperty(&win_name,1,&winName),"alloc failed");
487  ERROR(XStringListToTextProperty(&icon_name,1,&iconName),"alloc fialed");
488  wm_hints->initial_state=NormalState;  // not iconified at first
489  wm_hints->input=1;                  // needs keyboard input
490  wm_hints->icon_pixmap=icon_pixmap;
491  wm_hints->flags=StateHint | IconPixmapHint | InputHint;
492  class_hints->res_name=argv[0];
493  class_hints->res_class="(C) 1995 Crack dot Com, Jonathan Clark";
494  XSetWMProperties(display,mainwin,&winName,&iconName,argv,argc,size_hints,
495        wm_hints,class_hints);
496  XSelectInput(display,mainwin,ExposureMask|KeyPressMask|ButtonPressMask|
497        (fullscreen ? 0 : StructureNotifyMask));
498  ERROR(font_info=XLoadQueryFont(display,"9x15"),"cannot open 9x15");
499  getGC(mainwin,&gc,font_info);
500
501/* try to determine what type of monitor we are using */
502
503
504  // detect which type of screen the X client will run on...
505  // if they requested 24 bit mode, check for that type of display
506 
507
508
509  XSetBackground(display,gc,BlackPixel(display,screen_num));
510
511  XMapWindow(display,mainwin);
512  do
513  { XNextEvent(display, &report);
514  } while (report.type!= Expose);     // wait for our window to pop up
515
516        if (fullscreen)
517        {
518
519                int src_x, src_y, x, y;
520                unsigned nchildren, width, height, border_width, depth;
521                Window root, child, rootwin, parentwin, currentwin, *children;
522                XWindowAttributes attribs;
523
524                XGetGeometry(display, mainwin, &root, &src_x, &src_y, &width, &height, &border_width, &depth);
525                XFillRectangle(display, mainwin, gc, 0, 0, width, height);
526                XTranslateCoordinates (display, mainwin, root, src_x, src_y, &x, &y, &child);
527                parentwin = mainwin;
528                do
529                {
530                        currentwin = parentwin;
531                        XQueryTree(display, currentwin, &rootwin, &parentwin, &children, &nchildren);
532                        XFree(children);
533                } while (rootwin != parentwin);
534                XGetWindowAttributes(display, currentwin, &attribs);
535                XMoveWindow(display, mainwin, -((attribs.width - width)/2), -(attribs.height
536                        - height - ((attribs.width - width)/2)));
537
538#ifdef _AIX
539//              XDAEChangeDisplayResolution(display, mainwin, Resolution640X480X60Hz);
540#endif
541
542        }
543
544  XDefineCursor(display,mainwin, CreateNullCursor(display,mainwin));
545
546  screen=new image(xres+1,yres+1,NULL,2); 
547
548  XCMap=XCreateColormap(display,mainwin,X_visual,AllocAll); 
549  screen->clear();
550  update_dirty(screen);
551
552  for (i=1;i<argc;i++)
553  { if (!strcmp(argv[i],"-grab_pointer"))
554    {
555      i++;
556      int sec;
557      if (i<argc && sscanf(argv[i],"%d",&sec))
558      { printf("-grab_pointer : delaying for %d seconds\n",sec);
559        sleep(sec);
560      }
561      if (XGrabPointer(display,mainwin,True,
562                       PointerMotionMask|ButtonMotionMask|
563                       Button1MotionMask|
564                       Button2MotionMask|
565                       Button3MotionMask|
566                       Button4MotionMask|
567                       Button5MotionMask,
568                       GrabModeAsync,
569                       GrabModeAsync,
570                       mainwin,
571                       None,
572                       CurrentTime)==GrabSuccess)
573        printf("Pointer grab in effect!\n");
574      else
575        printf("Unable to grab pointer  :(\n");
576    }
577  }
578   
579}
580
581void close_graphics()
582{
583  if (lastl) delete lastl; lastl=NULL;
584  delete screen;
585#ifdef _AIX
586//      XDAEChangeDisplayResolution(display, mainwin, DefaultResolution);
587#endif
588  XUnloadFont(display,font_info->fid);
589  XFreeGC(display,gc);
590  XFree((char *)my_visual);
591  XCloseDisplay(display);
592}
593
594void scale_image(image *im, int src_x, int src_y, int src_w, int src_h)
595{
596
597  uchar *src;
598  ushort *dst;
599  ushort pixel;
600  int dx;
601  int y;
602  int next_dst_line;
603  int w;
604  XImage_Info *xi=(XImage_Info *)im->special->extended_descriptor;
605
606  if (pixel_scale == 2)
607  {
608          src=im->scan_line(src_y)+src_x;
609      dst=(ushort *) (xi->XImg->data+src_y*xi->XImg->bytes_per_line*2+src_x*2);
610          next_dst_line = xi->XImg->bytes_per_line/2;
611          w = im->width();
612
613          for (y=src_h;y;y--)
614          {
615                for (dx=0;dx<src_w;dx++)
616                {
617                  pixel = *(src+dx);
618                  pixel |= pixel<<8;
619                  *(dst+dx) = pixel;
620                  *(dst+dx+next_dst_line) = pixel;
621                }
622                src += w;
623                dst += xi->XImg->bytes_per_line;
624          }
625
626  }
627
628}
629
630void copy_24part(uchar *Xdata, image *im, int x1, int y1, int x2, int y2)
631{
632  uchar *src=im->scan_line(y1)+x1;
633  ushort *dst=(ushort *)Xdata+(y1*2)*im->width()+x1;
634
635  int src_add=im->width()-(x2-x1+1);
636
637  int x,y,w=(x2-x1+1)*2;
638  ushort v;
639  for (y=y1;y<=y2;y++)
640  {
641    for (x=x1;x<=x2;x++)
642    {
643      v=*(src++);
644      *(dst++)=(v|(v<<8));
645    }   
646    dst=(ushort *) ((uchar *)dst+src_add*2);
647    memcpy(dst,(uchar *)dst-im->width()*2,w);
648    dst=(ushort *)((uchar *)dst+im->width()*2);
649
650    src+=src_add;
651  }
652}
653
654
655
656void put_part_image(Window win, image *im, int x, int y, int x1, int y1, int x2, int y2)
657{
658  CHECK(im->special);
659  XImage_Info *xi=(XImage_Info *)im->special->extended_descriptor;
660
661//      fprintf(stderr, "(%dx%d) ppi: d=%d,%d s=%d,%d->%d,%d\n", xres, yres, x, y, x1, y1, x2, y2);
662
663  if (pixel_scale>1)
664    scale_image(im,x1,y1,x2-x1+1,y2-y1+1);
665
666#ifndef NO_XSHM
667  if (doShm)
668  {   
669    XEvent ev;
670    XSync(display,False);
671    if (XCheckTypedEvent(display, ConfigureNotify,&ev)==False)
672    {
673      XShmPutImage(display,win,gc,xi->XImg,x1*pixel_scale,y1*pixel_scale,
674            x*pixel_scale,y*pixel_scale+(fullscreen?40:0),(x2-x1+1)*pixel_scale,
675                (y2-y1+1)*pixel_scale,True);
676      // wait for the Put to finish
677      wait_shm_finish();
678    } else     // screen size changed,  better wait till this event is handled cause put might be invalid
679      XPutBackEvent(display,&ev);
680
681  } 
682  else 
683#endif
684    XPutImage(display,win,gc,xi->XImg,x1*pixel_scale,y1*pixel_scale,
685      x*pixel_scale,y*pixel_scale+(fullscreen?40:0),(x2-x1+1)*pixel_scale,(y2-y1+1)*pixel_scale);
686
687}
688
689void put_image(image *im, int x, int y)
690{
691  put_part_image(mainwin,im,x,y,0,0,im->width()-1,im->height()-1); 
692}
693
694
695
696void update_dirty_window(Window win, image *im, int xoff, int yoff)
697{
698
699  int count;
700  dirty_rect *dr,*q;
701  image *Xim;
702  CHECK(im->special);  // make sure the image has the ablity to contain dirty areas
703  if (im->special->keep_dirt==0)
704    put_image(im,xoff,yoff);
705  else
706  {
707    count=im->special->dirties.number_nodes();
708    if (!count) return;  // if nothing to update, return
709    dr= (dirty_rect *) (im->special->dirties.first());
710    while (count>0)
711    {
712      put_part_image(win,im,xoff+dr->dx1,yoff+dr->dy1,dr->dx1,dr->dy1,dr->dx2,dr->dy2);     
713//      XDrawRectangle(display,mainwin,gc,xoff+dr->dx1,yoff+dr->dy1,
714//                   xoff+dr->dx2-dr->dx1+1,yoff+dr->dy2-dr->dy1+1);
715      q=dr;
716      dr=(dirty_rect *) (dr->next());
717      im->special->dirties.unlink((linked_node *)q);
718      delete q;
719      count--;
720    }
721  }
722//  XFlush(display);
723}
724
725void update_dirty(image *im, int xoff, int yoff)
726{ update_dirty_window(mainwin,im,xoff,yoff); }
727
728void palette::load()
729{
730  if (lastl)
731    delete lastl;
732  lastl=copy();
733
734  {
735    int i;
736    if (get_vmode()!=XWINDOWS_2)
737    {
738      XColor colors[256];
739      for (i=0;i<ncolors;i++)
740      {
741        colors[i].flags=DoRed|DoBlue|DoGreen;
742                                colors[i].pixel=i;
743                                colors[i].red=red(i)<<8|0xff;
744                                colors[i].green=green(i)<<8|0xff;
745                                colors[i].blue=blue(i)<<8|0xff;
746      }
747                        XStoreColors(display, XCMap, colors, 256);
748      XSetWindowColormap(display,mainwin,XCMap);
749    }
750    else lastl->black_white();
751    current_background=bg;
752  }
753}
754
755struct hist_entry
756{
757  long total;
758  unsigned char org;
759} ;
760
761static int histcompare(const void *i, const void *j)
762{
763  if (((hist_entry *)i)->org==0) return -1;  // make sure the background gets allocated
764  else return(((hist_entry *)j)->total - ((hist_entry *)i)->total);
765}
766
767
768void palette::load_nice()
769{
770  int i,fail,y,x,wd,j;
771  long closest_val,closest_pixel,k;
772  char *gotten;
773  image *im;
774  unsigned char *sl;
775  palette *Xpal;
776  hist_entry *histogram;
777  Colormap stdcm;
778  XColor color;
779
780  if (get_vmode()!=XWINDOWS_2) 
781  {
782    filter f(ncolors);
783
784    histogram=(hist_entry *)jmalloc(sizeof(hist_entry)*ncolors,"palette::histogram");
785    gotten=(char *)jmalloc(ncolors,"palette::gotten_colors");
786
787    memset(gotten,0,ncolors);
788    for (i=0;i<ncolors;i++)
789    { histogram[i].total=0;
790      histogram[i].org=i;
791    }
792
793    for (i=image_list.number_nodes(),im=(image *)image_list.first();i;i--,im=(image *)im->next())
794    {
795      if (im!=screen)
796      {
797        wd=im->width();
798        for (y=im->height();y;y--)
799        {
800          sl=im->scan_line(y-1);
801          for (x=0;x<wd;x++)
802            histogram[sl[x]].total++;
803        }
804      }
805    }
806    qsort(histogram,ncolors,sizeof(hist_entry),histcompare);
807    stdcm=XDefaultColormap(display,screen_num);
808    Xpal=NULL;
809    for (i=0,fail=0;i<ncolors;i++)
810    {
811      color.red=red(histogram[i].org)<<8;
812      color.green=green(histogram[i].org)<<8;
813      color.blue=blue(histogram[i].org)<<8;
814
815      if (XAllocColor(display,stdcm,&color))
816        f.set(histogram[i].org,color.pixel);
817      else  // if we couldn't allocate that color from X, find the closest.
818      {
819        if (!Xpal)
820        { Xpal=new palette(ncolors);
821          for (j=0;j<ncolors;j++)
822          {
823            color.pixel=j;
824            XQueryColor(display,stdcm,&color);
825            Xpal->set(j,color.red>>8,color.green>>8,color.blue>>8);
826          }
827        }
828        closest_val=0xfffffff;
829        for (j=0;j<ncolors;j++)
830        {
831          k=Xpal->red(j)*Xpal->red(j)+Xpal->green(j)*Xpal->green(j)+
832            Xpal->blue(j)*Xpal->blue(j);
833          if (k<closest_val)
834          { closest_val=k;
835            closest_pixel=j;
836          }
837        }
838        f.set(histogram[i].org,closest_pixel);
839      }
840    }
841    if (!Xpal)
842      Xpal=new palette(ncolors);
843    // store the color mapping we created back to the palette.
844    for (j=0;j<ncolors;j++)
845      Xpal->set(j,red(f.get_mapping(j)),green(f.get_mapping(j)),blue(f.get_mapping(j)));
846    for (j=0;j<ncolors;j++)
847      set(j,Xpal->red(j),Xpal->green(j),Xpal->blue(j)); 
848    bg=f.get_mapping(bg);
849     
850    // now remap all the images to fit this colormap!
851    for (i=image_list.number_nodes(),im=(image *)image_list.first();i;i--,im=(image *)im->next())
852      f.apply(im);
853
854    delete Xpal;
855    jfree(histogram);
856    jfree(gotten);
857  }
858  current_background=bg;
859}
860
Note: See TracBrowser for help on using the repository browser.