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

File Contents

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