ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/rxvttoolkit.C
Revision: 1.65
Committed: Fri Jun 8 20:04:12 2007 UTC (16 years, 11 months ago) by sasha
Content type: text/plain
Branch: MAIN
Changes since 1.64: +5 -0 lines
Log Message:
added preliminary support to use libAfterImage for background pixmap loading and rendering of transparency effects including blending of pixmap over background using several methods, and gaussian blurr of the transparency background

File Contents

# User Rev Content
1 root 1.57 /*----------------------------------------------------------------------*
2 root 1.5 * File: rxvttoolkit.C
3 root 1.1 *----------------------------------------------------------------------*
4     *
5     * All portions of code are copyright by their respective author/s.
6 root 1.56 * Copyright (c) 2003-2006 Marc Lehmann <pcg@goof.com>
7 root 1.1 *
8     * This program is free software; you can redistribute it and/or modify
9     * it under the terms of the GNU General Public License as published by
10     * the Free Software Foundation; either version 2 of the License, or
11     * (at your option) any later version.
12     *
13     * This program is distributed in the hope that it will be useful,
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16     * GNU General Public License for more details.
17     *
18     * You should have received a copy of the GNU General Public License
19     * along with this program; if not, write to the Free Software
20     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21     *----------------------------------------------------------------------*/
22    
23     #include "../config.h"
24     #include <rxvt.h>
25     #include <rxvttoolkit.h>
26    
27     #include <unistd.h>
28     #include <fcntl.h>
29    
30 root 1.23 #include <sys/utsname.h>
31 root 1.52 #include <sys/socket.h>
32     #include <sys/un.h>
33 root 1.1
34 root 1.31 #if XFT
35     # include <X11/extensions/Xrender.h>
36     #endif
37    
38 root 1.25 const char *const xa_names[] =
39 root 1.34 {
40     "TEXT",
41     "COMPOUND_TEXT",
42     "UTF8_STRING",
43     "MULTIPLE",
44     "TARGETS",
45     "TIMESTAMP",
46     "VT_SELECTION",
47     "INCR",
48     "WM_PROTOCOLS",
49     "WM_DELETE_WINDOW",
50     "CLIPBOARD",
51     "AVERAGE_WIDTH",
52     "WEIGHT_NAME",
53     "SLANT",
54     "CHARSET_REGISTRY",
55     "CHARSET_ENCODING",
56 root 1.25 #if ENABLE_FRILLS
57 root 1.34 "_MOTIF_WM_HINTS",
58 root 1.25 #endif
59     #if ENABLE_EWMH
60 root 1.34 "_NET_WM_PID",
61     "_NET_WM_NAME",
62     "_NET_WM_ICON_NAME",
63     "_NET_WM_PING",
64 root 1.25 #endif
65     #if USE_XIM
66 root 1.34 "WM_LOCALE_NAME",
67     "XIM_SERVERS",
68 root 1.25 #endif
69     #ifdef TRANSPARENT
70 root 1.34 "_XROOTPMAP_ID",
71     "ESETROOT_PMAP_ID",
72 root 1.25 #endif
73     #if ENABLE_XEMBED
74 root 1.34 "_XEMBED",
75     "_XEMBED_INFO",
76     #endif
77     #if !ENABLE_MINIMAL
78     "SCREEN_RESOURCES",
79     "XDCCC_LINEAR_RGB_CORRECTION",
80     "XDCCC_LINEAR_RGB_MATRICES",
81     "WM_COLORMAP_WINDOWS",
82     "WM_STATE",
83 root 1.38 "cursor",
84     # if USE_XIM
85     "TRANSPORT",
86     "LOCALES",
87     "_XIM_PROTOCOL",
88     "_XIM_XCONNECT",
89     "_XIM_MOREDATA",
90     # endif
91 root 1.25 #endif
92 root 1.34 };
93 root 1.25
94     /////////////////////////////////////////////////////////////////////////////
95    
96 root 1.1 refcounted::refcounted (const char *id)
97     {
98 root 1.2 this->id = strdup (id);
99 root 1.1 }
100    
101     refcounted::~refcounted ()
102     {
103     free (id);
104     }
105    
106     template<class T>
107     T *refcache<T>::get (const char *id)
108     {
109     for (T **i = this->begin (); i < this->end (); ++i)
110     {
111     if (!strcmp (id, (*i)->id))
112     {
113 root 1.23 ++(*i)->referenced;
114     (*i)->ref_next ();
115 root 1.1 return *i;
116     }
117     }
118    
119     T *obj = new T (id);
120    
121 root 1.23 if (obj && obj->ref_init ())
122 root 1.1 {
123 root 1.23 obj->referenced = 1;
124 root 1.1 this->push_back (obj);
125     return obj;
126     }
127     else
128     {
129     delete obj;
130     return 0;
131     }
132     }
133    
134     template<class T>
135     void refcache<T>::put (T *obj)
136     {
137     if (!obj)
138     return;
139    
140     if (!--obj->referenced)
141     {
142     this->erase (find (this->begin (), this->end (), obj));
143     delete obj;
144     }
145     }
146    
147     template<class T>
148 root 1.12 void refcache<T>::clear ()
149 root 1.1 {
150     while (this->size ())
151     put (*this->begin ());
152     }
153    
154     /////////////////////////////////////////////////////////////////////////////
155    
156     #ifdef USE_XIM
157 root 1.24
158 root 1.1 static void
159     #if XIMCB_PROTO_BROKEN
160     im_destroy_cb (XIC unused1, XPointer client_data, XPointer unused3)
161     #else
162     im_destroy_cb (XIM unused1, XPointer client_data, XPointer unused3)
163     #endif
164     {
165     rxvt_xim *xim = (rxvt_xim *)client_data;
166     rxvt_display *display = xim->display;
167    
168 root 1.5 xim->xim = 0;
169    
170 root 1.1 display->xims.erase (find (display->xims.begin (), display->xims.end (), xim));
171     display->im_change_cb ();
172     }
173    
174 root 1.23 bool
175     rxvt_xim::ref_init ()
176 root 1.1 {
177     display = GET_R->display; //HACK: TODO
178    
179 root 1.50 xim = XOpenIM (display->dpy, 0, 0, 0);
180 root 1.1
181     if (!xim)
182     return false;
183    
184     XIMCallback ximcallback;
185     ximcallback.client_data = (XPointer)this;
186     ximcallback.callback = im_destroy_cb;
187    
188 root 1.49 XSetIMValues (xim, XNDestroyCallback, &ximcallback, 0);
189 root 1.1
190     return true;
191     }
192    
193     rxvt_xim::~rxvt_xim ()
194     {
195     if (xim)
196     XCloseIM (xim);
197     }
198 root 1.24
199 root 1.1 #endif
200    
201     /////////////////////////////////////////////////////////////////////////////
202    
203 root 1.51 #if XFT
204     rxvt_drawable::~rxvt_drawable ()
205     {
206     if (xftdrawable)
207     XftDrawDestroy (xftdrawable);
208     }
209    
210     rxvt_drawable::operator XftDraw *()
211     {
212     if (!xftdrawable)
213     xftdrawable = XftDrawCreate (screen->dpy, drawable, screen->visual, screen->cmap);
214    
215     return xftdrawable;
216     }
217     #endif
218    
219     /////////////////////////////////////////////////////////////////////////////
220    
221     #if XFT
222    
223     // not strictly necessary as it is only used with superclass of zero_initialised
224     rxvt_screen::rxvt_screen ()
225     : scratch_area (0)
226     {
227     }
228    
229     rxvt_drawable &rxvt_screen::scratch_drawable (int w, int h)
230     {
231     // it's actually faster to re-allocate every time. don't ask me
232     // why, but its likely no big deal there are no roundtrips
233     // (I think/hope).
234     if (!scratch_area || w > scratch_w || h > scratch_h || 1/*D*/)
235     {
236     if (scratch_area)
237     {
238     XFreePixmap (dpy, scratch_area->drawable);
239     delete scratch_area;
240     }
241    
242     Pixmap pm = XCreatePixmap (dpy, RootWindowOfScreen (ScreenOfDisplay (dpy, display->screen)),
243     scratch_w = w, scratch_h = h, depth);
244    
245     scratch_area = new rxvt_drawable (this, pm);
246     }
247    
248     return *scratch_area;
249     }
250    
251     #endif
252    
253 root 1.26 void
254     rxvt_screen::set (rxvt_display *disp)
255     {
256     display = disp;
257 root 1.50 dpy = disp->dpy;
258 root 1.26
259 root 1.50 Screen *screen = ScreenOfDisplay (dpy, disp->screen);
260 root 1.26
261 root 1.27 depth = DefaultDepthOfScreen (screen);
262     visual = DefaultVisualOfScreen (screen);
263     cmap = DefaultColormapOfScreen (screen);
264 root 1.26 }
265    
266     void
267 root 1.59 rxvt_screen::select_visual (int bitdepth)
268 root 1.26 {
269 root 1.31 #if XFT
270 root 1.26 XVisualInfo vinfo;
271    
272 root 1.50 if (XMatchVisualInfo (dpy, display->screen, bitdepth, TrueColor, &vinfo))
273 root 1.26 {
274 root 1.28 depth = bitdepth;
275     visual = vinfo.visual;
276 root 1.59 cmap = XCreateColormap (dpy, display->root, visual, AllocNone);
277 root 1.26 }
278 root 1.31 #endif
279 root 1.26 }
280    
281     void
282     rxvt_screen::clear ()
283     {
284 root 1.51 #if XFT
285     if (scratch_area)
286     {
287     XFreePixmap (dpy, scratch_area->drawable);
288     delete scratch_area;
289     }
290     #endif
291    
292 root 1.50 if (cmap != DefaultColormapOfScreen (ScreenOfDisplay (dpy, display->screen)))
293     XFreeColormap (dpy, cmap);
294 root 1.26 }
295    
296     /////////////////////////////////////////////////////////////////////////////
297    
298 root 1.1 rxvt_display::rxvt_display (const char *id)
299     : refcounted (id)
300     , x_ev (this, &rxvt_display::x_cb)
301     , selection_owner (0)
302     {
303     }
304    
305 root 1.23 XrmDatabase
306 root 1.49 rxvt_display::get_resources (bool refresh)
307 root 1.23 {
308     char *homedir = (char *)getenv ("HOME");
309     char fname[1024];
310    
311     /*
312     * get resources using the X library function
313     */
314     char *displayResource, *xe;
315 root 1.49 XrmDatabase rdb1, database = 0;
316 root 1.23
317     // for ordering, see for example http://www.faqs.org/faqs/Xt-FAQ/ Subject: 20
318 root 1.60 // as opposed to "standard practise", we always read in ~/.Xdefaults
319 root 1.23
320     // 6. System wide per application default file.
321    
322     /* Add in $XAPPLRESDIR/Rxvt only; not bothering with XUSERFILESEARCHPATH */
323     if ((xe = (char *)getenv ("XAPPLRESDIR")))
324     {
325     snprintf (fname, sizeof (fname), "%s/%s", xe, RESCLASS);
326    
327     if ((rdb1 = XrmGetFileDatabase (fname)))
328     XrmMergeDatabases (rdb1, &database);
329     }
330    
331     // 5. User's per application default file.
332     // none
333    
334     // 4. User's defaults file.
335 root 1.60 if (homedir)
336     {
337     snprintf (fname, sizeof (fname), "%s/.Xdefaults", homedir);
338    
339     if ((rdb1 = XrmGetFileDatabase (fname)))
340     XrmMergeDatabases (rdb1, &database);
341     }
342    
343 root 1.23 /* Get any Xserver defaults */
344 root 1.49 if (refresh)
345     {
346     // fucking xlib keeps a copy of the rm string
347     Atom actual_type;
348     int actual_format;
349     unsigned long nitems, nremaining;
350     char *val = 0;
351    
352     #if XLIB_ILLEGAL_ACCESS
353 root 1.50 if (dpy->xdefaults)
354     XFree (dpy->xdefaults);
355 root 1.49 #endif
356    
357 root 1.55 if (XGetWindowProperty (dpy, RootWindow (dpy, 0), XA_RESOURCE_MANAGER,
358 root 1.49 0L, 100000000L, False,
359     XA_STRING, &actual_type, &actual_format,
360     &nitems, &nremaining,
361     (unsigned char **)&val) == Success
362     && actual_type == XA_STRING
363     && actual_format == 8)
364     displayResource = val;
365     else
366     {
367     displayResource = 0;
368 root 1.60
369 root 1.49 if (val)
370     XFree(val);
371     }
372    
373     #if XLIB_ILLEGAL_ACCESS
374 root 1.50 dpy->xdefaults = displayResource;
375 root 1.49 #endif
376     }
377     else
378 root 1.50 displayResource = XResourceManagerString (dpy);
379 root 1.23
380 root 1.49 if (displayResource)
381 root 1.23 {
382     if ((rdb1 = XrmGetStringDatabase (displayResource)))
383     XrmMergeDatabases (rdb1, &database);
384     }
385    
386 root 1.49 #if !XLIB_ILLEGAL_ACCESS
387     if (refresh && displayResource)
388     XFree (displayResource);
389     #endif
390    
391 root 1.23 /* Get screen specific resources */
392 root 1.50 displayResource = XScreenResourceString (ScreenOfDisplay (dpy, screen));
393 root 1.23
394 root 1.49 if (displayResource)
395 root 1.23 {
396     if ((rdb1 = XrmGetStringDatabase (displayResource)))
397     /* Merge with screen-independent resources */
398     XrmMergeDatabases (rdb1, &database);
399    
400     XFree (displayResource);
401     }
402    
403     // 3. User's per host defaults file
404     /* Add in XENVIRONMENT file */
405     if ((xe = (char *)getenv ("XENVIRONMENT"))
406     && (rdb1 = XrmGetFileDatabase (xe)))
407     XrmMergeDatabases (rdb1, &database);
408     else if (homedir)
409     {
410     struct utsname un;
411    
412     if (!uname (&un))
413     {
414     snprintf (fname, sizeof (fname), "%s/.Xdefaults-%s", homedir, un.nodename);
415    
416     if ((rdb1 = XrmGetFileDatabase (fname)))
417     XrmMergeDatabases (rdb1, &database);
418     }
419     }
420    
421     return database;
422     }
423    
424     bool rxvt_display::ref_init ()
425 root 1.1 {
426 root 1.14 #ifdef LOCAL_X_IS_UNIX
427     if (id[0] == ':')
428     {
429     val = rxvt_malloc (5 + strlen (id) + 1);
430     strcpy (val, "unix/");
431     strcat (val, id);
432 root 1.50 dpy = XOpenDisplay (val);
433 root 1.14 free (val);
434     }
435     else
436 root 1.15 #endif
437 root 1.50 dpy = 0;
438 root 1.14
439 root 1.50 if (!dpy)
440     dpy = XOpenDisplay (id);
441 root 1.1
442 root 1.50 if (!dpy)
443 root 1.1 return false;
444    
445 root 1.50 screen = DefaultScreen (dpy);
446     root = DefaultRootWindow (dpy);
447 root 1.1
448 sasha 1.65 #ifdef HAVE_AFTERIMAGE
449     ::dpy = dpy; /* init global var from libAfter... */
450     asv = create_asvisual_for_id( dpy, screen, DefaultDepth(dpy,screen), XVisualIDFromVisual(DefaultVisual(dpy,screen)), None, NULL );
451     #endif
452    
453 root 1.25 assert (sizeof (xa_names) / sizeof (char *) == NUM_XA);
454 root 1.50 XInternAtoms (dpy, (char **)xa_names, NUM_XA, False, xa);
455 root 1.25
456 root 1.50 XrmSetDatabase (dpy, get_resources (false));
457 root 1.1
458 root 1.12 #ifdef POINTER_BLANK
459     XColor blackcolour;
460     blackcolour.red = 0;
461     blackcolour.green = 0;
462     blackcolour.blue = 0;
463 root 1.50 Font f = XLoadFont (dpy, "fixed");
464     blank_cursor = XCreateGlyphCursor (dpy, f, f, ' ', ' ',
465 root 1.12 &blackcolour, &blackcolour);
466 root 1.50 XUnloadFont (dpy, f);
467 root 1.12 #endif
468    
469 root 1.50 int fd = XConnectionNumber (dpy);
470 root 1.23
471     // try to detect wether we have a local connection.
472     // assume unix domains socket == local, everything else not
473     // TODO: might want to check for inet/127.0.0.1
474     is_local = 0;
475     sockaddr_un sa;
476     socklen_t sl = sizeof (sa);
477    
478     if (!getsockname (fd, (sockaddr *)&sa, &sl))
479     is_local = sa.sun_family == AF_LOCAL;
480    
481 root 1.1 x_ev.start (fd, EVENT_READ);
482     fcntl (fd, F_SETFD, FD_CLOEXEC);
483    
484 root 1.50 XSelectInput (dpy, root, PropertyChangeMask);
485 root 1.1
486     flush ();
487    
488     return true;
489     }
490    
491 root 1.23 void
492     rxvt_display::ref_next ()
493     {
494     // TODO: somehow check wether the database files/resources changed
495 root 1.46 // before affording re-loading/parsing
496 root 1.50 XrmDestroyDatabase (XrmGetDatabase (dpy));
497     XrmSetDatabase (dpy, get_resources (true));
498 root 1.23 }
499    
500 root 1.1 rxvt_display::~rxvt_display ()
501     {
502 root 1.50 if (!dpy)
503 root 1.22 return;
504    
505 root 1.21 #ifdef POINTER_BLANK
506 root 1.50 XFreeCursor (dpy, blank_cursor);
507 root 1.21 #endif
508 root 1.1 x_ev.stop ();
509 root 1.12 #ifdef USE_XIM
510     xims.clear ();
511     #endif
512 root 1.50 XCloseDisplay (dpy);
513 root 1.1 }
514    
515     #ifdef USE_XIM
516     void rxvt_display::im_change_cb ()
517     {
518     for (im_watcher **i = imw.begin (); i != imw.end (); ++i)
519     (*i)->call ();
520     }
521 root 1.5
522     void rxvt_display::im_change_check ()
523     {
524 root 1.13 // try to only call im_change_cb when a new input method
525 root 1.5 // registers, as xlib crashes due to a race otherwise.
526     Atom actual_type, *atoms;
527     int actual_format;
528     unsigned long nitems, bytes_after;
529    
530 root 1.50 if (XGetWindowProperty (dpy, root, xa[XA_XIM_SERVERS], 0L, 1000000L,
531 root 1.5 False, XA_ATOM, &actual_type, &actual_format,
532     &nitems, &bytes_after, (unsigned char **)&atoms)
533     != Success )
534     return;
535    
536     if (actual_type == XA_ATOM && actual_format == 32)
537     for (int i = 0; i < nitems; i++)
538 root 1.50 if (XGetSelectionOwner (dpy, atoms[i]))
539 root 1.5 {
540     im_change_cb ();
541     break;
542     }
543    
544     XFree (atoms);
545     }
546 root 1.1 #endif
547    
548     void rxvt_display::x_cb (io_watcher &w, short revents)
549     {
550     do
551     {
552     XEvent xev;
553 root 1.50 XNextEvent (dpy, &xev);
554 root 1.1
555 root 1.5 #ifdef USE_XIM
556     if (!XFilterEvent (&xev, None))
557     {
558     if (xev.type == PropertyNotify
559     && xev.xany.window == root
560 root 1.25 && xev.xproperty.atom == xa[XA_XIM_SERVERS])
561 root 1.5 im_change_check ();
562     #endif
563     for (int i = xw.size (); i--; )
564     {
565     if (!xw[i])
566     xw.erase_unordered (i);
567     else if (xw[i]->window == xev.xany.window)
568     xw[i]->call (xev);
569     }
570 root 1.1 #ifdef USE_XIM
571 root 1.5 }
572 root 1.1 #endif
573     }
574 root 1.50 while (XEventsQueued (dpy, QueuedAlready));
575 root 1.1
576 root 1.50 XFlush (dpy);
577 root 1.1 }
578    
579     void rxvt_display::flush ()
580     {
581 root 1.50 if (XEventsQueued (dpy, QueuedAlready))
582 root 1.10 x_cb (x_ev, EVENT_READ);
583    
584 root 1.50 XFlush (dpy);
585 root 1.1 }
586    
587     void rxvt_display::reg (xevent_watcher *w)
588     {
589 root 1.62 if (!w->active)
590 root 1.61 {
591     xw.push_back (w);
592     w->active = xw.size ();
593     }
594 root 1.1 }
595    
596     void rxvt_display::unreg (xevent_watcher *w)
597     {
598     if (w->active)
599 root 1.61 {
600     xw[w->active - 1] = 0;
601     w->active = 0;
602     }
603 root 1.1 }
604    
605     void rxvt_display::set_selection_owner (rxvt_term *owner)
606     {
607     if (selection_owner && selection_owner != owner)
608     selection_owner->selection_clear ();
609    
610     selection_owner = owner;
611     }
612    
613     #ifdef USE_XIM
614 root 1.46
615 root 1.1 void rxvt_display::reg (im_watcher *w)
616     {
617     imw.push_back (w);
618     }
619    
620     void rxvt_display::unreg (im_watcher *w)
621     {
622     imw.erase (find (imw.begin (), imw.end (), w));
623     }
624    
625     rxvt_xim *rxvt_display::get_xim (const char *locale, const char *modifiers)
626     {
627     char *id;
628     int l, m;
629    
630     l = strlen (locale);
631     m = strlen (modifiers);
632    
633     if (!(id = (char *)malloc (l + m + 2)))
634     return 0;
635    
636     memcpy (id, locale, l); id[l] = '\n';
637     memcpy (id + l + 1, modifiers, m); id[l + m + 1] = 0;
638    
639     rxvt_xim *xim = xims.get (id);
640    
641     free (id);
642    
643     return xim;
644     }
645    
646     void rxvt_display::put_xim (rxvt_xim *xim)
647     {
648 root 1.46 # if XLIB_IS_RACEFREE
649 root 1.1 xims.put (xim);
650 root 1.46 # endif
651 root 1.1 }
652 root 1.46
653 root 1.1 #endif
654    
655     Atom rxvt_display::atom (const char *name)
656     {
657 root 1.50 return XInternAtom (dpy, name, False);
658 root 1.1 }
659    
660     /////////////////////////////////////////////////////////////////////////////
661    
662     template class refcache<rxvt_display>;
663     refcache<rxvt_display> displays;
664    
665     /////////////////////////////////////////////////////////////////////////////
666 root 1.58 //
667    
668     static unsigned int
669     insert_component (unsigned int value, unsigned int mask, unsigned int shift)
670     {
671     return (value * (mask + 1) >> 16) << shift;
672     }
673 root 1.38
674 root 1.1 bool
675 root 1.43 rxvt_color::alloc (rxvt_screen *screen, const rgba &color)
676 root 1.1 {
677 root 1.28 #if XFT
678 root 1.31 XRenderPictFormat *format;
679 root 1.28
680 root 1.48 // FUCKING Xft gets it wrong, of course, so work around it.
681     // Transparency users should eat shit and die, and then
682 root 1.31 // XRenderQueryPictIndexValues themselves plenty.
683 root 1.48 if ((screen->visual->c_class == TrueColor)
684 root 1.50 && (format = XRenderFindVisualFormat (screen->dpy, screen->visual)))
685 root 1.31 {
686     // the fun lies in doing everything manually...
687 root 1.40 c.color.red = color.r;
688     c.color.green = color.g;
689     c.color.blue = color.b;
690     c.color.alpha = color.a;
691    
692 root 1.58 c.pixel = insert_component (color.r, format->direct.redMask , format->direct.red )
693     | insert_component (color.g, format->direct.greenMask, format->direct.green)
694     | insert_component (color.b, format->direct.blueMask , format->direct.blue )
695     | insert_component (color.a, format->direct.alphaMask, format->direct.alpha);
696 root 1.29
697     return true;
698     }
699 root 1.31 else
700     {
701     XRenderColor d;
702    
703 root 1.40 d.red = color.r;
704     d.green = color.g;
705     d.blue = color.b;
706     d.alpha = color.a;
707 root 1.31
708 root 1.50 return XftColorAllocValue (screen->dpy, screen->visual, screen->cmap, &d, &c);
709 root 1.31 }
710 root 1.28 #else
711 root 1.46 c.red = color.r;
712     c.green = color.g;
713     c.blue = color.b;
714    
715 root 1.48 if (screen->visual->c_class == TrueColor)
716 root 1.35 {
717 root 1.64 c.pixel = (color.r >> (16 - popcount (screen->visual->red_mask )) << ctz (screen->visual->red_mask ))
718     | (color.g >> (16 - popcount (screen->visual->green_mask)) << ctz (screen->visual->green_mask))
719     | (color.b >> (16 - popcount (screen->visual->blue_mask )) << ctz (screen->visual->blue_mask ));
720 root 1.1
721 root 1.35 return true;
722     }
723 root 1.50 else if (XAllocColor (screen->dpy, screen->cmap, &c))
724 root 1.46 return true;
725 root 1.35 else
726 root 1.46 c.pixel = (color.r + color.g + color.b) > 128*3
727 root 1.50 ? WhitePixelOfScreen (DefaultScreenOfDisplay (screen->dpy))
728     : BlackPixelOfScreen (DefaultScreenOfDisplay (screen->dpy));
729 root 1.38 #endif
730 root 1.1
731     return false;
732 root 1.38 }
733    
734     bool
735     rxvt_color::set (rxvt_screen *screen, const char *name)
736     {
737 root 1.43 rgba c;
738 root 1.38 char eos;
739 root 1.39 int skip;
740 root 1.38
741 root 1.46 // parse the nonstandard "[alphapercent]" prefix
742 root 1.41 if (1 <= sscanf (name, "[%hd]%n", &c.a, &skip))
743 root 1.38 {
744 root 1.43 c.a = lerp<int, int, int> (0, rgba::MAX_CC, c.a);
745 root 1.39 name += skip;
746 root 1.38 }
747     else
748 root 1.43 c.a = rgba::MAX_CC;
749 root 1.39
750 root 1.46 // parse the non-standard "rgba:rrrr/gggg/bbbb/aaaa" format
751     if (strlen (name) != 4+5*4 || 4 != sscanf (name, "rgba:%4hx/%4hx/%4hx/%4hx%c", &c.r, &c.g, &c.b, &c.a, &eos))
752 root 1.38 {
753 root 1.39 XColor xc, xc_exact;
754    
755 root 1.50 if (XParseColor (screen->dpy, screen->cmap, name, &xc))
756 root 1.39 {
757     c.r = xc.red;
758     c.g = xc.green;
759     c.b = xc.blue;
760     }
761     else
762     {
763     c.r = 0xffff;
764     c.g = 0x6969;
765     c.b = 0xb4b4;
766    
767     rxvt_warn ("unable to parse color '%s', using pink instead.\n", name);
768     }
769 root 1.38 }
770    
771 root 1.39 return set (screen, c);
772 root 1.38 }
773    
774     bool
775 root 1.43 rxvt_color::set (rxvt_screen *screen, const rgba &color)
776 root 1.38 {
777 root 1.40 bool got = alloc (screen, color);
778 root 1.38
779     #if !ENABLE_MINIMAL
780     int cmap_size = screen->visual->map_entries;
781    
782     if (!got
783     && screen->visual->c_class == PseudoColor
784     && cmap_size < 4096)
785     {
786     XColor *colors = new XColor [screen->visual->map_entries];
787    
788     for (int i = 0; i < cmap_size; i++)
789     colors [i].pixel = i;
790    
791 root 1.43 // many kilobytes transfer per colour, but pseudocolor isn't worth
792     // many extra optimisations.
793 root 1.50 XQueryColors (screen->dpy, screen->cmap, colors, cmap_size);
794 root 1.38
795     int diff = 0x7fffffffUL;
796     XColor *best = colors;
797    
798     for (int i = 0; i < cmap_size; i++)
799     {
800 root 1.40 int d = (squared_diff<int> (color.r >> 2, colors [i].red >> 2))
801     + (squared_diff<int> (color.g >> 2, colors [i].green >> 2))
802     + (squared_diff<int> (color.b >> 2, colors [i].blue >> 2));
803 root 1.38
804     if (d < diff)
805     {
806     diff = d;
807     best = colors + i;
808     }
809     }
810    
811     //rxvt_warn ("could not allocate %04x %04x %04x, getting %04x %04x %04x instead (%d)\n",
812 root 1.40 // color.r, color.g, color.b, best->red, best->green, best->blue, diff);
813 root 1.38
814 root 1.43 got = alloc (screen, rgba (best->red, best->green, best->blue));
815 root 1.38
816 root 1.63 delete [] colors;
817 root 1.38 }
818 root 1.28 #endif
819 root 1.38
820     return got;
821 root 1.1 }
822    
823 root 1.39 void
824 root 1.44 rxvt_color::get (rgba &color)
825 root 1.1 {
826     #if XFT
827 root 1.40 color.r = c.color.red;
828     color.g = c.color.green;
829     color.b = c.color.blue;
830     color.a = c.color.alpha;
831 root 1.1 #else
832 root 1.40 color.r = c.red;
833     color.g = c.green;
834     color.b = c.blue;
835 root 1.43 color.a = rgba::MAX_CC;
836 root 1.1 #endif
837     }
838    
839 root 1.46 void
840     rxvt_color::get (XColor &color)
841     {
842     rgba c;
843     get (c);
844    
845     color.red = c.r;
846     color.green = c.g;
847     color.blue = c.b;
848     color.pixel = (Pixel)*this;
849     }
850    
851 root 1.1 void
852 root 1.26 rxvt_color::free (rxvt_screen *screen)
853 root 1.1 {
854 root 1.53 if (screen->visual->c_class == TrueColor)
855     return; // nothing to do
856    
857 root 1.1 #if XFT
858 root 1.50 XftColorFree (screen->dpy, screen->visual, screen->cmap, &c);
859 root 1.1 #else
860 root 1.50 XFreeColors (screen->dpy, screen->cmap, &c.pixel, 1, AllPlanes);
861 root 1.1 #endif
862     }
863    
864 root 1.42 void
865 root 1.43 rxvt_color::fade (rxvt_screen *screen, int percent, rxvt_color &result, const rgba &to)
866 root 1.1 {
867 root 1.43 rgba c;
868 root 1.44 get (c);
869 root 1.1
870 root 1.42 result.set (
871 root 1.26 screen,
872 root 1.43 rgba (
873 root 1.42 lerp (c.r, to.r, percent),
874     lerp (c.g, to.g, percent),
875     lerp (c.b, to.b, percent),
876     lerp (c.a, to.a, percent)
877 root 1.28 )
878 root 1.18 );
879 root 1.1 }
880