1 /*--------------------------------*-C-*---------------------------------*
2 * File: main.c
3 *----------------------------------------------------------------------*
4 * $Id: main.c,v 1.172 2002/10/24 01:50:58 gcw Exp $
5 *
6 * All portions of code are copyright by their respective author/s.
7 * Copyright (c) 1992 John Bovey, University of Kent at Canterbury <jdb@ukc.ac.uk>
8 * - original version
9 * Copyright (c) 1994 Robert Nation <nation@rocket.sanders.lockheed.com>
10 * - extensive modifications
11 * Copyright (c) 1995 Garrett D'Amore <garrett@netcom.com>
12 * Copyright (c) 1997 mj olesen <olesen@me.QueensU.CA>
13 * - extensive modifications
14 * Copyright (c) 1997,1998 Oezguer Kesim <kesim@math.fu-berlin.de>
15 * Copyright (c) 1998-2001 Geoff Wing <gcw@pobox.com>
16 * - extensive modifications
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 *---------------------------------------------------------------------*/
32
33 #include "../config.h" /* NECESSARY */
34 #include "xvt.h" /* NECESSARY */
35 #include "main.intpro" /* PROTOS for internal routines */
36
37 #include <signal.h>
38
39 #ifdef TTY_GID_SUPPORT
40 # include <grp.h>
41 #endif
42
43 #ifdef HAVE_TERMIOS_H
44 # include <termios.h>
45 #endif
46
47 /*----------------------------------------------------------------------*/
48 /* xvt_init() */
49 /* LIBPROTO */
50 xvt_t *
xvt_init(int argc,const char * const * argv)51 xvt_init(int argc, const char *const *argv)
52 {
53 const char **cmd_argv;
54 xvt_t *r;
55
56 r = (xvt_t *)xvt_calloc(1, sizeof(xvt_t));
57 xvt_set_r(r); /* only assignment to _xvt_vars */
58 if (xvt_init_vars(r) < 0) {
59 free(r);
60 return NULL;
61 }
62
63 /*
64 * Save and then give up any super-user privileges
65 * If we need privileges in any area then we must specifically request it.
66 * We should only need to be root in these cases:
67 * 1. write utmp entries on some systems
68 * 2. chown tty on some systems
69 */
70 xvt_privileges(r, SAVE);
71 xvt_privileges(r, IGNORE);
72
73 xvt_init_secondary(r);
74
75 cmd_argv = xvt_init_resources(r, argc, argv);
76
77 #if (MENUBAR_MAX)
78 xvt_menubar_read(r, r->h->rs[Rs_menu]);
79 #endif
80 #ifdef HAVE_SCROLLBARS
81 if (r->Options & Opt_scrollBar)
82 scrollbar_setIdle(); /* set existence for size calculations */
83 #endif
84
85 xvt_Create_Windows(r, argc, argv);
86
87 xvt_init_xlocale(r);
88
89 xvt_scr_reset(r); /* initialize screen */
90 xvt_Gr_reset(r); /* reset graphics */
91
92 #ifdef DEBUG_X
93 XSynchronize(r->Xdisplay, True);
94 XSetErrorHandler((XErrorHandler) abort);
95 #else
96 XSetErrorHandler((XErrorHandler) xvt_xerror_handler);
97 #endif
98
99 #ifdef HAVE_SCROLLBARS
100 if (r->Options & Opt_scrollBar)
101 xvt_Resize_scrollBar(r); /* create and map scrollbar */
102 #endif
103 #if (MENUBAR_MAX)
104 if (menubar_visible(r))
105 XMapWindow(r->Xdisplay, r->menuBar.win);
106 #endif
107 #ifdef TRANSPARENT
108 if (r->Options & Opt_transparent) {
109 XSelectInput(r->Xdisplay, Xroot, PropertyChangeMask);
110 xvt_check_our_parents(r);
111 }
112 #endif
113 XMapWindow(r->Xdisplay, r->TermWin.vt);
114 XMapWindow(r->Xdisplay, r->TermWin.parent[0]);
115
116 xvt_init_env(r);
117 xvt_init_command(r, cmd_argv);
118 return r;
119 }
120
121 /* ------------------------------------------------------------------------- *
122 * SIGNAL HANDLING & EXIT HANDLER *
123 * ------------------------------------------------------------------------- */
124 /*
125 * Catch a SIGCHLD signal and exit if the direct child has died
126 */
127 /* ARGSUSED */
128 /* EXTPROTO */
129 RETSIGTYPE
xvt_Child_signal(int sig)130 xvt_Child_signal(int sig __attribute__((unused)))
131 {
132 int pid, save_errno = errno;
133 xvt_t *r;
134
135 do {
136 errno = 0;
137 } while ((pid = waitpid(-1, NULL, WNOHANG)) == -1 && errno == EINTR);
138
139 r = xvt_get_r();
140 if (pid == r->h->cmd_pid)
141 exit(EXIT_SUCCESS);
142
143 errno = save_errno;
144 signal(SIGCHLD, xvt_Child_signal);
145 }
146
147 /*
148 * Catch a fatal signal and tidy up before quitting
149 */
150 /* EXTPROTO */
151 RETSIGTYPE
xvt_Exit_signal(int sig)152 xvt_Exit_signal(int sig)
153 {
154 signal(sig, SIG_DFL);
155 #ifdef DEBUG_CMD
156 xvt_print_error("signal %d", sig);
157 #endif
158 xvt_clean_exit();
159 kill(getpid(), sig);
160 }
161
162 /* ARGSUSED */
163 /* INTPROTO */
164 int
xvt_xerror_handler(const Display * display,const XErrorEvent * event)165 xvt_xerror_handler(const Display *display __attribute__((unused)), const XErrorEvent *event)
166 {
167 xvt_t *r = xvt_get_r();
168
169 if (r->h->allowedxerror == -1) {
170 r->h->allowedxerror = event->error_code;
171 return 0; /* ignored anyway */
172 }
173 xvt_print_error("XError: Request: %d . %d, Error: %d",
174 event->request_code, event->minor_code,
175 event->error_code);
176 /* XXX: probably should call xvt_clean_exit() bypassing X routines */
177 exit(EXIT_FAILURE);
178 /* NOTREACHED */
179 }
180
181 /*----------------------------------------------------------------------*/
182 /*
183 * Exit gracefully, clearing the utmp entry and restoring tty attributes
184 * TODO: if debugging, this should free up any known resources if we can
185 */
186 /* EXTPROTO */
187 void
xvt_clean_exit(void)188 xvt_clean_exit(void)
189 {
190 xvt_t *r = xvt_get_r();
191
192 #ifdef DEBUG_SCREEN
193 xvt_scr_release(r);
194 #endif
195 xvt_privileged_ttydev(r, RESTORE);
196 xvt_privileged_utmp(r, RESTORE);
197 #ifdef USE_XIM
198 if (r->h->Input_Context != NULL) {
199 XDestroyIC(r->h->Input_Context);
200 r->h->Input_Context = NULL;
201 }
202 #endif
203 }
204
205 /* ------------------------------------------------------------------------- *
206 * MEMORY ALLOCATION WRAPPERS *
207 * ------------------------------------------------------------------------- */
208 /* EXTPROTO */
209 void *
xvt_malloc(size_t size)210 xvt_malloc(size_t size)
211 {
212 void *p;
213
214 p = malloc(size);
215 if (p)
216 return p;
217
218 fprintf(stderr, APL_NAME ": memory allocation failure. Aborting");
219 xvt_clean_exit();
220 exit(EXIT_FAILURE);
221 /* NOTREACHED */
222 }
223
224 /* EXTPROTO */
225 void *
xvt_calloc(size_t number,size_t size)226 xvt_calloc(size_t number, size_t size)
227 {
228 void *p;
229
230 p = calloc(number, size);
231 if (p)
232 return p;
233
234 fprintf(stderr, APL_NAME ": memory allocation failure. Aborting");
235 xvt_clean_exit();
236 exit(EXIT_FAILURE);
237 /* NOTREACHED */
238 }
239
240 /* EXTPROTO */
241 void *
xvt_realloc(void * ptr,size_t size)242 xvt_realloc(void *ptr, size_t size)
243 {
244 void *p;
245
246 if (ptr)
247 p = realloc(ptr, size);
248 else
249 p = malloc(size);
250 if (p)
251 return p;
252
253 fprintf(stderr, APL_NAME ": memory allocation failure. Aborting");
254 xvt_clean_exit();
255 exit(EXIT_FAILURE);
256 /* NOTREACHED */
257 }
258 /* ------------------------------------------------------------------------- *
259 * PRIVILEGED OPERATIONS *
260 * ------------------------------------------------------------------------- */
261 /* take care of suid/sgid super-user (root) privileges */
262 /* INTPROTO */
263 void
xvt_privileges(xvt_t * r,int mode)264 xvt_privileges(xvt_t *r, int mode)
265 {
266 #if ! defined(__CYGWIN32__)
267 # if !defined(HAVE_SETEUID) && defined(HAVE_SETREUID)
268 /* setreuid() is the poor man's setuid(), seteuid() */
269 # define seteuid(a) setreuid(-1, (a))
270 # define setegid(a) setregid(-1, (a))
271 # define HAVE_SETEUID
272 # endif
273 # ifdef HAVE_SETEUID
274 switch (mode) {
275 case IGNORE:
276 /*
277 * change effective uid/gid - not real uid/gid - so we can switch
278 * back to root later, as required
279 */
280 seteuid(getuid());
281 setegid(getgid());
282 break;
283 case SAVE:
284 r->h->euid = geteuid();
285 r->h->egid = getegid();
286 break;
287 case RESTORE:
288 seteuid(r->h->euid);
289 setegid(r->h->egid);
290 break;
291 }
292 # else
293 switch (mode) {
294 case IGNORE:
295 setuid(getuid());
296 setgid(getgid());
297 /* FALLTHROUGH */
298 case SAVE:
299 /* FALLTHROUGH */
300 case RESTORE:
301 break;
302 }
303 # endif
304 #endif
305 }
306
307 #ifdef UTMP_SUPPORT
308 /* EXTPROTO */
309 void
xvt_privileged_utmp(xvt_t * r,char action)310 xvt_privileged_utmp(xvt_t *r, char action)
311 {
312 struct xvt_hidden *h = r->h;
313
314 D_MAIN((stderr, "xvt_privileged_utmp(%c); waiting for: %c (pid: %d)", action, h->next_utmp_action, getpid()));
315 if (h->next_utmp_action != action
316 || (action != SAVE && action != RESTORE)
317 || (r->Options & Opt_utmpInhibit)
318 || h->ttydev == NULL
319 || *h->ttydev == '\0')
320 return;
321
322 xvt_privileges(r, RESTORE);
323 if (action == SAVE) {
324 h->next_utmp_action = RESTORE;
325 xvt_makeutent(r, h->ttydev, h->rs[Rs_display_name]);
326 } else { /* action == RESTORE */
327 h->next_utmp_action = IGNORE;
328 xvt_cleanutent(r);
329 }
330 xvt_privileges(r, IGNORE);
331 }
332 #endif
333
334 #ifndef NO_SETOWNER_TTYDEV
335 /* EXTPROTO */
336 void
xvt_privileged_ttydev(xvt_t * r,char action)337 xvt_privileged_ttydev(xvt_t *r, char action)
338 {
339 struct xvt_hidden *h = r->h;
340
341 D_MAIN((stderr, "xvt_privileged_ttydev(r, %c); waiting for: %c (pid: %d)", action, h->next_tty_action, getpid()));
342 if (h->next_tty_action != action
343 || (action != SAVE && action != RESTORE)
344 || h->ttydev == NULL
345 || *h->ttydev == '\0')
346 return;
347
348 xvt_privileges(r, RESTORE);
349
350 if (action == SAVE) {
351 h->next_tty_action = RESTORE;
352 # ifndef RESET_TTY_TO_COMMON_DEFAULTS
353 /* store original tty status for restoration xvt_clean_exit() -- rgg 04/12/95 */
354 if (lstat(h->ttydev, &h->ttyfd_stat) < 0) /* you lose out */
355 h->next_tty_action = IGNORE;
356 else
357 # endif
358 {
359 chown(h->ttydev, getuid(), h->ttygid); /* fail silently */
360 chmod(h->ttydev, h->ttymode);
361 # ifdef HAVE_REVOKE
362 revoke(h->ttydev);
363 # endif
364 }
365 } else { /* action == RESTORE */
366 h->next_tty_action = IGNORE;
367 # ifndef RESET_TTY_TO_COMMON_DEFAULTS
368 chmod(h->ttydev, h->ttyfd_stat.st_mode);
369 chown(h->ttydev, h->ttyfd_stat.st_uid, h->ttyfd_stat.st_gid);
370 # else
371 chmod(h->ttydev,
372 (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH));
373 chown(h->ttydev, 0, 0);
374 # endif
375 }
376
377 xvt_privileges(r, IGNORE);
378
379 # ifndef RESET_TTY_TO_COMMON_DEFAULTS
380 D_MAIN((stderr, "%s \"%s\": mode %03o, uid %d, gid %d", action == RESTORE ? "Restoring" : (action == SAVE ? "Saving" : "UNKNOWN ERROR for"), h->ttydev, h->ttyfd_stat.st_mode, h->ttyfd_stat.st_uid, h->ttyfd_stat.st_gid));
381 # endif
382 }
383 #endif
384
385 /*----------------------------------------------------------------------*/
386 /*
387 * window size/position calculcations for XSizeHint and other storage.
388 * if width/height are non-zero then override calculated width/height
389 */
390 /* EXTPROTO */
391 void
xvt_window_calc(xvt_t * r,unsigned int width,unsigned int height)392 xvt_window_calc(xvt_t *r, unsigned int width, unsigned int height)
393 {
394 short recalc_x, recalc_y;
395 int x, y, sb_w, mb_h, flags;
396 unsigned int w, h;
397 unsigned int max_width, max_height;
398
399 r->szHint.flags = PMinSize | PResizeInc | PBaseSize | PWinGravity;
400 r->szHint.win_gravity = NorthWestGravity;
401 /* r->szHint.min_aspect.x = r->szHint.min_aspect.y = 1; */
402
403 recalc_x = recalc_y = 0;
404 flags = 0;
405 if (!r->h->parsed_geometry) {
406 r->h->parsed_geometry = 1;
407 if (r->h->rs[Rs_geometry])
408 flags = XParseGeometry(r->h->rs[Rs_geometry], &x, &y, &w, &h);
409 if (flags & WidthValue) {
410 r->TermWin.ncol = BOUND_POSITIVE_INT16(w);
411 r->szHint.flags |= USSize;
412 }
413 if (flags & HeightValue) {
414 r->TermWin.nrow = BOUND_POSITIVE_INT16(h);
415 r->szHint.flags |= USSize;
416 }
417 if (flags & XValue) {
418 r->szHint.x = x;
419 r->szHint.flags |= USPosition;
420 if (flags & XNegative) {
421 recalc_x = 1;
422 r->szHint.win_gravity = NorthEastGravity;
423 }
424 }
425 if (flags & YValue) {
426 r->szHint.y = y;
427 r->szHint.flags |= USPosition;
428 if (flags & YNegative) {
429 recalc_y = 1;
430 if (r->szHint.win_gravity == NorthEastGravity)
431 r->szHint.win_gravity = SouthEastGravity;
432 else
433 r->szHint.win_gravity = SouthWestGravity;
434 }
435 }
436 }
437 /* TODO: BOUNDS */
438 r->TermWin.width = r->TermWin.ncol * r->TermWin.fwidth;
439 r->TermWin.height = r->TermWin.nrow * r->TermWin.fheight;
440 max_width = MAX_COLS * r->TermWin.fwidth;
441 max_height = MAX_ROWS * r->TermWin.fheight;
442
443 r->szHint.base_width = r->szHint.base_height = 2 * r->TermWin.int_bwidth;
444
445 sb_w = mb_h = 0;
446 r->h->window_vt_x = r->h->window_vt_y = 0;
447 if (scrollbar_visible(r)) {
448 sb_w = scrollbar_TotalWidth();
449 r->szHint.base_width += sb_w;
450 if (!(r->Options & Opt_scrollBar_right))
451 r->h->window_vt_x = sb_w;
452 }
453 if (menubar_visible(r)) {
454 mb_h = menuBar_TotalHeight();
455 r->szHint.base_height += mb_h;
456 r->h->window_vt_y = mb_h;
457 }
458 r->szHint.width_inc = r->TermWin.fwidth;
459 r->szHint.height_inc = r->TermWin.fheight;
460 r->szHint.min_width = r->szHint.base_width + r->szHint.width_inc;
461 r->szHint.min_height = r->szHint.base_height + r->szHint.height_inc;
462
463 if (width && width - r->szHint.base_width < max_width) {
464 r->szHint.width = width;
465 r->TermWin.width = width - r->szHint.base_width;
466 } else {
467 MIN_IT(r->TermWin.width, max_width);
468 r->szHint.width = r->szHint.base_width + r->TermWin.width;
469 }
470 if (height && height - r->szHint.base_height < max_height) {
471 r->szHint.height = height;
472 r->TermWin.height = height - r->szHint.base_height;
473 } else {
474 MIN_IT(r->TermWin.height, max_height);
475 r->szHint.height = r->szHint.base_height + r->TermWin.height;
476 }
477 if (scrollbar_visible(r) && (r->Options & Opt_scrollBar_right))
478 r->h->window_sb_x = r->szHint.width - sb_w;
479
480 if (recalc_x)
481 r->szHint.x += (DisplayWidth(r->Xdisplay, Xscreen)
482 - r->szHint.width - 2 * r->TermWin.ext_bwidth);
483 if (recalc_y)
484 r->szHint.y += (DisplayHeight(r->Xdisplay, Xscreen)
485 - r->szHint.height - 2 * r->TermWin.ext_bwidth);
486
487 r->TermWin.ncol = r->TermWin.width / r->TermWin.fwidth;
488 r->TermWin.nrow = r->TermWin.height / r->TermWin.fheight;
489 return;
490 }
491
492 /*----------------------------------------------------------------------*/
493 /*
494 * Tell the teletype handler what size the window is.
495 * Called after a window size change.
496 */
497 /* EXTPROTO */
498 void
xvt_tt_winsize(int fd,unsigned short col,unsigned short row)499 xvt_tt_winsize(int fd, unsigned short col, unsigned short row)
500 {
501 struct winsize ws;
502
503 if (fd < 0)
504 return;
505 ws.ws_col = col;
506 ws.ws_row = row;
507 ws.ws_xpixel = ws.ws_ypixel = 0;
508 ioctl(fd, TIOCSWINSZ, &ws);
509 }
510
511 /*----------------------------------------------------------------------*/
512 /* xvt_change_font() - Switch to a new font */
513 /*
514 * init = 1 - initialize
515 *
516 * fontname == FONT_UP - switch to bigger font
517 * fontname == FONT_DN - switch to smaller font
518 */
519 /* EXTPROTO */
520 void
xvt_change_font(xvt_t * r,int init,const char * fontname)521 xvt_change_font(xvt_t *r, int init, const char *fontname)
522 {
523 const char *msg = "can't load font \"%s\"";
524 int fh, fw, recheckfonts;
525 int pf;
526 int idx = 0; /* index into r->h->rs[Rs_font] */
527 XFontStruct *xfont;
528 #ifdef MULTICHAR_SET
529 int i;
530 char *c, *enc;
531 char tmpbuf[64];
532 #endif
533
534 #define IDX2FNUM(i) ((i) == 0 ? FONT0_IDX : ((i) <= FONT0_IDX ? ((i)-1) : (i)))
535 #define FNUM2IDX(f) ((f) == FONT0_IDX ? 0 : ((f) < FONT0_IDX ? ((f)+1) : (f)))
536
537 if (!init) {
538 pf = r->h->fnum;
539 switch (fontname[0]) {
540 case '\0':
541 r->h->fnum = FONT0_IDX;
542 fontname = NULL;
543 break;
544
545 /* special (internal) prefix for font commands */
546 case FONT_CMD:
547 idx = atoi(fontname + 1);
548 switch (fontname[1]) {
549 case '+': /* corresponds to FONT_UP */
550 xvt_font_up_down(r, (idx ? idx : 1), 1);
551 break;
552
553 case '-': /* corresponds to FONT_DN */
554 xvt_font_up_down(r, (idx ? idx : 1), -1);
555 break;
556
557 default:
558 if (fontname[1] != '\0' && !isdigit(fontname[1]))
559 return;
560 if (idx < 0 || idx >= MAX_NFONTS)
561 return;
562 r->h->fnum = IDX2FNUM(idx);
563 break;
564 }
565 fontname = NULL;
566 break;
567
568 default:
569 if (fontname == NULL)
570 return;
571 else
572 /* search for existing fontname */
573 for (idx = 0; idx < MAX_NFONTS; idx++)
574 if (r->h->rs[Rs_font + idx] == NULL) continue;
575 if (!STRCMP(r->h->rs[Rs_font + idx], fontname)) {
576 r->h->fnum = IDX2FNUM(idx);
577 fontname = NULL;
578 break;
579 }
580 break;
581 }
582 /* re-position around the normal font */
583 idx = FNUM2IDX(r->h->fnum);
584
585 if (pf == r->h->fnum)
586 return; /* no change */
587
588 if (fontname != NULL) {
589 char *name;
590
591 xfont = XLoadQueryFont(r->Xdisplay, fontname);
592 if (!xfont)
593 return;
594
595 name = xvt_malloc(STRLEN(fontname + 1) * sizeof(char));
596
597 if (name == NULL) {
598 XFreeFont(r->Xdisplay, xfont);
599 return;
600 }
601 STRCPY(name, fontname);
602 if (r->h->newfont[idx] != NULL)
603 free(r->h->newfont[idx]);
604 r->h->newfont[idx] = name;
605 r->h->rs[Rs_font + idx] = r->h->newfont[idx];
606 }
607 }
608 if (r->TermWin.font)
609 XFreeFont(r->Xdisplay, r->TermWin.font);
610
611 /* load font or substitute */
612 xfont = XLoadQueryFont(r->Xdisplay, r->h->rs[Rs_font + idx]);
613 if (!xfont) {
614 xvt_print_error(msg, r->h->rs[Rs_font + idx]);
615 r->h->rs[Rs_font + idx] = "fixed";
616 xfont = XLoadQueryFont(r->Xdisplay, "fixed");
617 if (!xfont) {
618 xvt_print_error(msg, "fixed");
619 goto Abort;
620 }
621 }
622 r->TermWin.font = xfont;
623
624 #ifndef NO_BOLDFONT
625 /* fail silently */
626 if (init && r->h->rs[Rs_boldFont] != NULL)
627 r->TermWin.boldFont_loaded = XLoadQueryFont(r->Xdisplay,
628 r->h->rs[Rs_boldFont]);
629 #endif
630
631 /* alter existing GC */
632 if (!init)
633 XSetFont(r->Xdisplay, r->TermWin.gc, r->TermWin.font->fid);
634
635 /* set the sizes */
636 fw = xvt_get_fontwidest(r->TermWin.font);
637 fh = r->TermWin.font->ascent + r->TermWin.font->descent
638 + r->TermWin.lineSpace;
639 if (fw == r->TermWin.font->min_bounds.width)
640 r->TermWin.propfont &= ~PROPFONT_NORMAL;/* Mono-spaced font */
641 else
642 r->TermWin.propfont |= PROPFONT_NORMAL; /* Proportional font */
643 recheckfonts = !(fw == r->TermWin.fwidth && fh == r->TermWin.fheight);
644 r->TermWin.fwidth = fw;
645 r->TermWin.fheight = fh;
646
647 /* check that size of boldFont is okay */
648 #ifndef NO_BOLDFONT
649 if (recheckfonts) {
650 r->TermWin.boldFont = NULL;
651 if (r->TermWin.boldFont_loaded != NULL) {
652 fw = xvt_get_fontwidest(r->TermWin.boldFont_loaded);
653 fh = r->TermWin.boldFont_loaded->ascent
654 + r->TermWin.boldFont_loaded->descent;
655 if (fw <= r->TermWin.fwidth && fh <= r->TermWin.fheight)
656 r->TermWin.boldFont = r->TermWin.boldFont_loaded;
657 if (fw == r->TermWin.fwidth /* && fh == r->TermWin.fheight */ )
658 r->TermWin.propfont &= ~PROPFONT_BOLD;
659 else
660 r->TermWin.propfont |= PROPFONT_BOLD;
661 }
662 }
663 #endif /* NO_BOLDFONT */
664
665 #ifdef MULTICHAR_SET
666 if (r->TermWin.mfont)
667 XFreeFont(r->Xdisplay, r->TermWin.mfont);
668
669 xfont = NULL;
670 /* load font or substitute */
671 if (r->h->rs[Rs_mfont + idx] == NULL
672 || (xfont = XLoadQueryFont(r->Xdisplay,
673 r->h->rs[Rs_mfont + idx])) == NULL) {
674 /* TODO: this is now mainly handled in xvt_set_defaultfont() */
675 i = 0;
676 c = enc = "";
677 switch (r->encoding_method) {
678 case GB:
679 c = "-*-r-*-%.2d-*-gb2312.1980-0";
680 enc = "GB";
681 break;
682 case BIG5:
683 c = "-*-r-*-%.2d-*-big5-0";
684 enc = "BIG5";
685 break;
686 case EUCJ:
687 case SJIS:
688 c = "-*-%.2d-*-jisx0208*-*";
689 enc = "EUCJ/SJIS";
690 break;
691 case EUCKR:
692 c = "-*-%.2d-*-ksc5601*-*";
693 enc = "KR";
694 break;
695 default:
696 i = fh; /* jump past next two sections */
697 break;
698 }
699 for (; i < fh / 2; i++) {
700 sprintf(tmpbuf, c, fh - i);
701 xfont = XLoadQueryFont(r->Xdisplay, tmpbuf);
702 if (xfont) {
703 r->h->rs[Rs_mfont + idx] = xvt_malloc(STRLEN(tmpbuf) + 1);
704 STRCPY(r->h->rs[Rs_mfont + idx], tmpbuf);
705 break;
706 }
707 }
708 if (xfont == NULL && i != fh)
709 xvt_print_error("no similar multichar font: encoding %s; size %d",
710 enc, fh);
711 }
712 r->TermWin.mfont = xfont;
713
714 if (recheckfonts)
715 if (r->TermWin.mfont != NULL) {
716 fw = xvt_get_fontwidest(r->TermWin.mfont);
717 fh = r->TermWin.mfont->ascent + r->TermWin.mfont->descent;
718 if (fw > (r->TermWin.fwidth * 2) || fh > r->TermWin.fheight)
719 r->TermWin.mfont = NULL;
720 if (fw == (r->TermWin.fwidth * 2) /* && fh==r->TermWin.fheight */ )
721 r->TermWin.propfont &= ~PROPFONT_MULTI;
722 else
723 r->TermWin.propfont |= PROPFONT_MULTI;
724 }
725 #endif /* MULTICHAR_SET */
726
727 /* Fontset setting is only valid when xlocale initialized. Since
728 * xvt_init_xlocale() is called after here, so we don't set fontset when
729 * initialization, but let it set by xvt_init_xlocale() */
730 if (init)
731 xvt_setTermFontSet(r, -1);
732 else
733 xvt_setTermFontSet(r, idx);
734
735 xvt_set_colorfgbg(r);
736
737 if (!init) {
738 xvt_resize_all_windows(r, 0, 0, 0);
739 xvt_scr_touch(r, True);
740 }
741 return;
742 Abort:
743 xvt_print_error("aborting"); /* fatal problem */
744 exit(EXIT_FAILURE);
745 }
746
747 /* INTPROTO */
748 void
xvt_font_up_down(xvt_t * r,int n,int direction)749 xvt_font_up_down(xvt_t *r, int n, int direction)
750 {
751 const char *p;
752 int initial, j;
753
754 for (j = 0; j < n; j++) {
755 initial = r->h->fnum;
756 for (;;) {
757 r->h->fnum += direction;
758 if (r->h->fnum == MAX_NFONTS || r->h->fnum == -1) {
759 r->h->fnum = initial;
760 return;
761 }
762 p = r->h->rs[Rs_font + FNUM2IDX(r->h->fnum)];
763 if (p != NULL && STRLEN(p) > 1)
764 break;
765 }
766 }
767 }
768 #undef IDX2FNUM
769 #undef FNUM2IDX
770
771 #ifdef STRICT_FONT_CHECKING
772 /* INTPROTO */
773 int
xvt_get_fontwidest(XFontStruct * f)774 xvt_get_fontwidest(XFontStruct *f)
775 {
776 int i, cw, fw = 0;
777
778 if (f->min_bounds.width == f->max_bounds.width)
779 return f->min_bounds.width;
780 if (f->per_char == NULL)
781 return f->max_bounds.width;
782 for (i = f->max_char_or_byte2 - f->min_char_or_byte2; --i >= 0;) {
783 cw = f->per_char[i].width;
784 MAX_IT(fw, cw);
785 }
786 return fw;
787 }
788 #endif
789
790 /*----------------------------------------------------------------------*/
791 /*----------------------------------------------------------------------*/
792 /* xterm sequences - title, iconName, color (exptl) */
793 /* EXTPROTO */
794 void
xvt_set_title(xvt_t * r,const char * str)795 xvt_set_title(xvt_t *r, const char *str)
796 {
797 #ifndef SMART_WINDOW_TITLE
798 XStoreName(r->Xdisplay, r->TermWin.parent[0], str);
799 #else
800 char *name;
801
802 if (XFetchName(r->Xdisplay, r->TermWin.parent[0], &name) == 0)
803 name = NULL;
804 if (name == NULL || STRCMP(name, str))
805 XStoreName(r->Xdisplay, r->TermWin.parent[0], str);
806 if (name)
807 XFree(name);
808 #endif
809 }
810
811 /* EXTPROTO */
812 void
xvt_set_iconName(xvt_t * r,const char * str)813 xvt_set_iconName(xvt_t *r, const char *str)
814 {
815 #ifndef SMART_WINDOW_TITLE
816 XSetIconName(r->Xdisplay, r->TermWin.parent[0], str);
817 #else
818 char *name;
819
820 if (XGetIconName(r->Xdisplay, r->TermWin.parent[0], &name))
821 name = NULL;
822 if (name == NULL || STRCMP(name, str))
823 XSetIconName(r->Xdisplay, r->TermWin.parent[0], str);
824 if (name)
825 XFree(name);
826 #endif
827 }
828
829 #ifdef XTERM_COLOR_CHANGE
830 /* EXTPROTO */
831 void
xvt_set_window_color(xvt_t * r,int idx,const char * color)832 xvt_set_window_color(xvt_t *r, int idx, const char *color)
833 {
834 XColor xcol;
835 int i;
836
837 if (color == NULL || *color == '\0')
838 return;
839
840 /* handle color aliases */
841 if (isdigit(*color)) {
842 i = atoi(color);
843 if (i >= 8 && i <= 15) { /* bright colors */
844 i -= 8;
845 # ifndef NO_BRIGHTCOLOR
846 r->PixColors[idx] = r->PixColors[minBrightCOLOR + i];
847 SET_PIXCOLOR(r->h, idx);
848 goto Done;
849 # endif
850 }
851 if (i >= 0 && i <= 7) { /* normal colors */
852 r->PixColors[idx] = r->PixColors[minCOLOR + i];
853 SET_PIXCOLOR(r->h, idx);
854 goto Done;
855 }
856 }
857 if (!xvt_rXParseAllocColor(r, &xcol, color))
858 return;
859 /* XStoreColor (r->Xdisplay, XCMAP, XColor*); */
860
861 /*
862 * FIXME: should free colors here, but no idea how to do it so instead,
863 * so just keep gobbling up the colormap
864 */
865 # if 0
866 for (i = Color_Black; i <= Color_White; i++)
867 if (r->PixColors[idx] == r->PixColors[i])
868 break;
869 if (i > Color_White) {
870 /* fprintf (stderr, "XFreeColors: r->PixColors [%d] = %lu\n", idx, r->PixColors [idx]); */
871 XFreeColors(r->Xdisplay, XCMAP, (r->PixColors + idx), 1,
872 DisplayPlanes(r->Xdisplay, Xscreen));
873 }
874 # endif
875
876 r->PixColors[idx] = xcol.pixel;
877 SET_PIXCOLOR(r->h, idx);
878
879 /* XSetWindowAttributes attr; */
880 /* Cursor cursor; */
881 Done:
882 if (idx == Color_bg && !(r->Options & Opt_transparent))
883 XSetWindowBackground(r->Xdisplay, r->TermWin.vt,
884 r->PixColors[Color_bg]);
885
886 /* handle Color_BD, scrollbar background, etc. */
887
888 xvt_set_colorfgbg(r);
889 xvt_recolour_cursor(r);
890 /* the only reasonable way to enforce a clean update */
891 xvt_scr_touch(r, False);
892 }
893
894 #else
895 # define xvt_set_window_color(r, idx,color) ((void)0)
896 #endif /* XTERM_COLOR_CHANGE */
897
898 /* EXTPROTO */
899 void
xvt_recolour_cursor(xvt_t * r)900 xvt_recolour_cursor(xvt_t *r)
901 {
902 XColor xcol[2];
903
904 xcol[0].pixel = r->PixColors[Color_pointer];
905 xcol[1].pixel = r->PixColors[Color_bg];
906 XQueryColors(r->Xdisplay, XCMAP, xcol, 2);
907 XRecolorCursor(r->Xdisplay, r->TermWin_cursor, &(xcol[0]), &(xcol[1]));
908 }
909
910 /*----------------------------------------------------------------------*/
911 /*
912 * find if fg/bg matches any of the normal (low-intensity) colors
913 */
914 /* INTPROTO */
915 void
xvt_set_colorfgbg(xvt_t * r)916 xvt_set_colorfgbg(xvt_t *r)
917 {
918 unsigned int i;
919 const char *xpmb = "\0";
920 char fstr[sizeof("default") + 1], bstr[sizeof("default") + 1];
921
922 r->h->env_colorfgbg = xvt_malloc(sizeof("COLORFGBG=default;default;bg")
923 + 1);
924 STRCPY(fstr, "default");
925 STRCPY(bstr, "default");
926 for (i = Color_Black; i <= Color_White; i++)
927 if (r->PixColors[Color_fg] == r->PixColors[i]) {
928 sprintf(fstr, "%d", (i - Color_Black));
929 break;
930 }
931 for (i = Color_Black; i <= Color_White; i++)
932 if (r->PixColors[Color_bg] == r->PixColors[i]) {
933 sprintf(bstr, "%d", (i - Color_Black));
934 #ifdef XPM_BACKGROUND
935 xpmb = "default;";
936 #endif
937 break;
938 }
939 sprintf(r->h->env_colorfgbg, "COLORFGBG=%s;%s%s", fstr, xpmb, bstr);
940 putenv(r->h->env_colorfgbg);
941
942 #ifndef NO_BRIGHTCOLOR
943 r->h->colorfgbg = DEFAULT_RSTYLE;
944 for (i = minCOLOR; i <= maxCOLOR; i++) {
945 if (r->PixColors[Color_fg] == r->PixColors[i]
946 # ifndef NO_BOLD_UNDERLINE_REVERSE
947 && r->PixColors[Color_fg] == r->PixColors[Color_BD]
948 # endif /* ! NO_BOLD_UNDERLINE_REVERSE */
949 /* if we wanted boldFont to have precedence */
950 # if 0 /* ifndef NO_BOLDFONT */
951 && r->TermWin.boldFont == NULL
952 # endif /* NO_BOLDFONT */
953 )
954 r->h->colorfgbg = SET_FGCOLOR(r->h->colorfgbg, i);
955 if (r->PixColors[Color_bg] == r->PixColors[i])
956 r->h->colorfgbg = SET_BGCOLOR(r->h->colorfgbg, i);
957 }
958 #endif
959 }
960
961 /*----------------------------------------------------------------------*/
962 /*
963 * Colour determination for low colour displays, routine from
964 * Hans de Goede <hans@highrise.nl>
965 */
966
967 /* EXTPROTO */
968 int
xvt_rXParseAllocColor(xvt_t * r,XColor * screen_in_out,const char * colour)969 xvt_rXParseAllocColor(xvt_t *r, XColor *screen_in_out, const char *colour)
970 {
971 int res = 0;
972
973 if (!XParseColor(r->Xdisplay, XCMAP, colour, screen_in_out))
974 xvt_print_error("can't determine colour: %s", colour);
975 else
976 res = xvt_rXAllocColor(r, screen_in_out, colour);
977 return res;
978 }
979
980 /* EXTPROTO */
981 int
xvt_rXAllocColor(xvt_t * r,XColor * screen_in_out,const char * colour)982 xvt_rXAllocColor(xvt_t *r, XColor *screen_in_out, const char *colour)
983 {
984 int res;
985
986 if ((res = XAllocColor(r->Xdisplay, XCMAP, screen_in_out)))
987 return res;
988
989 /* try again with closest match */
990 if (XDEPTH >= 4 && XDEPTH <= 8) {
991 int i, numcol;
992 int best_pixel = 0;
993 unsigned long best_diff, diff;
994 XColor *colors;
995
996 #define rSQR(x) ((x)*(x))
997
998 best_diff = 0;
999 numcol = 0x01 << XDEPTH;
1000 if ((colors = xvt_malloc(numcol * sizeof(XColor)))) {
1001 for (i = 0; i < numcol; i++)
1002 colors[i].pixel = i;
1003
1004 XQueryColors(r->Xdisplay, XCMAP, colors, numcol);
1005 for (i = 0; i < numcol; i++) {
1006 diff = rSQR(screen_in_out->red - colors[i].red)
1007 + rSQR(screen_in_out->green - colors[i].green)
1008 + rSQR(screen_in_out->blue - colors[i].blue);
1009 if (i == 0 || diff < best_diff) {
1010 best_pixel = colors[i].pixel;
1011 best_diff = diff;
1012 }
1013 }
1014 *screen_in_out = colors[best_pixel];
1015 free(colors);
1016 res = XAllocColor(r->Xdisplay, XCMAP, screen_in_out);
1017 }
1018 }
1019 if (res == 0)
1020 xvt_print_error("can't allocate colour: %s", colour);
1021 return res;
1022 }
1023
1024 /* -------------------------------------------------------------------- *
1025 * - WINDOW RESIZING - *
1026 * -------------------------------------------------------------------- */
1027 /* EXTPROTO */
1028 void
xvt_resize_all_windows(xvt_t * r,unsigned int width,unsigned int height,int ignoreparent)1029 xvt_resize_all_windows(xvt_t *r, unsigned int width, unsigned int height, int ignoreparent)
1030 {
1031 int fix_screen;
1032 #ifdef SMART_RESIZE
1033 int old_width = r->szHint.width,
1034 old_height = r->szHint.height;
1035 #endif
1036
1037 xvt_window_calc(r, width, height);
1038 XSetWMNormalHints(r->Xdisplay, r->TermWin.parent[0], &r->szHint);
1039 if (!ignoreparent) {
1040 #ifdef SMART_RESIZE
1041 /*
1042 * resize by Marius Gedminas <marius.gedminas@uosis.mif.vu.lt>
1043 * reposition window on resize depending on placement on screen
1044 */
1045 int x, y, x1, y1;
1046 int dx, dy;
1047 unsigned int unused_w1, unused_h1, unused_b1, unused_d1;
1048 Window unused_cr;
1049
1050 XTranslateCoordinates(r->Xdisplay, r->TermWin.parent[0], Xroot,
1051 0, 0, &x, &y, &unused_cr);
1052 XGetGeometry(r->Xdisplay, r->TermWin.parent[0], &unused_cr, &x1, &y1,
1053 &unused_w1, &unused_h1, &unused_b1, &unused_d1);
1054 /*
1055 * if Xroot isn't the parent window, a WM will probably have offset
1056 * our position for handles and decorations. Counter it
1057 */
1058 if (x1 != x || y1 != y) {
1059 x -= x1;
1060 y -= y1;
1061 }
1062
1063 x1 = (DisplayWidth(r->Xdisplay, Xscreen) - old_width) / 2;
1064 y1 = (DisplayHeight(r->Xdisplay, Xscreen) - old_height) / 2;
1065 dx = old_width - r->szHint.width;
1066 dy = old_height - r->szHint.height;
1067
1068 /* Check position of the center of the window */
1069 if (x < x1) /* left half */
1070 dx = 0;
1071 else if (x == x1) /* exact center */
1072 dx /= 2;
1073 if (y < y1) /* top half */
1074 dy = 0;
1075 else if (y == y1) /* exact center */
1076 dy /= 2;
1077
1078 XMoveResizeWindow(r->Xdisplay, r->TermWin.parent[0], x + dx, y + dy,
1079 r->szHint.width, r->szHint.height);
1080 #else
1081 XResizeWindow(r->Xdisplay, r->TermWin.parent[0], r->szHint.width,
1082 r->szHint.height);
1083 #endif
1084 }
1085
1086 fix_screen = (r->TermWin.ncol != r->h->prev_ncol
1087 || r->TermWin.nrow != r->h->prev_nrow);
1088 if (fix_screen || width != r->h->old_width || height != r->h->old_height) {
1089 if (scrollbar_visible(r)) {
1090 XMoveResizeWindow(r->Xdisplay, r->scrollBar.win, r->h->window_sb_x,
1091 0, scrollbar_TotalWidth(), r->szHint.height);
1092 xvt_Resize_scrollBar(r);
1093 }
1094 if (menubar_visible(r))
1095 XMoveResizeWindow(r->Xdisplay, r->menuBar.win, r->h->window_vt_x,
1096 0, TermWin_TotalWidth(), menuBar_TotalHeight());
1097 XMoveResizeWindow(r->Xdisplay, r->TermWin.vt, r->h->window_vt_x,
1098 r->h->window_vt_y, TermWin_TotalWidth(),
1099 TermWin_TotalHeight());
1100 #ifdef XVT_GRAPHICS
1101 if (r->h->old_height)
1102 xvt_Gr_Resize(r, r->h->old_width - r->szHint.base_width,
1103 r->h->old_height - r->szHint.base_height);
1104 #endif
1105 xvt_scr_clear(r);
1106 xvt_resize_pixmap(r);
1107 }
1108
1109 if (fix_screen || r->h->old_height == 0) {
1110 int curr_screen = -1;
1111 u_int16_t old_ncol = r->h->prev_ncol;
1112
1113 /* scr_reset only works on the primary screen */
1114 if (r->h->old_height) /* this is not the first time through */
1115 curr_screen = xvt_scr_change_screen(r, PRIMARY);
1116 xvt_scr_reset(r);
1117 if (curr_screen >= 0) { /* this is not the first time through */
1118 xvt_scr_change_screen(r, curr_screen);
1119 xvt_selection_check(r, (old_ncol != r->TermWin.ncol ? 4 : 0));
1120 }
1121 }
1122
1123 r->h->old_width = r->szHint.width;
1124 r->h->old_height = r->szHint.height;
1125
1126 #ifdef USE_XIM
1127 xvt_IMSetStatusPosition(r);
1128 #endif
1129 }
1130
1131 /*
1132 * Set the width/height of the vt window in characters. Units are pixels.
1133 * good for toggling 80/132 columns
1134 */
1135 /* EXTPROTO */
1136 void
xvt_set_widthheight(xvt_t * r,unsigned int width,unsigned int height)1137 xvt_set_widthheight(xvt_t *r, unsigned int width, unsigned int height)
1138 {
1139 XWindowAttributes wattr;
1140
1141 if (width == 0 || height == 0) {
1142 XGetWindowAttributes(r->Xdisplay, Xroot, &wattr);
1143 if (width == 0)
1144 width = wattr.width - r->szHint.base_width;
1145 if (height == 0)
1146 height = wattr.height - r->szHint.base_height;
1147 }
1148 if (width != r->TermWin.width || height != r->TermWin.height) {
1149 width += r->szHint.base_width;
1150 height += r->szHint.base_height;
1151 xvt_resize_all_windows(r, width, height, 0);
1152 }
1153 }
1154
1155 /* -------------------------------------------------------------------- *
1156 * - X INPUT METHOD ROUTINES - *
1157 * -------------------------------------------------------------------- */
1158 #ifdef USE_XIM
1159 /* INTPROTO */
1160 void
xvt_setSize(xvt_t * r,XRectangle * size)1161 xvt_setSize(xvt_t *r, XRectangle *size)
1162 {
1163 size->x = r->TermWin.int_bwidth;
1164 size->y = r->TermWin.int_bwidth;
1165 size->width = Width2Pixel(r->TermWin.ncol);
1166 size->height = Height2Pixel(r->TermWin.nrow);
1167 }
1168
1169 /* INTPROTO */
1170 void
xvt_setColor(xvt_t * r,unsigned long * fg,unsigned long * bg)1171 xvt_setColor(xvt_t *r, unsigned long *fg, unsigned long *bg)
1172 {
1173 *fg = r->PixColors[Color_fg];
1174 *bg = r->PixColors[Color_bg];
1175 }
1176
1177 /* Checking whether input method is running. */
1178 /* INTPROTO */
1179 Bool
xvt_IMisRunning(xvt_t * r)1180 xvt_IMisRunning(xvt_t *r)
1181 {
1182 char *p;
1183 Atom atom;
1184 Window win;
1185 char server[IMBUFSIZ];
1186
1187 /* get current locale modifier */
1188 if ((p = XSetLocaleModifiers(NULL)) != NULL) {
1189 STRCPY(server, "@server=");
1190 STRNCAT(server, &(p[4]), IMBUFSIZ - 9); /* skip "@im=" */
1191 if ((p = STRCHR(server + 1, '@')) != NULL) /* first one only */
1192 *p = '\0';
1193
1194 atom = XInternAtom(r->Xdisplay, server, False);
1195 win = XGetSelectionOwner(r->Xdisplay, atom);
1196 if (win != None)
1197 return True;
1198 }
1199 return False;
1200 }
1201
1202 /* EXTPROTO */
1203 void
xvt_IMSendSpot(xvt_t * r)1204 xvt_IMSendSpot(xvt_t *r)
1205 {
1206 XPoint spot;
1207 XVaNestedList preedit_attr;
1208
1209 if (r->h->Input_Context == NULL
1210 || !r->TermWin.focus
1211 || !(r->h->input_style & XIMPreeditPosition)
1212 || !(r->h->event_type == KeyPress
1213 || r->h->event_type == Expose
1214 || r->h->event_type == NoExpose
1215 || r->h->event_type == SelectionNotify
1216 || r->h->event_type == ButtonRelease
1217 || r->h->event_type == FocusIn)
1218 || !xvt_IMisRunning(r))
1219 return;
1220
1221 xvt_setPosition(r, &spot);
1222
1223 preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &spot, NULL);
1224 XSetICValues(r->h->Input_Context, XNPreeditAttributes, preedit_attr, NULL);
1225 XFree(preedit_attr);
1226 }
1227
1228 /* EXTPROTO */
1229 void
xvt_setTermFontSet(xvt_t * r,int idx)1230 xvt_setTermFontSet(xvt_t *r, int idx)
1231 {
1232 char *string;
1233 long length;
1234 XFontSet prev_fontset;
1235 int success = 0;
1236
1237 if (idx < 0 || idx >= MAX_NFONTS)
1238 return;
1239 D_MAIN((stderr, "xvt_setTermFontSet()"));
1240 prev_fontset = r->TermWin.fontset;
1241 r->TermWin.fontset = NULL;
1242
1243 length = 0;
1244 if (r->h->rs[Rs_font + idx])
1245 length += STRLEN(r->h->rs[Rs_font + idx]) + 1;
1246 # ifdef MULTICHAR_SET
1247 if (r->h->rs[Rs_mfont + idx])
1248 length += STRLEN(r->h->rs[Rs_mfont + idx]) + 1;
1249 # endif
1250 if (length == 0 || (string = xvt_malloc(length + 1)) == NULL)
1251 r->TermWin.fontset = NULL;
1252 else {
1253 int missing_charsetcount;
1254 char **missing_charsetlist, *def_string;
1255
1256 string[0] = '\0';
1257 if (r->h->rs[Rs_font + idx]) {
1258 STRCAT(string, r->h->rs[Rs_font + idx]);
1259 STRCAT(string, ",");
1260 }
1261 # ifdef MULTICHAR_SET
1262 if (r->h->rs[Rs_mfont + idx]) {
1263 STRCAT(string, r->h->rs[Rs_mfont + idx]);
1264 STRCAT(string, ",");
1265 }
1266 # endif
1267 string[STRLEN(string) - 1] = '\0';
1268 r->TermWin.fontset = XCreateFontSet(r->Xdisplay, string,
1269 &missing_charsetlist,
1270 &missing_charsetcount,
1271 &def_string);
1272 free(string);
1273 if (r->TermWin.fontset != NULL)
1274 success = 1;
1275 }
1276
1277 if (success) {
1278 if (prev_fontset != NULL)
1279 XFreeFontSet(r->Xdisplay, prev_fontset);
1280 } else
1281 r->TermWin.fontset = prev_fontset;
1282 }
1283
1284 /* INTPROTO */
1285 void
xvt_setPreeditArea(xvt_t * r,XRectangle * preedit_rect,XRectangle * status_rect,XRectangle * needed_rect)1286 xvt_setPreeditArea(xvt_t *r, XRectangle *preedit_rect, XRectangle *status_rect, XRectangle *needed_rect)
1287 {
1288 int mbh, vtx = 0;
1289
1290 if (scrollbar_visible(r) && !(r->Options & Opt_scrollBar_right))
1291 vtx = scrollbar_TotalWidth();
1292 mbh = menubar_visible(r) ? menuBar_TotalHeight() : 0;
1293 mbh -= r->TermWin.lineSpace;
1294
1295 preedit_rect->x = needed_rect->width + vtx;
1296 preedit_rect->y = Height2Pixel(r->TermWin.nrow - 1) + mbh;
1297
1298 preedit_rect->width = Width2Pixel(r->TermWin.ncol + 1) - needed_rect->width
1299 + vtx;
1300 preedit_rect->height = Height2Pixel(1);
1301
1302 status_rect->x = vtx;
1303 status_rect->y = Height2Pixel(r->TermWin.nrow - 1) + mbh;
1304
1305 status_rect->width = needed_rect->width ? needed_rect->width
1306 : Width2Pixel(r->TermWin.ncol + 1);
1307 status_rect->height = Height2Pixel(1);
1308 }
1309
1310 /* ARGSUSED */
1311 /* INTPROTO */
1312 void
xvt_IMDestroyCallback(XIM xim,XPointer client_data,XPointer call_data)1313 xvt_IMDestroyCallback(XIM xim __attribute__((unused)), XPointer client_data __attribute__((unused)), XPointer call_data __attribute__((unused)))
1314 {
1315 xvt_t *r = xvt_get_r();
1316
1317 r->h->Input_Context = NULL;
1318 /* To avoid Segmentation Fault in C locale: Solaris only? */
1319 if (STRCMP(r->h->locale, "C"))
1320 XRegisterIMInstantiateCallback(r->Xdisplay, NULL, NULL, NULL,
1321 xvt_IMInstantiateCallback, NULL);
1322 }
1323
1324 /*
1325 * X manual pages and include files don't match on some systems:
1326 * some think this is an XIDProc and others an XIMProc so we can't
1327 * use the first argument - need to update this to be nice for
1328 * both types via some sort of configure detection
1329 */
1330 /* ARGSUSED */
1331 /* EXTPROTO */
1332 void
xvt_IMInstantiateCallback(Display * unused,XPointer client_data,XPointer call_data)1333 xvt_IMInstantiateCallback(Display *unused __attribute__((unused)), XPointer client_data __attribute__((unused)), XPointer call_data __attribute__((unused)))
1334 {
1335 int i, found, had_im;
1336 const char *p;
1337 char **s;
1338 xvt_t *r = xvt_get_r();
1339 char buf[IMBUFSIZ];
1340
1341 D_MAIN((stderr, "xvt_IMInstantiateCallback()"));
1342 if (r->h->Input_Context)
1343 return;
1344
1345 found = had_im = 0;
1346 p = r->h->rs[Rs_inputMethod];
1347 if (p && *p) {
1348 had_im = 1;
1349 s = xvt_splitcommastring(p);
1350 for (i = 0; s[i]; i++) {
1351 if (*s[i]) {
1352 STRCPY(buf, "@im=");
1353 STRNCAT(buf, s[i], IMBUFSIZ - 5);
1354 if ((p = XSetLocaleModifiers(buf)) != NULL && *p
1355 && (xvt_IM_get_IC(r) == True)) {
1356 found = 1;
1357 break;
1358 }
1359 }
1360 }
1361 for (i = 0; s[i]; i++)
1362 free(s[i]);
1363 free(s);
1364 }
1365 if (found)
1366 return;
1367
1368 /* try with XMODIFIERS env. var. */
1369 if ((p = XSetLocaleModifiers("")) != NULL && *p) {
1370 xvt_IM_get_IC(r);
1371 return;
1372 }
1373
1374 /* try with no modifiers base IF the user didn't specify an IM */
1375 if (!had_im && (p = XSetLocaleModifiers("@im=none")) != NULL && *p
1376 && xvt_IM_get_IC(r) == True)
1377 return;
1378 }
1379
1380 /*
1381 * Try to open a XIM with the current modifiers, then see if we can
1382 * open a suitable preedit type
1383 */
1384 /* INTPROTO */
1385 Bool
xvt_IM_get_IC(xvt_t * r)1386 xvt_IM_get_IC(xvt_t *r)
1387 {
1388 int i, j, found;
1389 XIM xim;
1390 XPoint spot;
1391 XRectangle rect, status_rect, needed_rect;
1392 unsigned long fg, bg;
1393 const char *p;
1394 char **s;
1395 XIMStyles *xim_styles;
1396 XVaNestedList preedit_attr, status_attr;
1397 XIMCallback ximcallback;
1398 struct xvt_hidden *h = r->h;
1399
1400 D_MAIN((stderr, "xvt_IM_get_IC()"));
1401 xim = XOpenIM(r->Xdisplay, NULL, NULL, NULL);
1402 if (xim == NULL)
1403 return False;
1404
1405 xim_styles = NULL;
1406 if (XGetIMValues(xim, XNQueryInputStyle, &xim_styles, NULL)
1407 || !xim_styles || !xim_styles->count_styles) {
1408 XCloseIM(xim);
1409 return False;
1410 }
1411
1412 p = h->rs[Rs_preeditType] ? h->rs[Rs_preeditType]
1413 : "OverTheSpot,OffTheSpot,Root";
1414 s = xvt_splitcommastring(p);
1415 for (i = found = 0; !found && s[i]; i++) {
1416 if (!STRCMP(s[i], "OverTheSpot"))
1417 h->input_style = (XIMPreeditPosition | XIMStatusNothing);
1418 else if (!STRCMP(s[i], "OffTheSpot"))
1419 h->input_style = (XIMPreeditArea | XIMStatusArea);
1420 else if (!STRCMP(s[i], "Root"))
1421 h->input_style = (XIMPreeditNothing | XIMStatusNothing);
1422
1423 for (j = 0; j < xim_styles->count_styles; j++)
1424 if (h->input_style == xim_styles->supported_styles[j]) {
1425 found = 1;
1426 break;
1427 }
1428 }
1429 for (i = 0; s[i]; i++)
1430 free(s[i]);
1431 free(s);
1432 XFree(xim_styles);
1433
1434 if (!found) {
1435 XCloseIM(xim);
1436 return False;
1437 }
1438
1439 ximcallback.callback = xvt_IMDestroyCallback;
1440
1441 /* XXX: not sure why we need this (as well as IC one below) */
1442 XSetIMValues(xim, XNDestroyCallback, &ximcallback, NULL);
1443
1444 preedit_attr = status_attr = NULL;
1445
1446 if (h->input_style & XIMPreeditPosition) {
1447 xvt_setSize(r, &rect);
1448 xvt_setPosition(r, &spot);
1449 xvt_setColor(r, &fg, &bg);
1450
1451 preedit_attr = XVaCreateNestedList(0, XNArea, &rect,
1452 XNSpotLocation, &spot,
1453 XNForeground, fg,
1454 XNBackground, bg,
1455 XNFontSet, r->TermWin.fontset,
1456 NULL);
1457 } else if (h->input_style & XIMPreeditArea) {
1458 xvt_setColor(r, &fg, &bg);
1459
1460 /*
1461 * The necessary width of preedit area is unknown
1462 * until create input context.
1463 */
1464 needed_rect.width = 0;
1465
1466 xvt_setPreeditArea(r, &rect, &status_rect, &needed_rect);
1467
1468 preedit_attr = XVaCreateNestedList(0, XNArea, &rect,
1469 XNForeground, fg,
1470 XNBackground, bg,
1471 XNFontSet, r->TermWin.fontset,
1472 NULL);
1473 status_attr = XVaCreateNestedList(0, XNArea, &status_rect,
1474 XNForeground, fg,
1475 XNBackground, bg,
1476 XNFontSet, r->TermWin.fontset, NULL);
1477 }
1478 h->Input_Context = XCreateIC(xim, XNInputStyle, h->input_style,
1479 XNClientWindow, r->TermWin.parent[0],
1480 XNFocusWindow, r->TermWin.parent[0],
1481 XNDestroyCallback, &ximcallback,
1482 preedit_attr ? XNPreeditAttributes : NULL,
1483 preedit_attr,
1484 status_attr ? XNStatusAttributes : NULL,
1485 status_attr, NULL);
1486 if (preedit_attr)
1487 XFree(preedit_attr);
1488 if (status_attr)
1489 XFree(status_attr);
1490 if (h->Input_Context == NULL) {
1491 xvt_print_error("failed to create input context");
1492 XCloseIM(xim);
1493 return False;
1494 }
1495 if (h->input_style & XIMPreeditArea)
1496 xvt_IMSetStatusPosition(r);
1497 D_MAIN((stderr, "xvt_IM_get_IC() - successful connection"));
1498 return True;
1499 }
1500
1501 /* EXTPROTO */
1502 void
xvt_IMSetStatusPosition(xvt_t * r)1503 xvt_IMSetStatusPosition(xvt_t *r)
1504 {
1505 XRectangle preedit_rect, status_rect, *needed_rect;
1506 XVaNestedList preedit_attr, status_attr;
1507
1508 if (r->h->Input_Context == NULL
1509 || !r->TermWin.focus
1510 || !(r->h->input_style & XIMPreeditArea)
1511 || !xvt_IMisRunning(r))
1512 return;
1513
1514 /* Getting the necessary width of preedit area */
1515 status_attr = XVaCreateNestedList(0, XNAreaNeeded, &needed_rect, NULL);
1516 XGetICValues(r->h->Input_Context, XNStatusAttributes, status_attr, NULL);
1517 XFree(status_attr);
1518
1519 xvt_setPreeditArea(r, &preedit_rect, &status_rect, needed_rect);
1520
1521 preedit_attr = XVaCreateNestedList(0, XNArea, &preedit_rect, NULL);
1522 status_attr = XVaCreateNestedList(0, XNArea, &status_rect, NULL);
1523
1524 XSetICValues(r->h->Input_Context,
1525 XNPreeditAttributes, preedit_attr,
1526 XNStatusAttributes, status_attr, NULL);
1527
1528 XFree(preedit_attr);
1529 XFree(status_attr);
1530 }
1531 #endif /* USE_XIM */
1532
1533 /*----------------------------------------------------------------------*/
1534 static xvt_t *_xvt_vars = NULL;
1535
1536 /* EXTPROTO */
1537 xvt_t *
xvt_get_r(void)1538 xvt_get_r(void)
1539 {
1540 return _xvt_vars;
1541 }
1542 /* INTPROTO */
1543 void
xvt_set_r(xvt_t * r)1544 xvt_set_r(xvt_t *r)
1545 {
1546 _xvt_vars = r;
1547 }
1548
1549 /*----------------------- end-of-file (C source) -----------------------*/
1550