ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/main.C
Revision: 1.263
Committed: Thu Nov 22 15:07:10 2007 UTC (16 years, 6 months ago) by ayin
Content type: text/plain
Branch: MAIN
CVS Tags: rel-8_6
Changes since 1.262: +3 -0 lines
Log Message:
The removal of rxvt own parsing caused an inconsistency for keysym
directives between resources and command line options, because the
former are subjected to xlib parsing while the latter are not. Fix it
by generating resources from the command line options and merging them
later in the resource database.

File Contents

# Content
1 /*----------------------------------------------------------------------*
2 * File: main.C
3 *----------------------------------------------------------------------*
4 *
5 * All portions of code are copyright by their respective author/s.
6 * Copyright (c) 1992 John Bovey, University of Kent at Canterbury <jdb@ukc.ac.uk>
7 * - original version
8 * Copyright (c) 1994 Robert Nation <nation@rocket.sanders.lockheed.com>
9 * - extensive modifications
10 * Copyright (c) 1995 Garrett D'Amore <garrett@netcom.com>
11 * Copyright (c) 1997 mj olesen <olesen@me.QueensU.CA>
12 * - extensive modifications
13 * Copyright (c) 1997,1998 Oezguer Kesim <kesim@math.fu-berlin.de>
14 * Copyright (c) 1998-2001 Geoff Wing <gcw@pobox.com>
15 * - extensive modifications
16 * Copyright (c) 2003-2006 Marc Lehmann <pcg@goof.com>
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 *---------------------------------------------------------------------*/
32
33 #include "../config.h" /* NECESSARY */
34 #include "rxvt.h" /* NECESSARY */
35 #include "keyboard.h"
36 #include "rxvtperl.h"
37
38 #include <limits>
39
40 #include <csignal>
41 #include <cstring>
42
43 #ifdef HAVE_TERMIOS_H
44 # include <termios.h>
45 #endif
46
47 #ifdef HAVE_XSETLOCALE
48 # define X_LOCALE
49 # include <X11/Xlocale.h>
50 #else
51 # ifdef HAVE_SETLOCALE
52 # include <clocale>
53 # endif
54 #endif
55
56 vector<rxvt_term *> rxvt_term::termlist;
57
58 // used to tell global functions which terminal instance is "active"
59 rxvt_t rxvt_current_term;
60
61 static char curlocale[128], savelocale[128];
62
63 bool
64 rxvt_set_locale (const char *locale) NOTHROW
65 {
66 int size = strlen (locale) + 1;
67
68 if (size > sizeof (curlocale))
69 rxvt_fatal ("locale string too long, aborting.\n");
70
71 if (!locale || !memcmp (locale, curlocale, size))
72 return false;
73
74 memcpy (curlocale, locale, size);
75 setlocale (LC_CTYPE, curlocale);
76 return true;
77 }
78
79 void
80 rxvt_push_locale (const char *locale) NOTHROW
81 {
82 strcpy (savelocale, curlocale);
83 rxvt_set_locale (locale);
84 }
85
86 void
87 rxvt_pop_locale () NOTHROW
88 {
89 rxvt_set_locale (savelocale);
90 }
91
92 #if ENABLE_COMBINING
93 class rxvt_composite_vec rxvt_composite;
94
95 text_t rxvt_composite_vec::compose (unicode_t c1, unicode_t c2)
96 {
97 compose_char *cc;
98
99 // break compose chains, as stupid readline really likes to duplicate
100 // composing characters for some reason near the end of a line.
101 cc = (*this)[c1];
102 while (cc)
103 {
104 if (cc->c2 == c2) return c1;
105 cc = (*this)[cc->c1];
106 }
107
108 // check to see wether this combination already exists otherwise
109 for (cc = v.end (); cc-- > v.begin (); )
110 {
111 if (cc->c1 == c1 && cc->c2 == c2)
112 return COMPOSE_LO + (cc - v.begin ());
113 }
114
115 // allocate a new combination
116 if (v.size () == COMPOSE_HI - COMPOSE_LO + 1)
117 {
118 static int seen;
119
120 if (!seen++)
121 fprintf (stderr, "too many unrepresentable composite characters, try --enable-unicode3\n");
122
123 return REPLACEMENT_CHAR;
124 }
125
126 v.push_back (compose_char (c1, c2));
127
128 return v.size () - 1 + COMPOSE_LO;
129 }
130
131 int rxvt_composite_vec::expand (unicode_t c, wchar_t *r)
132 {
133 compose_char *cc = (*this)[c];
134
135 if (!cc)
136 {
137 if (r) *r = c;
138 return 1;
139 }
140
141 int len = expand (cc->c1, r);
142
143 if (r) r += len;
144
145 if (cc->c2 != NOCHAR)
146 {
147 len++;
148 if (r) *r++ = cc->c2;
149 }
150
151 return len;
152
153 }
154 #endif
155
156 rxvt_term::rxvt_term ()
157 :
158 #if ENABLE_TRANSPARENCY || ENABLE_PERL
159 rootwin_ev (this, &rxvt_term::rootwin_cb),
160 #endif
161 #if HAVE_BG_PIXMAP
162 update_background_ev(this, &rxvt_term::update_background_cb),
163 #endif
164 #ifdef HAVE_SCROLLBARS
165 scrollbar_ev (this, &rxvt_term::x_cb),
166 #endif
167 #ifdef CURSOR_BLINK
168 cursor_blink_ev (this, &rxvt_term::cursor_blink_cb),
169 #endif
170 #ifdef TEXT_BLINK
171 text_blink_ev (this, &rxvt_term::text_blink_cb),
172 #endif
173 #ifndef NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
174 cont_scroll_ev (this, &rxvt_term::cont_scroll_cb),
175 #endif
176 #ifdef SELECTION_SCROLLING
177 sel_scroll_ev (this, &rxvt_term::sel_scroll_cb),
178 #endif
179 #if defined(MOUSE_WHEEL) && defined(MOUSE_SLIP_WHEELING)
180 slip_wheel_ev (this, &rxvt_term::slip_wheel_cb),
181 #endif
182 #ifdef POINTER_BLANK
183 pointer_ev (this, &rxvt_term::pointer_cb),
184 #endif
185 #ifdef USE_XIM
186 im_ev (this, &rxvt_term::im_cb),
187 #endif
188 #ifndef NO_BELL
189 bell_ev (this, &rxvt_term::bell_cb),
190 #endif
191 termwin_ev (this, &rxvt_term::x_cb),
192 vt_ev (this, &rxvt_term::x_cb),
193 child_ev (this, &rxvt_term::child_cb),
194 prepare_ev (this, &rxvt_term::prepare_cb),
195 flush_ev (this, &rxvt_term::flush_cb),
196 destroy_ev (this, &rxvt_term::destroy_cb),
197 pty_ev (this, &rxvt_term::pty_cb),
198 incr_ev (this, &rxvt_term::incr_cb)
199 {
200 cmdbuf_ptr = cmdbuf_endp = cmdbuf_base;
201
202 termlist.push_back (this);
203
204 #ifdef KEYSYM_RESOURCE
205 keyboard = new keyboard_manager;
206 #endif
207 }
208
209 // clean up the most important stuff, do *not* call x or free mem etc.
210 // for use before an emergency exit
211 void
212 rxvt_term::emergency_cleanup ()
213 {
214 if (cmd_pid)
215 kill (-cmd_pid, SIGHUP);
216
217 pty_ev.stop ();
218 delete pty; pty = 0;
219 }
220
221 rxvt_term::~rxvt_term ()
222 {
223 termlist.erase (find (termlist.begin (), termlist.end(), this));
224
225 emergency_cleanup ();
226
227 #if ENABLE_STYLES
228 for (int i = RS_styleCount; --i; )
229 if (fontset[i] != fontset[0])
230 delete fontset[i];
231 #endif
232 delete fontset[0];
233
234 if (display)
235 {
236 selection_clear ();
237
238 #ifdef USE_XIM
239 im_destroy ();
240 #endif
241 #ifdef XTERM_SCROLLBAR
242 if (xscrollbarGC) XFreeGC (dpy, xscrollbarGC);
243 if (ShadowGC) XFreeGC (dpy, ShadowGC);
244 #endif
245 #ifdef PLAIN_SCROLLBAR
246 if (pscrollbarGC) XFreeGC (dpy, pscrollbarGC);
247 #endif
248 #ifdef NEXT_SCROLLBAR
249 if (blackGC) XFreeGC (dpy, blackGC);
250 if (whiteGC) XFreeGC (dpy, whiteGC);
251 if (grayGC) XFreeGC (dpy, grayGC);
252 if (darkGC) XFreeGC (dpy, darkGC);
253 if (stippleGC) XFreeGC (dpy, stippleGC);
254 if (dimple) XFreePixmap (dpy, dimple);
255 if (upArrow) XFreePixmap (dpy, upArrow);
256 if (downArrow) XFreePixmap (dpy, downArrow);
257 if (upArrowHi) XFreePixmap (dpy, upArrowHi);
258 if (downArrowHi) XFreePixmap (dpy, downArrowHi);
259 #endif
260 #ifdef RXVT_SCROLLBAR
261 if (topShadowGC) XFreeGC (dpy, topShadowGC);
262 if (botShadowGC) XFreeGC (dpy, botShadowGC);
263 if (scrollbarGC) XFreeGC (dpy, scrollbarGC);
264 #endif
265 if (gc) XFreeGC (dpy, gc);
266
267 delete drawable;
268 // destroy all windows
269 if (parent[0])
270 XDestroyWindow (dpy, parent[0]);
271
272 for (int i = 0; i < TOTAL_COLORS; i++)
273 if (ISSET_PIXCOLOR (i))
274 {
275 pix_colors_focused [i].free (this);
276 #if OFF_FOCUS_FADING
277 pix_colors_unfocused [i].free (this);
278 #endif
279 }
280
281 clear ();
282 }
283
284 delete [] pix_colors_focused;
285 #if OFF_FOCUS_FADING
286 delete [] pix_colors_unfocused;
287 #endif
288
289 #ifdef HAVE_BG_PIXMAP
290 bgPixmap.destroy ();
291 #endif
292 displays.put (display);
293
294 scr_release ();
295
296 /* clear all resources */
297 for (int i = 0; i < allocated.size (); i++)
298 free (allocated [i]);
299
300 free (selection.text);
301 // TODO: manage env vars in child only(!)
302 free (env_display);
303 free (env_term);
304 free (locale);
305 free (v_buffer);
306 free (incr_buf);
307
308 delete envv;
309 delete argv;
310
311 #ifdef KEYSYM_RESOURCE
312 delete keyboard;
313 #endif
314 #ifndef NO_RESOURCES
315 XrmDestroyDatabase (option_db);
316 #endif
317 }
318
319 // child has exited, usually destroys
320 void
321 rxvt_term::child_cb (ev::child &w, int status)
322 {
323 HOOK_INVOKE ((this, HOOK_CHILD_EXIT, DT_INT, status, DT_END));
324
325 cmd_pid = 0;
326
327 if (!option (Opt_hold))
328 destroy ();
329 }
330
331 void
332 rxvt_term::destroy ()
333 {
334 if (destroy_ev.active)
335 return;
336
337 HOOK_INVOKE ((this, HOOK_DESTROY, DT_END));
338
339 #if ENABLE_OVERLAY
340 scr_overlay_off ();
341 #endif
342
343 if (display)
344 {
345 #if USE_XIM
346 im_ev.stop (display);
347 #endif
348 #if HAVE_SCROLLBARS
349 scrollbar_ev.stop (display);
350 #endif
351 #if ENABLE_TRANSPARENCY || ENABLE_PERL
352 rootwin_ev.stop (display);
353 #endif
354 incr_ev.stop ();
355 termwin_ev.stop (display);
356 vt_ev.stop (display);
357 }
358
359 prepare_ev.stop ();
360 pty_ev.stop ();
361 #ifdef CURSOR_BLINK
362 cursor_blink_ev.stop ();
363 #endif
364 #ifdef TEXT_BLINK
365 text_blink_ev.stop ();
366 #endif
367 #ifndef NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
368 cont_scroll_ev.stop ();
369 #endif
370 #ifdef SELECTION_SCROLLING
371 sel_scroll_ev.stop ();
372 #endif
373 #ifdef POINTER_BLANK
374 pointer_ev.stop ();
375 #endif
376
377 destroy_ev.start ();
378 }
379
380 void
381 rxvt_term::destroy_cb (ev::idle &w, int revents)
382 {
383 make_current ();
384
385 delete this;
386 }
387
388 /*----------------------------------------------------------------------*/
389 /*
390 * Exit gracefully, clearing the utmp entry and restoring tty attributes
391 * TODO: if debugging, this should free up any known resources if we can
392 */
393 static XErrorHandler old_xerror_handler;
394
395 static void
396 rxvt_emergency_cleanup ()
397 {
398 for (rxvt_term **t = rxvt_term::termlist.begin (); t < rxvt_term::termlist.end (); t++)
399 (*t)->emergency_cleanup ();
400 }
401
402 #if !ENABLE_MINIMAL
403 static void
404 print_x_error (Display *dpy, XErrorEvent *event)
405 {
406 char buffer[BUFSIZ];
407 char mesg[BUFSIZ];
408 char number[32];
409 char *mtype = "XlibMessage";
410 XGetErrorText(dpy, event->error_code, buffer, BUFSIZ);
411 XGetErrorDatabaseText(dpy, mtype, "XError", "X Error", mesg, BUFSIZ);
412 rxvt_warn ("An X Error occured, trying to continue after report.\n");
413 rxvt_warn ("%s: %s\n", mesg, buffer);
414 XGetErrorDatabaseText(dpy, mtype, "MajorCode", "Request Major code %d", mesg, BUFSIZ);
415 rxvt_warn (strncat (mesg, "\n", BUFSIZ), event->request_code);
416 sprintf(number, "%d", event->request_code);
417 XGetErrorDatabaseText(dpy, "XRequest", number, "", buffer, BUFSIZ);
418 rxvt_warn ("(which is %s)\n", buffer);
419 if (event->request_code >= 128) {
420 XGetErrorDatabaseText(dpy, mtype, "MinorCode", "Request Minor code %d",
421 mesg, BUFSIZ);
422 rxvt_warn (strncat (mesg, "\n", BUFSIZ), event->minor_code);
423 }
424 if ((event->error_code == BadWindow) ||
425 (event->error_code == BadPixmap) ||
426 (event->error_code == BadCursor) ||
427 (event->error_code == BadFont) ||
428 (event->error_code == BadDrawable) ||
429 (event->error_code == BadColor) ||
430 (event->error_code == BadGC) ||
431 (event->error_code == BadIDChoice) ||
432 (event->error_code == BadValue) ||
433 (event->error_code == BadAtom)) {
434 if (event->error_code == BadValue)
435 XGetErrorDatabaseText(dpy, mtype, "Value", "Value 0x%x",
436 mesg, BUFSIZ);
437 else if (event->error_code == BadAtom)
438 XGetErrorDatabaseText(dpy, mtype, "AtomID", "AtomID 0x%x",
439 mesg, BUFSIZ);
440 else
441 XGetErrorDatabaseText(dpy, mtype, "ResourceID", "ResourceID 0x%x",
442 mesg, BUFSIZ);
443 rxvt_warn (strncat (mesg, "\n", BUFSIZ), event->resourceid);
444 }
445 XGetErrorDatabaseText(dpy, mtype, "ErrorSerial", "Error Serial #%d",
446 mesg, BUFSIZ);
447 rxvt_warn (strncat (mesg, "\n", BUFSIZ), event->serial);
448 }
449 #endif
450
451 int
452 rxvt_xerror_handler (Display *display, XErrorEvent *event)
453 {
454 if (GET_R->allowedxerror == -1)
455 GET_R->allowedxerror = event->error_code;
456 else
457 {
458 // GET_R is most likely not the terminal which caused the error,
459 // so just output the error and continue
460 #if ENABLE_MINIMAL
461 old_xerror_handler (display, event);
462 #else
463 print_x_error (display, event);
464 #endif
465 }
466
467 return 0;
468 }
469
470 int
471 rxvt_xioerror_handler (Display *display)
472 {
473 rxvt_warn ("X connection to '%s' broken, unable to recover, exiting.\n",
474 DisplayString (display));
475 rxvt_emergency_cleanup ();
476 _exit (EXIT_FAILURE);
477 }
478
479 /*----------------------------------------------------------------------*/
480 bool
481 rxvt_term::init (int argc, const char *const *argv, stringvec *envv)
482 {
483 this->envv = envv;
484
485 SET_R (this);
486 set_locale ("");
487 set_environ (envv); // few things in X do not call setlocale :(
488
489 if (!init_vars ())
490 return false;
491
492 init_secondary ();
493
494 const char **cmd_argv = init_resources (argc, argv);
495
496 #ifdef KEYSYM_RESOURCE
497 keyboard->register_done ();
498 #endif
499
500 #ifdef HAVE_SCROLLBARS
501 if (option (Opt_scrollBar))
502 scrollBar.setIdle (); /* set existence for size calculations */
503 #endif
504
505 pty = ptytty::create ();
506
507 create_windows (argc, argv);
508
509 init_xlocale ();
510
511 scr_reset (); // initialize screen
512
513 #if 0
514 XSynchronize (dpy, True);
515 #endif
516
517 #ifdef HAVE_SCROLLBARS
518 if (option (Opt_scrollBar))
519 resize_scrollbar (); /* create and map scrollbar */
520 #endif
521 #ifdef HAVE_BG_PIXMAP
522 {
523 bgPixmap.set_target (this);
524
525 #ifdef ENABLE_TRANSPARENCY
526 if (option (Opt_transparent))
527 {
528 bgPixmap.set_transparent ();
529 #ifdef HAVE_AFTERIMAGE
530 if (rs [Rs_blurradius])
531 bgPixmap.set_blur_radius (rs [Rs_blurradius]);
532 #endif
533 if (ISSET_PIXCOLOR (Color_tint))
534 bgPixmap.set_tint (pix_colors_focused [Color_tint]);
535 if (rs [Rs_shade])
536 bgPixmap.set_shade (rs [Rs_shade]);
537
538 bgPixmap.set_root_pixmap ();
539 XSelectInput (dpy, display->root, PropertyChangeMask);
540 rootwin_ev.start (display, display->root);
541 }
542 #endif
543
544 #ifdef BG_IMAGE_FROM_FILE
545 if (rs[Rs_backgroundPixmap] != NULL)
546 {
547 const char *p = rs[Rs_backgroundPixmap];
548
549 if ((p = strchr (p, ';')) != NULL)
550 {
551 p++;
552 bgPixmap.set_geometry (p);
553 }
554 else
555 bgPixmap.set_defaultGeometry ();
556
557 if (bgPixmap.set_file (rs[Rs_backgroundPixmap]))
558 if (!bgPixmap.window_position_sensitive ())
559 update_background ();
560 }
561 #endif
562 }
563 #endif
564
565 #if ENABLE_PERL
566 rootwin_ev.start (display, display->root);
567 #endif
568
569 set_colorfgbg ();
570
571 init_command (cmd_argv);
572
573 free (cmd_argv);
574
575 if (pty->pty >= 0)
576 pty_ev.start (pty->pty, ev::READ);
577
578 prepare_ev.start ();
579
580 HOOK_INVOKE ((this, HOOK_START, DT_END));
581
582 #if ENABLE_XEMBED
583 if (rs[Rs_embed])
584 {
585 long info[2] = { 0, XEMBED_MAPPED };
586
587 XChangeProperty (dpy, parent[0], xa[XA_XEMBED_INFO], xa[XA_XEMBED_INFO],
588 32, PropModeReplace, (unsigned char *)&info, 2);
589 }
590 #endif
591
592 XMapWindow (dpy, vt);
593 XMapWindow (dpy, parent[0]);
594
595 return true;
596 }
597
598 static struct sig_handlers
599 {
600 ev::sig sw_term, sw_int;
601
602 /*
603 * Catch a fatal signal and tidy up before quitting
604 */
605 void
606 sig_term (ev::sig &w, int revents)
607 {
608 rxvt_emergency_cleanup ();
609 w.stop ();
610 kill (getpid (), w.signum);
611 }
612
613 sig_handlers ()
614 : sw_term (this, &sig_handlers::sig_term),
615 sw_int (this, &sig_handlers::sig_term)
616 {
617 }
618 } sig_handlers;
619
620 char **rxvt_environ; // startup environment
621
622 void
623 rxvt_init ()
624 {
625 ptytty::init ();
626
627 if (!ev::ev_default_loop (0))
628 rxvt_fatal ("cannot initialise libev (bad value for LIBEV_METHODS?)\n");
629
630 rxvt_environ = environ;
631
632 signal (SIGHUP, SIG_IGN);
633 signal (SIGPIPE, SIG_IGN);
634
635 sig_handlers.sw_term.start (SIGTERM); ev::ev_unref ();
636 sig_handlers.sw_int.start (SIGINT); ev::ev_unref ();
637
638 /* need to trap SIGURG for SVR4 (Unixware) rlogin */
639 /* signal (SIGURG, SIG_DFL); */
640
641 old_xerror_handler = XSetErrorHandler ((XErrorHandler) rxvt_xerror_handler);
642 // TODO: handle this with exceptions and tolerate the memory loss
643 XSetIOErrorHandler (rxvt_xioerror_handler);
644
645 XrmInitialize ();
646 }
647
648 /* ------------------------------------------------------------------------- *
649 * MEMORY ALLOCATION WRAPPERS *
650 * ------------------------------------------------------------------------- */
651 void *
652 rxvt_malloc (size_t size)
653 {
654 void *p = malloc (size);
655
656 if (!p)
657 rxvt_fatal ("memory allocation failure. aborting.\n");
658
659 return p;
660 }
661
662 void *
663 rxvt_calloc (size_t number, size_t size)
664 {
665 void *p = calloc (number, size);
666
667 if (!p)
668 rxvt_fatal ("memory allocation failure. aborting.\n");
669
670 return p;
671 }
672
673 void *
674 rxvt_realloc (void *ptr, size_t size)
675 {
676 void *p = realloc (ptr, size);
677
678 if (!p)
679 rxvt_fatal ("memory allocation failure. aborting.\n");
680
681 return p;
682 }
683
684 /*----------------------------------------------------------------------*/
685 /*
686 * window size/position calculations for XSizeHint and other storage.
687 * if width/height are non-zero then override calculated width/height
688 */
689 void
690 rxvt_term::window_calc (unsigned int newwidth, unsigned int newheight)
691 {
692 short recalc_x, recalc_y;
693 int x, y, sb_w, flags;
694 unsigned int w, h;
695 unsigned int max_width, max_height;
696
697 szHint.flags = PMinSize | PResizeInc | PBaseSize | PWinGravity;
698 szHint.win_gravity = NorthWestGravity;
699 /* szHint.min_aspect.x = szHint.min_aspect.y = 1; */
700
701 recalc_x = recalc_y = 0;
702 flags = 0;
703
704 if (!parsed_geometry)
705 {
706 parsed_geometry = 1;
707
708 if (rs[Rs_geometry])
709 flags = XParseGeometry (rs[Rs_geometry], &x, &y, &w, &h);
710
711 if (flags & WidthValue)
712 {
713 ncol = clamp (w, 0, std::numeric_limits<int16_t>::max ());
714 szHint.flags |= USSize;
715 }
716
717 if (flags & HeightValue)
718 {
719 nrow = clamp (h, 0, std::numeric_limits<int16_t>::max ());
720 szHint.flags |= USSize;
721 }
722
723 if (flags & XValue)
724 {
725 szHint.x = x;
726 szHint.flags |= USPosition;
727
728 if (flags & XNegative)
729 {
730 recalc_x = 1;
731 szHint.win_gravity = NorthEastGravity;
732 }
733 }
734
735 if (flags & YValue)
736 {
737 szHint.y = y;
738 szHint.flags |= USPosition;
739
740 if (flags & YNegative)
741 {
742 recalc_y = 1;
743
744 if (szHint.win_gravity == NorthEastGravity)
745 szHint.win_gravity = SouthEastGravity;
746 else
747 szHint.win_gravity = SouthWestGravity;
748 }
749 }
750 }
751
752 /* TODO: BOUNDS */
753 width = ncol * fwidth;
754 height = nrow * fheight;
755 max_width = MAX_COLS * fwidth;
756 max_height = MAX_ROWS * fheight;
757
758 szHint.base_width = szHint.base_height = 2 * int_bwidth;
759
760 sb_w = 0;
761 window_vt_x = window_vt_y = int_bwidth;
762
763 if (scrollBar.state)
764 {
765 sb_w = scrollbar_TotalWidth ();
766 szHint.base_width += sb_w;
767
768 if (!option (Opt_scrollBar_right))
769 window_vt_x += sb_w;
770 }
771
772 szHint.width_inc = fwidth;
773 szHint.height_inc = fheight;
774 szHint.min_width = szHint.base_width + szHint.width_inc;
775 szHint.min_height = szHint.base_height + szHint.height_inc;
776
777 if (newwidth && newwidth - szHint.base_width < max_width)
778 {
779 szHint.width = newwidth;
780 width = newwidth - szHint.base_width;
781 }
782 else
783 {
784 min_it (width, max_width);
785 szHint.width = szHint.base_width + width;
786 }
787
788 if (newheight && newheight - szHint.base_height < max_height)
789 {
790 szHint.height = newheight;
791 height = newheight - szHint.base_height;
792 }
793 else
794 {
795 min_it (height, max_height);
796 szHint.height = szHint.base_height + height;
797 }
798
799 if (scrollBar.state && option (Opt_scrollBar_right))
800 window_sb_x = szHint.width - sb_w;
801
802 if (recalc_x)
803 szHint.x += DisplayWidth (dpy, display->screen) - szHint.width - 2 * ext_bwidth;
804
805 if (recalc_y)
806 szHint.y += DisplayHeight (dpy, display->screen) - szHint.height - 2 * ext_bwidth;
807
808 ncol = width / fwidth;
809 nrow = height / fheight;
810 }
811
812 /*----------------------------------------------------------------------*/
813 /*
814 * Tell the teletype handler what size the window is.
815 * Called after a window size change.
816 */
817 void
818 rxvt_term::tt_winch ()
819 {
820 if (pty->pty < 0)
821 return;
822
823 struct winsize ws;
824
825 ws.ws_col = ncol;
826 ws.ws_row = nrow;
827 ws.ws_xpixel = width;
828 ws.ws_ypixel = height;
829 (void)ioctl (pty->pty, TIOCSWINSZ, &ws);
830
831 #if 0
832 // TIOCSWINSZ⎈ is supposed to do this automatically and correctly
833 if (cmd_pid) /* force through to the command */
834 kill (-cmd_pid, SIGWINCH);
835 #endif
836 }
837
838 /*----------------------------------------------------------------------*/
839 /* set_fonts () - load and set the various fonts
840 *
841 * init = 1 - initialize
842 *
843 * fontname == FONT_UP - switch to bigger font
844 * fontname == FONT_DN - switch to smaller font
845 */
846 bool
847 rxvt_term::set_fonts ()
848 {
849 rxvt_fontset *fs = new rxvt_fontset (this);
850 rxvt_fontprop prop;
851
852 if (!fs
853 || !fs->populate (rs[Rs_font] ? rs[Rs_font] : "fixed")
854 || !fs->realize_font (1))
855 {
856 delete fs;
857 return false;
858 }
859
860 #if ENABLE_STYLES
861 for (int i = RS_styleCount; --i; )
862 if (fontset[i] != fontset[0])
863 delete fontset[i];
864 #endif
865
866 delete fontset[0];
867 fontset[0] = fs;
868
869 prop = (*fs)[1]->properties ();
870 prop.height += lineSpace;
871
872 fs->set_prop (prop, false);
873
874 fwidth = prop.width;
875 fheight = prop.height;
876 fbase = prop.ascent;
877
878 for (int style = 1; style < 4; style++)
879 {
880 #if ENABLE_STYLES
881 const char *res = rs[Rs_font + style];
882
883 if (res && !*res)
884 fontset[style] = fontset[0];
885 else
886 {
887 fontset[style] = fs = new rxvt_fontset (this);
888 rxvt_fontprop prop2 = prop;
889
890 if (res)
891 {
892 fs->populate (res);
893 fs->set_prop (prop2, false);
894 }
895 else
896 {
897 fs->populate (fontset[0]->fontdesc);
898
899 if (SET_STYLE (0, style) & RS_Bold) prop2.weight = rxvt_fontprop::bold;
900 if (SET_STYLE (0, style) & RS_Italic) prop2.slant = rxvt_fontprop::italic;
901
902 fs->set_prop (prop2, true);
903 }
904
905 }
906 #else
907 fontset[style] = fontset[0];
908 #endif
909 }
910
911 if (parent[0])
912 {
913 resize_all_windows (0, 0, 0);
914 scr_remap_chars ();
915 scr_touch (true);
916 }
917
918 return true;
919 }
920
921 void
922 rxvt_term::set_string_property (Atom prop, const char *str, int len)
923 {
924 XChangeProperty (dpy, parent[0],
925 prop, XA_STRING, 8, PropModeReplace,
926 (const unsigned char *)str, len >= 0 ? len : strlen (str));
927 }
928
929 void
930 rxvt_term::set_utf8_property (Atom prop, const char *str, int len)
931 {
932 wchar_t *ws = rxvt_mbstowcs (str, len);
933 char *s = rxvt_wcstoutf8 (ws);
934
935 XChangeProperty (dpy, parent[0],
936 prop, xa[XA_UTF8_STRING], 8, PropModeReplace,
937 (const unsigned char *)s, strlen (s));
938
939 free (s);
940 free (ws);
941 }
942
943 /*----------------------------------------------------------------------*/
944 /*----------------------------------------------------------------------*/
945 /* xterm sequences - title, iconName, color (exptl) */
946 void
947 rxvt_term::set_title (const char *str)
948 {
949 set_string_property (XA_WM_NAME, str);
950 #if ENABLE_EWMH
951 set_utf8_property (xa[XA_NET_WM_NAME], str);
952 #endif
953 }
954
955 void
956 rxvt_term::set_icon_name (const char *str)
957 {
958 set_string_property (XA_WM_ICON_NAME, str);
959 #if ENABLE_EWMH
960 set_utf8_property (xa[XA_NET_WM_ICON_NAME], str);
961 #endif
962 }
963
964 void
965 rxvt_term::set_window_color (int idx, const char *color)
966 {
967 #ifdef XTERM_COLOR_CHANGE
968 rxvt_color xcol;
969 int i;
970
971 if (color == NULL || *color == '\0')
972 return;
973
974 color = strdup (color);
975 allocated.push_back ((void *)color);
976 rs[Rs_color + idx] = color;
977
978 /* handle color aliases */
979 if (isdigit (*color))
980 {
981 i = atoi (color);
982
983 if (i >= 8 && i <= 15)
984 { /* bright colors */
985 i -= 8;
986 pix_colors_focused[idx] = pix_colors_focused[minBrightCOLOR + i];
987 goto done;
988 }
989
990 if (i >= 0 && i <= 7)
991 { /* normal colors */
992 pix_colors_focused[idx] = pix_colors_focused[minCOLOR + i];
993 goto done;
994 }
995 }
996
997 set_color (xcol, color);
998
999 /*
1000 * FIXME: should free colors here, but no idea how to do it so instead,
1001 * so just keep gobbling up the colormap
1002 */
1003
1004 pix_colors_focused[idx] = xcol;
1005
1006 /* XSetWindowAttributes attr; */
1007 /* Cursor cursor; */
1008 done:
1009 /*TODO: handle Color_BD, scrollbar background, etc. */
1010
1011 update_fade_color (idx);
1012 recolour_cursor ();
1013 scr_recolour ();
1014 #endif /* XTERM_COLOR_CHANGE */
1015 }
1016
1017 void
1018 rxvt_term::recolour_cursor ()
1019 {
1020 XColor fg, bg;
1021
1022 (ISSET_PIXCOLOR (Color_pointer_fg)
1023 ? pix_colors_focused[Color_pointer_fg]
1024 : pix_colors_focused[Color_fg]).get (fg);
1025
1026 (ISSET_PIXCOLOR (Color_pointer_bg)
1027 ? pix_colors_focused[Color_pointer_bg]
1028 : pix_colors_focused[Color_bg]).get (bg);
1029
1030 XRecolorCursor (dpy, TermWin_cursor, &fg, &bg);
1031 }
1032
1033 /*----------------------------------------------------------------------*/
1034 /*
1035 * find if fg/bg matches any of the normal (low-intensity) colors
1036 */
1037 void
1038 rxvt_term::set_colorfgbg ()
1039 {
1040 unsigned int i;
1041 const char *xpmb = "\0";
1042 char fstr[sizeof ("default") + 1], bstr[sizeof ("default") + 1];
1043
1044 strcpy (fstr, "default");
1045 strcpy (bstr, "default");
1046 for (i = Color_Black; i <= Color_White; i++)
1047 if (pix_colors[Color_fg] == pix_colors[i])
1048 {
1049 sprintf (fstr, "%d", (i - Color_Black));
1050 break;
1051 }
1052
1053 for (i = Color_Black; i <= Color_White; i++)
1054 if (pix_colors[Color_bg] == pix_colors[i])
1055 {
1056 sprintf (bstr, "%d", (i - Color_Black));
1057 #ifdef BG_IMAGE_FROM_FILE
1058 xpmb = "default;";
1059 #endif
1060 break;
1061 }
1062
1063 sprintf (env_colorfgbg, "COLORFGBG=%s;%s%s", fstr, xpmb, bstr);
1064 }
1065
1066 /*----------------------------------------------------------------------*/
1067
1068 bool
1069 rxvt_term::set_color (rxvt_color &color, const char *name)
1070 {
1071 if (color.set (this, name))
1072 return true;
1073
1074 rxvt_warn ("can't get colour '%s', continuing without.\n", name);
1075 return false;
1076 }
1077
1078 void
1079 rxvt_term::alias_color (int dst, int src)
1080 {
1081 pix_colors[dst].set (this, rs[Rs_color + dst] = rs[Rs_color + src]);
1082 }
1083
1084 /* -------------------------------------------------------------------- *
1085 * - WINDOW RESIZING - *
1086 * -------------------------------------------------------------------- */
1087 void
1088 rxvt_term::resize_all_windows (unsigned int newwidth, unsigned int newheight, int ignoreparent)
1089 {
1090 int fix_screen;
1091 int old_width = szHint.width;
1092 int old_height = szHint.height;
1093
1094 window_calc (newwidth, newheight);
1095
1096 if (!HOOK_INVOKE ((this, HOOK_RESIZE_ALL_WINDOWS, DT_INT, newwidth, DT_INT, newheight, DT_END)))
1097 XSetWMNormalHints (dpy, parent[0], &szHint);
1098
1099 if (!ignoreparent)
1100 {
1101 #ifdef SMART_RESIZE
1102 /*
1103 * resize by Marius Gedminas <marius.gedminas@uosis.mif.vu.lt>
1104 * reposition window on resize depending on placement on screen
1105 */
1106 int x, y, x1, y1;
1107 int dx, dy;
1108 unsigned int unused_w1, unused_h1, unused_b1, unused_d1;
1109 Window unused_cr;
1110
1111 XTranslateCoordinates (dpy, parent[0], display->root,
1112 0, 0, &x, &y, &unused_cr);
1113 XGetGeometry (dpy, parent[0], &unused_cr, &x1, &y1,
1114 &unused_w1, &unused_h1, &unused_b1, &unused_d1);
1115 /*
1116 * if display->root isn't the parent window, a WM will probably have offset
1117 * our position for handles and decorations. Counter it
1118 */
1119 if (x1 != x || y1 != y)
1120 {
1121 x -= x1;
1122 y -= y1;
1123 }
1124
1125 x1 = (DisplayWidth (dpy, display->screen) - old_width ) / 2;
1126 y1 = (DisplayHeight (dpy, display->screen) - old_height) / 2;
1127 dx = old_width - szHint.width;
1128 dy = old_height - szHint.height;
1129
1130 /* Check position of the center of the window */
1131 if (x < x1) /* left half */
1132 dx = 0;
1133 else if (x == x1) /* exact center */
1134 dx /= 2;
1135 if (y < y1) /* top half */
1136 dy = 0;
1137 else if (y == y1) /* exact center */
1138 dy /= 2;
1139
1140 XMoveResizeWindow (dpy, parent[0], x + dx, y + dy,
1141 szHint.width, szHint.height);
1142 #else
1143 XResizeWindow (dpy, parent[0], szHint.width, szHint.height);
1144 #endif
1145 }
1146
1147 fix_screen = ncol != prev_ncol || nrow != prev_nrow;
1148
1149 if (fix_screen || newwidth != old_width || newheight != old_height)
1150 {
1151 if (scrollBar.state)
1152 {
1153 XMoveResizeWindow (dpy, scrollBar.win,
1154 window_sb_x, 0,
1155 scrollbar_TotalWidth (), szHint.height);
1156 resize_scrollbar ();
1157 }
1158
1159 XMoveResizeWindow (dpy, vt,
1160 window_vt_x, window_vt_y,
1161 width, height);
1162
1163 #ifdef HAVE_BG_PIXMAP
1164 if (bgPixmap.window_size_sensitive ())
1165 update_background ();
1166 #endif
1167
1168 scr_clear ();
1169 }
1170
1171 if (fix_screen || old_height == 0)
1172 scr_reset ();
1173
1174 // TODO, with nvidia-8178, resizes kill the alpha channel, report if not fixed in newer version
1175 //scr_touch (false);
1176
1177 #ifdef HAVE_BG_PIXMAP
1178 // TODO: this don't seem to have any effect - do we still need it ? If so - in which case exactly ?
1179 // if (bgPixmap.pixmap)
1180 // scr_touch (false);
1181 #endif
1182
1183 #ifdef USE_XIM
1184 IMSetPosition ();
1185 #endif
1186 }
1187
1188 /*
1189 * Set the width/height of the vt window in characters. Units are pixels.
1190 * good for toggling 80/132 columns
1191 */
1192 void
1193 rxvt_term::set_widthheight (unsigned int newwidth, unsigned int newheight)
1194 {
1195 XWindowAttributes wattr;
1196
1197 if (newwidth == 0 || newheight == 0)
1198 {
1199 XGetWindowAttributes (dpy, display->root, &wattr);
1200
1201 if (newwidth == 0)
1202 newwidth = wattr.width - szHint.base_width;
1203 if (newheight == 0)
1204 newheight = wattr.height - szHint.base_height;
1205 }
1206
1207 if (newwidth != width || newheight != height)
1208 {
1209 newwidth += szHint.base_width;
1210 newheight += szHint.base_height;
1211 resize_all_windows (newwidth, newheight, 0);
1212 }
1213 }
1214
1215 /* -------------------------------------------------------------------- *
1216 * - X INPUT METHOD ROUTINES - *
1217 * -------------------------------------------------------------------- */
1218 #ifdef USE_XIM
1219
1220 void
1221 rxvt_term::im_set_color (unsigned long &fg, unsigned long &bg)
1222 {
1223 fg = pix_colors [Color_fg];
1224 bg = pix_colors [Color_bg];
1225 }
1226
1227 void
1228 rxvt_term::im_set_size (XRectangle &size)
1229 {
1230 // the int_bwidth terms make no sense to me
1231 size.x = int_bwidth;
1232 size.y = int_bwidth;
1233 size.width = Width2Pixel (ncol) + int_bwidth;
1234 size.height = Height2Pixel (nrow) + int_bwidth;
1235 }
1236
1237 void
1238 rxvt_term::im_set_preedit_area (XRectangle &preedit_rect,
1239 XRectangle &status_rect,
1240 const XRectangle &needed_rect)
1241 {
1242 preedit_rect.x = needed_rect.width;
1243 preedit_rect.y = 0;
1244 preedit_rect.width = Width2Pixel (ncol) - needed_rect.width + 1;
1245 preedit_rect.height = fheight;
1246
1247 status_rect.x = 0;
1248 status_rect.y = 0;
1249 status_rect.width = needed_rect.width ? needed_rect.width : Width2Pixel (ncol) + 1;
1250 status_rect.height = fheight;
1251 }
1252
1253 /* Checking whether input method is running. */
1254 bool
1255 rxvt_term::IMisRunning ()
1256 {
1257 char *p;
1258 Atom atom;
1259 Window win;
1260 char server[IMBUFSIZ];
1261
1262 /* get current locale modifier */
1263 if ((p = XSetLocaleModifiers (NULL)) != NULL)
1264 {
1265 strcpy (server, "@server=");
1266 strncat (server, & (p[4]), IMBUFSIZ - 9); /* skip "@im=" */
1267
1268 if ((p = strchr (server + 1, '@')) != NULL) /* first one only */
1269 *p = '\0';
1270
1271 atom = XInternAtom (dpy, server, False);
1272 win = XGetSelectionOwner (dpy, atom);
1273
1274 if (win != None)
1275 return True;
1276 }
1277
1278 return False;
1279 }
1280
1281 void
1282 rxvt_term::IMSendSpot ()
1283 {
1284 XPoint nspot;
1285 XVaNestedList preedit_attr;
1286
1287 if (!Input_Context
1288 || !focus
1289 || !(input_style & (XIMPreeditPosition | XIMPreeditCallbacks)))
1290 return;
1291
1292 im_set_position (nspot);
1293
1294 if (nspot.x == spot.x && nspot.y == spot.y)
1295 return;
1296
1297 spot = nspot;
1298
1299 preedit_attr = XVaCreateNestedList (0, XNSpotLocation, &spot, NULL);
1300 XSetICValues (Input_Context, XNPreeditAttributes, preedit_attr, NULL);
1301 XFree (preedit_attr);
1302 }
1303
1304 void
1305 rxvt_term::im_destroy ()
1306 {
1307 if (input_method)
1308 {
1309 if (Input_Context && input_method->xim)
1310 XDestroyIC (Input_Context);
1311
1312 display->put_xim (input_method);
1313 input_method = 0;
1314 }
1315
1316 Input_Context = 0;
1317 }
1318
1319 #ifdef ENABLE_XIM_ONTHESPOT
1320
1321 static void
1322 xim_preedit_start (XIC ic, XPointer client_data, XPointer call_data)
1323 {
1324 ((rxvt_term *)client_data)->make_current ();
1325 HOOK_INVOKE (((rxvt_term *)client_data, HOOK_XIM_PREEDIT_START, DT_END));
1326 }
1327
1328 static void
1329 xim_preedit_done (XIC ic, XPointer client_data, XPointer call_data)
1330 {
1331 ((rxvt_term *)client_data)->make_current ();
1332 HOOK_INVOKE (((rxvt_term *)client_data, HOOK_XIM_PREEDIT_DONE, DT_END));
1333 }
1334
1335 static void
1336 xim_preedit_draw (XIC ic, XPointer client_data, XIMPreeditDrawCallbackStruct *call_data)
1337 {
1338 rxvt_term *term = (rxvt_term *)client_data;
1339 XIMText *text = call_data->text;
1340
1341 term->make_current ();
1342
1343 if (text)
1344 {
1345 void *str;
1346
1347 if (!text->encoding_is_wchar && text->string.multi_byte)
1348 {
1349 // of course, X makes it ugly again
1350 if (term->rs[Rs_imLocale])
1351 SET_LOCALE (term->rs[Rs_imLocale]);
1352
1353 str = rxvt_temp_buf ((text->length + 1) * sizeof (wchar_t));
1354 mbstowcs ((wchar_t *)str, text->string.multi_byte, text->length + 1);
1355
1356 if (term->rs[Rs_imLocale])
1357 SET_LOCALE (term->locale);
1358 }
1359 else
1360 str = (void *)text->string.wide_char;
1361
1362 HOOK_INVOKE ((term, HOOK_XIM_PREEDIT_DRAW,
1363 DT_INT, call_data->caret,
1364 DT_INT, call_data->chg_first,
1365 DT_INT, call_data->chg_length,
1366 DT_LCS_LEN, (void *)text->feedback, text->feedback ? (int)text->length : 0,
1367 DT_WCS_LEN, str, str ? (int)text->length : 0,
1368 DT_END));
1369 }
1370 else
1371 HOOK_INVOKE ((term, HOOK_XIM_PREEDIT_DRAW,
1372 DT_INT, call_data->caret,
1373 DT_INT, call_data->chg_first,
1374 DT_INT, call_data->chg_length,
1375 DT_END));
1376 }
1377
1378 #if 0
1379 static void
1380 xim_preedit_caret (XIC ic, XPointer client_data, XIMPreeditCaretCallbackStruct *call_data)
1381 {
1382 ((rxvt_term *)client_data)->make_current ();
1383 HOOK_INVOKE (((rxvt_term *)client_data, HOOK_XIM_PREEDIT_CARET,
1384 DT_INT, call_data->position,
1385 DT_INT, call_data->direction,
1386 DT_INT, call_data->style,
1387 DT_END));
1388 }
1389 #endif
1390
1391 #endif
1392
1393 /*
1394 * Try to open a XIM with the current modifiers, then see if we can
1395 * open a suitable preedit type
1396 */
1397 bool
1398 rxvt_term::IM_get_IC (const char *modifiers)
1399 {
1400 int i, j, found;
1401 XIM xim;
1402 XPoint spot;
1403 XRectangle rect, status_rect, needed_rect;
1404 unsigned long fg, bg;
1405 const char *p;
1406 char **s;
1407 XIMStyles *xim_styles;
1408 #ifdef ENABLE_XIM_ONTHESPOT
1409 XIMCallback xcb[4];
1410 #endif
1411
1412 set_environ (envv);
1413
1414 if (! ((p = XSetLocaleModifiers (modifiers)) && *p))
1415 return false;
1416
1417 input_method = display->get_xim (locale, modifiers);
1418 if (input_method == NULL)
1419 return false;
1420
1421 xim = input_method->xim;
1422 spot.x = spot.y = -1;
1423
1424 xim_styles = NULL;
1425 if (XGetIMValues (xim, XNQueryInputStyle, &xim_styles, NULL)
1426 || !xim_styles || !xim_styles->count_styles)
1427 {
1428 im_destroy ();
1429 return false;
1430 }
1431
1432 const char *pet[] = { rs[Rs_preeditType], "OverTheSpot,OffTheSpot,Root,None" };
1433
1434 for (int pi = 0; pi < 2; pi++)
1435 {
1436 p = pet[pi];
1437
1438 if (!p)
1439 continue;
1440
1441 s = rxvt_splitcommastring (p);
1442
1443 for (i = found = 0; !found && s[i]; i++)
1444 {
1445 if (!strcmp (s[i], "OverTheSpot"))
1446 input_style = XIMPreeditPosition | XIMStatusNothing;
1447 else if (!strcmp (s[i], "OffTheSpot"))
1448 input_style = XIMPreeditArea | XIMStatusArea;
1449 else if (!strcmp (s[i], "Root"))
1450 input_style = XIMPreeditNothing | XIMStatusNothing;
1451 else if (!strcmp (s[i], "None"))
1452 input_style = XIMPreeditNone | XIMStatusNone;
1453 #ifdef ENABLE_XIM_ONTHESPOT
1454 else if (SHOULD_INVOKE (HOOK_XIM_PREEDIT_START) && !strcmp (s[i], "OnTheSpot"))
1455 input_style = XIMPreeditCallbacks | XIMStatusNothing;
1456 #endif
1457 else
1458 input_style = XIMPreeditNothing | XIMStatusNothing;
1459
1460 for (j = 0; j < xim_styles->count_styles; j++)
1461 if (input_style == xim_styles->supported_styles[j])
1462 {
1463 rxvt_freecommastring (s);
1464
1465 found = 1;
1466 goto foundpet;
1467 }
1468
1469 }
1470
1471 rxvt_freecommastring (s);
1472 }
1473
1474 foundpet:
1475
1476 XFree (xim_styles);
1477
1478 if (!found)
1479 {
1480 im_destroy ();
1481 return false;
1482 }
1483
1484 XFontSet fs = 0;
1485 XVaNestedList preedit_attr = 0, status_attr = 0;
1486
1487 if (input_style & (XIMPreeditPosition | XIMPreeditArea))
1488 {
1489 // fake us a font-set, please
1490 char **missing_charset_list;
1491 int missing_charset_count;
1492 char *def_string;
1493 char pat[512];
1494
1495 sprintf (pat,
1496 "-*-*-*-R-*-*-%d-*-*-*-*-*-*,"
1497 "-*-*-*-R-*-*-%d-*-*-*-*-*-*,"
1498 "-*-*-*-R-*-*-%d-*-*-*-*-*-*,"
1499 "-*-*-*-R-*-*-%d-*-*-*-*-*-*,"
1500 "-*-*-*-R-*-*-%d-*-*-*-*-*-*,"
1501 "*",
1502 fheight,
1503 fheight + 1, fheight - 1,
1504 fheight - 2, fheight + 2);
1505
1506 fs = XCreateFontSet (dpy, rs[Rs_imFont] ? rs[Rs_imFont] : pat,
1507 &missing_charset_list, &missing_charset_count, &def_string);
1508
1509 if (missing_charset_list)
1510 XFreeStringList (missing_charset_list);
1511
1512 if (!fs)
1513 {
1514 input_style &= ~(XIMPreeditPosition | XIMPreeditArea);
1515 rxvt_warn ("unable to create fontset for input method, try \"-pt Root\". Continuing.\n");
1516 }
1517 }
1518
1519 if (input_style & XIMPreeditPosition)
1520 {
1521 im_set_size (rect);
1522 im_set_position (spot);
1523 im_set_color (fg, bg);
1524
1525 preedit_attr = XVaCreateNestedList (0,
1526 XNForeground, fg,
1527 XNBackground, bg,
1528 XNArea, &rect,
1529 XNSpotLocation, &spot,
1530 XNFontSet, fs,
1531 NULL);
1532 }
1533 else if (input_style & XIMPreeditArea)
1534 {
1535 im_set_color (fg, bg);
1536
1537 /*
1538 * The necessary width of preedit area is unknown
1539 * until create input context.
1540 */
1541 needed_rect.width = 0;
1542 im_set_preedit_area (rect, status_rect, needed_rect);
1543
1544 preedit_attr = XVaCreateNestedList (0,
1545 XNForeground, fg,
1546 XNBackground, bg,
1547 XNArea, &rect,
1548 XNFontSet, fs,
1549 NULL);
1550 status_attr = XVaCreateNestedList (0,
1551 XNForeground, fg,
1552 XNBackground, bg,
1553 XNArea, &status_rect,
1554 XNFontSet, fs,
1555 NULL);
1556 }
1557 #if ENABLE_XIM_ONTHESPOT
1558 else if (input_style & XIMPreeditCallbacks)
1559 {
1560 im_set_position (spot);
1561
1562 xcb[0].client_data = (XPointer)this; xcb[0].callback = (XIMProc)xim_preedit_start;
1563 xcb[1].client_data = (XPointer)this; xcb[1].callback = (XIMProc)xim_preedit_done;
1564 xcb[2].client_data = (XPointer)this; xcb[2].callback = (XIMProc)xim_preedit_draw;
1565 # if 0
1566 xcb[3].client_data = (XPointer)this; xcb[3].callback = (XIMProc)xim_preedit_caret;
1567 # endif
1568
1569 preedit_attr = XVaCreateNestedList (0,
1570 XNSpotLocation, &spot,
1571 XNPreeditStartCallback, &xcb[0],
1572 XNPreeditDoneCallback , &xcb[1],
1573 XNPreeditDrawCallback , &xcb[2],
1574 # if 0
1575 XNPreeditCaretCallback, &xcb[3],
1576 # endif
1577 NULL);
1578 }
1579 #endif
1580
1581 Input_Context = XCreateIC (xim,
1582 XNInputStyle, input_style,
1583 XNClientWindow, vt,
1584 XNFocusWindow, parent[0],
1585 preedit_attr ? XNPreeditAttributes : NULL,
1586 preedit_attr,
1587 status_attr ? XNStatusAttributes : NULL,
1588 status_attr, NULL);
1589
1590 if (preedit_attr) XFree (preedit_attr);
1591 if (status_attr) XFree (status_attr);
1592 if (fs) XFreeFontSet (dpy, fs);
1593
1594 if (Input_Context == NULL)
1595 {
1596 rxvt_warn ("failed to create input context, continuing without XIM.\n");
1597 im_destroy ();
1598 return false;
1599 }
1600
1601 #if 0
1602 // unfortunately, only the focus window is used by XIM, hard to fix
1603 if (!XGetICValues (Input_Context, XNFilterEvents, &vt_emask_xim, NULL))
1604 vt_select_input ();
1605 #endif
1606
1607 IMSetPosition ();
1608
1609 return true;
1610 }
1611
1612 void
1613 rxvt_term::im_cb ()
1614 {
1615 int i;
1616 const char *p;
1617 char **s;
1618 char buf[IMBUFSIZ];
1619
1620 make_current ();
1621
1622 im_destroy ();
1623
1624 if (Input_Context)
1625 return;
1626
1627 #if defined(HAVE_XSETLOCALE) || defined(HAVE_SETLOCALE)
1628 if (rs[Rs_imLocale])
1629 SET_LOCALE (rs[Rs_imLocale]);
1630 #endif
1631
1632 p = rs[Rs_inputMethod];
1633 if (p && *p)
1634 {
1635 bool found = false;
1636
1637 s = rxvt_splitcommastring (p);
1638
1639 for (i = 0; s[i]; i++)
1640 {
1641 if (*s[i])
1642 {
1643 strcpy (buf, "@im=");
1644 strncat (buf, s[i], IMBUFSIZ - 5);
1645 if (IM_get_IC (buf))
1646 {
1647 found = true;
1648 break;
1649 }
1650 }
1651 }
1652
1653 rxvt_freecommastring (s);
1654
1655 if (found)
1656 goto done;
1657 }
1658
1659 /* try with XMODIFIERS env. var. */
1660 if (IM_get_IC (""))
1661 goto done;
1662
1663 /* try with no modifiers base IF the user didn't specify an IM */
1664 if (IM_get_IC ("@im=none"))
1665 goto done;
1666
1667 done:
1668 #if defined(HAVE_XSETLOCALE) || defined(HAVE_SETLOCALE)
1669 if (rs[Rs_imLocale])
1670 SET_LOCALE (locale);
1671 #endif
1672 }
1673
1674 void
1675 rxvt_term::IMSetPosition ()
1676 {
1677 XRectangle preedit_rect, status_rect, *needed_rect;
1678 XVaNestedList preedit_attr, status_attr;
1679
1680 if (!Input_Context
1681 || !focus
1682 || !(input_style & (XIMPreeditArea | XIMPreeditPosition))
1683 || !IMisRunning ())
1684 return;
1685
1686 if (input_style & XIMPreeditPosition)
1687 {
1688 im_set_size (preedit_rect);
1689 preedit_attr = XVaCreateNestedList (0, XNArea, &preedit_rect, NULL);
1690
1691 XSetICValues (Input_Context,
1692 XNPreeditAttributes, preedit_attr, NULL);
1693 }
1694 else
1695 {
1696 /* Getting the necessary width of preedit area */
1697 status_attr = XVaCreateNestedList (0, XNAreaNeeded, &needed_rect, NULL);
1698 XGetICValues (Input_Context, XNStatusAttributes, status_attr, NULL);
1699 XFree (status_attr);
1700
1701 im_set_preedit_area (preedit_rect, status_rect, *needed_rect);
1702 XFree (needed_rect);
1703
1704 preedit_attr = XVaCreateNestedList (0, XNArea, &preedit_rect, NULL);
1705 status_attr = XVaCreateNestedList (0, XNArea, &status_rect, NULL);
1706
1707 XSetICValues (Input_Context,
1708 XNPreeditAttributes, preedit_attr,
1709 XNStatusAttributes, status_attr,
1710 NULL);
1711
1712 XFree (status_attr);
1713 }
1714
1715 XFree (preedit_attr);
1716 }
1717 #endif /* USE_XIM */
1718
1719 void
1720 rxvt_term::get_window_origin (int &x, int &y)
1721 {
1722 Window cr;
1723 XTranslateCoordinates (dpy, parent[0], display->root, 0, 0, &x, &y, &cr);
1724 /* fprintf( stderr, "origin is %+d%+d\n", x, y);*/
1725 }
1726
1727 Pixmap
1728 rxvt_term::get_pixmap_property (int prop_id)
1729 {
1730 if (prop_id > 0 && prop_id < NUM_XA)
1731 if (xa[prop_id])
1732 {
1733 int aformat;
1734 unsigned long nitems, bytes_after;
1735 Atom atype;
1736 unsigned char *prop = NULL;
1737 int result = XGetWindowProperty (dpy, display->root, xa[prop_id],
1738 0L, 1L, False, XA_PIXMAP, &atype, &aformat,
1739 &nitems, &bytes_after, &prop);
1740 if (result == Success && prop && atype == XA_PIXMAP)
1741 {
1742 return *(Pixmap *)prop;
1743 }
1744 }
1745 return None;
1746 }
1747
1748 #ifdef HAVE_BG_PIXMAP
1749 # if TRACE_PIXMAPS
1750 # undef update_background
1751 int rxvt_term::trace_update_background (const char* file, int line)
1752 {
1753 fprintf (stderr, "%s:%d:update_background()\n", file, line);
1754 update_background ();
1755 }
1756 # endif
1757 int
1758 rxvt_term::update_background ()
1759 {
1760 bgPixmap.invalidate ();
1761
1762 /* no chance of real time refresh if we are blurring! */
1763 if (bgPixmap.invalid_since + 0.5 < ev::now () && !(bgPixmap.flags & bgPixmap_t::blurNeeded))
1764 bgPixmap.render ();
1765 else
1766 {
1767 update_background_ev.stop ();
1768
1769 if (!bgPixmap.need_client_side_rendering())
1770 update_background_ev.start (.05);
1771 else if (bgPixmap.flags & bgPixmap_t::blurNeeded)
1772 update_background_ev.start (.20); /* very slow !!! */
1773 else
1774 update_background_ev.start (.07);
1775 }
1776
1777 return 0;
1778 }
1779
1780 void
1781 rxvt_term::update_background_cb (ev::timer &w, int revents)
1782 {
1783 bgPixmap.render ();
1784 }
1785
1786 #endif /* HAVE_BG_PIXMAP */
1787
1788 /*----------------------- end-of-file (C source) -----------------------*/