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

# Content
1 /*----------------------------------------------------------------------*
2 * File: rxvttoolkit.C
3 *----------------------------------------------------------------------*
4 *
5 * All portions of code are copyright by their respective author/s.
6 * Copyright (c) 2003-2006 Marc Lehmann <pcg@goof.com>
7 *
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 #include <sys/utsname.h>
31 #include <sys/socket.h>
32 #include <sys/un.h>
33
34 #if XFT
35 # include <X11/extensions/Xrender.h>
36 #endif
37
38 const char *const xa_names[] =
39 {
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 #if ENABLE_FRILLS
57 "_MOTIF_WM_HINTS",
58 #endif
59 #if ENABLE_EWMH
60 "_NET_WM_PID",
61 "_NET_WM_NAME",
62 "_NET_WM_ICON_NAME",
63 "_NET_WM_PING",
64 #endif
65 #if USE_XIM
66 "WM_LOCALE_NAME",
67 "XIM_SERVERS",
68 #endif
69 #ifdef TRANSPARENT
70 "_XROOTPMAP_ID",
71 "ESETROOT_PMAP_ID",
72 #endif
73 #if ENABLE_XEMBED
74 "_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 "cursor",
84 # if USE_XIM
85 "TRANSPORT",
86 "LOCALES",
87 "_XIM_PROTOCOL",
88 "_XIM_XCONNECT",
89 "_XIM_MOREDATA",
90 # endif
91 #endif
92 };
93
94 /////////////////////////////////////////////////////////////////////////////
95
96 refcounted::refcounted (const char *id)
97 {
98 this->id = strdup (id);
99 }
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 ++(*i)->referenced;
114 (*i)->ref_next ();
115 return *i;
116 }
117 }
118
119 T *obj = new T (id);
120
121 if (obj && obj->ref_init ())
122 {
123 obj->referenced = 1;
124 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 void refcache<T>::clear ()
149 {
150 while (this->size ())
151 put (*this->begin ());
152 }
153
154 /////////////////////////////////////////////////////////////////////////////
155
156 #ifdef USE_XIM
157
158 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 xim->xim = 0;
169
170 display->xims.erase (find (display->xims.begin (), display->xims.end (), xim));
171 display->im_change_cb ();
172 }
173
174 bool
175 rxvt_xim::ref_init ()
176 {
177 display = GET_R->display; //HACK: TODO
178
179 xim = XOpenIM (display->dpy, 0, 0, 0);
180
181 if (!xim)
182 return false;
183
184 XIMCallback ximcallback;
185 ximcallback.client_data = (XPointer)this;
186 ximcallback.callback = im_destroy_cb;
187
188 XSetIMValues (xim, XNDestroyCallback, &ximcallback, 0);
189
190 return true;
191 }
192
193 rxvt_xim::~rxvt_xim ()
194 {
195 if (xim)
196 XCloseIM (xim);
197 }
198
199 #endif
200
201 /////////////////////////////////////////////////////////////////////////////
202
203 #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 void
254 rxvt_screen::set (rxvt_display *disp)
255 {
256 display = disp;
257 dpy = disp->dpy;
258
259 Screen *screen = ScreenOfDisplay (dpy, disp->screen);
260
261 depth = DefaultDepthOfScreen (screen);
262 visual = DefaultVisualOfScreen (screen);
263 cmap = DefaultColormapOfScreen (screen);
264 }
265
266 void
267 rxvt_screen::select_visual (int bitdepth)
268 {
269 #if XFT
270 XVisualInfo vinfo;
271
272 if (XMatchVisualInfo (dpy, display->screen, bitdepth, TrueColor, &vinfo))
273 {
274 depth = bitdepth;
275 visual = vinfo.visual;
276 cmap = XCreateColormap (dpy, display->root, visual, AllocNone);
277 }
278 #endif
279 }
280
281 void
282 rxvt_screen::clear ()
283 {
284 #if XFT
285 if (scratch_area)
286 {
287 XFreePixmap (dpy, scratch_area->drawable);
288 delete scratch_area;
289 }
290 #endif
291
292 if (cmap != DefaultColormapOfScreen (ScreenOfDisplay (dpy, display->screen)))
293 XFreeColormap (dpy, cmap);
294 }
295
296 /////////////////////////////////////////////////////////////////////////////
297
298 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 XrmDatabase
306 rxvt_display::get_resources (bool refresh)
307 {
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 XrmDatabase rdb1, database = 0;
316
317 // for ordering, see for example http://www.faqs.org/faqs/Xt-FAQ/ Subject: 20
318 // as opposed to "standard practise", we always read in ~/.Xdefaults
319
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 if (homedir)
336 {
337 snprintf (fname, sizeof (fname), "%s/.Xdefaults", homedir);
338
339 if ((rdb1 = XrmGetFileDatabase (fname)))
340 XrmMergeDatabases (rdb1, &database);
341 }
342
343 /* Get any Xserver defaults */
344 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 if (dpy->xdefaults)
354 XFree (dpy->xdefaults);
355 #endif
356
357 if (XGetWindowProperty (dpy, RootWindow (dpy, 0), XA_RESOURCE_MANAGER,
358 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
369 if (val)
370 XFree(val);
371 }
372
373 #if XLIB_ILLEGAL_ACCESS
374 dpy->xdefaults = displayResource;
375 #endif
376 }
377 else
378 displayResource = XResourceManagerString (dpy);
379
380 if (displayResource)
381 {
382 if ((rdb1 = XrmGetStringDatabase (displayResource)))
383 XrmMergeDatabases (rdb1, &database);
384 }
385
386 #if !XLIB_ILLEGAL_ACCESS
387 if (refresh && displayResource)
388 XFree (displayResource);
389 #endif
390
391 /* Get screen specific resources */
392 displayResource = XScreenResourceString (ScreenOfDisplay (dpy, screen));
393
394 if (displayResource)
395 {
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 {
426 #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 dpy = XOpenDisplay (val);
433 free (val);
434 }
435 else
436 #endif
437 dpy = 0;
438
439 if (!dpy)
440 dpy = XOpenDisplay (id);
441
442 if (!dpy)
443 return false;
444
445 screen = DefaultScreen (dpy);
446 root = DefaultRootWindow (dpy);
447
448 #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 assert (sizeof (xa_names) / sizeof (char *) == NUM_XA);
454 XInternAtoms (dpy, (char **)xa_names, NUM_XA, False, xa);
455
456 XrmSetDatabase (dpy, get_resources (false));
457
458 #ifdef POINTER_BLANK
459 XColor blackcolour;
460 blackcolour.red = 0;
461 blackcolour.green = 0;
462 blackcolour.blue = 0;
463 Font f = XLoadFont (dpy, "fixed");
464 blank_cursor = XCreateGlyphCursor (dpy, f, f, ' ', ' ',
465 &blackcolour, &blackcolour);
466 XUnloadFont (dpy, f);
467 #endif
468
469 int fd = XConnectionNumber (dpy);
470
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 x_ev.start (fd, EVENT_READ);
482 fcntl (fd, F_SETFD, FD_CLOEXEC);
483
484 XSelectInput (dpy, root, PropertyChangeMask);
485
486 flush ();
487
488 return true;
489 }
490
491 void
492 rxvt_display::ref_next ()
493 {
494 // TODO: somehow check wether the database files/resources changed
495 // before affording re-loading/parsing
496 XrmDestroyDatabase (XrmGetDatabase (dpy));
497 XrmSetDatabase (dpy, get_resources (true));
498 }
499
500 rxvt_display::~rxvt_display ()
501 {
502 if (!dpy)
503 return;
504
505 #ifdef POINTER_BLANK
506 XFreeCursor (dpy, blank_cursor);
507 #endif
508 x_ev.stop ();
509 #ifdef USE_XIM
510 xims.clear ();
511 #endif
512 XCloseDisplay (dpy);
513 }
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
522 void rxvt_display::im_change_check ()
523 {
524 // try to only call im_change_cb when a new input method
525 // 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 if (XGetWindowProperty (dpy, root, xa[XA_XIM_SERVERS], 0L, 1000000L,
531 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 if (XGetSelectionOwner (dpy, atoms[i]))
539 {
540 im_change_cb ();
541 break;
542 }
543
544 XFree (atoms);
545 }
546 #endif
547
548 void rxvt_display::x_cb (io_watcher &w, short revents)
549 {
550 do
551 {
552 XEvent xev;
553 XNextEvent (dpy, &xev);
554
555 #ifdef USE_XIM
556 if (!XFilterEvent (&xev, None))
557 {
558 if (xev.type == PropertyNotify
559 && xev.xany.window == root
560 && xev.xproperty.atom == xa[XA_XIM_SERVERS])
561 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 #ifdef USE_XIM
571 }
572 #endif
573 }
574 while (XEventsQueued (dpy, QueuedAlready));
575
576 XFlush (dpy);
577 }
578
579 void rxvt_display::flush ()
580 {
581 if (XEventsQueued (dpy, QueuedAlready))
582 x_cb (x_ev, EVENT_READ);
583
584 XFlush (dpy);
585 }
586
587 void rxvt_display::reg (xevent_watcher *w)
588 {
589 if (!w->active)
590 {
591 xw.push_back (w);
592 w->active = xw.size ();
593 }
594 }
595
596 void rxvt_display::unreg (xevent_watcher *w)
597 {
598 if (w->active)
599 {
600 xw[w->active - 1] = 0;
601 w->active = 0;
602 }
603 }
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
615 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 # if XLIB_IS_RACEFREE
649 xims.put (xim);
650 # endif
651 }
652
653 #endif
654
655 Atom rxvt_display::atom (const char *name)
656 {
657 return XInternAtom (dpy, name, False);
658 }
659
660 /////////////////////////////////////////////////////////////////////////////
661
662 template class refcache<rxvt_display>;
663 refcache<rxvt_display> displays;
664
665 /////////////////////////////////////////////////////////////////////////////
666 //
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
674 bool
675 rxvt_color::alloc (rxvt_screen *screen, const rgba &color)
676 {
677 #if XFT
678 XRenderPictFormat *format;
679
680 // FUCKING Xft gets it wrong, of course, so work around it.
681 // Transparency users should eat shit and die, and then
682 // XRenderQueryPictIndexValues themselves plenty.
683 if ((screen->visual->c_class == TrueColor)
684 && (format = XRenderFindVisualFormat (screen->dpy, screen->visual)))
685 {
686 // the fun lies in doing everything manually...
687 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 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
697 return true;
698 }
699 else
700 {
701 XRenderColor d;
702
703 d.red = color.r;
704 d.green = color.g;
705 d.blue = color.b;
706 d.alpha = color.a;
707
708 return XftColorAllocValue (screen->dpy, screen->visual, screen->cmap, &d, &c);
709 }
710 #else
711 c.red = color.r;
712 c.green = color.g;
713 c.blue = color.b;
714
715 if (screen->visual->c_class == TrueColor)
716 {
717 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
721 return true;
722 }
723 else if (XAllocColor (screen->dpy, screen->cmap, &c))
724 return true;
725 else
726 c.pixel = (color.r + color.g + color.b) > 128*3
727 ? WhitePixelOfScreen (DefaultScreenOfDisplay (screen->dpy))
728 : BlackPixelOfScreen (DefaultScreenOfDisplay (screen->dpy));
729 #endif
730
731 return false;
732 }
733
734 bool
735 rxvt_color::set (rxvt_screen *screen, const char *name)
736 {
737 rgba c;
738 char eos;
739 int skip;
740
741 // parse the nonstandard "[alphapercent]" prefix
742 if (1 <= sscanf (name, "[%hd]%n", &c.a, &skip))
743 {
744 c.a = lerp<int, int, int> (0, rgba::MAX_CC, c.a);
745 name += skip;
746 }
747 else
748 c.a = rgba::MAX_CC;
749
750 // 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 {
753 XColor xc, xc_exact;
754
755 if (XParseColor (screen->dpy, screen->cmap, name, &xc))
756 {
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 }
770
771 return set (screen, c);
772 }
773
774 bool
775 rxvt_color::set (rxvt_screen *screen, const rgba &color)
776 {
777 bool got = alloc (screen, color);
778
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 // many kilobytes transfer per colour, but pseudocolor isn't worth
792 // many extra optimisations.
793 XQueryColors (screen->dpy, screen->cmap, colors, cmap_size);
794
795 int diff = 0x7fffffffUL;
796 XColor *best = colors;
797
798 for (int i = 0; i < cmap_size; i++)
799 {
800 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
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 // color.r, color.g, color.b, best->red, best->green, best->blue, diff);
813
814 got = alloc (screen, rgba (best->red, best->green, best->blue));
815
816 delete [] colors;
817 }
818 #endif
819
820 return got;
821 }
822
823 void
824 rxvt_color::get (rgba &color)
825 {
826 #if XFT
827 color.r = c.color.red;
828 color.g = c.color.green;
829 color.b = c.color.blue;
830 color.a = c.color.alpha;
831 #else
832 color.r = c.red;
833 color.g = c.green;
834 color.b = c.blue;
835 color.a = rgba::MAX_CC;
836 #endif
837 }
838
839 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 void
852 rxvt_color::free (rxvt_screen *screen)
853 {
854 if (screen->visual->c_class == TrueColor)
855 return; // nothing to do
856
857 #if XFT
858 XftColorFree (screen->dpy, screen->visual, screen->cmap, &c);
859 #else
860 XFreeColors (screen->dpy, screen->cmap, &c.pixel, 1, AllPlanes);
861 #endif
862 }
863
864 void
865 rxvt_color::fade (rxvt_screen *screen, int percent, rxvt_color &result, const rgba &to)
866 {
867 rgba c;
868 get (c);
869
870 result.set (
871 screen,
872 rgba (
873 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 )
878 );
879 }
880