ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/main.C
Revision: 1.7
Committed: Wed Nov 26 10:42:34 2003 UTC (20 years, 6 months ago) by pcg
Content type: text/plain
Branch: MAIN
Changes since 1.6: +3 -1 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 /*--------------------------------*-C-*---------------------------------*
2 * File: main.c
3 *----------------------------------------------------------------------*
4 * $Id: main.C,v 1.6 2003/11/25 17:11:33 pcg 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 "rxvt.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 void *
48 rxvt_term::operator new (size_t s)
49 {
50 void *p = malloc (s);
51
52 MEMSET (p, 0, s);
53 return p;
54 }
55
56 void
57 rxvt_term::operator delete (void *p, size_t s)
58 {
59 free (p);
60 }
61
62 rxvt_term::rxvt_term ()
63 : pty_ev (this, &rxvt_term::pty_cb),
64 #ifdef CURSOR_BLINK
65 blink_ev (this, &rxvt_term::blink_cb),
66 #endif
67 #ifdef POINTER_BLANK
68 pointer_ev (this, &rxvt_term::pointer_cb),
69 #endif
70 x_ev (this, &rxvt_term::x_cb)
71 {
72 cmdbuf_ptr = cmdbuf_endp = cmdbuf_base;
73 }
74
75 rxvt_term::~rxvt_term ()
76 {
77 delete PixColors;
78 }
79
80 /*----------------------------------------------------------------------*/
81 /* rxvt_init() */
82 /* LIBPROTO */
83 rxvt_t
84 rxvt_init(int argc, const char *const *argv)
85 {
86 SET_R(new rxvt_term);
87 dR;
88
89 if (!R->init_vars () || !R->init (argc, argv))
90 {
91 delete R;
92 return NULL;
93 }
94
95 return R;
96 }
97
98 bool
99 rxvt_term::init (int argc, const char *const *argv)
100 {
101 dR;//TODO (scrollbar, setidle)
102
103 /*
104 * Save and then give up any super-user privileges
105 * If we need privileges in any area then we must specifically request it.
106 * We should only need to be root in these cases:
107 * 1. write utmp entries on some systems
108 * 2. chown tty on some systems
109 */
110 rxvt_privileges (this, SAVE);
111 rxvt_privileges (this, IGNORE);
112
113 rxvt_init_secondary (this);
114
115 const char **cmd_argv = rxvt_init_resources (this, argc, argv);
116
117 #if (MENUBAR_MAX)
118 rxvt_menubar_read (this, rs[Rs_menu]);
119 #endif
120 #ifdef HAVE_SCROLLBARS
121 if (Options & Opt_scrollBar)
122 scrollbar_setIdle (); /* set existence for size calculations */
123 #endif
124
125 rxvt_Create_Windows (this, argc, argv);
126
127 rxvt_init_xlocale (this);
128
129 rxvt_scr_reset (this); /* initialize screen */
130 #ifdef RXVT_GRAPHICS
131 rxvt_Gr_reset (this); /* reset graphics */
132 #endif
133
134 #if 0
135 #ifdef DEBUG_X
136 XSynchronize(Xdisplay, True);
137 XSetErrorHandler((XErrorHandler) abort);
138 #else
139 XSetErrorHandler((XErrorHandler) rxvt_xerror_handler);
140 #endif
141 #endif
142
143 #ifdef HAVE_SCROLLBARS
144 if (Options & Opt_scrollBar)
145 rxvt_Resize_scrollBar (this); /* create and map scrollbar */
146 #endif
147 #if (MENUBAR_MAX)
148 if (menubar_visible(r))
149 XMapWindow (Xdisplay, menuBar.win);
150 #endif
151 #ifdef TRANSPARENT
152 if (Options & Opt_transparent)
153 {
154 XSelectInput (Xdisplay, Xroot, PropertyChangeMask);
155 rxvt_check_our_parents (this);
156 }
157 #endif
158 XMapWindow (Xdisplay, TermWin.vt);
159 XMapWindow (Xdisplay, TermWin.parent[0]);
160
161 rxvt_init_env (this);
162 rxvt_init_command (this, cmd_argv);
163
164 x_ev.start (Xfd, EVENT_READ);
165 pty_ev.start (cmd_fd, EVENT_READ);
166
167 flush ();
168
169 return true;
170 }
171
172 /* ------------------------------------------------------------------------- *
173 * SIGNAL HANDLING & EXIT HANDLER *
174 * ------------------------------------------------------------------------- */
175 /*
176 * Catch a SIGCHLD signal and exit if the direct child has died
177 */
178 /* ARGSUSED */
179 /* EXTPROTO */
180 RETSIGTYPE
181 rxvt_Child_signal(int sig __attribute__ ((unused)))
182 {
183 dR;
184 int pid, save_errno = errno;
185
186 do {
187 errno = 0;
188 } while ((pid = waitpid(-1, NULL, WNOHANG)) == -1 && errno == EINTR);
189
190 if (pid == R->cmd_pid)
191 exit(EXIT_SUCCESS);
192
193 errno = save_errno;
194 signal(SIGCHLD, rxvt_Child_signal);
195 }
196
197 /*
198 * Catch a fatal signal and tidy up before quitting
199 */
200 /* EXTPROTO */
201 RETSIGTYPE
202 rxvt_Exit_signal(int sig)
203 {
204 signal(sig, SIG_DFL);
205 #ifdef DEBUG_CMD
206 rxvt_print_error("signal %d", sig);
207 #endif
208 rxvt_clean_exit();
209 kill(getpid(), sig);
210 }
211
212 /* ARGSUSED */
213 /* INTPROTO */
214 int
215 rxvt_xerror_handler(const Display * display
216 __attribute__ ((unused)), const XErrorEvent * event)
217 {
218 dR;
219
220 if (R->allowedxerror == -1) {
221 R->allowedxerror = event->error_code;
222 return 0; /* ignored anyway */
223 }
224 rxvt_print_error("XError: Request: %d . %d, Error: %d",
225 event->request_code, event->minor_code,
226 event->error_code);
227 /* XXX: probably should call rxvt_clean_exit() bypassing X routines */
228 exit(EXIT_FAILURE);
229 /* NOTREACHED */
230 }
231
232 /*----------------------------------------------------------------------*/
233 /*
234 * Exit gracefully, clearing the utmp entry and restoring tty attributes
235 * TODO: if debugging, this should free up any known resources if we can
236 */
237 /* EXTPROTO */
238 void
239 rxvt_clean_exit(void)
240 {
241 dR;
242
243 #ifdef DEBUG_SCREEN
244 rxvt_scr_release(aR);
245 #endif
246 #ifndef NO_SETOWNER_TTYDEV
247 rxvt_privileged_ttydev(aR_ RESTORE);
248 #endif
249 #ifdef UTMP_SUPPORT
250 rxvt_privileged_utmp(aR_ RESTORE);
251 #endif
252 #ifdef USE_XIM
253 if (R->Input_Context != NULL) {
254 XDestroyIC(R->Input_Context);
255 R->Input_Context = NULL;
256 }
257 #endif
258 }
259
260 /* ------------------------------------------------------------------------- *
261 * MEMORY ALLOCATION WRAPPERS *
262 * ------------------------------------------------------------------------- */
263 /* EXTPROTO */
264 void *
265 rxvt_malloc(size_t size)
266 {
267 void *p;
268
269 p = malloc(size);
270 if (p)
271 return p;
272
273 fprintf(stderr, APL_NAME ": memory allocation failure. Aborting");
274 rxvt_clean_exit();
275 exit(EXIT_FAILURE);
276 /* NOTREACHED */
277 }
278
279 /* EXTPROTO */
280 void *
281 rxvt_calloc(size_t number, size_t size)
282 {
283 void *p;
284
285 p = calloc(number, size);
286 if (p)
287 return p;
288
289 fprintf(stderr, APL_NAME ": memory allocation failure. Aborting");
290 rxvt_clean_exit();
291 exit(EXIT_FAILURE);
292 /* NOTREACHED */
293 }
294
295 /* EXTPROTO */
296 void *
297 rxvt_realloc(void *ptr, size_t size)
298 {
299 void *p;
300
301 if (ptr)
302 p = realloc(ptr, size);
303 else
304 p = malloc(size);
305 if (p)
306 return p;
307
308 fprintf(stderr, APL_NAME ": memory allocation failure. Aborting");
309 rxvt_clean_exit();
310 exit(EXIT_FAILURE);
311 /* NOTREACHED */
312 }
313
314 /* ------------------------------------------------------------------------- *
315 * PRIVILEGED OPERATIONS *
316 * ------------------------------------------------------------------------- */
317 /* take care of suid/sgid super-user (root) privileges */
318 /* INTPROTO */
319 void
320 rxvt_privileges(pR_ int mode)
321 {
322 #if ! defined(__CYGWIN32__)
323 # if !defined(HAVE_SETEUID) && defined(HAVE_SETREUID)
324 /* setreuid() is the poor man's setuid(), seteuid() */
325 # define seteuid(a) setreuid(-1, (a))
326 # define setegid(a) setregid(-1, (a))
327 # define HAVE_SETEUID
328 # endif
329 # ifdef HAVE_SETEUID
330 switch (mode) {
331 case IGNORE:
332 /*
333 * change effective uid/gid - not real uid/gid - so we can switch
334 * back to root later, as required
335 */
336 seteuid(getuid());
337 setegid(getgid());
338 break;
339 case SAVE:
340 R->euid = geteuid();
341 R->egid = getegid();
342 break;
343 case RESTORE:
344 seteuid(R->euid);
345 setegid(R->egid);
346 break;
347 }
348 # else
349 switch (mode) {
350 case IGNORE:
351 setuid(getuid());
352 setgid(getgid());
353 /* FALLTHROUGH */
354 case SAVE:
355 /* FALLTHROUGH */
356 case RESTORE:
357 break;
358 }
359 # endif
360 #endif
361 }
362
363 #ifdef UTMP_SUPPORT
364 /* EXTPROTO */
365 void
366 rxvt_privileged_utmp(pR_ char action)
367 {
368 D_MAIN((stderr, "rxvt_privileged_utmp(%c); waiting for: %c (pid: %d)",
369 action, R->next_utmp_action, getpid()));
370 if (R->next_utmp_action != action || (action != SAVE && action != RESTORE)
371 || (R->Options & Opt_utmpInhibit)
372 || R->ttydev == NULL || *R->ttydev == '\0')
373 return;
374
375 rxvt_privileges(aR_ RESTORE);
376 if (action == SAVE) {
377 R->next_utmp_action = RESTORE;
378 rxvt_makeutent(aR_ R->ttydev, R->rs[Rs_display_name]);
379 } else { /* action == RESTORE */
380 R->next_utmp_action = IGNORE;
381 rxvt_cleanutent(aR);
382 }
383 rxvt_privileges(aR_ IGNORE);
384 }
385 #endif
386
387 #ifndef NO_SETOWNER_TTYDEV
388 /* EXTPROTO */
389 void
390 rxvt_privileged_ttydev(pR_ char action)
391 {
392 D_MAIN((stderr,
393 "rxvt_privileged_ttydev(aR_ %c); waiting for: %c (pid: %d)",
394 action, R->next_tty_action, getpid()));
395 if (R->next_tty_action != action || (action != SAVE && action != RESTORE)
396 || R->ttydev == NULL || *R->ttydev == '\0')
397 return;
398
399 rxvt_privileges(aR_ RESTORE);
400
401 if (action == SAVE) {
402 R->next_tty_action = RESTORE;
403 # ifndef RESET_TTY_TO_COMMON_DEFAULTS
404 /* store original tty status for restoration rxvt_clean_exit() -- rgg 04/12/95 */
405 if (lstat(R->ttydev, &R->ttyfd_stat) < 0) /* you lose out */
406 R->next_tty_action = IGNORE;
407 else
408 # endif
409 {
410 chown(R->ttydev, getuid(), R->ttygid); /* fail silently */
411 chmod(R->ttydev, R->ttymode);
412 # ifdef HAVE_REVOKE
413 revoke(R->ttydev);
414 # endif
415 }
416 } else { /* action == RESTORE */
417 R->next_tty_action = IGNORE;
418 # ifndef RESET_TTY_TO_COMMON_DEFAULTS
419 chmod(R->ttydev, R->ttyfd_stat.st_mode);
420 chown(R->ttydev, R->ttyfd_stat.st_uid, R->ttyfd_stat.st_gid);
421 # else
422 chmod(R->ttydev,
423 (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH));
424 chown(R->ttydev, 0, 0);
425 # endif
426 }
427
428 rxvt_privileges(aR_ IGNORE);
429
430 # ifndef RESET_TTY_TO_COMMON_DEFAULTS
431 D_MAIN((stderr, "%s \"%s\": mode %03o, uid %d, gid %d",
432 action == RESTORE ? "Restoring" : (action ==
433 SAVE ? "Saving" :
434 "UNKNOWN ERROR for"), R->ttydev,
435 R->ttyfd_stat.st_mode, R->ttyfd_stat.st_uid,
436 R->ttyfd_stat.st_gid));
437 # endif
438 }
439 #endif
440
441 /*----------------------------------------------------------------------*/
442 /*
443 * window size/position calculcations for XSizeHint and other storage.
444 * if width/height are non-zero then override calculated width/height
445 */
446 /* EXTPROTO */
447 void
448 rxvt_window_calc(pR_ unsigned int width, unsigned int height)
449 {
450 short recalc_x, recalc_y;
451 int x, y, sb_w, mb_h, flags;
452 unsigned int w, h;
453 unsigned int max_width, max_height;
454
455 D_SIZE((stderr, "< Cols/Rows: %3d x %3d ; Width/Height: %4d x %4d",
456 R->TermWin.ncol, R->TermWin.nrow, R->szHint.width,
457 R->szHint.height));
458 R->szHint.flags = PMinSize | PResizeInc | PBaseSize | PWinGravity;
459 R->szHint.win_gravity = NorthWestGravity;
460 /* R->szHint.min_aspect.x = R->szHint.min_aspect.y = 1; */
461
462 recalc_x = recalc_y = 0;
463 flags = 0;
464 if (!R->parsed_geometry) {
465 R->parsed_geometry = 1;
466 if (R->rs[Rs_geometry])
467 flags = XParseGeometry(R->rs[Rs_geometry], &x, &y, &w, &h);
468 if (flags & WidthValue) {
469 R->TermWin.ncol = BOUND_POSITIVE_INT16(w);
470 R->szHint.flags |= USSize;
471 }
472 if (flags & HeightValue) {
473 R->TermWin.nrow = BOUND_POSITIVE_INT16(h);
474 R->szHint.flags |= USSize;
475 }
476 if (flags & XValue) {
477 R->szHint.x = x;
478 R->szHint.flags |= USPosition;
479 if (flags & XNegative) {
480 recalc_x = 1;
481 R->szHint.win_gravity = NorthEastGravity;
482 }
483 }
484 if (flags & YValue) {
485 R->szHint.y = y;
486 R->szHint.flags |= USPosition;
487 if (flags & YNegative) {
488 recalc_y = 1;
489 if (R->szHint.win_gravity == NorthEastGravity)
490 R->szHint.win_gravity = SouthEastGravity;
491 else
492 R->szHint.win_gravity = SouthWestGravity;
493 }
494 }
495 }
496 /* TODO: BOUNDS */
497 R->TermWin.width = R->TermWin.ncol * R->TermWin.fwidth;
498 R->TermWin.height = R->TermWin.nrow * R->TermWin.fheight;
499 max_width = MAX_COLS * R->TermWin.fwidth;
500 max_height = MAX_ROWS * R->TermWin.fheight;
501
502 R->szHint.base_width = R->szHint.base_height = 2 * R->TermWin.int_bwidth;
503
504 sb_w = mb_h = 0;
505 R->window_vt_x = R->window_vt_y = 0;
506 if (scrollbar_visible(R)) {
507 sb_w = scrollbar_TotalWidth();
508 R->szHint.base_width += sb_w;
509 if (!(R->Options & Opt_scrollBar_right))
510 R->window_vt_x = sb_w;
511 }
512 if (menubar_visible(R)) {
513 mb_h = menuBar_TotalHeight();
514 R->szHint.base_height += mb_h;
515 R->window_vt_y = mb_h;
516 }
517 R->szHint.width_inc = R->TermWin.fwidth;
518 R->szHint.height_inc = R->TermWin.fheight;
519 R->szHint.min_width = R->szHint.base_width + R->szHint.width_inc;
520 R->szHint.min_height = R->szHint.base_height + R->szHint.height_inc;
521
522 if (width && width - R->szHint.base_width < max_width) {
523 R->szHint.width = width;
524 R->TermWin.width = width - R->szHint.base_width;
525 } else {
526 MIN_IT(R->TermWin.width, max_width);
527 R->szHint.width = R->szHint.base_width + R->TermWin.width;
528 }
529 if (height && height - R->szHint.base_height < max_height) {
530 R->szHint.height = height;
531 R->TermWin.height = height - R->szHint.base_height;
532 } else {
533 MIN_IT(R->TermWin.height, max_height);
534 R->szHint.height = R->szHint.base_height + R->TermWin.height;
535 }
536 if (scrollbar_visible(R) && (R->Options & Opt_scrollBar_right))
537 R->window_sb_x = R->szHint.width - sb_w;
538
539 if (recalc_x)
540 R->szHint.x += (DisplayWidth(R->Xdisplay, Xscreen)
541 - R->szHint.width - 2 * R->TermWin.ext_bwidth);
542 if (recalc_y)
543 R->szHint.y += (DisplayHeight(R->Xdisplay, Xscreen)
544 - R->szHint.height - 2 * R->TermWin.ext_bwidth);
545
546 R->TermWin.ncol = R->TermWin.width / R->TermWin.fwidth;
547 R->TermWin.nrow = R->TermWin.height / R->TermWin.fheight;
548 D_SIZE((stderr, "> Cols/Rows: %3d x %3d ; Width/Height: %4d x %4d",
549 R->TermWin.ncol, R->TermWin.nrow, R->szHint.width,
550 R->szHint.height));
551 return;
552 }
553
554 /*----------------------------------------------------------------------*/
555 /*
556 * Tell the teletype handler what size the window is.
557 * Called after a window size change.
558 */
559 /* EXTPROTO */
560 void
561 rxvt_tt_winsize(int fd, unsigned short col, unsigned short row, int pid)
562 {
563 struct winsize ws;
564
565 if (fd < 0)
566 return;
567 ws.ws_col = col;
568 ws.ws_row = row;
569 ws.ws_xpixel = ws.ws_ypixel = 0;
570 #ifndef DEBUG_SIZE
571 (void)ioctl(fd, TIOCSWINSZ, &ws);
572 #else
573 if (ioctl(fd, TIOCSWINSZ, &ws) < 0) {
574 D_SIZE((stderr, "Failed to send TIOCSWINSZ to fd %d", fd));
575 }
576 # ifdef SIGWINCH
577 else if (pid) /* force through to the command */
578 kill(pid, SIGWINCH);
579 # endif
580 #endif
581 }
582
583 /*----------------------------------------------------------------------*/
584 /* rxvt_change_font() - Switch to a new font */
585 /*
586 * init = 1 - initialize
587 *
588 * fontname == FONT_UP - switch to bigger font
589 * fontname == FONT_DN - switch to smaller font
590 */
591 /* EXTPROTO */
592 void
593 rxvt_change_font(pR_ int init, const char *fontname)
594 {
595 }
596
597 /* INTPROTO */
598 void
599 rxvt_font_up_down(pR_ int n, int direction)
600 {
601 }
602
603 /*----------------------------------------------------------------------*/
604 /*----------------------------------------------------------------------*/
605 /* xterm sequences - title, iconName, color (exptl) */
606 /* EXTPROTO */
607 void
608 rxvt_set_title(pR_ const char *str)
609 {
610 #ifndef SMART_WINDOW_TITLE
611 XStoreName(R->Xdisplay, R->TermWin.parent[0], str);
612 #else
613 char *name;
614
615 if (XFetchName(R->Xdisplay, R->TermWin.parent[0], &name) == 0)
616 name = NULL;
617 if (name == NULL || STRCMP(name, str))
618 XStoreName(R->Xdisplay, R->TermWin.parent[0], str);
619 if (name)
620 XFree(name);
621 #endif
622 }
623
624 /* EXTPROTO */
625 void
626 rxvt_set_iconName(pR_ const char *str)
627 {
628 #ifndef SMART_WINDOW_TITLE
629 XSetIconName(R->Xdisplay, R->TermWin.parent[0], str);
630 #else
631 char *name;
632
633 if (XGetIconName(R->Xdisplay, R->TermWin.parent[0], &name))
634 name = NULL;
635 if (name == NULL || STRCMP(name, str))
636 XSetIconName(R->Xdisplay, R->TermWin.parent[0], str);
637 if (name)
638 XFree(name);
639 #endif
640 }
641
642 #ifdef XTERM_COLOR_CHANGE
643 /* EXTPROTO */
644 void
645 rxvt_set_window_color(pR_ int idx, const char *color)
646 {
647 rxvt_color xcol;
648 int i;
649
650 if (color == NULL || *color == '\0')
651 return;
652
653 /* handle color aliases */
654 if (isdigit(*color)) {
655 i = atoi(color);
656 if (i >= 8 && i <= 15) { /* bright colors */
657 i -= 8;
658 # ifndef NO_BRIGHTCOLOR
659 R->PixColors[idx] = R->PixColors[minBrightCOLOR + i];
660 SET_PIXCOLOR(R, idx);
661 goto Done;
662 # endif
663 }
664 if (i >= 0 && i <= 7) { /* normal colors */
665 R->PixColors[idx] = R->PixColors[minCOLOR + i];
666 SET_PIXCOLOR(R, idx);
667 goto Done;
668 }
669 }
670 if (!rxvt_rXParseAllocColor(aR_ & xcol, color))
671 return;
672 /* XStoreColor (R->Xdisplay, XCMAP, XColor*); */
673
674 /*
675 * FIXME: should free colors here, but no idea how to do it so instead,
676 * so just keep gobbling up the colormap
677 */
678 # if 0
679 for (i = Color_Black; i <= Color_White; i++)
680 if (R->PixColors[idx] == R->PixColors[i])
681 break;
682 if (i > Color_White) {
683 /* fprintf (stderr, "XFreeColors: R->PixColors [%d] = %lu\n", idx, R->PixColors [idx]); */
684 XFreeColors(R->Xdisplay, XCMAP, (R->PixColors + idx), 1,
685 DisplayPlanes(R->Xdisplay, Xscreen));
686 }
687 # endif
688
689 R->PixColors[idx] = xcol;
690 SET_PIXCOLOR(R, idx);
691
692 /* XSetWindowAttributes attr; */
693 /* Cursor cursor; */
694 Done:
695 if (idx == Color_bg && !(R->Options & Opt_transparent))
696 XSetWindowBackground(R->Xdisplay, R->TermWin.vt,
697 R->PixColors[Color_bg]);
698
699 /* handle Color_BD, scrollbar background, etc. */
700
701 rxvt_set_colorfgbg(aR);
702 rxvt_recolour_cursor(aR);
703 /* the only reasonable way to enforce a clean update */
704 rxvt_scr_poweron(aR);
705 }
706
707 #else
708 # define rxvt_set_window_color(aR_ idx,color) ((void)0)
709 #endif /* XTERM_COLOR_CHANGE */
710
711 /* EXTPROTO */
712 void
713 rxvt_recolour_cursor(pR)
714 {
715 rxvt_color xcol[2];
716
717 #if TODO
718 xcol[0] = R->PixColors[Color_pointer];
719 xcol[1] = R->PixColors[Color_bg];
720 XQueryColors(R->Xdisplay, XCMAP, xcol, 2);
721 XRecolorCursor(R->Xdisplay, R->TermWin_cursor, &(xcol[0]), &(xcol[1]));
722 #endif
723 }
724
725 /*----------------------------------------------------------------------*/
726 /*
727 * find if fg/bg matches any of the normal (low-intensity) colors
728 */
729 /* INTPROTO */
730 void
731 rxvt_set_colorfgbg(pR)
732 {
733 unsigned int i;
734 const char *xpmb = "\0";
735 char fstr[sizeof("default") + 1], bstr[sizeof("default") + 1];
736
737 R->env_colorfgbg =
738 (char *)rxvt_malloc(sizeof("COLORFGBG=default;default;bg") + 1);
739 STRCPY(fstr, "default");
740 STRCPY(bstr, "default");
741 for (i = Color_Black; i <= Color_White; i++)
742 if (R->PixColors[Color_fg] == R->PixColors[i]) {
743 sprintf(fstr, "%d", (i - Color_Black));
744 break;
745 }
746 for (i = Color_Black; i <= Color_White; i++)
747 if (R->PixColors[Color_bg] == R->PixColors[i]) {
748 sprintf(bstr, "%d", (i - Color_Black));
749 #ifdef XPM_BACKGROUND
750 xpmb = "default;";
751 #endif
752 break;
753 }
754 sprintf(R->env_colorfgbg, "COLORFGBG=%s;%s%s", fstr, xpmb, bstr);
755 putenv(R->env_colorfgbg);
756
757 #ifndef NO_BRIGHTCOLOR
758 R->colorfgbg = DEFAULT_RSTYLE;
759 for (i = minCOLOR; i <= maxCOLOR; i++) {
760 if (R->PixColors[Color_fg] == R->PixColors[i])
761 R->colorfgbg = SET_FGCOLOR(R->colorfgbg, i);
762 if (R->PixColors[Color_bg] == R->PixColors[i])
763 R->colorfgbg = SET_BGCOLOR(R->colorfgbg, i);
764 }
765 #endif
766 }
767
768 /*----------------------------------------------------------------------*/
769 /*
770 * Colour determination for low colour displays, routine from
771 * Hans de Goede <hans@highrise.nl>
772 */
773
774 /* EXTPROTO */
775 int
776 rxvt_rXParseAllocColor(pR_ rxvt_color * screen_in_out, const char *colour)
777 {
778 screen_in_out->set(aR_ colour);
779
780 if (!screen_in_out->set(aR_ colour)) {
781 rxvt_print_error("can't allocate colour: %s", colour);
782 return false;
783 }
784
785 return true;
786 }
787
788 /* -------------------------------------------------------------------- *
789 * - WINDOW RESIZING - *
790 * -------------------------------------------------------------------- */
791 /* EXTPROTO */
792 void
793 rxvt_resize_all_windows(pR_ unsigned int width, unsigned int height,
794 int ignoreparent)
795 {
796 int fix_screen;
797
798 #ifdef SMART_RESIZE
799 int old_width = R->szHint.width, old_height = R->szHint.height;
800 #endif
801
802 rxvt_window_calc(aR_ width, height);
803 XSetWMNormalHints(R->Xdisplay, R->TermWin.parent[0], &R->szHint);
804 if (!ignoreparent) {
805 #ifdef SMART_RESIZE
806 /*
807 * resize by Marius Gedminas <marius.gedminas@uosis.mif.vu.lt>
808 * reposition window on resize depending on placement on screen
809 */
810 int x, y, x1, y1;
811 int dx, dy;
812 unsigned int unused_w1, unused_h1, unused_b1, unused_d1;
813 Window unused_cr;
814
815 XTranslateCoordinates(R->Xdisplay, R->TermWin.parent[0], Xroot,
816 0, 0, &x, &y, &unused_cr);
817 XGetGeometry(R->Xdisplay, R->TermWin.parent[0], &unused_cr, &x1, &y1,
818 &unused_w1, &unused_h1, &unused_b1, &unused_d1);
819 /*
820 * if Xroot isn't the parent window, a WM will probably have offset
821 * our position for handles and decorations. Counter it
822 */
823 if (x1 != x || y1 != y) {
824 x -= x1;
825 y -= y1;
826 }
827
828 x1 = (DisplayWidth(R->Xdisplay, Xscreen) - old_width) / 2;
829 y1 = (DisplayHeight(R->Xdisplay, Xscreen) - old_height) / 2;
830 dx = old_width - R->szHint.width;
831 dy = old_height - R->szHint.height;
832
833 /* Check position of the center of the window */
834 if (x < x1) /* left half */
835 dx = 0;
836 else if (x == x1) /* exact center */
837 dx /= 2;
838 if (y < y1) /* top half */
839 dy = 0;
840 else if (y == y1) /* exact center */
841 dy /= 2;
842
843 XMoveResizeWindow(R->Xdisplay, R->TermWin.parent[0], x + dx, y + dy,
844 R->szHint.width, R->szHint.height);
845 #else
846 XResizeWindow(R->Xdisplay, R->TermWin.parent[0], R->szHint.width,
847 R->szHint.height);
848 #endif
849 }
850
851 fix_screen = (R->TermWin.ncol != R->prev_ncol
852 || R->TermWin.nrow != R->prev_nrow);
853 if (fix_screen || width != R->old_width || height != R->old_height) {
854 if (scrollbar_visible(R)) {
855 XMoveResizeWindow(R->Xdisplay, R->scrollBar.win, R->window_sb_x,
856 0, scrollbar_TotalWidth(), R->szHint.height);
857 rxvt_Resize_scrollBar(aR);
858 }
859 if (menubar_visible(R))
860 XMoveResizeWindow(R->Xdisplay, R->menuBar.win, R->window_vt_x,
861 0, TermWin_TotalWidth(), menuBar_TotalHeight());
862 XMoveResizeWindow(R->Xdisplay, R->TermWin.vt, R->window_vt_x,
863 R->window_vt_y, TermWin_TotalWidth(),
864 TermWin_TotalHeight());
865 #ifdef RXVT_GRAPHICS
866 if (R->old_height)
867 rxvt_Gr_Resize(aR_ R->old_width - R->szHint.base_width,
868 R->old_height - R->szHint.base_height);
869 #endif
870 rxvt_scr_clear(aR);
871 #ifdef XPM_BACKGROUND
872 rxvt_resize_pixmap(aR);
873 #endif
874 }
875
876 if (fix_screen || R->old_height == 0) {
877 int curr_screen = -1;
878 uint16_t old_ncol = R->prev_ncol;
879
880 /* scr_reset only works on the primary screen */
881 if (R->old_height) /* this is not the first time through */
882 curr_screen = rxvt_scr_change_screen(aR_ PRIMARY);
883 rxvt_scr_reset(aR);
884 if (curr_screen >= 0) { /* this is not the first time through */
885 rxvt_scr_change_screen(aR_ curr_screen);
886 rxvt_selection_check(aR_(old_ncol != R->TermWin.ncol ? 4 : 0));
887 }
888 }
889
890 R->old_width = R->szHint.width;
891 R->old_height = R->szHint.height;
892
893 #ifdef USE_XIM
894 rxvt_IMSetStatusPosition(aR);
895 #endif
896 }
897
898 /*
899 * Set the width/height of the vt window in characters. Units are pixels.
900 * good for toggling 80/132 columns
901 */
902 /* EXTPROTO */
903 void
904 rxvt_set_widthheight(pR_ unsigned int width, unsigned int height)
905 {
906 XWindowAttributes wattr;
907
908 if (width == 0 || height == 0) {
909 XGetWindowAttributes(R->Xdisplay, Xroot, &wattr);
910 if (width == 0)
911 width = wattr.width - R->szHint.base_width;
912 if (height == 0)
913 height = wattr.height - R->szHint.base_height;
914 }
915 if (width != R->TermWin.width || height != R->TermWin.height) {
916 width += R->szHint.base_width;
917 height += R->szHint.base_height;
918 rxvt_resize_all_windows(aR_ width, height, 0);
919 }
920 }
921
922 /* -------------------------------------------------------------------- *
923 * - X INPUT METHOD ROUTINES - *
924 * -------------------------------------------------------------------- */
925 #ifdef USE_XIM
926 /* INTPROTO */
927 void
928 rxvt_setSize(pR_ XRectangle * size)
929 {
930 size->x = R->TermWin.int_bwidth;
931 size->y = R->TermWin.int_bwidth;
932 size->width = Width2Pixel(R->TermWin.ncol);
933 size->height = Height2Pixel(R->TermWin.nrow);
934 }
935
936 /* INTPROTO */
937 void
938 rxvt_setColor(pR_ unsigned long *fg, unsigned long *bg)
939 {
940 *fg = R->PixColors[Color_fg];
941 *bg = R->PixColors[Color_bg];
942 }
943
944 /* Checking whether input method is running. */
945 /* INTPROTO */
946 Bool
947 rxvt_IMisRunning(pR)
948 {
949 char *p;
950 Atom atom;
951 Window win;
952 char server[IMBUFSIZ];
953
954 /* get current locale modifier */
955 if ((p = XSetLocaleModifiers(NULL)) != NULL) {
956 STRCPY(server, "@server=");
957 STRNCAT(server, &(p[4]), IMBUFSIZ - 9); /* skip "@im=" */
958 if ((p = STRCHR(server + 1, '@')) != NULL) /* first one only */
959 *p = '\0';
960
961 atom = XInternAtom(R->Xdisplay, server, False);
962 win = XGetSelectionOwner(R->Xdisplay, atom);
963 if (win != None)
964 return True;
965 }
966 return False;
967 }
968
969 /* EXTPROTO */
970 void
971 rxvt_IMSendSpot(pR)
972 {
973 XPoint spot;
974 XVaNestedList preedit_attr;
975
976 if (R->Input_Context == NULL
977 || !R->TermWin.focus || !(R->input_style & XIMPreeditPosition)
978 || !(R->event_type == KeyPress
979 || R->event_type == Expose
980 || R->event_type == NoExpose
981 || R->event_type == SelectionNotify
982 || R->event_type == ButtonRelease || R->event_type == FocusIn)
983 || !rxvt_IMisRunning(aR))
984 return;
985
986 rxvt_setPosition(aR_ & spot);
987
988 preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &spot, NULL);
989 XSetICValues(R->Input_Context, XNPreeditAttributes, preedit_attr, NULL);
990 XFree(preedit_attr);
991 }
992
993 /* EXTPROTO */
994 void
995 rxvt_setTermFontSet(pR_ int idx)
996 {
997 char *string;
998 long length;
999 int success = 0;
1000
1001 if (idx < 0 || idx >= MAX_NFONTS)
1002 return;
1003 }
1004
1005 /* INTPROTO */
1006 void
1007 rxvt_setPreeditArea(pR_ XRectangle * preedit_rect, XRectangle * status_rect,
1008 XRectangle * needed_rect)
1009 {
1010 int mbh, vtx = 0;
1011
1012 if (scrollbar_visible(R) && !(R->Options & Opt_scrollBar_right))
1013 vtx = scrollbar_TotalWidth();
1014 mbh = menubar_visible(R) ? menuBar_TotalHeight() : 0;
1015 mbh -= R->TermWin.lineSpace;
1016
1017 preedit_rect->x = needed_rect->width + vtx;
1018 preedit_rect->y = Height2Pixel(R->TermWin.nrow - 1) + mbh;
1019
1020 preedit_rect->width = Width2Pixel(R->TermWin.ncol + 1) - needed_rect->width
1021 + vtx;
1022 preedit_rect->height = Height2Pixel(1);
1023
1024 status_rect->x = vtx;
1025 status_rect->y = Height2Pixel(R->TermWin.nrow - 1) + mbh;
1026
1027 status_rect->width = needed_rect->width ? needed_rect->width
1028 : Width2Pixel(R->TermWin.ncol + 1);
1029 status_rect->height = Height2Pixel(1);
1030 }
1031
1032 /* ARGSUSED */
1033 /* INTPROTO */
1034 void
1035 rxvt_IMDestroyCallback(XIM xim __attribute__ ((unused)), XPointer client_data
1036 __attribute__ ((unused)), XPointer call_data
1037 __attribute__ ((unused)))
1038 {
1039 dR;
1040
1041 R->Input_Context = NULL;
1042 /* To avoid Segmentation Fault in C locale: Solaris only? */
1043 if (STRCMP(R->locale, "C"))
1044 XRegisterIMInstantiateCallback(R->Xdisplay, NULL, NULL, NULL,
1045 rxvt_IMInstantiateCallback, NULL);
1046 }
1047
1048 /*
1049 * X manual pages and include files don't match on some systems:
1050 * some think this is an XIDProc and others an XIMProc so we can't
1051 * use the first argument - need to update this to be nice for
1052 * both types via some sort of configure detection
1053 */
1054 /* ARGSUSED */
1055 /* EXTPROTO */
1056 void
1057 rxvt_IMInstantiateCallback(Display * unused
1058 __attribute__ ((unused)), XPointer client_data
1059 __attribute__ ((unused)), XPointer call_data
1060 __attribute__ ((unused)))
1061 {
1062 dR;
1063 int i, found, had_im;
1064 const char *p;
1065 char **s;
1066 char buf[IMBUFSIZ];
1067
1068 D_MAIN((stderr, "rxvt_IMInstantiateCallback()"));
1069 if (R->Input_Context)
1070 return;
1071
1072 found = had_im = 0;
1073 p = R->rs[Rs_inputMethod];
1074 if (p && *p) {
1075 had_im = 1;
1076 s = rxvt_splitcommastring(p);
1077 for (i = 0; s[i]; i++) {
1078 if (*s[i]) {
1079 STRCPY(buf, "@im=");
1080 STRNCAT(buf, s[i], IMBUFSIZ - 5);
1081 if ((p = XSetLocaleModifiers(buf)) != NULL && *p
1082 && (rxvt_IM_get_IC(aR) == True)) {
1083 found = 1;
1084 break;
1085 }
1086 }
1087 }
1088 for (i = 0; s[i]; i++)
1089 free(s[i]);
1090 free(s);
1091 }
1092 if (found)
1093 return;
1094
1095 /* try with XMODIFIERS env. var. */
1096 if ((p = XSetLocaleModifiers("")) != NULL && *p) {
1097 rxvt_IM_get_IC(aR);
1098 return;
1099 }
1100
1101 /* try with no modifiers base IF the user didn't specify an IM */
1102 if (!had_im && (p = XSetLocaleModifiers("@im=none")) != NULL && *p
1103 && rxvt_IM_get_IC(aR) == True)
1104 return;
1105 }
1106
1107 /*
1108 * Try to open a XIM with the current modifiers, then see if we can
1109 * open a suitable preedit type
1110 */
1111 /* INTPROTO */
1112 Bool
1113 rxvt_IM_get_IC(pR)
1114 {
1115 int i, j, found;
1116 XIM xim;
1117 XPoint spot;
1118 XRectangle rect, status_rect, needed_rect;
1119 unsigned long fg, bg;
1120 const char *p;
1121 char **s;
1122 XIMStyles *xim_styles;
1123 XVaNestedList preedit_attr, status_attr;
1124 XIMCallback ximcallback;
1125
1126 D_MAIN((stderr, "rxvt_IM_get_IC()"));
1127 xim = XOpenIM(R->Xdisplay, NULL, NULL, NULL);
1128 if (xim == NULL)
1129 return False;
1130
1131 xim_styles = NULL;
1132 if (XGetIMValues(xim, XNQueryInputStyle, &xim_styles, NULL)
1133 || !xim_styles || !xim_styles->count_styles) {
1134 XCloseIM(xim);
1135 return False;
1136 }
1137
1138 p = R->rs[Rs_preeditType] ? R->rs[Rs_preeditType]
1139 : "OverTheSpot,OffTheSpot,Root";
1140 s = rxvt_splitcommastring(p);
1141 for (i = found = 0; !found && s[i]; i++) {
1142 if (!STRCMP(s[i], "OverTheSpot"))
1143 R->input_style = (XIMPreeditPosition | XIMStatusNothing);
1144 else if (!STRCMP(s[i], "OffTheSpot"))
1145 R->input_style = (XIMPreeditArea | XIMStatusArea);
1146 else if (!STRCMP(s[i], "Root"))
1147 R->input_style = (XIMPreeditNothing | XIMStatusNothing);
1148
1149 for (j = 0; j < xim_styles->count_styles; j++)
1150 if (R->input_style == xim_styles->supported_styles[j]) {
1151 found = 1;
1152 break;
1153 }
1154 }
1155 for (i = 0; s[i]; i++)
1156 free(s[i]);
1157 free(s);
1158 XFree(xim_styles);
1159
1160 if (!found) {
1161 XCloseIM(xim);
1162 return False;
1163 }
1164
1165 ximcallback.callback = rxvt_IMDestroyCallback;
1166
1167 /* XXX: not sure why we need this (as well as IC one below) */
1168 XSetIMValues(xim, XNDestroyCallback, &ximcallback, NULL);
1169
1170 preedit_attr = status_attr = NULL;
1171
1172 if (R->input_style & XIMPreeditPosition) {
1173 rxvt_setSize(aR_ & rect);
1174 rxvt_setPosition(aR_ & spot);
1175 rxvt_setColor(aR_ & fg, &bg);
1176
1177 preedit_attr = XVaCreateNestedList(0, XNArea, &rect,
1178 XNSpotLocation, &spot,
1179 XNForeground, fg, XNBackground, bg,
1180 //XNFontSet, R->TermWin.fontset,
1181 NULL);
1182 } else if (R->input_style & XIMPreeditArea) {
1183 rxvt_setColor(aR_ & fg, &bg);
1184
1185 /*
1186 * The necessary width of preedit area is unknown
1187 * until create input context.
1188 */
1189 needed_rect.width = 0;
1190
1191 rxvt_setPreeditArea(aR_ & rect, &status_rect, &needed_rect);
1192
1193 preedit_attr = XVaCreateNestedList(0, XNArea, &rect,
1194 XNForeground, fg, XNBackground, bg,
1195 //XNFontSet, R->TermWin.fontset,
1196 NULL);
1197 status_attr = XVaCreateNestedList(0, XNArea, &status_rect,
1198 XNForeground, fg, XNBackground, bg,
1199 //XNFontSet, R->TermWin.fontset,
1200 NULL);
1201 }
1202 R->Input_Context = XCreateIC(xim, XNInputStyle, R->input_style,
1203 XNClientWindow, R->TermWin.parent[0],
1204 XNFocusWindow, R->TermWin.parent[0],
1205 XNDestroyCallback, &ximcallback,
1206 preedit_attr ? XNPreeditAttributes : NULL,
1207 preedit_attr,
1208 status_attr ? XNStatusAttributes : NULL,
1209 status_attr, NULL);
1210 if (preedit_attr)
1211 XFree(preedit_attr);
1212 if (status_attr)
1213 XFree(status_attr);
1214 if (R->Input_Context == NULL) {
1215 rxvt_print_error("failed to create input context");
1216 XCloseIM(xim);
1217 return False;
1218 }
1219 if (R->input_style & XIMPreeditArea)
1220 rxvt_IMSetStatusPosition(aR);
1221 D_MAIN((stderr, "rxvt_IM_get_IC() - successful connection"));
1222 return True;
1223 }
1224
1225 /* EXTPROTO */
1226 void
1227 rxvt_IMSetStatusPosition(pR)
1228 {
1229 XRectangle preedit_rect, status_rect, *needed_rect;
1230 XVaNestedList preedit_attr, status_attr;
1231
1232 if (R->Input_Context == NULL
1233 || !R->TermWin.focus || !(R->input_style & XIMPreeditArea)
1234 || !rxvt_IMisRunning(aR))
1235 return;
1236
1237 /* Getting the necessary width of preedit area */
1238 status_attr = XVaCreateNestedList(0, XNAreaNeeded, &needed_rect, NULL);
1239 XGetICValues(R->Input_Context, XNStatusAttributes, status_attr, NULL);
1240 XFree(status_attr);
1241
1242 rxvt_setPreeditArea(aR_ & preedit_rect, &status_rect, needed_rect);
1243
1244 preedit_attr = XVaCreateNestedList(0, XNArea, &preedit_rect, NULL);
1245 status_attr = XVaCreateNestedList(0, XNArea, &status_rect, NULL);
1246
1247 XSetICValues(R->Input_Context,
1248 XNPreeditAttributes, preedit_attr,
1249 XNStatusAttributes, status_attr, NULL);
1250
1251 XFree(preedit_attr);
1252 XFree(status_attr);
1253 }
1254 #endif /* USE_XIM */
1255
1256 /*----------------------------------------------------------------------*/
1257 rxvt_t rxvt_current_term;
1258
1259 /*----------------------- end-of-file (C source) -----------------------*/