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.39 by root, Tue Jan 31 00:25:16 2006 UTC vs.
Revision 1.115 by sf-exg, Fri Feb 11 01:24:46 2011 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>
35#endif
36 33
37#if XFT 34#if XFT
38# include <X11/extensions/Xrender.h> 35# include <X11/extensions/Xrender.h>
39#endif 36#endif
40 37
41const char *const xa_names[] = 38static const char *const xa_names[] =
42{ 39{
43 "TEXT", 40 "TEXT",
44 "COMPOUND_TEXT", 41 "COMPOUND_TEXT",
45 "UTF8_STRING", 42 "UTF8_STRING",
46 "MULTIPLE", 43 "MULTIPLE",
62#if ENABLE_EWMH 59#if ENABLE_EWMH
63 "_NET_WM_PID", 60 "_NET_WM_PID",
64 "_NET_WM_NAME", 61 "_NET_WM_NAME",
65 "_NET_WM_ICON_NAME", 62 "_NET_WM_ICON_NAME",
66 "_NET_WM_PING", 63 "_NET_WM_PING",
64 "_NET_WM_ICON",
67#endif 65#endif
68#if USE_XIM 66#if USE_XIM
69 "WM_LOCALE_NAME", 67 "WM_LOCALE_NAME",
70 "XIM_SERVERS", 68 "XIM_SERVERS",
71#endif 69#endif
72#ifdef TRANSPARENT 70#ifdef ENABLE_TRANSPARENCY
73 "_XROOTPMAP_ID", 71 "_XROOTPMAP_ID",
74 "ESETROOT_PMAP_ID", 72 "ESETROOT_PMAP_ID",
75#endif 73#endif
76#if ENABLE_XEMBED 74#if ENABLE_XEMBED
77 "_XEMBED", 75 "_XEMBED",
177bool 175bool
178rxvt_xim::ref_init () 176rxvt_xim::ref_init ()
179{ 177{
180 display = GET_R->display; //HACK: TODO 178 display = GET_R->display; //HACK: TODO
181 179
182 xim = XOpenIM (display->display, NULL, NULL, NULL); 180 xim = XOpenIM (display->dpy, 0, 0, 0);
183 181
184 if (!xim) 182 if (!xim)
185 return false; 183 return false;
186 184
187 XIMCallback ximcallback; 185 XIMCallback ximcallback;
188 ximcallback.client_data = (XPointer)this; 186 ximcallback.client_data = (XPointer)this;
189 ximcallback.callback = im_destroy_cb; 187 ximcallback.callback = im_destroy_cb;
190 188
191 XSetIMValues (xim, XNDestroyCallback, &ximcallback, NULL); 189 XSetIMValues (xim, XNDestroyCallback, &ximcallback, (char *)0);
192 190
193 return true; 191 return true;
194} 192}
195 193
196rxvt_xim::~rxvt_xim () 194rxvt_xim::~rxvt_xim ()
201 199
202#endif 200#endif
203 201
204///////////////////////////////////////////////////////////////////////////// 202/////////////////////////////////////////////////////////////////////////////
205 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 if (!scratch_area || w > scratch_w || h > scratch_h)
233 {
234 if (scratch_area)
235 {
236 XFreePixmap (dpy, scratch_area->drawable);
237 delete scratch_area;
238 }
239
240 Pixmap pm = XCreatePixmap (dpy, RootWindowOfScreen (ScreenOfDisplay (dpy, display->screen)),
241 scratch_w = w, scratch_h = h, depth);
242
243 scratch_area = new rxvt_drawable (this, pm);
244 }
245
246 return *scratch_area;
247}
248
249#endif
250
206void 251void
207rxvt_screen::set (rxvt_display *disp) 252rxvt_screen::set (rxvt_display *disp)
208{ 253{
209 display = disp; 254 display = disp;
210 xdisp = disp->display; 255 dpy = disp->dpy;
211 256
212 Screen *screen = ScreenOfDisplay (xdisp, disp->screen); 257 Screen *screen = ScreenOfDisplay (dpy, disp->screen);
213 258
214 depth = DefaultDepthOfScreen (screen); 259 depth = DefaultDepthOfScreen (screen);
215 visual = DefaultVisualOfScreen (screen); 260 visual = DefaultVisualOfScreen (screen);
216 cmap = DefaultColormapOfScreen (screen); 261 cmap = DefaultColormapOfScreen (screen);
217} 262}
218 263
219void 264void
220rxvt_screen::set (rxvt_display *disp, int bitdepth) 265rxvt_screen::select_visual (int bitdepth)
221{ 266{
222 set (disp);
223
224#if XFT 267#if XFT
225 XVisualInfo vinfo; 268 XVisualInfo vinfo;
226 269
227 if (XMatchVisualInfo (xdisp, display->screen, bitdepth, TrueColor, &vinfo)) 270 if (XMatchVisualInfo (dpy, display->screen, bitdepth, TrueColor, &vinfo))
228 { 271 {
229 depth = bitdepth; 272 depth = bitdepth;
230 visual = vinfo.visual; 273 visual = vinfo.visual;
231 cmap = XCreateColormap (xdisp, disp->root, visual, AllocNone); 274 cmap = XCreateColormap (dpy, display->root, visual, AllocNone);
232 } 275 }
233#endif 276#endif
234} 277}
235 278
236void 279void
237rxvt_screen::clear () 280rxvt_screen::clear ()
238{ 281{
282#if XFT
283 if (scratch_area)
284 {
285 XFreePixmap (dpy, scratch_area->drawable);
286 delete scratch_area;
287 }
288#endif
289
239 if (cmap != DefaultColormapOfScreen (ScreenOfDisplay (xdisp, display->screen))) 290 if (cmap != DefaultColormapOfScreen (ScreenOfDisplay (dpy, display->screen)))
240 XFreeColormap (xdisp, cmap); 291 XFreeColormap (dpy, cmap);
241} 292}
242 293
243///////////////////////////////////////////////////////////////////////////// 294/////////////////////////////////////////////////////////////////////////////
244 295
245rxvt_display::rxvt_display (const char *id) 296rxvt_display::rxvt_display (const char *id)
246: refcounted (id) 297: refcounted (id)
247, x_ev (this, &rxvt_display::x_cb)
248, selection_owner (0) 298, selection_owner (0)
299, clipboard_owner (0)
249{ 300{
301 x_ev .set<rxvt_display, &rxvt_display::x_cb > (this);
302 flush_ev.set<rxvt_display, &rxvt_display::flush_cb> (this);
250} 303}
251 304
252XrmDatabase 305XrmDatabase
253rxvt_display::get_resources () 306rxvt_display::get_resources (bool refresh)
254{ 307{
255 char *homedir = (char *)getenv ("HOME"); 308 char *homedir = getenv ("HOME");
256 char fname[1024]; 309 char fname[1024];
257 310
258 /* 311 /*
259 * get resources using the X library function 312 * get resources using the X library function
260 */ 313 */
261 char *displayResource, *xe; 314 char *displayResource, *xe;
262 XrmDatabase database, rdb1; 315 XrmDatabase rdb1, database = 0;
263 316
264 database = NULL; 317#if !XLIB_ILLEGAL_ACCESS
318 /* work around a bug in XrmSetDatabase where it frees the db, see ref_next */
319 database = XrmGetStringDatabase ("");
320#endif
265 321
266 // for ordering, see for example http://www.faqs.org/faqs/Xt-FAQ/ Subject: 20 322 // for ordering, see for example http://www.faqs.org/faqs/Xt-FAQ/ Subject: 20
323 // as opposed to "standard practise", we always read in ~/.Xdefaults
267 324
268 // 6. System wide per application default file. 325 // 6. System wide per application default file.
269 326
270 /* Add in $XAPPLRESDIR/Rxvt only; not bothering with XUSERFILESEARCHPATH */ 327 /* Add in $XAPPLRESDIR/Rxvt only; not bothering with XUSERFILESEARCHPATH */
271 if ((xe = (char *)getenv ("XAPPLRESDIR"))) 328 if ((xe = getenv ("XAPPLRESDIR")))
272 { 329 {
273 snprintf (fname, sizeof (fname), "%s/%s", xe, RESCLASS); 330 snprintf (fname, sizeof (fname), "%s/%s", xe, RESCLASS);
274 331
275 if ((rdb1 = XrmGetFileDatabase (fname))) 332 if ((rdb1 = XrmGetFileDatabase (fname)))
276 XrmMergeDatabases (rdb1, &database); 333 XrmMergeDatabases (rdb1, &database);
278 335
279 // 5. User's per application default file. 336 // 5. User's per application default file.
280 // none 337 // none
281 338
282 // 4. User's defaults file. 339 // 4. User's defaults file.
340 if (homedir)
341 {
342 snprintf (fname, sizeof (fname), "%s/.Xdefaults", homedir);
343
344 if ((rdb1 = XrmGetFileDatabase (fname)))
345 XrmMergeDatabases (rdb1, &database);
346 }
347
283 /* Get any Xserver defaults */ 348 /* Get any Xserver defaults */
349 if (refresh)
350 {
351 // fucking xlib keeps a copy of the rm string
352 Atom actual_type;
353 int actual_format;
354 unsigned long nitems, nremaining;
355 char *val = 0;
356
357#if XLIB_ILLEGAL_ACCESS
358 if (dpy->xdefaults)
359 XFree (dpy->xdefaults);
360#endif
361
362 if (XGetWindowProperty (dpy, RootWindow (dpy, 0), XA_RESOURCE_MANAGER,
363 0L, 100000000L, False,
364 XA_STRING, &actual_type, &actual_format,
365 &nitems, &nremaining,
366 (unsigned char **)&val) == Success
367 && actual_type == XA_STRING
368 && actual_format == 8)
369 displayResource = val;
370 else
371 {
372 displayResource = 0;
373
374 if (val)
375 XFree (val);
376 }
377
378#if XLIB_ILLEGAL_ACCESS
379 dpy->xdefaults = displayResource;
380#endif
381 }
382 else
284 displayResource = XResourceManagerString (display); 383 displayResource = XResourceManagerString (dpy);
285 384
286 if (displayResource != NULL) 385 if (displayResource)
287 { 386 {
288 if ((rdb1 = XrmGetStringDatabase (displayResource))) 387 if ((rdb1 = XrmGetStringDatabase (displayResource)))
289 XrmMergeDatabases (rdb1, &database); 388 XrmMergeDatabases (rdb1, &database);
290 } 389 }
291 else if (homedir)
292 {
293 snprintf (fname, sizeof (fname), "%s/.Xdefaults", homedir);
294 390
295 if ((rdb1 = XrmGetFileDatabase (fname))) 391#if !XLIB_ILLEGAL_ACCESS
296 XrmMergeDatabases (rdb1, &database); 392 if (refresh && displayResource)
297 } 393 XFree (displayResource);
394#endif
298 395
299 /* Get screen specific resources */ 396 /* Get screen specific resources */
300 displayResource = XScreenResourceString (ScreenOfDisplay (display, screen)); 397 displayResource = XScreenResourceString (ScreenOfDisplay (dpy, screen));
301 398
302 if (displayResource != NULL) 399 if (displayResource)
303 { 400 {
304 if ((rdb1 = XrmGetStringDatabase (displayResource))) 401 if ((rdb1 = XrmGetStringDatabase (displayResource)))
305 /* Merge with screen-independent resources */ 402 /* Merge with screen-independent resources */
306 XrmMergeDatabases (rdb1, &database); 403 XrmMergeDatabases (rdb1, &database);
307 404
308 XFree (displayResource); 405 XFree (displayResource);
309 } 406 }
310 407
311 // 3. User's per host defaults file 408 // 3. User's per host defaults file
312 /* Add in XENVIRONMENT file */ 409 /* Add in XENVIRONMENT file */
313 if ((xe = (char *)getenv ("XENVIRONMENT")) 410 if ((xe = getenv ("XENVIRONMENT"))
314 && (rdb1 = XrmGetFileDatabase (xe))) 411 && (rdb1 = XrmGetFileDatabase (xe)))
315 XrmMergeDatabases (rdb1, &database); 412 XrmMergeDatabases (rdb1, &database);
316 else if (homedir) 413 else if (homedir)
317 { 414 {
318 struct utsname un; 415 struct utsname un;
332bool rxvt_display::ref_init () 429bool rxvt_display::ref_init ()
333{ 430{
334#ifdef LOCAL_X_IS_UNIX 431#ifdef LOCAL_X_IS_UNIX
335 if (id[0] == ':') 432 if (id[0] == ':')
336 { 433 {
337 val = rxvt_malloc (5 + strlen (id) + 1); 434 if (!(val = rxvt_temp_buf<char> (5 + strlen (id) + 1)))
435 return false;
338 strcpy (val, "unix/"); 436 strcpy (val, "unix/");
339 strcat (val, id); 437 strcat (val, id);
340 display = XOpenDisplay (val); 438 dpy = XOpenDisplay (val);
341 free (val);
342 } 439 }
343 else 440 else
344#endif 441#endif
345 display = 0; 442 dpy = 0;
346 443
347 if (!display) 444 if (!dpy)
348 display = XOpenDisplay (id); 445 dpy = XOpenDisplay (id);
349 446
350 if (!display) 447 if (!dpy)
351 return false; 448 return false;
352 449
353 screen = DefaultScreen (display); 450 screen = DefaultScreen (dpy);
354 root = DefaultRootWindow (display); 451 root = DefaultRootWindow (dpy);
355 452
356 assert (sizeof (xa_names) / sizeof (char *) == NUM_XA); 453 assert (ARRAY_LENGTH(xa_names) == NUM_XA);
357 XInternAtoms (display, (char **)xa_names, NUM_XA, False, xa); 454 XInternAtoms (dpy, (char **)xa_names, NUM_XA, False, xa);
358 455
359 XrmSetDatabase (display, get_resources ()); 456 XrmSetDatabase (dpy, get_resources (false));
360 457
361#ifdef POINTER_BLANK 458#ifdef POINTER_BLANK
362 XColor blackcolour; 459 XColor blackcolour;
363 blackcolour.red = 0; 460 blackcolour.red = 0;
364 blackcolour.green = 0; 461 blackcolour.green = 0;
365 blackcolour.blue = 0; 462 blackcolour.blue = 0;
366 Font f = XLoadFont (display, "fixed"); 463 Font f = XLoadFont (dpy, "fixed");
367 blank_cursor = XCreateGlyphCursor (display, f, f, ' ', ' ', 464 blank_cursor = XCreateGlyphCursor (dpy, f, f, ' ', ' ',
368 &blackcolour, &blackcolour); 465 &blackcolour, &blackcolour);
369 XUnloadFont (display, f); 466 XUnloadFont (dpy, f);
370#endif 467#endif
371 468
372 int fd = XConnectionNumber (display); 469 int fd = XConnectionNumber (dpy);
373 470
374#ifndef NO_SLOW_LINK_SUPPORT
375 // try to detect wether we have a local connection. 471 // try to detect whether we have a local connection.
376 // assume unix domains socket == local, everything else not 472 // assume unix domain socket == local, everything else not
377 // TODO: might want to check for inet/127.0.0.1 473 // TODO: might want to check for inet/127.0.0.1
378 is_local = 0; 474 is_local = 0;
379 sockaddr_un sa; 475 sockaddr_un sa;
380 socklen_t sl = sizeof (sa); 476 socklen_t sl = sizeof (sa);
381 477
382 if (!getsockname (fd, (sockaddr *)&sa, &sl)) 478 if (!getsockname (fd, (sockaddr *)&sa, &sl))
383 is_local = sa.sun_family == AF_LOCAL; 479 is_local = sa.sun_family == AF_UNIX;
384#endif
385 480
481 flush_ev.start ();
386 x_ev.start (fd, EVENT_READ); 482 x_ev.start (fd, ev::READ);
387 fcntl (fd, F_SETFD, FD_CLOEXEC); 483 fcntl (fd, F_SETFD, FD_CLOEXEC);
388 484
389 XSelectInput (display, root, PropertyChangeMask); 485 XSelectInput (dpy, root, PropertyChangeMask);
390 486
391 flush (); 487 flush ();
392 488
393 return true; 489 return true;
394} 490}
395 491
396void 492void
397rxvt_display::ref_next () 493rxvt_display::ref_next ()
398{ 494{
399 // TODO: somehow check wether the database files/resources changed 495 // TODO: somehow check whether the database files/resources changed
400 // before re-loading/parsing 496 // before affording re-loading/parsing
401 XrmDestroyDatabase (XrmGetDatabase (display)); 497 XrmDestroyDatabase (XrmGetDatabase (dpy));
498#if XLIB_ILLEGAL_ACCESS
499 /* work around a bug in XrmSetDatabase where it frees the db */
500 dpy->db = 0;
501#endif
402 XrmSetDatabase (display, get_resources ()); 502 XrmSetDatabase (dpy, get_resources (true));
403} 503}
404 504
405rxvt_display::~rxvt_display () 505rxvt_display::~rxvt_display ()
406{ 506{
407 if (!display) 507 if (!dpy)
408 return; 508 return;
409 509
410#ifdef POINTER_BLANK 510#ifdef POINTER_BLANK
411 XFreeCursor (display, blank_cursor); 511 XFreeCursor (dpy, blank_cursor);
412#endif 512#endif
413 x_ev.stop (); 513 x_ev.stop ();
514 flush_ev.stop ();
414#ifdef USE_XIM 515#ifdef USE_XIM
415 xims.clear (); 516 xims.clear ();
416#endif 517#endif
518 XrmDestroyDatabase (XrmGetDatabase (dpy));
417 XCloseDisplay (display); 519 XCloseDisplay (dpy);
418} 520}
419 521
420#ifdef USE_XIM 522#ifdef USE_XIM
421void rxvt_display::im_change_cb () 523void rxvt_display::im_change_cb ()
422{ 524{
430 // registers, as xlib crashes due to a race otherwise. 532 // registers, as xlib crashes due to a race otherwise.
431 Atom actual_type, *atoms; 533 Atom actual_type, *atoms;
432 int actual_format; 534 int actual_format;
433 unsigned long nitems, bytes_after; 535 unsigned long nitems, bytes_after;
434 536
435 if (XGetWindowProperty (display, root, xa[XA_XIM_SERVERS], 0L, 1000000L, 537 if (XGetWindowProperty (dpy, root, xa[XA_XIM_SERVERS], 0L, 1000000L,
436 False, XA_ATOM, &actual_type, &actual_format, 538 False, XA_ATOM, &actual_type, &actual_format,
437 &nitems, &bytes_after, (unsigned char **)&atoms) 539 &nitems, &bytes_after, (unsigned char **)&atoms)
438 != Success ) 540 != Success)
439 return; 541 return;
440 542
441 if (actual_type == XA_ATOM && actual_format == 32) 543 if (actual_type == XA_ATOM && actual_format == 32)
442 for (int i = 0; i < nitems; i++) 544 for (int i = 0; i < nitems; i++)
443 if (XGetSelectionOwner (display, atoms[i])) 545 if (XGetSelectionOwner (dpy, atoms[i]))
444 { 546 {
445 im_change_cb (); 547 im_change_cb ();
446 break; 548 break;
447 } 549 }
448 550
449 XFree (atoms); 551 XFree (atoms);
450} 552}
451#endif 553#endif
452 554
453void rxvt_display::x_cb (io_watcher &w, short revents) 555void rxvt_display::x_cb (ev::io &w, int revents)
454{ 556{
557 flush_ev.start ();
558}
559
560void rxvt_display::flush_cb (ev::prepare &w, int revents)
561{
562 while (XEventsQueued (dpy, QueuedAfterFlush))
455 do 563 do
456 { 564 {
457 XEvent xev; 565 XEvent xev;
458 XNextEvent (display, &xev); 566 XNextEvent (dpy, &xev);
459 567
460#ifdef USE_XIM 568#ifdef USE_XIM
461 if (!XFilterEvent (&xev, None)) 569 if (!XFilterEvent (&xev, None))
462 { 570 {
463 if (xev.type == PropertyNotify 571 if (xev.type == PropertyNotify
464 && xev.xany.window == root 572 && xev.xany.window == root
465 && xev.xproperty.atom == xa[XA_XIM_SERVERS]) 573 && xev.xproperty.atom == xa[XA_XIM_SERVERS])
466 im_change_check (); 574 im_change_check ();
467#endif 575#endif
576 if (xev.type == MappingNotify)
577 XRefreshKeyboardMapping (&xev.xmapping);
578
468 for (int i = xw.size (); i--; ) 579 for (int i = xw.size (); i--; )
469 { 580 {
470 if (!xw[i]) 581 if (!xw[i])
471 xw.erase_unordered (i); 582 xw.erase_unordered (i);
472 else if (xw[i]->window == xev.xany.window) 583 else if (xw[i]->window == xev.xany.window)
473 xw[i]->call (xev); 584 xw[i]->call (xev);
474 } 585 }
475#ifdef USE_XIM 586#ifdef USE_XIM
476 } 587 }
477#endif 588#endif
478 } 589 }
479 while (XEventsQueued (display, QueuedAlready)); 590 while (XEventsQueued (dpy, QueuedAlready));
480 591
481 XFlush (display); 592 w.stop ();
482}
483
484void rxvt_display::flush ()
485{
486 if (XEventsQueued (display, QueuedAlready))
487 x_cb (x_ev, EVENT_READ);
488
489 XFlush (display);
490} 593}
491 594
492void rxvt_display::reg (xevent_watcher *w) 595void rxvt_display::reg (xevent_watcher *w)
493{ 596{
597 if (!w->active)
598 {
494 xw.push_back (w); 599 xw.push_back (w);
495 w->active = xw.size (); 600 w->active = xw.size ();
601 }
496} 602}
497 603
498void rxvt_display::unreg (xevent_watcher *w) 604void rxvt_display::unreg (xevent_watcher *w)
499{ 605{
500 if (w->active) 606 if (w->active)
607 {
501 xw[w->active - 1] = 0; 608 xw[w->active - 1] = 0;
609 w->active = 0;
610 }
502} 611}
503 612
504void rxvt_display::set_selection_owner (rxvt_term *owner) 613void rxvt_display::set_selection_owner (rxvt_term *owner, bool clipboard)
505{ 614{
615 rxvt_term * &cur_owner = !clipboard ? selection_owner : clipboard_owner;
616
506 if (selection_owner && selection_owner != owner) 617 if (cur_owner && cur_owner != owner)
507 selection_owner->selection_clear (); 618 {
619 rxvt_term *term = cur_owner;
620 term->selection_clear (clipboard);
621 term->flush ();
622 }
508 623
509 selection_owner = owner; 624 cur_owner = owner;
510} 625}
511 626
512#ifdef USE_XIM 627#ifdef USE_XIM
628
513void rxvt_display::reg (im_watcher *w) 629void rxvt_display::reg (im_watcher *w)
514{ 630{
515 imw.push_back (w); 631 imw.push_back (w);
516} 632}
517 633
526 int l, m; 642 int l, m;
527 643
528 l = strlen (locale); 644 l = strlen (locale);
529 m = strlen (modifiers); 645 m = strlen (modifiers);
530 646
531 if (!(id = (char *)malloc (l + m + 2))) 647 if (!(id = rxvt_temp_buf<char> (l + m + 2)))
532 return 0; 648 return 0;
533 649
534 memcpy (id, locale, l); id[l] = '\n'; 650 memcpy (id, locale, l); id[l] = '\n';
535 memcpy (id + l + 1, modifiers, m); id[l + m + 1] = 0; 651 memcpy (id + l + 1, modifiers, m); id[l + m + 1] = 0;
536 652
537 rxvt_xim *xim = xims.get (id); 653 rxvt_xim *xim = xims.get (id);
538 654
539 free (id);
540
541 return xim; 655 return xim;
542} 656}
543 657
544void rxvt_display::put_xim (rxvt_xim *xim) 658void rxvt_display::put_xim (rxvt_xim *xim)
545{ 659{
546#if XLIB_IS_RACEFREE 660# if XLIB_IS_RACEFREE
547 xims.put (xim); 661 xims.put (xim);
548#endif 662# endif
549} 663}
664
550#endif 665#endif
551 666
552Atom rxvt_display::atom (const char *name) 667Atom rxvt_display::atom (const char *name)
553{ 668{
554 return XInternAtom (display, name, False); 669 return XInternAtom (dpy, name, False);
555} 670}
556 671
557///////////////////////////////////////////////////////////////////////////// 672/////////////////////////////////////////////////////////////////////////////
558 673
559template class refcache<rxvt_display>; 674template class refcache<rxvt_display>;
560refcache<rxvt_display> displays; 675refcache<rxvt_display> displays;
561 676
562///////////////////////////////////////////////////////////////////////////// 677/////////////////////////////////////////////////////////////////////////////
563 678//
679
680static unsigned int
681insert_component (unsigned int value, unsigned int mask, unsigned int shift)
682{
683 return (value * (mask + 1) >> 16) << shift;
684}
685
564bool 686bool
565rxvt_color::alloc (rxvt_screen *screen, rxvt_rgba rgba) 687rxvt_color::alloc (rxvt_screen *screen, const rgba &color)
566{ 688{
689 //TODO: only supports 24 bit
690 int alpha = color.a >= 0xff00 ? 0xffff : color.a;
691
567#if XFT 692#if XFT
568 XRenderPictFormat *format; 693 XRenderPictFormat *format;
569 694
570 // FUCKING Xft gets it wrong, of course, so work around it 695 // FUCKING Xft gets it wrong, of course, so work around it.
571 // transparency users should eat shit and die, and then 696 // Transparency users should eat shit and die, and then
572 // XRenderQueryPictIndexValues themselves plenty. 697 // XRenderQueryPictIndexValues themselves plenty.
573 if ((screen->visual->c_class == TrueColor || screen->visual->c_class == DirectColor) 698 if ((screen->visual->c_class == TrueColor)
574 && (format = XRenderFindVisualFormat (screen->xdisp, screen->visual))) 699 && (format = XRenderFindVisualFormat (screen->dpy, screen->visual)))
575 { 700 {
576 // the fun lies in doing everything manually... 701 // the fun lies in doing everything manually...
577 c.color.red = rgba.r; 702 c.color.red = color.r;
578 c.color.green = rgba.g; 703 c.color.green = color.g;
579 c.color.blue = rgba.b; 704 c.color.blue = color.b;
580 c.color.alpha = rgba.a; 705 c.color.alpha = alpha;
581 706
582 c.pixel = ((rgba.r * format->direct.redMask / rxvt_rgba::MAX_CC) << format->direct.red ) 707 c.pixel = insert_component (color.r, format->direct.redMask , format->direct.red )
583 | ((rgba.g * format->direct.greenMask / rxvt_rgba::MAX_CC) << format->direct.green) 708 | insert_component (color.g, format->direct.greenMask, format->direct.green)
584 | ((rgba.b * format->direct.blueMask / rxvt_rgba::MAX_CC) << format->direct.blue ) 709 | insert_component (color.b, format->direct.blueMask , format->direct.blue )
585 | ((rgba.a * format->direct.alphaMask / rxvt_rgba::MAX_CC) << format->direct.alpha); 710 | insert_component (alpha , format->direct.alphaMask, format->direct.alpha);
586 711
587 return true; 712 return true;
588 } 713 }
589 else 714 else
590 { 715 {
591 XRenderColor d; 716 XRenderColor d;
592 717
593 d.red = rgba.r; 718 d.red = color.r;
594 d.green = rgba.g; 719 d.green = color.g;
595 d.blue = rgba.b; 720 d.blue = color.b;
596 d.alpha = rgba.a; 721 d.alpha = alpha;
597 722
598 return XftColorAllocValue (screen->xdisp, screen->visual, screen->cmap, &d, &c); 723 return XftColorAllocValue (screen->dpy, screen->visual, screen->cmap, &d, &c);
599 } 724 }
600#else 725#else
601 if (screen->visual->c_class == TrueColor || screen->visual->c_class == DirectColor) 726 c.red = color.r;
727 c.green = color.g;
728 c.blue = color.b;
729
730 if (screen->visual->c_class == TrueColor)
602 { 731 {
603 p = (rgba.r * (screen->visual->red_mask >> ctz (screen->visual->red_mask )) 732 c.pixel = (color.r >> (16 - rxvt_popcount (screen->visual->red_mask )) << rxvt_ctz (screen->visual->red_mask ))
604 / rxvt_rgba::MAX_CC) << ctz (screen->visual->red_mask ) 733 | (color.g >> (16 - rxvt_popcount (screen->visual->green_mask)) << rxvt_ctz (screen->visual->green_mask))
605 | (rgba.g * (screen->visual->green_mask >> ctz (screen->visual->green_mask)) 734 | (color.b >> (16 - rxvt_popcount (screen->visual->blue_mask )) << rxvt_ctz (screen->visual->blue_mask ));
606 / rxvt_rgba::MAX_CC) << ctz (screen->visual->green_mask)
607 | (rgba.b * (screen->visual->blue_mask >> ctz (screen->visual->blue_mask ))
608 / rxvt_rgba::MAX_CC) << ctz (screen->visual->blue_mask );
609 735
610 return true; 736 return true;
611 } 737 }
738 else if (XAllocColor (screen->dpy, screen->cmap, &c))
739 return true;
612 else 740 else
613 { 741 c.pixel = (color.r + color.g + color.b) > 128*3
614 XColor xc;
615
616 xc.red = rgba.r;
617 xc.green = rgba.g;
618 xc.blue = rgba.b;
619
620 if (XAllocColor (screen->xdisp, screen->cmap, &xc))
621 {
622 p = xc.pixel;
623 return true;
624 }
625 else
626 p = (rgba.r + rgba.g + rgba.b) > 128*3
627 ? WhitePixelOfScreen (DefaultScreenOfDisplay (screen->xdisp)) 742 ? WhitePixelOfScreen (DefaultScreenOfDisplay (screen->dpy))
628 : BlackPixelOfScreen (DefaultScreenOfDisplay (screen->xdisp)); 743 : BlackPixelOfScreen (DefaultScreenOfDisplay (screen->dpy));
629 }
630#endif 744#endif
631 745
632 return false; 746 return false;
633} 747}
634 748
635bool 749bool
636rxvt_color::set (rxvt_screen *screen, const char *name) 750rxvt_color::set (rxvt_screen *screen, const char *name)
637{ 751{
638 rxvt_rgba c; 752 rgba c;
639 char eos; 753 char eos;
640 int skip; 754 int skip;
641 755
756 c.a = rgba::MAX_CC;
757
758 // parse the nonstandard "[alphapercent]" prefix
642 if (1 <= sscanf (name, "[%hx]%n", &c.a, &skip)) 759 if (1 <= sscanf (name, "[%hd]%n", &c.a, &skip))
643 { 760 {
644 switch (skip) 761 c.a = lerp<int, int, int> (0, rgba::MAX_CC, c.a);
645 {
646 case 2 + 1: c.a *= rxvt_rgba::MAX_CC / 0x000f; break;
647 case 2 + 2: c.a *= rxvt_rgba::MAX_CC / 0x00ff; break;
648 case 2 + 3: c.a *= rxvt_rgba::MAX_CC / 0x0fff; break;
649 case 2 + 4: c.a *= rxvt_rgba::MAX_CC / 0xffff; break;
650 }
651
652 name += skip; 762 name += skip;
653 } 763 }
654 else
655 c.a = rxvt_rgba::MAX_CC;
656 764
657 // parse the non-standard rgba format 765 // parse the non-standard "rgba:rrrr/gggg/bbbb/aaaa" format
658 if (strlen (name) != 4+5*4 || 4 != sscanf (name, "rgba:%hx/%hx/%hx/%hx%c", &c.r, &c.g, &c.b, &c.a, &eos)) 766 if (strlen (name) != 4+5*4 || 4 != sscanf (name, "rgba:%4hx/%4hx/%4hx/%4hx%c", &c.r, &c.g, &c.b, &c.a, &eos))
659 { 767 {
660 XColor xc, xc_exact; 768 XColor xc;
661 769
662 if (XParseColor (screen->xdisp, screen->cmap, name, &xc)) 770 if (XParseColor (screen->dpy, screen->cmap, name, &xc))
663 { 771 {
664 c.r = xc.red; 772 c.r = xc.red;
665 c.g = xc.green; 773 c.g = xc.green;
666 c.b = xc.blue; 774 c.b = xc.blue;
667 } 775 }
677 785
678 return set (screen, c); 786 return set (screen, c);
679} 787}
680 788
681bool 789bool
682rxvt_color::set (rxvt_screen *screen, rxvt_rgba rgba) 790rxvt_color::set (rxvt_screen *screen, const rgba &color)
683{ 791{
684 bool got = alloc (screen, rgba); 792 bool got = alloc (screen, color);
685 793
686#if !ENABLE_MINIMAL 794#if !ENABLE_MINIMAL
687 int cmap_size = screen->visual->map_entries; 795 int cmap_size = screen->visual->map_entries;
688 796
689 if (!got 797 if (!got
692 { 800 {
693 XColor *colors = new XColor [screen->visual->map_entries]; 801 XColor *colors = new XColor [screen->visual->map_entries];
694 802
695 for (int i = 0; i < cmap_size; i++) 803 for (int i = 0; i < cmap_size; i++)
696 colors [i].pixel = i; 804 colors [i].pixel = i;
697 805
806 // many kilobytes transfer per colour, but pseudocolor isn't worth
807 // many extra optimisations.
698 XQueryColors (screen->xdisp, screen->cmap, colors, cmap_size); 808 XQueryColors (screen->dpy, screen->cmap, colors, cmap_size);
699 809
700 int diff = 0x7fffffffUL; 810 int diff = 0x7fffffffUL;
701 XColor *best = colors; 811 XColor *best = colors;
702 812
703 for (int i = 0; i < cmap_size; i++) 813 for (int i = 0; i < cmap_size; i++)
704 { 814 {
705 int d = (squared_diff<int> (rgba.r >> 2, colors [i].red >> 2)) 815 int d = (squared_diff<int> (color.r >> 2, colors [i].red >> 2))
706 + (squared_diff<int> (rgba.g >> 2, colors [i].green >> 2)) 816 + (squared_diff<int> (color.g >> 2, colors [i].green >> 2))
707 + (squared_diff<int> (rgba.b >> 2, colors [i].blue >> 2)); 817 + (squared_diff<int> (color.b >> 2, colors [i].blue >> 2));
708 818
709 if (d < diff) 819 if (d < diff)
710 { 820 {
711 diff = d; 821 diff = d;
712 best = colors + i; 822 best = colors + i;
713 } 823 }
714 } 824 }
715 825
716 //rxvt_warn ("could not allocate %04x %04x %04x, getting %04x %04x %04x instead (%d)\n", 826 //rxvt_warn ("could not allocate %04x %04x %04x, getting %04x %04x %04x instead (%d)\n",
717 // rgba.r, rgba.g, rgba.b, best->red, best->green, best->blue, diff); 827 // color.r, color.g, color.b, best->red, best->green, best->blue, diff);
718 828
719 got = alloc (screen, rxvt_rgba (best->red, best->green, best->blue)); 829 got = alloc (screen, rgba (best->red, best->green, best->blue));
720 830
721 delete colors; 831 delete [] colors;
722 } 832 }
723#endif 833#endif
724 834
725 return got; 835 return got;
726} 836}
727 837
728void 838void
729rxvt_color::get (rxvt_screen *screen, rxvt_rgba &rgba) 839rxvt_color::get (rgba &color)
730{ 840{
731#if XFT 841#if XFT
732 rgba.r = c.color.red; 842 color.r = c.color.red;
733 rgba.g = c.color.green; 843 color.g = c.color.green;
734 rgba.b = c.color.blue; 844 color.b = c.color.blue;
735 rgba.a = c.color.alpha; 845 color.a = c.color.alpha;
736#else 846#else
737 XColor c;
738
739 c.pixel = p;
740 XQueryColor (screen->xdisp, screen->cmap, &c);
741
742 rgba.r = c.red; 847 color.r = c.red;
743 rgba.g = c.green; 848 color.g = c.green;
744 rgba.b = c.blue; 849 color.b = c.blue;
745 rgba.a = rxvt_rgba::MAX_CC; 850 color.a = rgba::MAX_CC;
746#endif 851#endif
747} 852}
748 853
749void 854void
855rxvt_color::get (XColor &color)
856{
857 rgba c;
858 get (c);
859
860 color.red = c.r;
861 color.green = c.g;
862 color.blue = c.b;
863 color.pixel = (Pixel)*this;
864}
865
866void
750rxvt_color::free (rxvt_screen *screen) 867rxvt_color::free (rxvt_screen *screen)
751{ 868{
869 if (screen->visual->c_class == TrueColor)
870 return; // nothing to do
871
752#if XFT 872#if XFT
753 XftColorFree (screen->xdisp, screen->visual, screen->cmap, &c); 873 XftColorFree (screen->dpy, screen->visual, screen->cmap, &c);
754#else 874#else
755 XFreeColors (screen->xdisp, screen->cmap, &p, 1, AllPlanes); 875 XFreeColors (screen->dpy, screen->cmap, &c.pixel, 1, AllPlanes);
756#endif 876#endif
757} 877}
758 878
759rxvt_color 879void
760rxvt_color::fade (rxvt_screen *screen, int percent)
761{
762 rxvt_color faded;
763
764 rxvt_rgba c;
765 get (screen, c);
766
767 c.r = lerp (0, c.r, percent);
768 c.g = lerp (0, c.g, percent);
769 c.b = lerp (0, c.b, percent);
770
771 faded.set (screen, c);
772
773 return faded;
774}
775
776rxvt_color
777rxvt_color::fade (rxvt_screen *screen, int percent, rxvt_color &fadeto) 880rxvt_color::fade (rxvt_screen *screen, int percent, rxvt_color &result, const rgba &to)
778{ 881{
779 rxvt_rgba c, fc; 882 rgba c;
780 rxvt_color faded; 883 get (c);
781
782 get (screen, c);
783 fadeto.get (screen, fc);
784 884
785 faded.set ( 885 result.set (
786 screen, 886 screen,
787 rxvt_rgba ( 887 rgba (
788 lerp (fc.r, c.r, percent), 888 lerp (c.r, to.r, percent),
789 lerp (fc.g, c.g, percent), 889 lerp (c.g, to.g, percent),
790 lerp (fc.b, c.b, percent), 890 lerp (c.b, to.b, percent),
791 lerp (fc.a, c.a, percent) 891 lerp (c.a, to.a, percent)
792 ) 892 )
793 ); 893 );
894}
794 895
896rxvt_selection::rxvt_selection (rxvt_display *disp, int selnum, Time tm, Window win, Atom prop, sel_cb cb, void *ptr)
897: display (disp), request_time (tm), request_win (win), request_prop (prop), request_cb (cb), user_data (ptr)
898{
899 assert (selnum >= Sel_Primary && selnum <= Sel_Clipboard);
900
901 timer_ev.set<rxvt_selection, &rxvt_selection::timer_cb> (this);
902 timer_ev.repeat = 10.;
903 x_ev.set<rxvt_selection, &rxvt_selection::x_cb> (this);
904
905 incr_buf = 0;
906 incr_buf_size = incr_buf_fill = 0;
907 selection_wait = Sel_normal;
908
909#if X_HAVE_UTF8_STRING
910 selection_type = Sel_UTF8String;
911 if (request (display->xa[XA_UTF8_STRING], selnum))
912 return;
913#else
914 selection_type = Sel_CompoundText;
915 if (request (display->xa[XA_COMPOUND_TEXT], selnum))
916 return;
917#endif
918
919 // fallback to CUT_BUFFER0 if the requested property has no owner
920 handle_selection (display->root, XA_CUT_BUFFER0, false);
921}
922
923rxvt_selection::~rxvt_selection ()
924{
925 stop ();
926}
927
928void
929rxvt_selection::stop ()
930{
931 free (incr_buf);
932 incr_buf = 0;
933 timer_ev.stop ();
934 x_ev.stop (display);
935}
936
937bool
938rxvt_selection::request (Atom target, int selnum)
939{
940 Atom sel;
941
942 selection_type |= selnum;
943
944 if (selnum == Sel_Primary)
945 sel = XA_PRIMARY;
946 else if (selnum == Sel_Secondary)
947 sel = XA_SECONDARY;
948 else
949 sel = display->xa[XA_CLIPBOARD];
950
951 if (XGetSelectionOwner (display->dpy, sel) != None)
952 {
953 XConvertSelection (display->dpy, sel, target, request_prop,
954 request_win, request_time);
955 x_ev.start (display, request_win);
956 timer_ev.again ();
957 return true;
958 }
959
795 return faded; 960 return false;
796} 961}
797 962
963void
964rxvt_selection::handle_selection (Window win, Atom prop, bool delete_prop)
965{
966 Display *dpy = display->dpy;
967 char *data = 0;
968 unsigned int data_len = 0;
969 unsigned long bytes_after;
970 XTextProperty ct;
971
972 // check for failed XConvertSelection
973 if (prop == None)
974 {
975 bool error = true;
976 int selnum = selection_type & Sel_whereMask;
977
978 if (selection_type & Sel_CompoundText)
979 {
980 selection_type = 0;
981 error = !request (XA_STRING, selnum);
982 }
983
984 if (selection_type & Sel_UTF8String)
985 {
986 selection_type = Sel_CompoundText;
987 error = !request (display->xa[XA_COMPOUND_TEXT], selnum);
988 }
989
990 if (error)
991 {
992 ct.value = 0;
993 goto bailout;
994 }
995
996 return;
997 }
998
999 // length == (2^31 - 1) / 4, as gdk
1000 if (XGetWindowProperty (dpy, win, prop,
1001 0, 0x1fffffff,
1002 delete_prop, AnyPropertyType,
1003 &ct.encoding, &ct.format,
1004 &ct.nitems, &bytes_after,
1005 &ct.value) != Success)
1006 {
1007 ct.value = 0;
1008 goto bailout;
1009 }
1010
1011 if (ct.encoding == None)
1012 goto bailout;
1013
1014 if (ct.value == 0)
1015 goto bailout;
1016
1017 if (ct.encoding == display->xa[XA_INCR])
1018 {
1019 // INCR selection, start handshake
1020 if (!delete_prop)
1021 XDeleteProperty (dpy, win, prop);
1022
1023 selection_wait = Sel_incr;
1024 timer_ev.again ();
1025
1026 goto bailout;
1027 }
1028
1029 if (ct.nitems == 0)
1030 {
1031 if (selection_wait == Sel_incr)
1032 {
1033 XFree (ct.value);
1034
1035 // finally complete, now paste the whole thing
1036 selection_wait = Sel_normal;
1037 ct.value = (unsigned char *)incr_buf;
1038 ct.nitems = incr_buf_fill;
1039 incr_buf = 0;
1040 timer_ev.stop ();
1041 }
1042 else
1043 {
1044 // avoid recursion
1045 if (win != display->root || prop != XA_CUT_BUFFER0)
1046 {
1047 XFree (ct.value);
1048
1049 // fallback to CUT_BUFFER0 if the requested property
1050 // has an owner but is empty
1051 handle_selection (display->root, XA_CUT_BUFFER0, False);
1052 return;
1053 }
1054
1055 goto bailout;
1056 }
1057 }
1058 else if (selection_wait == Sel_incr)
1059 {
1060 timer_ev.again ();
1061
1062 while (incr_buf_fill + ct.nitems > incr_buf_size)
1063 {
1064 incr_buf_size = incr_buf_size ? incr_buf_size * 2 : 128*1024;
1065 incr_buf = (char *)rxvt_realloc (incr_buf, incr_buf_size);
1066 }
1067
1068 memcpy (incr_buf + incr_buf_fill, ct.value, ct.nitems);
1069 incr_buf_fill += ct.nitems;
1070
1071 goto bailout;
1072 }
1073
1074 char **cl;
1075 int cr;
1076
1077 // we honour the first item only
1078
1079#if !ENABLE_MINIMAL
1080 // xlib is horribly broken with respect to UTF8_STRING, and nobody cares to fix it
1081 // so recode it manually
1082 if (ct.encoding == display->xa[XA_UTF8_STRING])
1083 {
1084 wchar_t *w = rxvt_utf8towcs ((const char *)ct.value, ct.nitems);
1085 data = rxvt_wcstombs (w);
1086 free (w);
1087 }
1088 else
1089#endif
1090 if (XmbTextPropertyToTextList (dpy, &ct, &cl, &cr) >= 0
1091 && cl)
1092 {
1093 data = strdup (cl[0]);
1094 XFreeStringList (cl);
1095 }
1096 else
1097 {
1098 // paste raw
1099 data = strdup ((const char *)ct.value);
1100 }
1101
1102 data_len = strlen (data);
1103
1104bailout:
1105 XFree (ct.value);
1106
1107 if (selection_wait == Sel_normal)
1108 {
1109 stop ();
1110 request_cb (data, data_len, this, user_data);
1111 free (data);
1112 }
1113}
1114
1115void
1116rxvt_selection::timer_cb (ev::timer &w, int revents)
1117{
1118 if (selection_wait == Sel_incr)
1119 rxvt_warn ("data loss: timeout on INCR selection paste, ignoring.\n");
1120
1121 stop ();
1122 request_cb (NULL, 0, this, user_data);
1123}
1124
1125void
1126rxvt_selection::x_cb (XEvent &xev)
1127{
1128 switch (xev.type)
1129 {
1130 case PropertyNotify:
1131 if (selection_wait == Sel_incr
1132 && xev.xproperty.atom == request_prop
1133 && xev.xproperty.state == PropertyNewValue)
1134 handle_selection (xev.xproperty.window, xev.xproperty.atom, true);
1135 break;
1136
1137 case SelectionNotify:
1138 if (selection_wait == Sel_normal
1139 && xev.xselection.time == request_time
1140 && xev.xselection.property == request_prop)
1141 {
1142 timer_ev.stop ();
1143 handle_selection (xev.xselection.requestor, xev.xselection.property, true);
1144 }
1145 break;
1146 }
1147}

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines