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

# User Rev Content
1 root 1.224 /*----------------------------------------------------------------------*
2 pcg 1.66 * File: main.C
3 pcg 1.1 *----------------------------------------------------------------------*
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 pcg 1.3 * - original version
8 pcg 1.1 * Copyright (c) 1994 Robert Nation <nation@rocket.sanders.lockheed.com>
9 pcg 1.3 * - extensive modifications
10 pcg 1.1 * Copyright (c) 1995 Garrett D'Amore <garrett@netcom.com>
11     * Copyright (c) 1997 mj olesen <olesen@me.QueensU.CA>
12 pcg 1.3 * - extensive modifications
13 pcg 1.1 * Copyright (c) 1997,1998 Oezguer Kesim <kesim@math.fu-berlin.de>
14     * Copyright (c) 1998-2001 Geoff Wing <gcw@pobox.com>
15 pcg 1.3 * - extensive modifications
16 root 1.164 * Copyright (c) 2003-2006 Marc Lehmann <pcg@goof.com>
17 pcg 1.1 *
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 pcg 1.3 #include "../config.h" /* NECESSARY */
34     #include "rxvt.h" /* NECESSARY */
35 root 1.155 #include "keyboard.h"
36     #include "rxvtperl.h"
37 pcg 1.1
38 root 1.151 #include <limits>
39    
40 root 1.123 #include <csignal>
41 root 1.128 #include <cstring>
42 pcg 1.1
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 pcg 1.65 vector<rxvt_term *> rxvt_term::termlist;
52    
53 root 1.191 // used to tell global functions which terminal instance is "active"
54     rxvt_t rxvt_current_term;
55    
56 root 1.156 static char curlocale[128], savelocale[128];
57 pcg 1.15
58 pcg 1.65 bool
59 root 1.191 rxvt_set_locale (const char *locale) NOTHROW
60 pcg 1.15 {
61 root 1.228 int size = strlen (locale) + 1;
62 root 1.227
63 root 1.228 if (size > sizeof (curlocale))
64 root 1.227 rxvt_fatal ("locale string too long, aborting.\n");
65    
66 root 1.228 if (!locale || !memcmp (locale, curlocale, size))
67 pcg 1.65 return false;
68    
69 root 1.228 memcpy (curlocale, locale, size);
70 pcg 1.65 setlocale (LC_CTYPE, curlocale);
71     return true;
72 pcg 1.15 }
73    
74 root 1.169 void
75 root 1.191 rxvt_push_locale (const char *locale) NOTHROW
76 root 1.156 {
77     strcpy (savelocale, curlocale);
78     rxvt_set_locale (locale);
79     }
80    
81     void
82 root 1.191 rxvt_pop_locale () NOTHROW
83 root 1.156 {
84     rxvt_set_locale (savelocale);
85     }
86    
87 pcg 1.53 #if ENABLE_COMBINING
88 pcg 1.51 class rxvt_composite_vec rxvt_composite;
89    
90 pcg 1.54 text_t rxvt_composite_vec::compose (unicode_t c1, unicode_t c2)
91 pcg 1.51 {
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 pcg 1.54 int rxvt_composite_vec::expand (unicode_t c, wchar_t *r)
127 pcg 1.51 {
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 pcg 1.53 #endif
150 pcg 1.51
151 pcg 1.4 rxvt_term::rxvt_term ()
152 pcg 1.26 :
153 root 1.226 #if TRANSPARENT || ENABLE_PERL
154 pcg 1.27 rootwin_ev (this, &rxvt_term::rootwin_cb),
155 sasha 1.233 check_our_aprents_ev(this, &rxvt_term::check_our_parents_cb),
156 root 1.80 #endif
157 pcg 1.27 #ifdef HAVE_SCROLLBARS
158     scrollbar_ev (this, &rxvt_term::x_cb),
159     #endif
160 pcg 1.5 #ifdef CURSOR_BLINK
161 pcg 1.26 cursor_blink_ev (this, &rxvt_term::cursor_blink_cb),
162 pcg 1.21 #endif
163     #ifdef TEXT_BLINK
164 pcg 1.26 text_blink_ev (this, &rxvt_term::text_blink_cb),
165 pcg 1.5 #endif
166 root 1.70 #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 pcg 1.6 #ifdef POINTER_BLANK
176 pcg 1.26 pointer_ev (this, &rxvt_term::pointer_cb),
177 pcg 1.6 #endif
178 pcg 1.35 #ifdef USE_XIM
179     im_ev (this, &rxvt_term::im_cb),
180     #endif
181 root 1.193 #ifndef NO_BELL
182     bell_ev (this, &rxvt_term::bell_cb),
183     #endif
184 root 1.80 termwin_ev (this, &rxvt_term::x_cb),
185     vt_ev (this, &rxvt_term::x_cb),
186 root 1.189 child_ev (this, &rxvt_term::child_cb),
187 pcg 1.26 check_ev (this, &rxvt_term::check_cb),
188 root 1.76 flush_ev (this, &rxvt_term::flush_cb),
189 pcg 1.26 destroy_ev (this, &rxvt_term::destroy_cb),
190     pty_ev (this, &rxvt_term::pty_cb),
191 pcg 1.35 incr_ev (this, &rxvt_term::incr_cb)
192 pcg 1.4 {
193     cmdbuf_ptr = cmdbuf_endp = cmdbuf_base;
194 pcg 1.65
195     termlist.push_back (this);
196 root 1.128
197     #ifdef KEYSYM_RESOURCE
198     keyboard = new keyboard_manager;
199     #endif
200 pcg 1.4 }
201    
202 root 1.134 // 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 pcg 1.4 {
206 root 1.94 if (cmd_pid)
207     kill (-cmd_pid, SIGHUP);
208    
209 root 1.223 pty_ev.stop ();
210 root 1.184 delete pty; pty = 0;
211 root 1.134 }
212    
213     rxvt_term::~rxvt_term ()
214     {
215     termlist.erase (find (termlist.begin (), termlist.end(), this));
216    
217     emergency_cleanup ();
218 root 1.132
219 root 1.108 #if ENABLE_STYLES
220     for (int i = RS_styleCount; --i; )
221 root 1.149 if (fontset[i] != fontset[0])
222     delete fontset[i];
223 root 1.108 #endif
224 root 1.149 delete fontset[0];
225 pcg 1.34
226     if (display)
227 pcg 1.44 {
228 pcg 1.60 selection_clear ();
229    
230 root 1.77 #ifdef USE_XIM
231     im_destroy ();
232     #endif
233 pcg 1.60 #ifdef XTERM_SCROLLBAR
234 root 1.218 if (xscrollbarGC) XFreeGC (dpy, xscrollbarGC);
235     if (ShadowGC) XFreeGC (dpy, ShadowGC);
236 pcg 1.60 #endif
237     #ifdef PLAIN_SCROLLBAR
238 root 1.218 if (pscrollbarGC) XFreeGC (dpy, pscrollbarGC);
239 pcg 1.60 #endif
240     #ifdef NEXT_SCROLLBAR
241 root 1.218 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 pcg 1.60 #endif
252 root 1.180 #ifdef RXVT_SCROLLBAR
253 root 1.218 if (topShadowGC) XFreeGC (dpy, topShadowGC);
254     if (botShadowGC) XFreeGC (dpy, botShadowGC);
255     if (scrollbarGC) XFreeGC (dpy, scrollbarGC);
256 pcg 1.60 #endif
257 root 1.218 if (gc) XFreeGC (dpy, gc);
258 pcg 1.60
259 root 1.149 delete drawable;
260 pcg 1.45 // destroy all windows
261 root 1.149 if (parent[0])
262 root 1.218 XDestroyWindow (dpy, parent[0]);
263 root 1.206
264 root 1.216 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 root 1.206 clear ();
274 pcg 1.44 }
275 pcg 1.34
276 root 1.229 delete [] pix_colors_focused;
277 root 1.145 #if OFF_FOCUS_FADING
278 root 1.229 delete [] pix_colors_unfocused;
279 root 1.73 #endif
280 pcg 1.27
281 pcg 1.29 displays.put (display);
282 pcg 1.33
283 pcg 1.34 scr_release ();
284    
285 pcg 1.60 /* clear all resources */
286     for (int i = 0; i < allocated.size (); i++)
287 root 1.134 free (allocated [i]);
288 pcg 1.60
289     free (selection.text);
290     // TODO: manage env vars in child only(!)
291 pcg 1.34 free (env_display);
292     free (env_term);
293     free (locale);
294 root 1.120 free (v_buffer);
295 root 1.119 free (incr_buf);
296 pcg 1.34
297 pcg 1.33 delete envv;
298     delete argv;
299 root 1.128
300     #ifdef KEYSYM_RESOURCE
301 root 1.134 delete keyboard;
302 root 1.128 #endif
303 pcg 1.4 }
304    
305 root 1.189 // child has exited, usually destroys
306 pcg 1.8 void
307 root 1.189 rxvt_term::child_cb (child_watcher &w, int status)
308 root 1.152 {
309 root 1.189 HOOK_INVOKE ((this, HOOK_CHILD_EXIT, DT_INT, status, DT_END));
310    
311 root 1.152 cmd_pid = 0;
312    
313 root 1.232 if (!option (Opt_hold))
314 root 1.152 destroy ();
315     }
316    
317     void
318 pcg 1.8 rxvt_term::destroy ()
319     {
320 root 1.77 if (destroy_ev.active)
321     return;
322    
323 root 1.200 HOOK_INVOKE ((this, HOOK_DESTROY, DT_END));
324 root 1.191
325 root 1.94 #if ENABLE_OVERLAY
326     scr_overlay_off ();
327     #endif
328    
329 pcg 1.27 if (display)
330     {
331 root 1.80 #if USE_XIM
332 pcg 1.29 im_ev.stop (display);
333     #endif
334 root 1.80 #if HAVE_SCROLLBARS
335 pcg 1.27 scrollbar_ev.stop (display);
336     #endif
337 root 1.226 #if TRANSPARENT || ENABLE_PERL
338 root 1.77 rootwin_ev.stop (display);
339 root 1.80 #endif
340     incr_ev.stop ();
341 root 1.77 termwin_ev.stop (display);
342     vt_ev.stop (display);
343 pcg 1.27 }
344    
345 pcg 1.9 check_ev.stop ();
346 pcg 1.8 pty_ev.stop ();
347     #ifdef CURSOR_BLINK
348 pcg 1.21 cursor_blink_ev.stop ();
349     #endif
350     #ifdef TEXT_BLINK
351     text_blink_ev.stop ();
352 pcg 1.8 #endif
353 root 1.70 #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 pcg 1.8 #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 root 1.177 make_current ();
370 pcg 1.8
371     delete this;
372     }
373    
374 pcg 1.1 /*----------------------------------------------------------------------*/
375 root 1.134 /*
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 root 1.209 #if !ENABLE_MINIMAL
389 root 1.135 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 root 1.134 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 root 1.146 // GET_R is most likely not the terminal which caused the error,
445     // so just output the error and continue
446 root 1.209 #if ENABLE_MINIMAL
447     old_xerror_handler (display, event);
448     #else
449 root 1.135 print_x_error (display, event);
450     #endif
451 root 1.134 }
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 pcg 1.60 bool
467 root 1.194 rxvt_term::init (int argc, const char *const *argv, stringvec *envv)
468 pcg 1.1 {
469 root 1.194 this->envv = envv;
470    
471 pcg 1.60 SET_R (this);
472 root 1.177 set_locale ("");
473 root 1.176 set_environ (envv); // few things in X do not call setlocale :(
474 pcg 1.1
475 root 1.175 if (!init_vars ())
476     return false;
477 pcg 1.8
478 root 1.175 init_secondary ();
479 pcg 1.1
480 root 1.175 const char **cmd_argv = init_resources (argc, argv);
481 pcg 1.3
482 root 1.128 #ifdef KEYSYM_RESOURCE
483 root 1.175 keyboard->register_done ();
484 root 1.128 #endif
485 pcg 1.16
486 root 1.190 #ifdef HAVE_SCROLLBARS
487 root 1.232 if (option (Opt_scrollBar))
488 root 1.190 scrollBar.setIdle (); /* set existence for size calculations */
489     #endif
490    
491 root 1.196 pty = ptytty::create ();
492 root 1.184
493 root 1.175 create_windows (argc, argv);
494 pcg 1.1
495 root 1.175 init_xlocale ();
496 pcg 1.1
497 root 1.175 scr_reset (); // initialize screen
498 pcg 1.1
499 root 1.117 #if 0
500 root 1.218 XSynchronize (dpy, True);
501 pcg 1.1 #endif
502    
503     #ifdef HAVE_SCROLLBARS
504 root 1.232 if (option (Opt_scrollBar))
505 root 1.175 resize_scrollbar (); /* create and map scrollbar */
506 pcg 1.1 #endif
507     #ifdef TRANSPARENT
508 root 1.232 if (option (Opt_transparent))
509 root 1.175 {
510 root 1.218 XSelectInput (dpy, display->root, PropertyChangeMask);
511 root 1.175 check_our_parents ();
512     rootwin_ev.start (display, display->root);
513     }
514 pcg 1.1 #endif
515 root 1.226 #if ENABLE_PERL
516     rootwin_ev.start (display, display->root);
517     #endif
518 pcg 1.28
519 root 1.175 set_colorfgbg ();
520 root 1.108
521 root 1.175 init_command (cmd_argv);
522 pcg 1.1
523 root 1.175 free (cmd_argv);
524 root 1.128
525 root 1.184 if (pty->pty >= 0)
526     pty_ev.start (pty->pty, EVENT_READ);
527 pcg 1.7
528 root 1.175 check_ev.start ();
529 pcg 1.10
530 root 1.175 HOOK_INVOKE ((this, HOOK_START, DT_END));
531 root 1.155
532 root 1.203 #if ENABLE_XEMBED
533     if (rs[Rs_embed])
534     {
535     long info[2] = { 0, XEMBED_MAPPED };
536    
537 root 1.218 XChangeProperty (dpy, parent[0], xa[XA_XEMBED_INFO], xa[XA_XEMBED_INFO],
538 root 1.203 32, PropModeReplace, (unsigned char *)&info, 2);
539     }
540     #endif
541    
542 root 1.218 XMapWindow (dpy, vt);
543     XMapWindow (dpy, parent[0]);
544 root 1.191
545 pcg 1.4 return true;
546 pcg 1.1 }
547    
548 root 1.148 static struct sig_handlers
549     {
550 root 1.189 sig_watcher sw_term, sw_int;
551 root 1.148
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 root 1.189 : sw_term (this, &sig_handlers::sig_term),
565 root 1.148 sw_int (this, &sig_handlers::sig_term)
566     {
567     }
568     } sig_handlers;
569    
570 root 1.175 char **rxvt_environ; // startup environment
571    
572 pcg 1.60 void
573 root 1.94 rxvt_init ()
574 pcg 1.60 {
575 root 1.196 ptytty::init ();
576 root 1.186
577 root 1.175 rxvt_environ = environ;
578    
579 root 1.114 signal (SIGHUP, SIG_IGN);
580     signal (SIGPIPE, SIG_IGN);
581 pcg 1.60
582 root 1.148 sig_handlers.sw_term.start (SIGTERM);
583     sig_handlers.sw_int.start (SIGINT);
584    
585 pcg 1.60 /* need to trap SIGURG for SVR4 (Unixware) rlogin */
586     /* signal (SIGURG, SIG_DFL); */
587    
588     old_xerror_handler = XSetErrorHandler ((XErrorHandler) rxvt_xerror_handler);
589 root 1.114 // TODO: handle this with exceptions and tolerate the memory loss
590 root 1.134 XSetIOErrorHandler (rxvt_xioerror_handler);
591 root 1.166
592     XrmInitialize ();
593 pcg 1.60 }
594    
595 pcg 1.1 /* ------------------------------------------------------------------------- *
596     * MEMORY ALLOCATION WRAPPERS *
597     * ------------------------------------------------------------------------- */
598 root 1.114 void *
599 pcg 1.32 rxvt_malloc (size_t size)
600 pcg 1.1 {
601 root 1.114 void *p = malloc (size);
602 pcg 1.1
603 root 1.114 if (!p)
604     rxvt_fatal ("memory allocation failure. aborting.\n");
605 pcg 1.26
606 root 1.114 return p;
607 pcg 1.1 }
608    
609 root 1.148 void *
610 pcg 1.32 rxvt_calloc (size_t number, size_t size)
611 pcg 1.1 {
612 root 1.114 void *p = calloc (number, size);
613 pcg 1.3
614 root 1.114 if (!p)
615     rxvt_fatal ("memory allocation failure. aborting.\n");
616 pcg 1.26
617 root 1.114 return p;
618 pcg 1.1 }
619    
620 root 1.191 void *
621 pcg 1.32 rxvt_realloc (void *ptr, size_t size)
622 pcg 1.1 {
623 root 1.114 void *p = realloc (ptr, size);
624 pcg 1.26
625 root 1.114 if (!p)
626     rxvt_fatal ("memory allocation failure. aborting.\n");
627 pcg 1.1
628 root 1.114 return p;
629 pcg 1.1 }
630 pcg 1.3
631 pcg 1.1 /*----------------------------------------------------------------------*/
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 root 1.149 rxvt_term::window_calc (unsigned int newwidth, unsigned int newheight)
638 pcg 1.1 {
639 root 1.134 short recalc_x, recalc_y;
640 root 1.180 int x, y, sb_w, flags;
641 root 1.134 unsigned int w, h;
642     unsigned int max_width, max_height;
643 pcg 1.26
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 root 1.149
651 pcg 1.26 if (!parsed_geometry)
652     {
653     parsed_geometry = 1;
654 root 1.149
655 pcg 1.26 if (rs[Rs_geometry])
656 pcg 1.32 flags = XParseGeometry (rs[Rs_geometry], &x, &y, &w, &h);
657 root 1.136
658 pcg 1.26 if (flags & WidthValue)
659     {
660 root 1.151 ncol = clamp (w, 0, std::numeric_limits<int16_t>::max ());
661 pcg 1.26 szHint.flags |= USSize;
662 pcg 1.3 }
663 root 1.136
664 pcg 1.26 if (flags & HeightValue)
665     {
666 root 1.151 nrow = clamp (h, 0, std::numeric_limits<int16_t>::max ());
667 pcg 1.26 szHint.flags |= USSize;
668 pcg 1.3 }
669 root 1.136
670 pcg 1.26 if (flags & XValue)
671     {
672     szHint.x = x;
673     szHint.flags |= USPosition;
674 root 1.149
675 pcg 1.26 if (flags & XNegative)
676     {
677     recalc_x = 1;
678     szHint.win_gravity = NorthEastGravity;
679 pcg 1.3 }
680     }
681 root 1.136
682 pcg 1.26 if (flags & YValue)
683     {
684     szHint.y = y;
685     szHint.flags |= USPosition;
686 root 1.149
687 pcg 1.26 if (flags & YNegative)
688     {
689     recalc_y = 1;
690 root 1.149
691 pcg 1.26 if (szHint.win_gravity == NorthEastGravity)
692     szHint.win_gravity = SouthEastGravity;
693     else
694     szHint.win_gravity = SouthWestGravity;
695 pcg 1.3 }
696     }
697 pcg 1.1 }
698 pcg 1.53
699 pcg 1.26 /* TODO: BOUNDS */
700 root 1.149 width = ncol * fwidth;
701     height = nrow * fheight;
702     max_width = MAX_COLS * fwidth;
703     max_height = MAX_ROWS * fheight;
704 pcg 1.26
705 root 1.149 szHint.base_width = szHint.base_height = 2 * int_bwidth;
706 pcg 1.26
707 root 1.180 sb_w = 0;
708 root 1.149 window_vt_x = window_vt_y = int_bwidth;
709 pcg 1.67
710 root 1.180 if (scrollBar.state)
711 pcg 1.26 {
712 pcg 1.32 sb_w = scrollbar_TotalWidth ();
713 pcg 1.26 szHint.base_width += sb_w;
714 root 1.213
715 root 1.232 if (!option (Opt_scrollBar_right))
716 root 1.70 window_vt_x += sb_w;
717 pcg 1.26 }
718 pcg 1.67
719 root 1.219 szHint.width_inc = fwidth;
720 root 1.149 szHint.height_inc = fheight;
721 root 1.219 szHint.min_width = szHint.base_width + szHint.width_inc;
722 pcg 1.26 szHint.min_height = szHint.base_height + szHint.height_inc;
723    
724 root 1.149 if (newwidth && newwidth - szHint.base_width < max_width)
725 pcg 1.26 {
726 root 1.149 szHint.width = newwidth;
727     width = newwidth - szHint.base_width;
728 pcg 1.26 }
729     else
730     {
731 root 1.150 min_it (width, max_width);
732 root 1.149 szHint.width = szHint.base_width + width;
733 pcg 1.26 }
734 pcg 1.67
735 root 1.149 if (newheight && newheight - szHint.base_height < max_height)
736 pcg 1.26 {
737 root 1.149 szHint.height = newheight;
738     height = newheight - szHint.base_height;
739 pcg 1.26 }
740     else
741     {
742 root 1.150 min_it (height, max_height);
743 root 1.149 szHint.height = szHint.base_height + height;
744 pcg 1.26 }
745 pcg 1.67
746 root 1.232 if (scrollBar.state && option (Opt_scrollBar_right))
747 pcg 1.26 window_sb_x = szHint.width - sb_w;
748    
749     if (recalc_x)
750 root 1.218 szHint.x += DisplayWidth (dpy, display->screen) - szHint.width - 2 * ext_bwidth;
751 root 1.206
752 pcg 1.26 if (recalc_y)
753 root 1.218 szHint.y += DisplayHeight (dpy, display->screen) - szHint.height - 2 * ext_bwidth;
754 pcg 1.26
755 root 1.149 ncol = width / fwidth;
756     nrow = height / fheight;
757 pcg 1.1 }
758    
759     /*----------------------------------------------------------------------*/
760     /*
761     * Tell the teletype handler what size the window is.
762     * Called after a window size change.
763     */
764     void
765 pcg 1.9 rxvt_term::tt_winch ()
766 pcg 1.1 {
767 root 1.184 if (pty->pty < 0)
768 root 1.94 return;
769    
770 pcg 1.20 struct winsize ws;
771 pcg 1.9
772 root 1.149 ws.ws_col = ncol;
773     ws.ws_row = nrow;
774     ws.ws_xpixel = width;
775     ws.ws_ypixel = height;
776 root 1.184 (void)ioctl (pty->pty, TIOCSWINSZ, &ws);
777 root 1.94
778     #if 0
779     // TIOCSWINSZ⎈ is supposed to do this automatically and correctly
780     if (cmd_pid) /* force through to the command */
781 root 1.140 kill (-cmd_pid, SIGWINCH);
782 pcg 1.1 #endif
783     }
784    
785     /*----------------------------------------------------------------------*/
786 root 1.108 /* set_fonts () - load and set the various fonts
787 root 1.147 *
788 pcg 1.1 * init = 1 - initialize
789     *
790     * fontname == FONT_UP - switch to bigger font
791     * fontname == FONT_DN - switch to smaller font
792     */
793 pcg 1.41 bool
794 root 1.108 rxvt_term::set_fonts ()
795 pcg 1.41 {
796 root 1.108 rxvt_fontset *fs = new rxvt_fontset (this);
797     rxvt_fontprop prop;
798    
799     if (!fs
800 root 1.114 || !fs->populate (rs[Rs_font] ? rs[Rs_font] : "fixed")
801 root 1.108 || !fs->realize_font (1))
802 pcg 1.41 {
803 root 1.108 delete fs;
804     return false;
805 pcg 1.41 }
806 root 1.108
807     #if ENABLE_STYLES
808     for (int i = RS_styleCount; --i; )
809 root 1.149 if (fontset[i] != fontset[0])
810     delete fontset[i];
811 root 1.108 #endif
812    
813 root 1.149 delete fontset[0];
814     fontset[0] = fs;
815 root 1.108
816 root 1.114 prop = (*fs)[1]->properties ();
817 root 1.149 prop.height += lineSpace;
818 root 1.230
819     fs->set_prop (prop, false);
820 root 1.108
821 root 1.149 fwidth = prop.width;
822     fheight = prop.height;
823 root 1.158 fbase = prop.ascent;
824 root 1.108
825     for (int style = 1; style < 4; style++)
826 pcg 1.41 {
827 root 1.108 #if ENABLE_STYLES
828     const char *res = rs[Rs_font + style];
829 pcg 1.41
830 root 1.108 if (res && !*res)
831 root 1.149 fontset[style] = fontset[0];
832 root 1.108 else
833 pcg 1.41 {
834 root 1.149 fontset[style] = fs = new rxvt_fontset (this);
835 root 1.108 rxvt_fontprop prop2 = prop;
836 pcg 1.41
837 root 1.108 if (res)
838 root 1.231 {
839     fs->populate (res);
840     fs->set_prop (prop2, false);
841     }
842 root 1.108 else
843 pcg 1.42 {
844 root 1.231 fs->populate (fontset[0]->fontdesc);
845 pcg 1.42
846 root 1.108 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 root 1.231
849     fs->set_prop (prop2, true);
850 root 1.108 }
851 root 1.76
852 pcg 1.41 }
853 root 1.108 #else
854 root 1.149 fontset[style] = fontset[0];
855 root 1.108 #endif
856 pcg 1.41 }
857    
858 root 1.149 if (parent[0])
859 root 1.108 {
860     resize_all_windows (0, 0, 0);
861     scr_remap_chars ();
862     scr_touch (true);
863     }
864 pcg 1.1
865 root 1.108 return true;
866 pcg 1.41 }
867 pcg 1.1
868 root 1.118 void rxvt_term::set_string_property (Atom prop, const char *str, int len)
869     {
870 root 1.218 XChangeProperty (dpy, parent[0],
871 root 1.118 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 root 1.218 XChangeProperty (dpy, parent[0],
881 root 1.118 prop, xa[XA_UTF8_STRING], 8, PropModeReplace,
882     (const unsigned char *)s, strlen (s));
883    
884     free (s);
885     free (ws);
886     }
887    
888 pcg 1.1 /*----------------------------------------------------------------------*/
889     /*----------------------------------------------------------------------*/
890     /* xterm sequences - title, iconName, color (exptl) */
891     void
892 pcg 1.22 rxvt_term::set_title (const char *str)
893 pcg 1.1 {
894 root 1.118 set_string_property (XA_WM_NAME, str);
895 root 1.144 #if ENABLE_EWMH
896 root 1.121 set_utf8_property (xa[XA_NET_WM_NAME], str);
897 pcg 1.1 #endif
898     }
899    
900     void
901 pcg 1.60 rxvt_term::set_icon_name (const char *str)
902 pcg 1.1 {
903 root 1.118 set_string_property (XA_WM_ICON_NAME, str);
904 root 1.144 #if ENABLE_EWMH
905 root 1.121 set_utf8_property (xa[XA_NET_WM_ICON_NAME], str);
906 pcg 1.1 #endif
907     }
908    
909     #ifdef XTERM_COLOR_CHANGE
910     void
911 pcg 1.22 rxvt_term::set_window_color (int idx, const char *color)
912 pcg 1.1 {
913 pcg 1.46 rxvt_color xcol;
914     int i;
915 root 1.212
916 pcg 1.26 if (color == NULL || *color == '\0')
917     return;
918 pcg 1.1
919 root 1.212 color = strdup (color);
920     allocated.push_back ((void *)color);
921     rs[Rs_color + idx] = color;
922    
923 pcg 1.26 /* handle color aliases */
924 pcg 1.32 if (isdigit (*color))
925 pcg 1.26 {
926 pcg 1.32 i = atoi (color);
927 root 1.134
928 pcg 1.26 if (i >= 8 && i <= 15)
929     { /* bright colors */
930     i -= 8;
931 root 1.94 pix_colors_focused[idx] = pix_colors_focused[minBrightCOLOR + i];
932 root 1.145 goto done;
933 root 1.134 }
934 pcg 1.26
935     if (i >= 0 && i <= 7)
936     { /* normal colors */
937 root 1.94 pix_colors_focused[idx] = pix_colors_focused[minCOLOR + i];
938 root 1.145 goto done;
939 pcg 1.3 }
940 pcg 1.1 }
941 pcg 1.65
942 root 1.212 set_color (xcol, color);
943 pcg 1.1
944 pcg 1.26 /*
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 pcg 1.1
949 root 1.94 pix_colors_focused[idx] = xcol;
950 pcg 1.1
951 pcg 1.26 /* XSetWindowAttributes attr; */
952     /* Cursor cursor; */
953 root 1.145 done:
954 root 1.108 /*TODO: handle Color_BD, scrollbar background, etc. */
955 pcg 1.26
956 root 1.225 update_fade_color (idx);
957 pcg 1.26 recolour_cursor ();
958 root 1.108 scr_recolour ();
959 pcg 1.1 }
960    
961     #else
962 pcg 1.22 # define set_window_color (idx,color) ((void)0)
963 pcg 1.3 #endif /* XTERM_COLOR_CHANGE */
964 pcg 1.1
965     void
966 pcg 1.15 rxvt_term::recolour_cursor ()
967 pcg 1.1 {
968 root 1.215 XColor fg, bg;
969 pcg 1.1
970 root 1.215 (ISSET_PIXCOLOR (Color_pointer_fg)
971     ? pix_colors_focused[Color_pointer_fg]
972     : pix_colors_focused[Color_fg]).get (fg);
973 root 1.108
974 root 1.215 (ISSET_PIXCOLOR (Color_pointer_bg)
975     ? pix_colors_focused[Color_pointer_bg]
976     : pix_colors_focused[Color_bg]).get (bg);
977    
978 root 1.218 XRecolorCursor (dpy, TermWin_cursor, &fg, &bg);
979 pcg 1.1 }
980    
981     /*----------------------------------------------------------------------*/
982     /*
983     * find if fg/bg matches any of the normal (low-intensity) colors
984     */
985     void
986 pcg 1.22 rxvt_term::set_colorfgbg ()
987 pcg 1.1 {
988 root 1.108 unsigned int i;
989     const char *xpmb = "\0";
990     char fstr[sizeof ("default") + 1], bstr[sizeof ("default") + 1];
991 pcg 1.26
992 root 1.94 strcpy (fstr, "default");
993     strcpy (bstr, "default");
994 pcg 1.26 for (i = Color_Black; i <= Color_White; i++)
995 root 1.94 if (pix_colors[Color_fg] == pix_colors[i])
996 pcg 1.26 {
997 pcg 1.32 sprintf (fstr, "%d", (i - Color_Black));
998 pcg 1.26 break;
999     }
1000 root 1.108
1001 pcg 1.26 for (i = Color_Black; i <= Color_White; i++)
1002 root 1.94 if (pix_colors[Color_bg] == pix_colors[i])
1003 pcg 1.26 {
1004 pcg 1.32 sprintf (bstr, "%d", (i - Color_Black));
1005 pcg 1.1 #ifdef XPM_BACKGROUND
1006 pcg 1.26 xpmb = "default;";
1007 pcg 1.1 #endif
1008 pcg 1.26 break;
1009     }
1010 pcg 1.33
1011 pcg 1.32 sprintf (env_colorfgbg, "COLORFGBG=%s;%s%s", fstr, xpmb, bstr);
1012 pcg 1.1 }
1013    
1014     /*----------------------------------------------------------------------*/
1015    
1016 root 1.208 bool
1017     rxvt_term::set_color (rxvt_color &color, const char *name)
1018 pcg 1.1 {
1019 root 1.208 if (color.set (this, name))
1020     return true;
1021 pcg 1.1
1022 root 1.208 rxvt_warn ("can't get colour '%s', continuing without.\n", name);
1023     return false;
1024 pcg 1.1 }
1025    
1026 root 1.216 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 pcg 1.1 /* -------------------------------------------------------------------- *
1033     * - WINDOW RESIZING - *
1034     * -------------------------------------------------------------------- */
1035     void
1036 root 1.149 rxvt_term::resize_all_windows (unsigned int newwidth, unsigned int newheight, int ignoreparent)
1037 pcg 1.1 {
1038 pcg 1.17 int fix_screen;
1039 root 1.197 int old_width = szHint.width;
1040     int old_height = szHint.height;
1041 pcg 1.1
1042 root 1.149 window_calc (newwidth, newheight);
1043 root 1.219
1044     if (!HOOK_INVOKE ((this, HOOK_RESIZE_ALL_WINDOWS, DT_INT, newwidth, DT_INT, newheight, DT_END)))
1045     XSetWMNormalHints (dpy, parent[0], &szHint);
1046 pcg 1.67
1047 pcg 1.17 if (!ignoreparent)
1048     {
1049 pcg 1.3 #ifdef SMART_RESIZE
1050 pcg 1.17 /*
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 root 1.218 XTranslateCoordinates (dpy, parent[0], display->root,
1060 pcg 1.17 0, 0, &x, &y, &unused_cr);
1061 root 1.218 XGetGeometry (dpy, parent[0], &unused_cr, &x1, &y1,
1062 pcg 1.17 &unused_w1, &unused_h1, &unused_b1, &unused_d1);
1063     /*
1064 pcg 1.27 * if display->root isn't the parent window, a WM will probably have offset
1065 pcg 1.17 * our position for handles and decorations. Counter it
1066     */
1067 pcg 1.26 if (x1 != x || y1 != y)
1068     {
1069 pcg 1.17 x -= x1;
1070     y -= y1;
1071 pcg 1.26 }
1072 pcg 1.17
1073 root 1.218 x1 = (DisplayWidth (dpy, display->screen) - old_width ) / 2;
1074     y1 = (DisplayHeight (dpy, display->screen) - old_height) / 2;
1075 root 1.197 dx = old_width - szHint.width;
1076 pcg 1.17 dy = old_height - szHint.height;
1077    
1078 pcg 1.26 /* Check position of the center of the window */
1079 pcg 1.17 if (x < x1) /* left half */
1080 pcg 1.26 dx = 0;
1081 pcg 1.17 else if (x == x1) /* exact center */
1082 pcg 1.26 dx /= 2;
1083 pcg 1.17 if (y < y1) /* top half */
1084 pcg 1.26 dy = 0;
1085 pcg 1.17 else if (y == y1) /* exact center */
1086 pcg 1.26 dy /= 2;
1087 pcg 1.3
1088 root 1.218 XMoveResizeWindow (dpy, parent[0], x + dx, y + dy,
1089 pcg 1.17 szHint.width, szHint.height);
1090 pcg 1.1 #else
1091 root 1.218 XResizeWindow (dpy, parent[0], szHint.width, szHint.height);
1092 pcg 1.1 #endif
1093     }
1094    
1095 root 1.149 fix_screen = ncol != prev_ncol || nrow != prev_nrow;
1096 pcg 1.17
1097 root 1.149 if (fix_screen || newwidth != old_width || newheight != old_height)
1098 pcg 1.17 {
1099 root 1.180 if (scrollBar.state)
1100 pcg 1.17 {
1101 root 1.218 XMoveResizeWindow (dpy, scrollBar.win,
1102 pcg 1.67 window_sb_x, 0,
1103     scrollbar_TotalWidth (), szHint.height);
1104 pcg 1.17 resize_scrollbar ();
1105 pcg 1.3 }
1106 pcg 1.17
1107 root 1.218 XMoveResizeWindow (dpy, vt,
1108 pcg 1.67 window_vt_x, window_vt_y,
1109 root 1.159 width, height);
1110 root 1.132
1111 pcg 1.67 scr_clear ();
1112 pcg 1.1 #ifdef XPM_BACKGROUND
1113 pcg 1.22 resize_pixmap ();
1114 pcg 1.1 #endif
1115     }
1116    
1117 pcg 1.17 if (fix_screen || old_height == 0)
1118 root 1.197 scr_reset ();
1119 pcg 1.1
1120 root 1.217 // TODO, with nvidia-8178, resizes kill the alpha channel, report if not fixed in newer version
1121     //scr_touch (false);
1122    
1123 root 1.132 #ifdef XPM_BACKGROUND
1124 root 1.149 if (pixmap)
1125 root 1.132 scr_touch (false);
1126     #endif
1127    
1128 pcg 1.1 #ifdef USE_XIM
1129 root 1.220 IMSetPosition ();
1130 pcg 1.1 #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 root 1.149 rxvt_term::set_widthheight (unsigned int newwidth, unsigned int newheight)
1139 pcg 1.1 {
1140 pcg 1.26 XWindowAttributes wattr;
1141 pcg 1.1
1142 root 1.149 if (newwidth == 0 || newheight == 0)
1143 pcg 1.26 {
1144 root 1.218 XGetWindowAttributes (dpy, display->root, &wattr);
1145 root 1.142
1146 root 1.149 if (newwidth == 0)
1147     newwidth = wattr.width - szHint.base_width;
1148     if (newheight == 0)
1149     newheight = wattr.height - szHint.base_height;
1150 pcg 1.26 }
1151 root 1.80
1152 root 1.149 if (newwidth != width || newheight != height)
1153 pcg 1.26 {
1154 root 1.149 newwidth += szHint.base_width;
1155     newheight += szHint.base_height;
1156     resize_all_windows (newwidth, newheight, 0);
1157 pcg 1.1 }
1158     }
1159    
1160     /* -------------------------------------------------------------------- *
1161     * - X INPUT METHOD ROUTINES - *
1162     * -------------------------------------------------------------------- */
1163     #ifdef USE_XIM
1164 pcg 1.29
1165 pcg 1.1 void
1166 root 1.94 rxvt_term::im_set_color (unsigned long &fg, unsigned long &bg)
1167 pcg 1.1 {
1168 root 1.216 fg = pix_colors [Color_fg];
1169     bg = pix_colors [Color_bg];
1170 pcg 1.1 }
1171    
1172     void
1173 root 1.94 rxvt_term::im_set_size (XRectangle &size)
1174 pcg 1.1 {
1175 root 1.94 // the int_bwidth terms make no sense to me
1176 root 1.149 size.x = int_bwidth;
1177     size.y = int_bwidth;
1178     size.width = Width2Pixel (ncol) + int_bwidth;
1179     size.height = Height2Pixel (nrow) + int_bwidth;
1180 root 1.94 }
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 root 1.149 preedit_rect.width = Width2Pixel (ncol) - needed_rect.width + 1;
1190     preedit_rect.height = fheight;
1191 root 1.94
1192     status_rect.x = 0;
1193     status_rect.y = 0;
1194 root 1.149 status_rect.width = needed_rect.width ? needed_rect.width : Width2Pixel (ncol) + 1;
1195     status_rect.height = fheight;
1196 pcg 1.1 }
1197    
1198     /* Checking whether input method is running. */
1199 pcg 1.22 bool
1200     rxvt_term::IMisRunning ()
1201 pcg 1.1 {
1202 root 1.94 char *p;
1203     Atom atom;
1204     Window win;
1205     char server[IMBUFSIZ];
1206 pcg 1.26
1207     /* get current locale modifier */
1208 pcg 1.32 if ((p = XSetLocaleModifiers (NULL)) != NULL)
1209 pcg 1.26 {
1210 root 1.94 strcpy (server, "@server=");
1211     strncat (server, & (p[4]), IMBUFSIZ - 9); /* skip "@im=" */
1212    
1213     if ((p = strchr (server + 1, '@')) != NULL) /* first one only */
1214 pcg 1.26 *p = '\0';
1215    
1216 root 1.218 atom = XInternAtom (dpy, server, False);
1217     win = XGetSelectionOwner (dpy, atom);
1218 root 1.94
1219 pcg 1.26 if (win != None)
1220     return True;
1221 pcg 1.1 }
1222 root 1.94
1223 pcg 1.26 return False;
1224 pcg 1.1 }
1225    
1226     void
1227 pcg 1.22 rxvt_term::IMSendSpot ()
1228 pcg 1.1 {
1229 root 1.114 XPoint nspot;
1230 root 1.94 XVaNestedList preedit_attr;
1231 pcg 1.1
1232 root 1.94 if (!Input_Context
1233 root 1.149 || !focus
1234 root 1.202 || !(input_style & (XIMPreeditPosition | XIMPreeditCallbacks)))
1235 root 1.114 return;
1236    
1237     im_set_position (nspot);
1238    
1239     if (nspot.x == spot.x && nspot.y == spot.y)
1240 pcg 1.26 return;
1241 pcg 1.1
1242 root 1.114 spot = nspot;
1243 pcg 1.1
1244 pcg 1.32 preedit_attr = XVaCreateNestedList (0, XNSpotLocation, &spot, NULL);
1245     XSetICValues (Input_Context, XNPreeditAttributes, preedit_attr, NULL);
1246     XFree (preedit_attr);
1247 pcg 1.1 }
1248    
1249     void
1250 pcg 1.29 rxvt_term::im_destroy ()
1251     {
1252 root 1.114 if (input_method)
1253 pcg 1.29 {
1254 root 1.114 if (Input_Context && input_method->xim)
1255     XDestroyIC (Input_Context);
1256 pcg 1.29
1257     display->put_xim (input_method);
1258     input_method = 0;
1259     }
1260 root 1.114
1261     Input_Context = 0;
1262 pcg 1.1 }
1263    
1264 root 1.200 #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 root 1.201 #if 0
1324 root 1.200 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 root 1.201 #endif
1335 root 1.200
1336     #endif
1337    
1338 pcg 1.1 /*
1339     * Try to open a XIM with the current modifiers, then see if we can
1340     * open a suitable preedit type
1341     */
1342 pcg 1.22 bool
1343 pcg 1.29 rxvt_term::IM_get_IC (const char *modifiers)
1344 pcg 1.1 {
1345 root 1.94 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 root 1.200 #ifdef ENABLE_XIM_ONTHESPOT
1354     XIMCallback xcb[4];
1355     #endif
1356 pcg 1.29
1357 root 1.176 set_environ (envv);
1358 root 1.171
1359 pcg 1.32 if (! ((p = XSetLocaleModifiers (modifiers)) && *p))
1360 pcg 1.29 return false;
1361 pcg 1.26
1362 pcg 1.29 input_method = display->get_xim (locale, modifiers);
1363     if (input_method == NULL)
1364     return false;
1365    
1366     xim = input_method->xim;
1367 root 1.114 spot.x = spot.y = -1;
1368 pcg 1.26
1369     xim_styles = NULL;
1370     if (XGetIMValues (xim, XNQueryInputStyle, &xim_styles, NULL)
1371     || !xim_styles || !xim_styles->count_styles)
1372     {
1373 root 1.94 im_destroy ();
1374 pcg 1.29 return false;
1375 pcg 1.26 }
1376    
1377 root 1.116 const char *pet[] = { rs[Rs_preeditType], "OverTheSpot,OffTheSpot,Root,None" };
1378 root 1.94
1379 root 1.116 for (int pi = 0; pi < 2; pi++)
1380 pcg 1.26 {
1381 root 1.116 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 root 1.200 input_style = XIMPreeditPosition | XIMStatusNothing;
1392 root 1.116 else if (!strcmp (s[i], "OffTheSpot"))
1393 root 1.200 input_style = XIMPreeditArea | XIMStatusArea;
1394 root 1.116 else if (!strcmp (s[i], "Root"))
1395 root 1.200 input_style = XIMPreeditNothing | XIMStatusNothing;
1396 root 1.116 else if (!strcmp (s[i], "None"))
1397 root 1.200 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 root 1.116
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 pcg 1.26 }
1418 pcg 1.29
1419 root 1.116 foundpet:
1420 pcg 1.29
1421     XFree (xim_styles);
1422 pcg 1.26
1423     if (!found)
1424     {
1425 root 1.94 im_destroy ();
1426 pcg 1.29 return false;
1427 pcg 1.26 }
1428    
1429 root 1.94 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 root 1.149 fheight,
1448     fheight + 1, fheight - 1,
1449     fheight - 2, fheight + 2);
1450 root 1.94
1451 root 1.218 fs = XCreateFontSet (dpy, rs[Rs_imFont] ? rs[Rs_imFont] : pat,
1452 root 1.94 &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 pcg 1.26
1464     if (input_style & XIMPreeditPosition)
1465     {
1466 root 1.94 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 pcg 1.1 }
1478 pcg 1.26 else if (input_style & XIMPreeditArea)
1479     {
1480 root 1.94 im_set_color (fg, bg);
1481 pcg 1.26
1482     /*
1483     * The necessary width of preedit area is unknown
1484     * until create input context.
1485     */
1486     needed_rect.width = 0;
1487 root 1.94 im_set_preedit_area (rect, status_rect, needed_rect);
1488 pcg 1.26
1489 root 1.94 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 pcg 1.26 NULL);
1501     }
1502 root 1.205 #if ENABLE_XIM_ONTHESPOT
1503 root 1.200 else if (input_style & XIMPreeditCallbacks)
1504     {
1505 root 1.202 im_set_position (spot);
1506    
1507 root 1.200 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 root 1.205 # if 0
1511 root 1.200 xcb[3].client_data = (XPointer)this; xcb[3].callback = (XIMProc)xim_preedit_caret;
1512 root 1.205 # endif
1513 root 1.200
1514     preedit_attr = XVaCreateNestedList (0,
1515 root 1.202 XNSpotLocation, &spot,
1516 root 1.200 XNPreeditStartCallback, &xcb[0],
1517     XNPreeditDoneCallback , &xcb[1],
1518     XNPreeditDrawCallback , &xcb[2],
1519 root 1.205 # if 0
1520 root 1.200 XNPreeditCaretCallback, &xcb[3],
1521 root 1.205 # endif
1522 root 1.200 NULL);
1523     }
1524 root 1.205 #endif
1525 pcg 1.29
1526 root 1.94 Input_Context = XCreateIC (xim,
1527     XNInputStyle, input_style,
1528 root 1.149 XNClientWindow, vt,
1529     XNFocusWindow, parent[0],
1530 root 1.94 preedit_attr ? XNPreeditAttributes : NULL,
1531     preedit_attr,
1532     status_attr ? XNStatusAttributes : NULL,
1533     status_attr, NULL);
1534    
1535 pcg 1.32 if (preedit_attr) XFree (preedit_attr);
1536 root 1.220 if (status_attr) XFree (status_attr);
1537     if (fs) XFreeFontSet (dpy, fs);
1538 pcg 1.29
1539 pcg 1.26 if (Input_Context == NULL)
1540     {
1541 pcg 1.60 rxvt_warn ("failed to create input context, continuing without XIM.\n");
1542 root 1.94 im_destroy ();
1543 pcg 1.29 return false;
1544 pcg 1.26 }
1545 pcg 1.29
1546 root 1.200 #if 0
1547     // unfortunately, only the focus window is used by XIM, hard to fix
1548 root 1.198 if (!XGetICValues (Input_Context, XNFilterEvents, &vt_emask_xim, NULL))
1549     vt_select_input ();
1550 root 1.200 #endif
1551 root 1.198
1552 root 1.220 IMSetPosition ();
1553 pcg 1.29
1554     return true;
1555 pcg 1.16 }
1556    
1557     void
1558 pcg 1.29 rxvt_term::im_cb ()
1559 pcg 1.16 {
1560 root 1.147 int i;
1561 pcg 1.16 const char *p;
1562     char **s;
1563     char buf[IMBUFSIZ];
1564    
1565 root 1.177 make_current ();
1566 root 1.135
1567 pcg 1.29 im_destroy ();
1568    
1569     if (Input_Context)
1570 pcg 1.16 return;
1571    
1572     #if defined(HAVE_XSETLOCALE) || defined(HAVE_SETLOCALE)
1573 pcg 1.29 if (rs[Rs_imLocale])
1574 pcg 1.38 SET_LOCALE (rs[Rs_imLocale]);
1575 pcg 1.16 #endif
1576    
1577 pcg 1.29 p = rs[Rs_inputMethod];
1578 pcg 1.16 if (p && *p)
1579     {
1580     bool found = false;
1581    
1582     s = rxvt_splitcommastring (p);
1583 root 1.116
1584 pcg 1.16 for (i = 0; s[i]; i++)
1585     {
1586     if (*s[i])
1587     {
1588 root 1.94 strcpy (buf, "@im=");
1589     strncat (buf, s[i], IMBUFSIZ - 5);
1590 pcg 1.29 if (IM_get_IC (buf))
1591 pcg 1.16 {
1592     found = true;
1593     break;
1594     }
1595     }
1596     }
1597 root 1.116
1598     rxvt_freecommastring (s);
1599 pcg 1.16
1600     if (found)
1601     goto done;
1602     }
1603    
1604 pcg 1.26 /* try with XMODIFIERS env. var. */
1605 pcg 1.29 if (IM_get_IC (""))
1606 pcg 1.16 goto done;
1607    
1608 pcg 1.26 /* try with no modifiers base IF the user didn't specify an IM */
1609 pcg 1.29 if (IM_get_IC ("@im=none"))
1610 pcg 1.16 goto done;
1611    
1612     done:
1613     #if defined(HAVE_XSETLOCALE) || defined(HAVE_SETLOCALE)
1614 pcg 1.29 if (rs[Rs_imLocale])
1615 pcg 1.38 SET_LOCALE (locale);
1616 pcg 1.16 #endif
1617 pcg 1.1 }
1618    
1619     void
1620 root 1.220 rxvt_term::IMSetPosition ()
1621 pcg 1.1 {
1622 root 1.94 XRectangle preedit_rect, status_rect, *needed_rect;
1623     XVaNestedList preedit_attr, status_attr;
1624 pcg 1.1
1625 root 1.94 if (!Input_Context
1626 root 1.149 || !focus
1627 root 1.220 || !(input_style & (XIMPreeditArea | XIMPreeditPosition))
1628 pcg 1.26 || !IMisRunning ())
1629     return;
1630 pcg 1.1
1631 root 1.222 if (input_style & XIMPreeditPosition)
1632 root 1.221 {
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 pcg 1.1
1646 root 1.221 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 pcg 1.1 }
1662 pcg 1.3 #endif /* USE_XIM */
1663 pcg 1.1
1664     /*----------------------- end-of-file (C source) -----------------------*/