ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/main.C
Revision: 1.360
Committed: Fri Aug 19 16:01:37 2011 UTC (12 years, 9 months ago) by sf-exg
Content type: text/plain
Branch: MAIN
Changes since 1.359: +9 -0 lines
Log Message:
Force the size of the vt window to be a multiple of the cell size.

When the wm does not honour our size hints there are extra areas in the
vt window not covered by the terminal screen. Such gaps, when a bg
pixmap is set, would have to be cleared manually to properly refresh the
background. We take the simpler route and shrink the vt window so as to
avoid creating gaps.

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