ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/rxvttoolkit.C
Revision: 1.24
Committed: Wed Jan 25 00:42:21 2006 UTC (18 years, 4 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.23: +2 -0 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     refcounted::refcounted (const char *id)
38     {
39 root 1.2 this->id = strdup (id);
40 root 1.1 }
41    
42     refcounted::~refcounted ()
43     {
44     free (id);
45     }
46    
47     template<class T>
48     T *refcache<T>::get (const char *id)
49     {
50     for (T **i = this->begin (); i < this->end (); ++i)
51     {
52     if (!strcmp (id, (*i)->id))
53     {
54 root 1.23 ++(*i)->referenced;
55     (*i)->ref_next ();
56 root 1.1 return *i;
57     }
58     }
59    
60     T *obj = new T (id);
61    
62 root 1.23 if (obj && obj->ref_init ())
63 root 1.1 {
64 root 1.23 obj->referenced = 1;
65 root 1.1 this->push_back (obj);
66     return obj;
67     }
68     else
69     {
70     delete obj;
71     return 0;
72     }
73     }
74    
75     template<class T>
76     void refcache<T>::put (T *obj)
77     {
78     if (!obj)
79     return;
80    
81     if (!--obj->referenced)
82     {
83     this->erase (find (this->begin (), this->end (), obj));
84     delete obj;
85     }
86     }
87    
88     template<class T>
89 root 1.12 void refcache<T>::clear ()
90 root 1.1 {
91     while (this->size ())
92     put (*this->begin ());
93     }
94    
95     /////////////////////////////////////////////////////////////////////////////
96    
97     #ifdef USE_XIM
98 root 1.24
99 root 1.1 static void
100     #if XIMCB_PROTO_BROKEN
101     im_destroy_cb (XIC unused1, XPointer client_data, XPointer unused3)
102     #else
103     im_destroy_cb (XIM unused1, XPointer client_data, XPointer unused3)
104     #endif
105     {
106     rxvt_xim *xim = (rxvt_xim *)client_data;
107     rxvt_display *display = xim->display;
108    
109 root 1.5 xim->xim = 0;
110    
111 root 1.1 display->xims.erase (find (display->xims.begin (), display->xims.end (), xim));
112     display->im_change_cb ();
113     }
114    
115 root 1.23 bool
116     rxvt_xim::ref_init ()
117 root 1.1 {
118     display = GET_R->display; //HACK: TODO
119    
120     xim = XOpenIM (display->display, NULL, NULL, NULL);
121    
122     if (!xim)
123     return false;
124    
125     XIMCallback ximcallback;
126     ximcallback.client_data = (XPointer)this;
127     ximcallback.callback = im_destroy_cb;
128    
129     XSetIMValues (xim, XNDestroyCallback, &ximcallback, NULL);
130    
131     return true;
132     }
133    
134     rxvt_xim::~rxvt_xim ()
135     {
136     if (xim)
137     XCloseIM (xim);
138     }
139 root 1.24
140 root 1.1 #endif
141    
142     /////////////////////////////////////////////////////////////////////////////
143    
144     rxvt_display::rxvt_display (const char *id)
145     : refcounted (id)
146     , x_ev (this, &rxvt_display::x_cb)
147     , selection_owner (0)
148     {
149     }
150    
151 root 1.23 XrmDatabase
152     rxvt_display::get_resources ()
153     {
154     char *homedir = (char *)getenv ("HOME");
155     char fname[1024];
156    
157     /*
158     * get resources using the X library function
159     */
160     char *displayResource, *xe;
161     XrmDatabase database, rdb1;
162    
163     database = NULL;
164    
165     // for ordering, see for example http://www.faqs.org/faqs/Xt-FAQ/ Subject: 20
166    
167     // 6. System wide per application default file.
168    
169     /* Add in $XAPPLRESDIR/Rxvt only; not bothering with XUSERFILESEARCHPATH */
170     if ((xe = (char *)getenv ("XAPPLRESDIR")))
171     {
172     snprintf (fname, sizeof (fname), "%s/%s", xe, RESCLASS);
173    
174     if ((rdb1 = XrmGetFileDatabase (fname)))
175     XrmMergeDatabases (rdb1, &database);
176     }
177    
178     // 5. User's per application default file.
179     // none
180    
181     // 4. User's defaults file.
182     /* Get any Xserver defaults */
183     displayResource = XResourceManagerString (display);
184    
185     if (displayResource != NULL)
186     {
187     if ((rdb1 = XrmGetStringDatabase (displayResource)))
188     XrmMergeDatabases (rdb1, &database);
189     }
190     else if (homedir)
191     {
192     snprintf (fname, sizeof (fname), "%s/.Xdefaults", homedir);
193    
194     if ((rdb1 = XrmGetFileDatabase (fname)))
195     XrmMergeDatabases (rdb1, &database);
196     }
197    
198     /* Get screen specific resources */
199     displayResource = XScreenResourceString (ScreenOfDisplay (display, screen));
200    
201     if (displayResource != NULL)
202     {
203     if ((rdb1 = XrmGetStringDatabase (displayResource)))
204     /* Merge with screen-independent resources */
205     XrmMergeDatabases (rdb1, &database);
206    
207     XFree (displayResource);
208     }
209    
210     // 3. User's per host defaults file
211     /* Add in XENVIRONMENT file */
212     if ((xe = (char *)getenv ("XENVIRONMENT"))
213     && (rdb1 = XrmGetFileDatabase (xe)))
214     XrmMergeDatabases (rdb1, &database);
215     else if (homedir)
216     {
217     struct utsname un;
218    
219     if (!uname (&un))
220     {
221     snprintf (fname, sizeof (fname), "%s/.Xdefaults-%s", homedir, un.nodename);
222    
223     if ((rdb1 = XrmGetFileDatabase (fname)))
224     XrmMergeDatabases (rdb1, &database);
225     }
226     }
227    
228     return database;
229     }
230    
231     bool rxvt_display::ref_init ()
232 root 1.1 {
233 root 1.14 #ifdef LOCAL_X_IS_UNIX
234     if (id[0] == ':')
235     {
236     val = rxvt_malloc (5 + strlen (id) + 1);
237     strcpy (val, "unix/");
238     strcat (val, id);
239     display = XOpenDisplay (val);
240     free (val);
241     }
242     else
243 root 1.15 #endif
244 root 1.14 display = 0;
245    
246     if (!display)
247     display = XOpenDisplay (id);
248 root 1.1
249     if (!display)
250     return false;
251    
252     screen = DefaultScreen (display);
253     root = DefaultRootWindow (display);
254     visual = DefaultVisual (display, screen);
255     cmap = DefaultColormap (display, screen);
256     depth = DefaultDepth (display, screen);
257    
258 root 1.23 XrmSetDatabase (display, get_resources ());
259 root 1.1
260 root 1.12 #ifdef POINTER_BLANK
261     XColor blackcolour;
262     blackcolour.red = 0;
263     blackcolour.green = 0;
264     blackcolour.blue = 0;
265     Font f = XLoadFont (display, "fixed");
266     blank_cursor = XCreateGlyphCursor (display, f, f, ' ', ' ',
267     &blackcolour, &blackcolour);
268     XUnloadFont (display, f);
269     #endif
270    
271 root 1.1 #ifdef PREFER_24BIT
272     /*
273     * If depth is not 24, look for a 24bit visual.
274     */
275     if (depth != 24)
276     {
277     XVisualInfo vinfo;
278    
279     if (XMatchVisualInfo (display, screen, 24, TrueColor, &vinfo))
280     {
281     depth = 24;
282     visual = vinfo.visual;
283     cmap = XCreateColormap (display,
284     RootWindow (display, screen),
285     visual, AllocNone);
286     }
287     }
288     #endif
289    
290 root 1.23 int fd = XConnectionNumber (display);
291    
292     #ifndef NO_SLOW_LINK_SUPPORT
293     // try to detect wether we have a local connection.
294     // assume unix domains socket == local, everything else not
295     // TODO: might want to check for inet/127.0.0.1
296     is_local = 0;
297     sockaddr_un sa;
298     socklen_t sl = sizeof (sa);
299    
300     if (!getsockname (fd, (sockaddr *)&sa, &sl))
301     is_local = sa.sun_family == AF_LOCAL;
302     #endif
303    
304 root 1.1 x_ev.start (fd, EVENT_READ);
305     fcntl (fd, F_SETFD, FD_CLOEXEC);
306    
307     XSelectInput (display, root, PropertyChangeMask);
308     #ifdef USE_XIM
309     xa_xim_servers = XInternAtom (display, "XIM_SERVERS", 0);
310     #endif
311    
312     flush ();
313    
314     return true;
315     }
316    
317 root 1.23 void
318     rxvt_display::ref_next ()
319     {
320     // TODO: somehow check wether the database files/resources changed
321     // before re-loading/parsing
322     XrmDestroyDatabase (XrmGetDatabase (display));
323     XrmSetDatabase (display, get_resources ());
324     }
325    
326 root 1.1 rxvt_display::~rxvt_display ()
327     {
328 root 1.22 if (!display)
329     return;
330    
331 root 1.21 #ifdef POINTER_BLANK
332     XFreeCursor (display, blank_cursor);
333     #endif
334 root 1.1 x_ev.stop ();
335 root 1.12 #ifdef USE_XIM
336     xims.clear ();
337     #endif
338 root 1.22 XCloseDisplay (display);
339 root 1.1 }
340    
341     #ifdef USE_XIM
342     void rxvt_display::im_change_cb ()
343     {
344     for (im_watcher **i = imw.begin (); i != imw.end (); ++i)
345     (*i)->call ();
346     }
347 root 1.5
348     void rxvt_display::im_change_check ()
349     {
350 root 1.13 // try to only call im_change_cb when a new input method
351 root 1.5 // registers, as xlib crashes due to a race otherwise.
352     Atom actual_type, *atoms;
353     int actual_format;
354     unsigned long nitems, bytes_after;
355    
356     if (XGetWindowProperty (display, root, xa_xim_servers, 0L, 1000000L,
357     False, XA_ATOM, &actual_type, &actual_format,
358     &nitems, &bytes_after, (unsigned char **)&atoms)
359     != Success )
360     return;
361    
362     if (actual_type == XA_ATOM && actual_format == 32)
363     for (int i = 0; i < nitems; i++)
364     if (XGetSelectionOwner (display, atoms[i]))
365     {
366     im_change_cb ();
367     break;
368     }
369    
370     XFree (atoms);
371     }
372 root 1.1 #endif
373    
374     void rxvt_display::x_cb (io_watcher &w, short revents)
375     {
376     do
377     {
378     XEvent xev;
379     XNextEvent (display, &xev);
380    
381 root 1.5 #ifdef USE_XIM
382     if (!XFilterEvent (&xev, None))
383     {
384     if (xev.type == PropertyNotify
385     && xev.xany.window == root
386     && xev.xproperty.atom == xa_xim_servers)
387     im_change_check ();
388     #endif
389     for (int i = xw.size (); i--; )
390     {
391     if (!xw[i])
392     xw.erase_unordered (i);
393     else if (xw[i]->window == xev.xany.window)
394     xw[i]->call (xev);
395     }
396 root 1.1 #ifdef USE_XIM
397 root 1.5 }
398 root 1.1 #endif
399     }
400 root 1.6 while (XEventsQueued (display, QueuedAlready));
401 root 1.1
402 root 1.10 XFlush (display);
403 root 1.1 }
404    
405     void rxvt_display::flush ()
406     {
407 root 1.10 if (XEventsQueued (display, QueuedAlready))
408     x_cb (x_ev, EVENT_READ);
409    
410 root 1.8 XFlush (display);
411 root 1.1 }
412    
413     void rxvt_display::reg (xevent_watcher *w)
414     {
415     xw.push_back (w);
416     w->active = xw.size ();
417     }
418    
419     void rxvt_display::unreg (xevent_watcher *w)
420     {
421     if (w->active)
422     xw[w->active - 1] = 0;
423     }
424    
425     void rxvt_display::set_selection_owner (rxvt_term *owner)
426     {
427     if (selection_owner && selection_owner != owner)
428     selection_owner->selection_clear ();
429    
430     selection_owner = owner;
431     }
432    
433     #ifdef USE_XIM
434     void rxvt_display::reg (im_watcher *w)
435     {
436     imw.push_back (w);
437     }
438    
439     void rxvt_display::unreg (im_watcher *w)
440     {
441     imw.erase (find (imw.begin (), imw.end (), w));
442     }
443    
444     rxvt_xim *rxvt_display::get_xim (const char *locale, const char *modifiers)
445     {
446     char *id;
447     int l, m;
448    
449     l = strlen (locale);
450     m = strlen (modifiers);
451    
452     if (!(id = (char *)malloc (l + m + 2)))
453     return 0;
454    
455     memcpy (id, locale, l); id[l] = '\n';
456     memcpy (id + l + 1, modifiers, m); id[l + m + 1] = 0;
457    
458     rxvt_xim *xim = xims.get (id);
459    
460     free (id);
461    
462     return xim;
463     }
464    
465     void rxvt_display::put_xim (rxvt_xim *xim)
466     {
467 root 1.10 #if XLIB_IS_RACEFREE
468 root 1.1 xims.put (xim);
469 root 1.10 #endif
470 root 1.1 }
471     #endif
472    
473     Atom rxvt_display::atom (const char *name)
474     {
475     return XInternAtom (display, name, False);
476     }
477    
478     /////////////////////////////////////////////////////////////////////////////
479    
480     template class refcache<rxvt_display>;
481     refcache<rxvt_display> displays;
482    
483     /////////////////////////////////////////////////////////////////////////////
484    
485     bool
486     rxvt_color::set (rxvt_display *display, Pixel p)
487     {
488     #if XFT
489     XColor xc;
490    
491     xc.pixel = p;
492     if (!XQueryColor (display->display, display->cmap, &xc))
493     return false;
494    
495     XRenderColor d;
496    
497     d.red = xc.red;
498     d.green = xc.green;
499     d.blue = xc.blue;
500     d.alpha = 0xffff;
501    
502     return
503     XftColorAllocValue (display->display,
504     display->visual,
505     display->cmap,
506     &d, &c);
507     #else
508     this->p = p;
509     #endif
510    
511     return true;
512     }
513    
514     bool
515     rxvt_color::set (rxvt_display *display, const char *name)
516     {
517 root 1.7 #if XFT
518     return XftColorAllocName (display->display, display->visual, display->cmap,
519     name, &c);
520     #else
521 root 1.1 XColor xc;
522    
523     if (XParseColor (display->display, display->cmap, name, &xc))
524     return set (display, xc.red, xc.green, xc.blue);
525    
526     return false;
527 root 1.7 #endif
528 root 1.1 }
529    
530     bool
531     rxvt_color::set (rxvt_display *display, unsigned short cr, unsigned short cg, unsigned short cb)
532     {
533     XColor xc;
534    
535     xc.red = cr;
536     xc.green = cg;
537     xc.blue = cb;
538     xc.flags = DoRed | DoGreen | DoBlue;
539    
540     if (XAllocColor (display->display, display->cmap, &xc))
541     return set (display, xc.pixel);
542    
543     return false;
544     }
545    
546     void
547     rxvt_color::get (rxvt_display *display, unsigned short &cr, unsigned short &cg, unsigned short &cb)
548     {
549     #if XFT
550     cr = c.color.red;
551     cg = c.color.green;
552     cb = c.color.blue;
553     #else
554     XColor c;
555    
556     c.pixel = p;
557     XQueryColor (display->display, display->cmap, &c);
558    
559     cr = c.red;
560     cg = c.green;
561     cb = c.blue;
562     #endif
563     }
564    
565     void
566     rxvt_color::free (rxvt_display *display)
567     {
568     #if XFT
569     XftColorFree (display->display, display->visual, display->cmap, &c);
570     #else
571     XFreeColors (display->display, display->cmap, &p, 1, AllPlanes);
572     #endif
573     }
574    
575     rxvt_color
576     rxvt_color::fade (rxvt_display *display, int percent)
577     {
578 root 1.18 percent = 100 - percent;
579    
580 root 1.1 unsigned short cr, cg, cb;
581     rxvt_color faded;
582    
583     get (display, cr, cg, cb);
584 root 1.18
585     faded.set (
586     display,
587     cr * percent / 100,
588     cg * percent / 100,
589     cb * percent / 100
590     );
591    
592     return faded;
593     }
594    
595 root 1.19 #define LERP(a,b,p) (a * p + b * (100 - p)) / 100
596 root 1.18
597     rxvt_color
598     rxvt_color::fade (rxvt_display *display, int percent, rxvt_color &fadeto)
599     {
600     percent = 100 - percent;
601    
602     unsigned short cr, cg, cb;
603     unsigned short fcr, fcg, fcb;
604     rxvt_color faded;
605    
606     get (display, cr, cg, cb);
607     fadeto.get(display, fcr, fcg, fcb);
608    
609     faded.set (
610     display,
611     LERP (cr, fcr, percent),
612     LERP (cg, fcg, percent),
613     LERP (cb, fcb, percent)
614     );
615 root 1.1
616     return faded;
617     }
618