ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/rxvttoolkit.C
(Generate patch)

Comparing rxvt-unicode/src/rxvttoolkit.C (file contents):
Revision 1.29 by root, Sun Jan 29 21:45:47 2006 UTC vs.
Revision 1.103 by root, Fri Sep 4 15:40:13 2009 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines