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

# Content
1 /*--------------------------------*-C-*---------------------------------*
2 * File: rxvttoolkit.C
3 *----------------------------------------------------------------------*
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 #include <sys/utsname.h>
31
32 #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 this->id = strdup (id);
40 }
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 ++(*i)->referenced;
55 (*i)->ref_next ();
56 return *i;
57 }
58 }
59
60 T *obj = new T (id);
61
62 if (obj && obj->ref_init ())
63 {
64 obj->referenced = 1;
65 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 void refcache<T>::clear ()
90 {
91 while (this->size ())
92 put (*this->begin ());
93 }
94
95 /////////////////////////////////////////////////////////////////////////////
96
97 #ifdef USE_XIM
98
99 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 xim->xim = 0;
110
111 display->xims.erase (find (display->xims.begin (), display->xims.end (), xim));
112 display->im_change_cb ();
113 }
114
115 bool
116 rxvt_xim::ref_init ()
117 {
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
140 #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 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 {
233 #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 #endif
244 display = 0;
245
246 if (!display)
247 display = XOpenDisplay (id);
248
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 XrmSetDatabase (display, get_resources ());
259
260 #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 #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 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 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 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 rxvt_display::~rxvt_display ()
327 {
328 if (!display)
329 return;
330
331 #ifdef POINTER_BLANK
332 XFreeCursor (display, blank_cursor);
333 #endif
334 x_ev.stop ();
335 #ifdef USE_XIM
336 xims.clear ();
337 #endif
338 XCloseDisplay (display);
339 }
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
348 void rxvt_display::im_change_check ()
349 {
350 // try to only call im_change_cb when a new input method
351 // 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 #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 #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 #ifdef USE_XIM
397 }
398 #endif
399 }
400 while (XEventsQueued (display, QueuedAlready));
401
402 XFlush (display);
403 }
404
405 void rxvt_display::flush ()
406 {
407 if (XEventsQueued (display, QueuedAlready))
408 x_cb (x_ev, EVENT_READ);
409
410 XFlush (display);
411 }
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 #if XLIB_IS_RACEFREE
468 xims.put (xim);
469 #endif
470 }
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 #if XFT
518 return XftColorAllocName (display->display, display->visual, display->cmap,
519 name, &c);
520 #else
521 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 #endif
528 }
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 percent = 100 - percent;
579
580 unsigned short cr, cg, cb;
581 rxvt_color faded;
582
583 get (display, cr, cg, cb);
584
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 #define LERP(a,b,p) (a * p + b * (100 - p)) / 100
596
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
616 return faded;
617 }
618