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

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

File Contents

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