ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/rxvttoolkit.C
Revision: 1.32
Committed: Sun Jan 29 22:30:21 2006 UTC (18 years, 3 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.31: +4 -4 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 /*--------------------------------*-C-*---------------------------------*
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     * Copyright (c) 2003-2004 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 root 1.23 #include <sys/utsname.h>
31    
32 root 1.1 #ifndef NO_SLOW_LINK_SUPPORT
33     # include <sys/socket.h>
34     # include <sys/un.h>
35     #endif
36    
37 root 1.31 #if XFT
38     # include <X11/extensions/Xrender.h>
39     #endif
40    
41 root 1.25 const char *const xa_names[] =
42     {
43     "TEXT",
44     "COMPOUND_TEXT",
45     "UTF8_STRING",
46     "MULTIPLE",
47     "TARGETS",
48     "TIMESTAMP",
49     "VT_SELECTION",
50     "INCR",
51     "WM_PROTOCOLS",
52     "WM_DELETE_WINDOW",
53     "CLIPBOARD",
54     #if ENABLE_FRILLS
55     "_MOTIF_WM_HINTS",
56     #endif
57     #if ENABLE_EWMH
58     "_NET_WM_PID",
59     "_NET_WM_NAME",
60     "_NET_WM_ICON_NAME",
61     "_NET_WM_PING",
62     #endif
63     #if USE_XIM
64     "WM_LOCALE_NAME",
65     "XIM_SERVERS",
66     #endif
67     #ifdef TRANSPARENT
68     "_XROOTPMAP_ID",
69     "ESETROOT_PMAP_ID",
70     #endif
71     #if ENABLE_XEMBED
72     "_XEMBED",
73     "_XEMBED_INFO",
74     #endif
75     };
76    
77     /////////////////////////////////////////////////////////////////////////////
78    
79 root 1.1 refcounted::refcounted (const char *id)
80     {
81 root 1.2 this->id = strdup (id);
82 root 1.1 }
83    
84     refcounted::~refcounted ()
85     {
86     free (id);
87     }
88    
89     template<class T>
90     T *refcache<T>::get (const char *id)
91     {
92     for (T **i = this->begin (); i < this->end (); ++i)
93     {
94     if (!strcmp (id, (*i)->id))
95     {
96 root 1.23 ++(*i)->referenced;
97     (*i)->ref_next ();
98 root 1.1 return *i;
99     }
100     }
101    
102     T *obj = new T (id);
103    
104 root 1.23 if (obj && obj->ref_init ())
105 root 1.1 {
106 root 1.23 obj->referenced = 1;
107 root 1.1 this->push_back (obj);
108     return obj;
109     }
110     else
111     {
112     delete obj;
113     return 0;
114     }
115     }
116    
117     template<class T>
118     void refcache<T>::put (T *obj)
119     {
120     if (!obj)
121     return;
122    
123     if (!--obj->referenced)
124     {
125     this->erase (find (this->begin (), this->end (), obj));
126     delete obj;
127     }
128     }
129    
130     template<class T>
131 root 1.12 void refcache<T>::clear ()
132 root 1.1 {
133     while (this->size ())
134     put (*this->begin ());
135     }
136    
137     /////////////////////////////////////////////////////////////////////////////
138    
139     #ifdef USE_XIM
140 root 1.24
141 root 1.1 static void
142     #if XIMCB_PROTO_BROKEN
143     im_destroy_cb (XIC unused1, XPointer client_data, XPointer unused3)
144     #else
145     im_destroy_cb (XIM unused1, XPointer client_data, XPointer unused3)
146     #endif
147     {
148     rxvt_xim *xim = (rxvt_xim *)client_data;
149     rxvt_display *display = xim->display;
150    
151 root 1.5 xim->xim = 0;
152    
153 root 1.1 display->xims.erase (find (display->xims.begin (), display->xims.end (), xim));
154     display->im_change_cb ();
155     }
156    
157 root 1.23 bool
158     rxvt_xim::ref_init ()
159 root 1.1 {
160     display = GET_R->display; //HACK: TODO
161    
162     xim = XOpenIM (display->display, NULL, NULL, NULL);
163    
164     if (!xim)
165     return false;
166    
167     XIMCallback ximcallback;
168     ximcallback.client_data = (XPointer)this;
169     ximcallback.callback = im_destroy_cb;
170    
171     XSetIMValues (xim, XNDestroyCallback, &ximcallback, NULL);
172    
173     return true;
174     }
175    
176     rxvt_xim::~rxvt_xim ()
177     {
178     if (xim)
179     XCloseIM (xim);
180     }
181 root 1.24
182 root 1.1 #endif
183    
184     /////////////////////////////////////////////////////////////////////////////
185    
186 root 1.26 void
187     rxvt_screen::set (rxvt_display *disp)
188     {
189     display = disp;
190 root 1.27 xdisp = disp->display;
191 root 1.26
192     Screen *screen = ScreenOfDisplay (xdisp, disp->screen);
193    
194 root 1.27 depth = DefaultDepthOfScreen (screen);
195     visual = DefaultVisualOfScreen (screen);
196     cmap = DefaultColormapOfScreen (screen);
197 root 1.26 }
198    
199     void
200 root 1.28 rxvt_screen::set (rxvt_display *disp, int bitdepth)
201 root 1.26 {
202     set (disp);
203    
204 root 1.31 #if XFT
205 root 1.26 XVisualInfo vinfo;
206    
207 root 1.28 if (XMatchVisualInfo (xdisp, display->screen, bitdepth, TrueColor, &vinfo))
208 root 1.26 {
209 root 1.28 depth = bitdepth;
210     visual = vinfo.visual;
211     cmap = XCreateColormap (xdisp, disp->root, visual, AllocNone);
212 root 1.26 }
213 root 1.31 #endif
214 root 1.26 }
215    
216     void
217     rxvt_screen::clear ()
218     {
219     if (cmap != DefaultColormapOfScreen (ScreenOfDisplay (xdisp, display->screen)))
220     XFreeColormap (xdisp, cmap);
221     }
222    
223     /////////////////////////////////////////////////////////////////////////////
224    
225 root 1.1 rxvt_display::rxvt_display (const char *id)
226     : refcounted (id)
227     , x_ev (this, &rxvt_display::x_cb)
228     , selection_owner (0)
229     {
230     }
231    
232 root 1.23 XrmDatabase
233     rxvt_display::get_resources ()
234     {
235     char *homedir = (char *)getenv ("HOME");
236     char fname[1024];
237    
238     /*
239     * get resources using the X library function
240     */
241     char *displayResource, *xe;
242     XrmDatabase database, rdb1;
243    
244     database = NULL;
245    
246     // for ordering, see for example http://www.faqs.org/faqs/Xt-FAQ/ Subject: 20
247    
248     // 6. System wide per application default file.
249    
250     /* Add in $XAPPLRESDIR/Rxvt only; not bothering with XUSERFILESEARCHPATH */
251     if ((xe = (char *)getenv ("XAPPLRESDIR")))
252     {
253     snprintf (fname, sizeof (fname), "%s/%s", xe, RESCLASS);
254    
255     if ((rdb1 = XrmGetFileDatabase (fname)))
256     XrmMergeDatabases (rdb1, &database);
257     }
258    
259     // 5. User's per application default file.
260     // none
261    
262     // 4. User's defaults file.
263     /* Get any Xserver defaults */
264     displayResource = XResourceManagerString (display);
265    
266     if (displayResource != NULL)
267     {
268     if ((rdb1 = XrmGetStringDatabase (displayResource)))
269     XrmMergeDatabases (rdb1, &database);
270     }
271     else if (homedir)
272     {
273     snprintf (fname, sizeof (fname), "%s/.Xdefaults", homedir);
274    
275     if ((rdb1 = XrmGetFileDatabase (fname)))
276     XrmMergeDatabases (rdb1, &database);
277     }
278    
279     /* Get screen specific resources */
280     displayResource = XScreenResourceString (ScreenOfDisplay (display, screen));
281    
282     if (displayResource != NULL)
283     {
284     if ((rdb1 = XrmGetStringDatabase (displayResource)))
285     /* Merge with screen-independent resources */
286     XrmMergeDatabases (rdb1, &database);
287    
288     XFree (displayResource);
289     }
290    
291     // 3. User's per host defaults file
292     /* Add in XENVIRONMENT file */
293     if ((xe = (char *)getenv ("XENVIRONMENT"))
294     && (rdb1 = XrmGetFileDatabase (xe)))
295     XrmMergeDatabases (rdb1, &database);
296     else if (homedir)
297     {
298     struct utsname un;
299    
300     if (!uname (&un))
301     {
302     snprintf (fname, sizeof (fname), "%s/.Xdefaults-%s", homedir, un.nodename);
303    
304     if ((rdb1 = XrmGetFileDatabase (fname)))
305     XrmMergeDatabases (rdb1, &database);
306     }
307     }
308    
309     return database;
310     }
311    
312     bool rxvt_display::ref_init ()
313 root 1.1 {
314 root 1.14 #ifdef LOCAL_X_IS_UNIX
315     if (id[0] == ':')
316     {
317     val = rxvt_malloc (5 + strlen (id) + 1);
318     strcpy (val, "unix/");
319     strcat (val, id);
320     display = XOpenDisplay (val);
321     free (val);
322     }
323     else
324 root 1.15 #endif
325 root 1.14 display = 0;
326    
327     if (!display)
328     display = XOpenDisplay (id);
329 root 1.1
330     if (!display)
331     return false;
332    
333     screen = DefaultScreen (display);
334     root = DefaultRootWindow (display);
335    
336 root 1.25 assert (sizeof (xa_names) / sizeof (char *) == NUM_XA);
337     XInternAtoms (display, (char **)xa_names, NUM_XA, False, xa);
338    
339 root 1.23 XrmSetDatabase (display, get_resources ());
340 root 1.1
341 root 1.12 #ifdef POINTER_BLANK
342     XColor blackcolour;
343     blackcolour.red = 0;
344     blackcolour.green = 0;
345     blackcolour.blue = 0;
346     Font f = XLoadFont (display, "fixed");
347     blank_cursor = XCreateGlyphCursor (display, f, f, ' ', ' ',
348     &blackcolour, &blackcolour);
349     XUnloadFont (display, f);
350     #endif
351    
352 root 1.23 int fd = XConnectionNumber (display);
353    
354     #ifndef NO_SLOW_LINK_SUPPORT
355     // try to detect wether we have a local connection.
356     // assume unix domains socket == local, everything else not
357     // TODO: might want to check for inet/127.0.0.1
358     is_local = 0;
359     sockaddr_un sa;
360     socklen_t sl = sizeof (sa);
361    
362     if (!getsockname (fd, (sockaddr *)&sa, &sl))
363     is_local = sa.sun_family == AF_LOCAL;
364     #endif
365    
366 root 1.1 x_ev.start (fd, EVENT_READ);
367     fcntl (fd, F_SETFD, FD_CLOEXEC);
368    
369     XSelectInput (display, root, PropertyChangeMask);
370    
371     flush ();
372    
373     return true;
374     }
375    
376 root 1.23 void
377     rxvt_display::ref_next ()
378     {
379     // TODO: somehow check wether the database files/resources changed
380     // before re-loading/parsing
381     XrmDestroyDatabase (XrmGetDatabase (display));
382     XrmSetDatabase (display, get_resources ());
383     }
384    
385 root 1.1 rxvt_display::~rxvt_display ()
386     {
387 root 1.22 if (!display)
388     return;
389    
390 root 1.21 #ifdef POINTER_BLANK
391     XFreeCursor (display, blank_cursor);
392     #endif
393 root 1.1 x_ev.stop ();
394 root 1.12 #ifdef USE_XIM
395     xims.clear ();
396     #endif
397 root 1.22 XCloseDisplay (display);
398 root 1.1 }
399    
400     #ifdef USE_XIM
401     void rxvt_display::im_change_cb ()
402     {
403     for (im_watcher **i = imw.begin (); i != imw.end (); ++i)
404     (*i)->call ();
405     }
406 root 1.5
407     void rxvt_display::im_change_check ()
408     {
409 root 1.13 // try to only call im_change_cb when a new input method
410 root 1.5 // registers, as xlib crashes due to a race otherwise.
411     Atom actual_type, *atoms;
412     int actual_format;
413     unsigned long nitems, bytes_after;
414    
415 root 1.25 if (XGetWindowProperty (display, root, xa[XA_XIM_SERVERS], 0L, 1000000L,
416 root 1.5 False, XA_ATOM, &actual_type, &actual_format,
417     &nitems, &bytes_after, (unsigned char **)&atoms)
418     != Success )
419     return;
420    
421     if (actual_type == XA_ATOM && actual_format == 32)
422     for (int i = 0; i < nitems; i++)
423     if (XGetSelectionOwner (display, atoms[i]))
424     {
425     im_change_cb ();
426     break;
427     }
428    
429     XFree (atoms);
430     }
431 root 1.1 #endif
432    
433     void rxvt_display::x_cb (io_watcher &w, short revents)
434     {
435     do
436     {
437     XEvent xev;
438     XNextEvent (display, &xev);
439    
440 root 1.5 #ifdef USE_XIM
441     if (!XFilterEvent (&xev, None))
442     {
443     if (xev.type == PropertyNotify
444     && xev.xany.window == root
445 root 1.25 && xev.xproperty.atom == xa[XA_XIM_SERVERS])
446 root 1.5 im_change_check ();
447     #endif
448     for (int i = xw.size (); i--; )
449     {
450     if (!xw[i])
451     xw.erase_unordered (i);
452     else if (xw[i]->window == xev.xany.window)
453     xw[i]->call (xev);
454     }
455 root 1.1 #ifdef USE_XIM
456 root 1.5 }
457 root 1.1 #endif
458     }
459 root 1.6 while (XEventsQueued (display, QueuedAlready));
460 root 1.1
461 root 1.10 XFlush (display);
462 root 1.1 }
463    
464     void rxvt_display::flush ()
465     {
466 root 1.10 if (XEventsQueued (display, QueuedAlready))
467     x_cb (x_ev, EVENT_READ);
468    
469 root 1.8 XFlush (display);
470 root 1.1 }
471    
472     void rxvt_display::reg (xevent_watcher *w)
473     {
474     xw.push_back (w);
475     w->active = xw.size ();
476     }
477    
478     void rxvt_display::unreg (xevent_watcher *w)
479     {
480     if (w->active)
481     xw[w->active - 1] = 0;
482     }
483    
484     void rxvt_display::set_selection_owner (rxvt_term *owner)
485     {
486     if (selection_owner && selection_owner != owner)
487     selection_owner->selection_clear ();
488    
489     selection_owner = owner;
490     }
491    
492     #ifdef USE_XIM
493     void rxvt_display::reg (im_watcher *w)
494     {
495     imw.push_back (w);
496     }
497    
498     void rxvt_display::unreg (im_watcher *w)
499     {
500     imw.erase (find (imw.begin (), imw.end (), w));
501     }
502    
503     rxvt_xim *rxvt_display::get_xim (const char *locale, const char *modifiers)
504     {
505     char *id;
506     int l, m;
507    
508     l = strlen (locale);
509     m = strlen (modifiers);
510    
511     if (!(id = (char *)malloc (l + m + 2)))
512     return 0;
513    
514     memcpy (id, locale, l); id[l] = '\n';
515     memcpy (id + l + 1, modifiers, m); id[l + m + 1] = 0;
516    
517     rxvt_xim *xim = xims.get (id);
518    
519     free (id);
520    
521     return xim;
522     }
523    
524     void rxvt_display::put_xim (rxvt_xim *xim)
525     {
526 root 1.10 #if XLIB_IS_RACEFREE
527 root 1.1 xims.put (xim);
528 root 1.10 #endif
529 root 1.1 }
530     #endif
531    
532     Atom rxvt_display::atom (const char *name)
533     {
534     return XInternAtom (display, name, False);
535     }
536    
537     /////////////////////////////////////////////////////////////////////////////
538    
539     template class refcache<rxvt_display>;
540     refcache<rxvt_display> displays;
541    
542     /////////////////////////////////////////////////////////////////////////////
543    
544     bool
545 root 1.28 rxvt_color::set (rxvt_screen *screen, const char *name)
546 root 1.1 {
547     #if XFT
548 root 1.28 int l = strlen (name);
549     rxvt_rgba r;
550     char eos;
551     int mult;
552    
553     if ( l == 1+4*1 && 4 == sscanf (name, "#%1hx%1hx%1hx%1hx%c", &r.a, &r.r, &r.g, &r.b, &eos))
554 root 1.29 mult = rxvt_rgba::MAX_CC / 0x000f;
555 root 1.28 else if (l == 1+4*2 && 4 == sscanf (name, "#%2hx%2hx%2hx%2hx%c", &r.a, &r.r, &r.g, &r.b, &eos))
556 root 1.29 mult = rxvt_rgba::MAX_CC / 0x00ff;
557 root 1.28 else if (l == 1+4*4 && 4 == sscanf (name, "#%4hx%4hx%4hx%4hx%c", &r.a, &r.r, &r.g, &r.b, &eos))
558 root 1.29 mult = rxvt_rgba::MAX_CC / 0xffff;
559     else if (l == 4+5*4 && 4 == sscanf (name, "rgba:%hx/%hx/%hx/%hx%c", &r.r, &r.g, &r.b, &r.a, &eos))
560     mult = rxvt_rgba::MAX_CC / 0xffff;
561 root 1.28 else
562     return XftColorAllocName (screen->xdisp, screen->visual, screen->cmap, name, &c);
563 root 1.1
564 root 1.28 r.r *= mult; r.g *= mult; r.b *= mult; r.a *= mult;
565     return set (screen, r);
566 root 1.7 #else
567 root 1.1 XColor xc;
568    
569 root 1.26 if (XParseColor (screen->xdisp, screen->cmap, name, &xc))
570 root 1.28 return set (screen, rxvt_rgba (xc.red, xc.green, xc.blue));
571 root 1.1
572     return false;
573 root 1.7 #endif
574 root 1.1 }
575    
576     bool
577 root 1.28 rxvt_color::set (rxvt_screen *screen, rxvt_rgba rgba)
578 root 1.1 {
579 root 1.28 #if XFT
580 root 1.31 XRenderPictFormat *format;
581 root 1.28
582 root 1.31 // FUCKING Xft gets it wrong, of course, so work around it
583     // transparency users should eat shit and die, and then
584     // XRenderQueryPictIndexValues themselves plenty.
585     if (screen->visual->c_class == TrueColor
586     && (format = XRenderFindVisualFormat (screen->xdisp, screen->visual)))
587     {
588     // the fun lies in doing everything manually...
589     c.color.red = rgba.r;
590     c.color.green = rgba.g;
591     c.color.blue = rgba.b;
592     c.color.alpha = rgba.a;
593    
594 root 1.32 c.pixel = ((rgba.r * format->direct.redMask / rxvt_rgba::MAX_CC) << format->direct.red)
595     | ((rgba.g * format->direct.greenMask / rxvt_rgba::MAX_CC) << format->direct.green)
596     | ((rgba.b * format->direct.blueMask / rxvt_rgba::MAX_CC) << format->direct.blue)
597     | ((rgba.a * format->direct.alphaMask / rxvt_rgba::MAX_CC) << format->direct.alpha);
598 root 1.29
599     return true;
600     }
601 root 1.31 else
602     {
603     XRenderColor d;
604    
605     d.red = rgba.r;
606     d.green = rgba.g;
607     d.blue = rgba.b;
608     d.alpha = rgba.a;
609    
610     return XftColorAllocValue (screen->xdisp, screen->visual, screen->cmap, &d, &c);
611     }
612 root 1.29
613     return false;
614 root 1.28 #else
615 root 1.1 XColor xc;
616    
617 root 1.28 xc.red = rgba.r;
618     xc.green = rgba.g;
619     xc.blue = rgba.b;
620 root 1.1 xc.flags = DoRed | DoGreen | DoBlue;
621    
622 root 1.26 if (XAllocColor (screen->xdisp, screen->cmap, &xc))
623 root 1.28 {
624     p = xc.pixel;
625     return true;
626     }
627 root 1.1
628     return false;
629 root 1.28 #endif
630 root 1.1 }
631    
632     void
633 root 1.28 rxvt_color::get (rxvt_screen *screen, rxvt_rgba &rgba)
634 root 1.1 {
635     #if XFT
636 root 1.28 rgba.r = c.color.red;
637     rgba.g = c.color.green;
638     rgba.b = c.color.blue;
639     rgba.a = c.color.alpha;
640 root 1.1 #else
641     XColor c;
642    
643     c.pixel = p;
644 root 1.26 XQueryColor (screen->xdisp, screen->cmap, &c);
645 root 1.1
646 root 1.28 rgba.r = c.red;
647     rgba.g = c.green;
648     rgba.b = c.blue;
649     rgba.a = rxvt_rgba::MAX_CC;
650 root 1.1 #endif
651     }
652    
653     void
654 root 1.26 rxvt_color::free (rxvt_screen *screen)
655 root 1.1 {
656     #if XFT
657 root 1.26 XftColorFree (screen->xdisp, screen->visual, screen->cmap, &c);
658 root 1.1 #else
659 root 1.26 XFreeColors (screen->xdisp, screen->cmap, &p, 1, AllPlanes);
660 root 1.1 #endif
661     }
662    
663     rxvt_color
664 root 1.26 rxvt_color::fade (rxvt_screen *screen, int percent)
665 root 1.1 {
666 root 1.28 rxvt_color faded;
667 root 1.18
668 root 1.28 rxvt_rgba c;
669     get (screen, c);
670 root 1.1
671 root 1.28 c.r = lerp (0, c.r, percent);
672     c.g = lerp (0, c.g, percent);
673     c.b = lerp (0, c.b, percent);
674 root 1.18
675 root 1.28 faded.set (screen, c);
676 root 1.18
677     return faded;
678     }
679    
680     rxvt_color
681 root 1.26 rxvt_color::fade (rxvt_screen *screen, int percent, rxvt_color &fadeto)
682 root 1.18 {
683 root 1.28 rxvt_rgba c, fc;
684 root 1.18 rxvt_color faded;
685    
686 root 1.28 get (screen, c);
687     fadeto.get (screen, fc);
688 root 1.18
689     faded.set (
690 root 1.26 screen,
691 root 1.28 rxvt_rgba (
692     lerp (fc.r, c.r, percent),
693     lerp (fc.g, c.g, percent),
694     lerp (fc.b, c.b, percent),
695     lerp (fc.a, c.a, percent)
696     )
697 root 1.18 );
698 root 1.1
699     return faded;
700     }
701