ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/main.C
Revision: 1.233
Committed: Fri Jun 8 20:04:12 2007 UTC (16 years, 11 months ago) by sasha
Content type: text/plain
Branch: MAIN
Changes since 1.232: +1 -0 lines
Log Message:
added preliminary support to use libAfterImage for background pixmap loading and rendering of transparency effects including blending of pixmap over background using several methods, and gaussian blurr of the transparency background

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