1 /*--------------------------------*-C-*---------------------------------*
2  * File:	main.c
3  *----------------------------------------------------------------------*
4  *
5  * All portions of code are copyright by their respective author/s.
6  * Copyright (c) 1992        John Bovey <jdb@ukc.ac.uk>
7  * Copyright (c) 1994        Robert Nation <nation@rocket.sanders.lockheed.com>
8  * Copyright (c) 1995        Garrett D'Amore <garrett@netcom.com>
9  * Copyright (c) 1997        mj olesen <olesen@me.QueensU.CA>
10  * Copyright (c) 1997,1998   Oezguer Kesim <kesim@math.fu-berlin.de>
11  * Copyright (c) 1998-2001   Geoff Wing <gcw@pobox.com>
12  * Copyright (c) 2000        Xianping Ge <xge@ics.uci.edu>
13  * Copyright (c) 2003-2004   Marc Lehmann <pcg@goof.com>
14  * Copyright (c) 2005        Burgers A.R. <burgers@ecn.nl>
15  * Copyright (c) 2004-2005   Jingmin Zhou <jimmyzhou@users.sourceforge.net>
16  *
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation; either version 2 of the License, or
20  * (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program; if not, write to the Free Software
29  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
30  *----------------------------------------------------------------------*/
31 /*
32 ** $Id: main.c,v 1.145 2005/08/31 05:30:41 cvs Exp $
33 */
34 
35 #include "../config.h"
36 #include "rxvt.h"
37 
38 
39 
40 #ifdef DEBUG_VERBOSE
41 # define DEBUG_LEVEL 1
42 # define DEBUG_X
43 #else
44 # define DEBUG_LEVEL 0
45 #endif
46 
47 #if DEBUG_LEVEL
48 # define DBG_MSG(d,x) if(d <= DEBUG_LEVEL) fprintf x
49 #else
50 # define DBG_MSG(d,x)
51 #endif
52 
53 
54 
55 /*--------------------------------------------------------------------*
56  *         BEGIN `INTERNAL' ROUTINE PROTOTYPES                        *
57  *--------------------------------------------------------------------*/
58 void rxvt_clean_commands       (rxvt_t* r, int command_number);
59 void rxvt_free_hidden          (rxvt_t*);
60 void rxvt_font_up_down         (rxvt_t*, int, int);
61 int  rxvt_get_font_widest      (XFontStruct*);
62 void rxvt_set_colorfgbg        (rxvt_t*);
63 void rxvt_resize_sub_windows   (rxvt_t*);
64 void rxvt_recalc_szhint        (rxvt_t*, resize_reason_t reason, unsigned int* p_w, unsigned int* p_h);
65 #ifdef USE_XIM
66 void rxvt_IM_set_size          (rxvt_t*, XRectangle*);
67 void rxvt_IM_set_color         (rxvt_t*, unsigned long*, unsigned long*);
68 Bool rxvt_IM_is_running        (rxvt_t*);
69 void rxvt_IM_set_preedit_area  (rxvt_t*, XRectangle*, XRectangle*, XRectangle*);
70 void rxvt_IM_destroy_callback  (XIM, XPointer, XPointer);
71 Bool rxvt_IM_get_IC            (rxvt_t*);
72 #endif
73 void rxvt_set_r                (rxvt_t*);
74 #ifdef XFT_SUPPORT
75 void rxvt_init_font_fixed      (rxvt_t*);
76 # ifndef NO_BOLDFONT
77 void rxvt_init_bfont_xft       (rxvt_t*, XftPattern*);
78 # endif
79 # ifdef MULTICHAR_SET
80 int  rxvt_init_mfont_xft       (rxvt_t*, XftPattern*, const char*);
81 # endif
82 #endif	/* XFT_SUPPORT */
83 /*--------------------------------------------------------------------*
84  *         END   `INTERNAL' ROUTINE PROTOTYPES                        *
85  *--------------------------------------------------------------------*/
86 
87 
88 
89 /*----------------------------------------------------------------------*/
90 const char**	cmd_argv;
91 /*----------------------------------------------------------------------*/
92 
93 /* INTPROTO */
94 void
rxvt_free_commands(rxvt_t * r,int command_number)95 rxvt_free_commands (rxvt_t* r, int command_number)
96 {
97 	register int	i;
98 
99 	/* reset all tab commands to NULL */
100 	for (i = 0; i < MAX_PAGES; i ++)	{
101 		/* rs[ANYTHING] is static string, shouldn't use free to
102 		** release. So we simply reset them to NULL */
103 		r->h->rs[Rs_command+i] = NULL;
104 	}
105 
106 	/* free all command argv */
107 	for (i = 0; i < command_number; i ++)	{
108 		if (PVTS(r, i)->command_argv &&
109 			PVTS(r, i)->command_argc)	{
110 			register int	j;
111 
112 	        for (j = 0; j < PVTS(r, i)->command_argc; j ++)
113 	            free (PVTS(r, i)->command_argv[j]);
114 	        free (PVTS(r, i)->command_argv);
115 	        PVTS(r, i)->command_argv = NULL;
116 	        PVTS(r, i)->command_argc = 0;
117 		}
118 	}
119 }
120 
121 
122 
123 /* rxvt_init() */
124 /* LIBPROTO */
125 rxvt_t			*
rxvt_init(int argc,const char * const * argv)126 rxvt_init(int argc, const char *const *argv)
127 {
128 	register int	i;
129 	register int	itnum; /* initial terminal number */
130 	rxvt_t*			r;
131 
132 	r = (rxvt_t *)rxvt_calloc(1, sizeof(rxvt_t));
133 	rxvt_set_r(r);		/* only assignment to _rxvt_vars */
134 	if (rxvt_init_vars(r) < 0) {
135 		free(r);
136 		return NULL;
137 	}
138 	/* save global argc and argv */
139 	r->global_argc = argc;
140 	r->global_argv = (char**) argv;
141 
142 	rxvt_init_secondary(r);
143 	rxvt_init_hotkeys (r);
144 	cmd_argv = rxvt_init_resources(r, argc, argv);
145 
146 	rxvt_create_show_windows(r, argc, argv);
147 
148 #ifdef TRANSPARENT
149 	if (r->Options & Opt_transparent) {
150 		XSelectInput(r->Xdisplay, XROOT, PropertyChangeMask);
151 		rxvt_check_our_parents(r);
152 	}
153 #endif
154 
155 	rxvt_init_env(r);
156 	rxvt_init_command(r, cmd_argv);
157 	rxvt_init_screen (r);
158 
159 	/*
160 	** Initialize the pages
161 	*/
162 	if (!r->h->rs[Rs_init_term_num])
163 		itnum = 1;
164 	else	{
165 		itnum = atoi (r->h->rs[Rs_init_term_num]);
166 		itnum = max (1, itnum);
167 		itnum = min (itnum, MAX_PAGES);
168 	}
169 	for (i = 0; i < itnum; i ++)
170 		rxvt_append_page (r, NULL);
171 	rxvt_activate_page (r, 0);
172 
173 	/*
174 	** If commands are loaded only on init, free command resources
175 	** now. The future commands will only get NULL string as their
176 	** commands, and will fall back to default shell. This simplify
177 	** the logic to choose commands for a new terminal.
178 	*/
179 	if (r->Options2 & Opt2_cmdInitTabs)
180 		rxvt_free_commands (r, itnum);
181 
182 	/* Initialize xlocale after VT is created */
183 	rxvt_init_xlocale(r);
184 
185 	return r;
186 }
187 
188 /* ------------------------------------------------------------------------- *
189  *							SIGNAL HANDLING & EXIT HANDLER						*
190  * ------------------------------------------------------------------------- */
191 /*
192  * Catch a SIGCHLD signal and exit if the direct child has died
193  */
194 /* ARGSUSED */
195 /* EXTPROTO */
196 RETSIGTYPE
rxvt_Child_signal(int sig)197 rxvt_Child_signal(int sig __attribute__((unused)))
198 {
199 	int					pid, save_errno;
200 	rxvt_t*				r;
201 
202 	/* enable signal reentry, it's ok here */
203 	signal(SIGCHLD, rxvt_Child_signal);
204 
205 
206 	save_errno = errno;
207 	do {
208 		errno = 0;
209 	} while ((pid = waitpid(-1, NULL, WNOHANG)) == -1 &&
210 			errno == EINTR);
211 
212 	DBG_MSG(1,(stderr, "signal: child %d died\n", (int) pid));
213 	r = rxvt_get_r();
214 	if (pid != -1)	{
215 		register int	i;
216 
217 		for (i = 0; i <= LTAB(r); i ++)
218 			if (pid == PVTS(r, i)->cmd_pid)
219 				break;
220 
221 		if (i <= LTAB(r))	{
222 			DBG_MSG(1,(stderr, "Dead child %d is tab %d\n", (int) pid, i));
223 			/* one more vt died */
224 			r->vt_died ++;
225 			/* update child members */
226 			PVTS(r, i)->dead = 1;
227 			if (r->Options2 & Opt2_holdExit)
228 				PVTS(r, i)->hold = 1;
229 		}
230 		else	{
231 			errno = save_errno;
232 		}
233 	}
234 }
235 
236 
237 /*
238  * Catch a fatal signal and tidy up before quitting
239  */
240 /* EXTPROTO */
241 RETSIGTYPE
rxvt_Exit_signal(int sig)242 rxvt_Exit_signal(int sig)
243 {
244 #ifdef UTMP_SUPPORT
245 	register int	i;
246 #endif
247 	rxvt_t*			r;
248 
249 	DBG_MSG(1,(stderr, "Receive signal %d\n", (int) sig));
250 	signal(sig, SIG_DFL);
251 
252 	r = rxvt_get_r();
253 
254 #ifdef UTMP_SUPPORT
255 	for (i = 0; i <= LTAB(r); i ++)	{
256 		rxvt_privileges (RESTORE);
257 		rxvt_cleanutent (r, i);
258 		rxvt_privileges (IGNORE);
259 	}
260 #endif
261 
262 	/* resend signal to default handler */
263 	/* kill (getpid (), sig); */
264 	rxvt_clean_exit (r);
265 }
266 
267 
268 /* INTPROTO */
269 void
rxvt_free_hidden(rxvt_t * r)270 rxvt_free_hidden (rxvt_t* r)
271 {
272 #ifdef DEBUG
273 	if (None != r->h->bar_pointer)	{
274 		XFreeCursor (r->Xdisplay, r->h->bar_pointer);
275 		r->h->bar_pointer = None;
276 	}
277 # ifdef POINTER_BLANK
278 	if (None != r->h->blank_pointer)	{
279 		XFreeCursor (r->Xdisplay, r->h->blank_pointer);
280 		r->h->blank_pointer = None;
281 	}
282 # endif
283 #endif	/* DEBUG */
284 
285 #ifdef USE_XIM
286 	if (r->h->Input_Context)    {
287 		XDestroyIC (r->h->Input_Context);
288 		r->h->Input_Context = NULL;
289 	}
290 #endif
291 }
292 
293 
294 /* EXTPROTO */
295 void
rxvt_clean_exit(rxvt_t * r)296 rxvt_clean_exit (rxvt_t* r)
297 {
298 	register int	i;
299 
300 	/* restore default SIGCHLD signal handler */
301 	signal (SIGCHLD, SIG_DFL);
302 
303 	rxvt_free_hidden (r);
304 
305 #ifdef HAVE_X11_SM_SMLIB_H
306 	if (r->Options2 & Opt2_enableSessionMgt)
307 		rxvt_session_exit (r);
308 #endif
309 
310 	/* now kill all child processes, zsh puts them into background
311 	** if we do not do so */
312 	for (i = 0; i <= LTAB(r); i ++)
313 		kill (PVTS(r, i)->cmd_pid, SIGHUP);
314 
315 #ifdef DEBUG	/* Only free X resources in debug mode */
316 	/* Destroy windows before other X resources */
317 	if (None != r->TermWin.parent)	{
318 		XDestroySubwindows (r->Xdisplay, r->TermWin.parent);
319 		XDestroyWindow (r->Xdisplay, r->TermWin.parent);
320 		r->TermWin.parent = None;
321 	}
322 
323 # ifdef HAVE_SCROLLBARS
324 	rxvt_scrollbar_clean_exit (r);
325 # endif
326 
327 # ifdef HAVE_MENUBAR
328 	rxvt_menubar_clean_exit (r);
329 # endif
330 
331 	rxvt_tabbar_clean_exit (r);
332 
333 	if (NULL != r->TermWin.font)
334 		XFreeFont (r->Xdisplay, r->TermWin.font);
335 # ifndef NO_BOLDFONT
336 	if (NULL != r->TermWin.bfont &&
337 		r->TermWin.font != r->TermWin.bfont)	{
338 		XFreeFont (r->Xdisplay, r->TermWin.bfont);
339 		r->TermWin.bfont = NULL;
340 	}
341 # endif
342 # ifdef MULTICHAR_SET
343 	if (NULL != r->TermWin.mfont &&
344 		r->TermWin.font != r->TermWin.mfont)	{
345 		XFreeFont (r->Xdisplay, r->TermWin.mfont);
346 		r->TermWin.mfont = NULL;
347 	}
348 # endif
349 	r->TermWin.font = NULL;		/* clear font */
350 
351 # ifdef XFT_SUPPORT
352 	if (NULL != r->TermWin.xftfont)
353 		XftFontClose (r->Xdisplay, r->TermWin.xftfont);
354 #  ifndef NO_BOLDFONT
355 	if (NULL != r->TermWin.xftbfont &&
356 		r->TermWin.xftfont != r->TermWin.xftbfont)	{
357 		XftFontClose (r->Xdisplay, r->TermWin.xftbfont);
358 		r->TermWin.xftbfont = NULL;
359 	}
360 #  endif
361 #  ifdef MULTICHAR_SET
362 	if (NULL != r->TermWin.xftmfont &&
363 		r->TermWin.xftfont != r->TermWin.xftmfont)	{
364 		XftFontClose (r->Xdisplay, r->TermWin.xftmfont);
365 		r->TermWin.xftmfont = NULL;
366 	}
367 #  endif
368 	r->TermWin.xftfont = NULL;	/* clear font */
369 # endif
370 
371 	if (None != r->term_pointer)	{
372 		XFreeCursor (r->Xdisplay, r->term_pointer);
373 		r->term_pointer = None;
374 	}
375 	if (None != r->TermWin.gc)	{
376 		XFreeGC (r->Xdisplay, r->TermWin.gc);
377 		r->TermWin.gc = None;
378 	}
379 # ifdef TRANSPARENT
380 	if (None != r->TermWin.pixmap)	{
381 		XFreePixmap (r->Xdisplay, r->TermWin.pixmap);
382 		r->TermWin.pixmap = None;
383 	}
384 # endif
385 	XCloseDisplay (r->Xdisplay);
386 	r->Xdisplay = NULL;
387 
388 	free (r->tabstop);			r->tabstop = NULL;
389 	free (r->PixColors);		r->PixColors = NULL;
390 # ifdef OFF_FOCUS_FADING
391 	free (r->PixColorsUnfocus);	r->PixColorsUnfocus = NULL;
392 # endif
393 # ifdef XFT_SUPPORT
394 	free (r->XftColors);		r->XftColors = NULL;
395 # endif
396 	free (r->h);				r->h = NULL;
397 	free (r);					r = NULL;
398 
399 #endif	/* DEBUG */
400 
401 	exit(EXIT_SUCCESS);
402 }
403 
404 
405 /* ------------------------------------------------------------------------- *
406  *							MEMORY ALLOCATION WRAPPERS						*
407  * ------------------------------------------------------------------------- */
408 /* EXTPROTO */
409 void*
rxvt_malloc(size_t size)410 rxvt_malloc(size_t size)
411 {
412 	void*		p;
413 
414 	/* see AC_FUNC_MALLOC macro in autoconf documentation */
415 	if (0 == size)
416 		size = 1;
417 
418 	p = malloc(size);
419 	if (p)
420 		return p;
421 
422 	fprintf(stderr, APL_NAME ": memory allocation failure.  Aborting");
423 	exit(EXIT_FAILURE);
424 	/* NOTREACHED */
425 }
426 
427 
428 /* EXTPROTO */
429 void*
rxvt_calloc(size_t number,size_t size)430 rxvt_calloc(size_t number, size_t size)
431 {
432 	void*		p;
433 
434 	p = calloc(number, size);
435 	if (p)
436 		return p;
437 
438 	fprintf(stderr, APL_NAME ": memory allocation failure.  Aborting");
439 	exit(EXIT_FAILURE);
440 	 /* NOTREACHED */
441 }
442 
443 
444 /* EXTPROTO */
445 void*
rxvt_realloc(void * ptr,size_t size)446 rxvt_realloc(void *ptr, size_t size)
447 {
448 	void*		p;
449 
450 	if (ptr)
451 		p = realloc(ptr, size);
452 	else
453 		p = malloc(size);
454 	if (p)
455 		return p;
456 
457 	fprintf(stderr, APL_NAME ": memory allocation failure.  Aborting");
458 	exit(EXIT_FAILURE);
459 	/* NOTREACHED */
460 }
461 
462 
463 /* ------------------------------------------------------------------------- *
464  *							PRIVILEGED OPERATIONS							*
465  * ------------------------------------------------------------------------- */
466 
467 #if (defined(HAVE_SETEUID) || defined(HAVE_SETREUID)) && !defined(OS_CYGWIN)
468 static uid_t		g_euid;
469 static gid_t		g_egid;
470 #endif
471 
472 /* take care of suid/sgid super-user (root) privileges */
473 /* EXTPROTO */
474 void
rxvt_privileges(int mode)475 rxvt_privileges(int mode)
476 {
477 #if !defined(OS_CYGWIN)
478 # if !defined(HAVE_SETEUID) && defined(HAVE_SETREUID)
479 /* setreuid() is the poor man's setuid(), seteuid() */
480 #  define seteuid(a)	setreuid(-1, (a))
481 #  define setegid(a)	setregid(-1, (a))
482 #  define HAVE_SETEUID
483 # endif
484 # ifdef HAVE_SETEUID
485 	switch (mode) {
486 	case IGNORE:
487 	/*
488 	 * change effective uid/gid - not real uid/gid - so we can switch
489 	 * back to root later, as required
490 	 */
491 		seteuid(getuid());
492 		setegid(getgid());
493 		break;
494 	case SAVE:
495 		g_euid = geteuid();
496 		g_egid = getegid();
497 		break;
498 	case RESTORE:
499 		seteuid(g_euid);
500 		setegid(g_egid);
501 		break;
502 	}
503 # else
504 	switch (mode) {
505 	case IGNORE:
506 		if (setuid(getuid()) < 0)
507 			exit (EXIT_FAILURE);
508 		if (setgid(getgid()) < 0)
509 			exit (EXIT_FAILURE);
510 		/* FALLTHROUGH */
511 	case SAVE:
512 		/* FALLTHROUGH */
513 	case RESTORE:
514 		break;
515 	}
516 # endif
517 #endif
518 }
519 
520 
521 #ifdef UTMP_SUPPORT
522 /* EXTPROTO */
523 void
rxvt_privileged_utmp(rxvt_t * r,int page,char action)524 rxvt_privileged_utmp(rxvt_t* r, int page, char action)
525 {
526 	DBG_MSG(1,(stderr, "rxvt_privileged_utmp %d (%c); waiting for: %c (pid: %d)\n", page, action, PVTS(r, page)->next_utmp_action, (int) getpid()));
527 
528 	if (PVTS(r, page)->next_utmp_action != action ||
529 		(action != SAVE && action != RESTORE) ||
530 		(r->Options & Opt_utmpInhibit) ||
531 		PVTS(r, page)->ttydev == NULL ||
532 		*(PVTS(r, page)->ttydev) == (char) 0)
533 		return;
534 
535 	rxvt_privileges(RESTORE);
536 	if (action == SAVE) {
537 		PVTS(r, page)->next_utmp_action = RESTORE;
538 		rxvt_makeutent(r, page, PVTS(r, page)->ttydev, r->h->rs[Rs_display_name]);
539 	}
540 	else {		/* action == RESTORE */
541 		PVTS(r, page)->next_utmp_action = IGNORE;
542 		rxvt_cleanutent(r, page);
543 	}
544 	rxvt_privileges(IGNORE);
545 }
546 #endif
547 
548 
549 #ifndef NO_SETOWNER_TTYDEV
550 /* EXTPROTO */
551 void
rxvt_privileged_ttydev(rxvt_t * r,int page,char action)552 rxvt_privileged_ttydev(rxvt_t* r, int page, char action)
553 {
554 	DBG_MSG(1,(stderr, "rxvt_privileged_ttydev %d (r, %c); waiting for: %c (pid: %d)\n", page, action, PVTS(r, page)->next_tty_action, getpid()));
555 	if (PVTS(r, page)->next_tty_action != action ||
556 		(action != SAVE && action != RESTORE) ||
557 		PVTS(r, page)->ttydev == NULL ||
558 		*(PVTS(r, page)->ttydev) == (char) 0)
559 		return;
560 
561 	rxvt_privileges(RESTORE);
562 
563 	if (action == SAVE) {
564 		PVTS(r, page)->next_tty_action = RESTORE;
565 # ifndef RESET_TTY_TO_COMMON_DEFAULTS
566 /* store original tty status for restoration rxvt_clean_exit() -- rgg 04/12/95 */
567 		if (lstat(PVTS(r, page)->ttydev, &h->ttyfd_stat) < 0)	/* you lose out */
568 			PVTS(r, page)->next_tty_action = IGNORE;
569 		else
570 # endif
571 		{
572 			/* fail silently */
573 			chown(PVTS(r, page)->ttydev, getuid(), r->h->ttygid);
574 			chmod(PVTS(r, page)->ttydev, PVTS(r, page)->ttymode);
575 # ifdef HAVE_REVOKE
576 			revoke(PVTS(r, page)->ttydev);
577 # endif
578 		}
579 	}
580 	else {			/* action == RESTORE */
581 		PVTS(r, page)->next_tty_action = IGNORE;
582 # ifndef RESET_TTY_TO_COMMON_DEFAULTS
583 		chmod(PVTS(r, page)->ttydev, PVTS(r, page)->ttyfd_stat.st_mode);
584 		chown(PVTS(r, page)->ttydev, PVTS(r, page)->ttyfd_stat.st_uid, PVTS(r, page)->ttyfd_stat.st_gid);
585 # else
586 		chmod(PVTS(r, page)->ttydev,
587 			(S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH));
588 		chown(PVTS(r, page)->ttydev, 0, 0);
589 # endif
590 	}
591 
592 	rxvt_privileges(IGNORE);
593 
594 # ifndef RESET_TTY_TO_COMMON_DEFAULTS
595 	DBG_MSG(1,(stderr, "%s \"%s\": mode %03o, uid %d, gid %d\n", action == RESTORE ? "Restoring" : (action == SAVE ? "Saving" : "UNKNOWN ERROR for"), PVTS(r, page)->ttydev, PVTS(r, page)->ttyfd_stat.st_mode, PVTS(r, page)->ttyfd_stat.st_uid, PVTS(r, page)->ttyfd_stat.st_gid));
596 # endif
597 }
598 #endif
599 
600 
601 /*----------------------------------------------------------------------*/
602 /*
603  * Tell the teletype handler what size the window is.
604  * Called after a window size change.
605  */
606 /* EXTPROTO */
607 void
rxvt_tt_winsize(int fd,unsigned short col,unsigned short row,pid_t pid)608 rxvt_tt_winsize(int fd, unsigned short col, unsigned short row, pid_t pid)
609 {
610 	struct winsize  ws;
611 
612 	if (fd < 0)
613 	return;
614 	ws.ws_col = col;
615 	ws.ws_row = row;
616 	ws.ws_xpixel = ws.ws_ypixel = 0;
617 #ifndef DEBUG
618 	(void)ioctl(fd, TIOCSWINSZ, &ws);
619 #else
620 	if (ioctl(fd, TIOCSWINSZ, &ws) < 0) {
621 		DBG_MSG(1,(stderr, "Failed to send TIOCSWINSZ to fd %d\n", fd));
622 	}
623 # ifdef SIGWINCH
624 	else if (pid)		/* force through to the command */
625 		kill(pid, SIGWINCH);
626 # endif
627 #endif	/* DEBUG */
628 }
629 
630 
631 
632 #define IDX2FNUM(i)		((FONT0_IDX + i) % MAX_NFONTS)
633 #define FNUM2IDX(f)		((FONT0_IDX + f) % MAX_NFONTS)
634 
635 
636 #ifdef XFT_SUPPORT
637 
638 # ifndef NO_BOLDFONT
639 /* INTPROTO */
640 void
rxvt_init_bfont_xft(rxvt_t * r,XftPattern * xpold)641 rxvt_init_bfont_xft (rxvt_t* r, XftPattern* xpold)
642 {
643 	XftResult		fr;
644 	XftPattern*		xp;
645 # ifdef DEBUG
646 	FT_Face			face;
647 # endif
648 
649 
650 	if (r->h->rs[Rs_xftwt] && !STRCASECMP(r->h->rs[Rs_xftwt], "bold"))
651 		return ;
652 
653 	xp = XftPatternDuplicate (xpold);
654 	if (NULL == xp)
655 		return ;
656 
657 	/* set font weight */
658 	XftPatternDel (xp, XFT_WEIGHT);
659 	XftPatternAddInteger (xp, XFT_WEIGHT, XFT_WEIGHT_BOLD);
660 
661 	r->TermWin.xftbpattern = XftFontMatch (r->Xdisplay, XSCREEN, xp, &fr);
662 
663 	if (NULL != r->TermWin.xftbpattern)	{
664 		r->TermWin.xftbfont = XftFontOpenPattern (r->Xdisplay, r->TermWin.xftbpattern);
665 		if (NULL == r->TermWin.xftbfont)	{
666 			/* fall back to normal font */
667 			XftPatternDestroy (r->TermWin.xftbpattern);
668 			r->TermWin.xftbpattern = NULL;
669 		}
670 # ifdef DEBUG
671 		else	{
672 			face = XftLockFace (r->TermWin.xftbfont);
673 			XftUnlockFace (r->TermWin.xftbfont);
674 		}
675 # endif
676 	}
677 
678 	XftPatternDestroy (xp);
679 }
680 # endif	/* NO_BOLDFONT */
681 
682 
683 # ifdef MULTICHAR_SET
684 /* INTPROTO */
685 int
rxvt_init_mfont_xft(rxvt_t * r,XftPattern * xp,const char * ofname)686 rxvt_init_mfont_xft (rxvt_t* r, XftPattern* xp, const char* ofname)
687 {
688 	XftResult		fr;
689 	int				len, olen;		/* font name length */
690 	char*			mfname;			/* mfont name to open */
691 	char*			omfname = NULL;	/* actually opened mfont name */
692 	int				width, height;
693 # ifdef DEBUG
694 	FT_Face			face;
695 # endif
696 
697 	/* temporary XftPattern */
698 	assert (NULL != xp);
699 	/* actually opened normal font name */
700 	assert (NULL != ofname);
701 
702 	/*
703 	** Now try to open freetype mfont
704 	*/
705 	DBG_MSG(2,(stderr, "load freetype mfont\n"));
706 
707 	/* font family */
708 	mfname = (char*) r->h->rs[Rs_xftmfont];
709 	if (NULL == mfname)
710 		mfname = rxvt_fallback_mfont_xft (r);
711 
712 	/*
713 	** If we should not use mfont, then we always use normal font
714 	*/
715 	if (r->Options2 & Opt2_xftNomFont)	{
716 		r->TermWin.xftmpattern = r->TermWin.xftpattern;
717 		r->TermWin.xftmfont = r->TermWin.xftfont;
718 		return 1;
719 	}
720 
721 	/*
722 	** shortcut:
723 	** mfont is the same as font, just alias mfont to font
724 	*/
725 	if (0 == STRCASECMP (ofname, mfname))	{
726 		r->TermWin.xftmpattern = r->TermWin.xftpattern;
727 		r->TermWin.xftmfont = r->TermWin.xftfont;
728 		return 1;
729 	}
730 
731 	/* font family */
732 	XftPatternDel (xp, XFT_FAMILY);
733 	XftPatternAddString (xp, XFT_FAMILY, mfname);
734 
735 	XftPatternDel (xp, XFT_SIZE);
736 	/* this seems to be optimal for simsun font */
737 	XftPatternAddInteger (xp, XFT_SIZE, r->h->rs[Rs_xftmsz] ?
738 		(double) r->TermWin.xftmsize :
739 		(double) (r->TermWin.xftfont->height - 1));
740 
741 	/* font pattern */
742 	r->TermWin.xftmpattern = XftFontMatch (r->Xdisplay, XSCREEN, xp, &fr);
743 	if (NULL == r->TermWin.xftmpattern)
744 		return 0;
745 
746 	/* globaladvance */
747 	if (r->Options2 & Opt2_xftGlobalAdvance)	{
748 		XftPatternDel (r->TermWin.xftmpattern, FC_GLOBAL_ADVANCE);
749 		XftPatternAddBool (r->TermWin.xftmpattern, FC_GLOBAL_ADVANCE, FcTrue);
750 	}
751 
752 #  ifdef DEBUG_VERBOSE
753 	FcPatternPrint (r->TermWin.xftmpattern);
754 #  endif
755 
756 	XftPatternGetString (r->TermWin.xftmpattern, XFT_FAMILY, 0, &omfname);
757 	assert (NULL != omfname);	/* shouldn't be NULL */
758 	len = STRLEN(mfname);
759 	olen = STRLEN(omfname);
760 	if (STRNCASECMP (omfname, mfname, (len < olen ? len : olen)))
761 		rxvt_print_error ("Cannot open mfont %s, use mfont %s instead.",
762 			mfname, omfname);
763 
764 	DBG_MSG(1, (stderr, "create xftmpattern = 0x%x on mfont %d\n",
765 		(unsigned int) r->TermWin.xftmpattern, r->h->rs[Rs_xftmsz] ?
766 		r->TermWin.xftmsize : r->TermWin.xftfont->height-1));
767 	r->TermWin.xftmfont = XftFontOpenPattern (r->Xdisplay, r->TermWin.xftmpattern);
768 
769 	if (NULL == r->TermWin.xftmfont)
770 		goto Failure;
771 
772 # ifdef DEBUG
773 	face = XftLockFace (r->TermWin.xftmfont);
774 	XftUnlockFace (r->TermWin.xftmfont);
775 # endif
776 
777 	width = r->TermWin.xftmfont->max_advance_width;
778 	if ((width & 0x01) == 1)	/* in case width is not even */
779 		r->TermWin.xftmono = 0;
780 	else
781 	if (STRCASECMP (ofname, omfname) &&
782 		(r->TermWin.fwidth != (width >> 1)))
783 		r->TermWin.xftmono = 0;
784 	else
785 	if (r->Options2 & Opt2_xftSlowOutput)
786 		r->TermWin.xftmono = 0;
787 	DBG_MSG(1, (stderr, "xftmono is %d\n", r->TermWin.xftmono));
788 	MAX_IT (r->TermWin.fwidth, (width >> 1));
789 
790 	height = r->TermWin.xftmfont->ascent + r->TermWin.xftmfont->descent;
791 # ifndef NO_LINESPACE
792 	height += r->TermWin.lineSpace;
793 # endif
794 	MAX_IT (r->TermWin.fheight, height);
795 
796 	return 1;
797 
798 
799 Failure:
800 	if (r->TermWin.xftmpattern)	{
801 		XftPatternDestroy (r->TermWin.xftmpattern);
802 		r->TermWin.xftmpattern = NULL;
803 	}
804 	return 0;
805 }
806 # endif	/* MULTICHAR_SET */
807 
808 
809 
810 /* EXTPROTO */
811 int
rxvt_init_font_xft(rxvt_t * r)812 rxvt_init_font_xft (rxvt_t* r)
813 {
814 	XftResult		fr;
815 	XftPattern*		xp;
816 	XGlyphInfo		ext1, ext2;
817 	int				len, olen;		/* font name length */
818 	char*			fname;			/* font name to open */
819 	char*			ofname = NULL;	/* actually opened font name */
820 # ifdef DEBUG
821 	FT_Face			face;
822 # endif
823 
824 
825 	DBG_MSG(2,(stderr, "rxvt_init_font_xft\n"));
826 
827 
828 	DBG_MSG(2,(stderr, "load freetype font\n"));
829 	xp = XftPatternCreate ();
830 	if (NULL == xp)
831 		return 0;
832 
833 	/* font family */
834 	fname = (char*) r->h->rs[Rs_xftfont];
835 	if (NULL == fname)
836 		fname = "Luxi Mono";
837 	XftPatternAddString (xp, XFT_FAMILY, fname);
838 
839 	/* No spacing between lines */
840 	XftPatternAddBool (xp, XFT_MINSPACE, FcFalse);
841 
842 	/* antialias */
843 	if (r->Options2 & Opt2_xftAntialias)
844 		XftPatternAddBool (xp, XFT_ANTIALIAS, FcTrue);
845 	else
846 		XftPatternAddBool (xp, XFT_ANTIALIAS, FcFalse);
847 
848 	/* hinting */
849 	if (r->Options2 & Opt2_xftHinting)
850 		XftPatternAddBool (xp, FC_HINTING, FcTrue);
851 	else
852 		XftPatternAddBool (xp, FC_HINTING, FcFalse);
853 
854 	/* autohint */
855 	if (r->Options2 & Opt2_xftAutoHint)
856 		XftPatternAddBool (xp, FC_AUTOHINT, FcTrue);
857 	else
858 		XftPatternAddBool (xp, FC_AUTOHINT, FcFalse);
859 
860 	/* font size, we always set it. if it's not set by the user, we
861 	** have chosen a default value (12) for it */
862 	XftPatternAddDouble (xp, XFT_SIZE, (double) r->TermWin.xftsize);
863 	/* Enforce Size/Pixel_Size = 1.0 */
864 	XftPatternAddDouble (xp, XFT_SCALE, (double) 1.0);
865 
866 	/* font width */
867 	if (r->h->rs[Rs_xftwd])	{
868 		if (0 == STRCASECMP (r->h->rs[Rs_xftwd], "ultracondensed"))
869 			XftPatternAddInteger (xp, FC_WIDTH, FC_WIDTH_ULTRACONDENSED);
870 		else
871 		if (0 == STRCASECMP (r->h->rs[Rs_xftwd], "condensed"))
872 			XftPatternAddInteger (xp, FC_WIDTH, FC_WIDTH_CONDENSED);
873 		else
874 		if (0 == STRCASECMP (r->h->rs[Rs_xftwd], "normal"))
875 			XftPatternAddInteger (xp, FC_WIDTH, FC_WIDTH_NORMAL);
876 		else
877 		if (0 == STRCASECMP (r->h->rs[Rs_xftwd], "expanded"))
878 			XftPatternAddInteger (xp, FC_WIDTH, FC_WIDTH_EXPANDED);
879 		else
880 		if (0 == STRCASECMP (r->h->rs[Rs_xftwd], "ultraexpanded"))
881 			XftPatternAddInteger (xp, FC_WIDTH, FC_WIDTH_ULTRAEXPANDED);
882 		else
883 			XftPatternAddInteger (xp, FC_WIDTH, FC_WIDTH_NORMAL);
884 	}
885 
886 	/* font weight */
887 	if (r->h->rs[Rs_xftwt])	{
888 		if (0 == STRCASECMP (r->h->rs[Rs_xftwt], "light"))
889 			XftPatternAddInteger (xp, XFT_WEIGHT, XFT_WEIGHT_LIGHT);
890 		else
891 		if (0 == STRCASECMP (r->h->rs[Rs_xftwt], "medium"))
892 			XftPatternAddInteger (xp, XFT_WEIGHT, XFT_WEIGHT_MEDIUM);
893 		else
894 		if (0 == STRCASECMP (r->h->rs[Rs_xftwt], "demibold"))
895 			XftPatternAddInteger (xp, XFT_WEIGHT, XFT_WEIGHT_DEMIBOLD);
896 		else
897 		if (0 == STRCASECMP (r->h->rs[Rs_xftwt], "bold"))
898 			XftPatternAddInteger (xp, XFT_WEIGHT, XFT_WEIGHT_BOLD);
899 		else
900 		if (0 == STRCASECMP (r->h->rs[Rs_xftwt], "black"))
901 			XftPatternAddInteger (xp, XFT_WEIGHT, XFT_WEIGHT_BLACK);
902 		else	/* default is medium */
903 			XftPatternAddInteger (xp, XFT_WEIGHT, XFT_WEIGHT_MEDIUM);
904 	}
905 
906 	/* font slant */
907 	if (r->h->rs[Rs_xftst])	{
908 		if (0 == STRCASECMP (r->h->rs[Rs_xftst], "roman"))
909 			XftPatternAddInteger (xp, XFT_SLANT, XFT_SLANT_ROMAN);
910 		else
911 		if (0 == STRCASECMP (r->h->rs[Rs_xftst], "italic"))
912 			XftPatternAddInteger (xp, XFT_SLANT, XFT_SLANT_ITALIC);
913 		else
914 		if (0 == STRCASECMP (r->h->rs[Rs_xftst], "oblique"))
915 			XftPatternAddInteger (xp, XFT_SLANT, XFT_SLANT_OBLIQUE);
916 		else	/* default is roman */
917 			XftPatternAddInteger (xp, XFT_SLANT, XFT_SLANT_ROMAN);
918 	}
919 
920 	/* font rgba */
921 	if (r->h->rs[Rs_xftrgb])	{
922 		if (0 == STRCASECMP (r->h->rs[Rs_xftrgb], "rgb"))
923 			XftPatternAddInteger (xp, XFT_RGBA, XFT_RGBA_RGB);
924 		else
925 		if (0 == STRCASECMP (r->h->rs[Rs_xftrgb], "bgr"))
926 			XftPatternAddInteger (xp, XFT_RGBA, XFT_RGBA_BGR);
927 		else
928 		if (0 == STRCASECMP (r->h->rs[Rs_xftrgb], "vrgb"))
929 			XftPatternAddInteger (xp, XFT_RGBA, XFT_RGBA_VRGB);
930 		else
931 		if (0 == STRCASECMP (r->h->rs[Rs_xftrgb], "vbgr"))
932 			XftPatternAddInteger (xp, XFT_RGBA, XFT_RGBA_VBGR);
933 		else
934 			XftPatternAddInteger (xp, XFT_RGBA, XFT_RGBA_NONE);
935 	}
936 
937 	/* Only accept mono fonts */
938 	/*
939 	XftPatternAddInteger (xp, XFT_SPACING, XFT_MONO);
940 	*/
941 
942 	r->TermWin.xftpattern = XftFontMatch (r->Xdisplay, XSCREEN, xp, &fr);
943 
944 	if (NULL == r->TermWin.xftpattern)
945 		goto Failure;
946 
947 	/* globaladvance */
948 	if (r->Options2 & Opt2_xftGlobalAdvance)	{
949 		XftPatternDel (r->TermWin.xftpattern, FC_GLOBAL_ADVANCE);
950 		XftPatternAddBool (r->TermWin.xftpattern, FC_GLOBAL_ADVANCE, FcTrue);
951 	}
952 
953 # ifdef DEBUG_VERBOSE
954 	FcPatternPrint (r->TermWin.xftpattern);
955 # endif
956 	XftPatternGetString (r->TermWin.xftpattern, XFT_FAMILY, 0, &ofname);
957 	assert (NULL != ofname);	/* shouldn't be NULL */
958 	len = STRLEN(fname);
959 	olen = STRLEN(ofname);
960 	if (STRNCASECMP (ofname, fname, (len < olen ? len : olen)))
961 		rxvt_print_error ("Cannot open font %s, use font %s instead.",
962 			fname, ofname);
963 
964 	DBG_MSG(1, (stderr, "create xftpattern = 0x%x on font %d\n",
965 		(unsigned int) r->TermWin.xftpattern, r->TermWin.xftsize));
966 	r->TermWin.xftfont = XftFontOpenPattern (r->Xdisplay, r->TermWin.xftpattern);
967 
968 	if (NULL == r->TermWin.xftfont)
969 		goto Failure;
970 
971 	r->TermWin.fwidth = r->TermWin.xftfont->max_advance_width;
972 	r->TermWin.fheight = r->TermWin.xftfont->ascent + r->TermWin.xftfont->descent;
973 # ifndef NO_LINESPACE
974 	r->TermWin.fheight += r->TermWin.lineSpace;
975 # endif
976 
977 #ifdef DEBUG
978 	face = XftLockFace (r->TermWin.xftfont);
979 	XftUnlockFace (r->TermWin.xftfont);
980 # endif
981 
982 	/*
983 	** Do not trust the font width
984 	*/
985 	XftTextExtents8 (r->Xdisplay, r->TermWin.xftfont, "W", 1, &ext1);
986 	XftTextExtents8 (r->Xdisplay, r->TermWin.xftfont, "i", 1, &ext2);
987 	if (ext1.xOff == ext2.xOff)
988 		r->TermWin.xftfnmono = r->TermWin.xftmono = 1;
989 	else
990 		r->TermWin.xftfnmono = r->TermWin.xftmono = 0;
991 	DBG_MSG(1, (stderr, "xftfnmono is %d\n", r->TermWin.xftfnmono));
992 
993 
994 # ifndef NO_BOLDFONT
995 	/*
996 	rxvt_init_bfont_xft (r, xp);
997 	*/
998 # endif
999 
1000 # ifdef MULTICHAR_SET
1001 	if (!rxvt_init_mfont_xft (r, xp, ofname))
1002 		goto Failure;
1003 # endif	/* MULTICHAR_SET */
1004 
1005 	XftPatternDestroy (xp); xp = NULL;
1006 
1007 	return 1;
1008 
1009 
1010 Failure:
1011 	if (xp)	{
1012 		XftPatternDestroy (xp); xp = NULL;
1013 	}
1014 	if (r->TermWin.xftpattern)	{
1015 		XftPatternDestroy (r->TermWin.xftpattern);
1016 		r->TermWin.xftpattern = NULL;
1017 	}
1018 	return 0;
1019 }
1020 
1021 
1022 /*----------------------------------------------------------------------*/
1023 /* rxvt_init_font_fixed () - initialize fixed font */
1024 /* INTPROTO */
1025 void
rxvt_init_font_fixed(rxvt_t * r)1026 rxvt_init_font_fixed (rxvt_t* r)
1027 {
1028 	XFontStruct*	xfont;
1029 
1030 
1031 	DBG_MSG(1,(stderr, " load font (fixed)\n"));
1032 	xfont = XLoadQueryFont (r->Xdisplay, "fixed");
1033 	if (NULL == xfont)	{
1034 		rxvt_print_error("fatal error, aborting...");
1035 		exit(EXIT_FAILURE);
1036 	}
1037 
1038 	r->TermWin.font = xfont;
1039 #ifndef NO_BOLDFONT
1040 	/*
1041 	r->TermWin.bfont = r->TermWin.xftbfont? xfont : NULL;
1042 	*/
1043 	r->TermWin.bfont = NULL;
1044 #endif
1045 #ifdef MULTICHAR_SET
1046 	r->TermWin.mfont = xfont;
1047 #endif
1048 }
1049 #endif	/* XFT_SUPPORT */
1050 
1051 
1052 /* rxvt_init_font_x11 () - initialize font */
1053 /* EXTPROTO */
1054 void
rxvt_init_font_x11(rxvt_t * r)1055 rxvt_init_font_x11 (rxvt_t *r)
1056 {
1057 	char*			msg = "can't load font \"%s\"";
1058 	XFontStruct*	xfont;
1059 #ifndef NO_BOLDFONT
1060 	XFontStruct*	bfont;
1061 	int				ckfont;
1062 #endif
1063 	int				fh = 0, fw = 0;
1064 	int				idx = 0;			/* index into rs_font[] */
1065 
1066 
1067 	DBG_MSG(1,(stderr, "rxvt_init_font_x11 \n"));
1068 
1069 
1070 #ifdef XFT_SUPPORT
1071 	/* Only load fixed font if we use freetype font */
1072 	if ((r->Options & Opt_xft) && r->TermWin.xftfont)	{
1073 		rxvt_init_font_fixed (r);
1074 		return;
1075 	}
1076 #endif
1077 
1078 
1079 	r->h->fnum = FONT0_IDX;
1080 	idx = FNUM2IDX(r->h->fnum);
1081 
1082 	/* OK, now it's time to load the default font */
1083 	DBG_MSG(1,(stderr, " load font (%s)\n", r->h->rs[Rs_font+idx]));
1084 	xfont = XLoadQueryFont (r->Xdisplay, r->h->rs[Rs_font+idx]);
1085 	if (NULL == xfont) {
1086 		/* failed to load font */
1087 		rxvt_print_error(msg, r->h->rs[Rs_font+idx]);
1088 
1089 		/* try to load fixed font */
1090 		r->h->rs[Rs_font+idx] = "fixed";
1091 		DBG_MSG(1,(stderr, " load font (%s)\n", r->h->rs[Rs_font+idx]));
1092 		xfont = XLoadQueryFont(r->Xdisplay, r->h->rs[Rs_font+idx]);
1093 		if (NULL == xfont) {
1094 			/* still failed to load font */
1095 			rxvt_print_error(msg, r->h->rs[Rs_font+idx]);
1096 
1097 			/* cannot load any font, fatal error, abort the program */
1098 			goto Abort;
1099 		}
1100 	}
1101 	/* Font loading succeeded */
1102 	if (NULL != xfont)	{
1103 		r->TermWin.font = xfont;
1104 	}
1105 
1106 
1107 	/* set the font sizes */
1108 	fw = rxvt_get_font_widest (r->TermWin.font);
1109 	fh = r->TermWin.font->ascent + r->TermWin.font->descent;
1110 #ifndef NO_LINESPACE
1111 	fh += r->TermWin.lineSpace;
1112 #endif
1113 
1114 	if (fw == r->TermWin.font->min_bounds.width)
1115 		/* Mono-spaced (fixed width) font */
1116 		r->TermWin.propfont &= ~PROPFONT_NORMAL;
1117 	else
1118 		/* Proportional font */
1119 		r->TermWin.propfont |= PROPFONT_NORMAL;
1120 
1121 #ifndef NO_BOLDFONT
1122 	ckfont = !(fw == r->TermWin.fwidth && fh == r->TermWin.fheight);
1123 #endif
1124 
1125 	r->TermWin.fwidth = fw;
1126 	r->TermWin.fheight = fh;
1127 
1128 
1129 #ifndef NO_BOLDFONT
1130 	bfont = NULL;
1131 	if (ckfont)	{
1132 		/* try to load boldFont, fail silently */
1133 		if (NULL != r->h->rs[Rs_boldFont])	{
1134 			DBG_MSG(1,(stderr, " load bfont (%s)\n", r->h->rs[Rs_boldFont]));
1135 			bfont = XLoadQueryFont (r->Xdisplay, r->h->rs[Rs_boldFont]);
1136 		}
1137 
1138 		if (NULL != bfont)	{
1139 			/* Loading bold font succeeded */
1140 			fw = rxvt_get_font_widest (bfont);
1141 			fh = bfont->ascent + bfont->descent;
1142 #ifndef NO_LINESPACE
1143 			fh += r->TermWin.lineSpace;
1144 #endif
1145 			if (fw <= r->TermWin.fwidth && fh <= r->TermWin.fheight) {
1146 				r->TermWin.bfont = bfont;
1147 				if (fw == r->TermWin.fwidth)
1148 					r->TermWin.propfont &= ~PROPFONT_NORMAL;
1149 				else
1150 					r->TermWin.propfont |= PROPFONT_NORMAL;
1151 			}
1152 			else	{
1153 				XFreeFont (r->Xdisplay, bfont);
1154 			}
1155 		}
1156 	}
1157 #endif /* NO_BOLDFONT */
1158 
1159 
1160 #ifdef MULTICHAR_SET
1161 	/* load font or substitute */
1162 	DBG_MSG(1,(stderr, " load mfont (%s)\n", r->h->rs[Rs_mfont+idx]));
1163 	xfont = XLoadQueryFont(r->Xdisplay, r->h->rs[Rs_mfont+idx]);
1164 	if (NULL == xfont) {
1165 		char*	ptr;
1166 
1167 		/* failed to load font */
1168 		rxvt_print_error(msg, r->h->rs[Rs_mfont+idx]);
1169 
1170 		ptr = rxvt_fallback_mfont_x11 (r);
1171 		DBG_MSG(1,(stderr, " load mfont (%s)\n", ptr));
1172 		xfont = XLoadQueryFont(r->Xdisplay, ptr);
1173 		if (NULL != xfont)
1174 			r->h->rs[Rs_mfont+idx] = ptr;
1175 		else	{
1176 			/* still failed to load font */
1177 			rxvt_print_error(msg, ptr);
1178 			/* cannot load any mfont, fatal error, abort the program */
1179 			goto Abort;
1180 		}
1181 	}
1182 	if (NULL != xfont)	{
1183 		r->TermWin.mfont = xfont;
1184 	}
1185 #endif	/* MULTICHAR_SET */
1186 
1187 	/* Succeeded to load font, return now */
1188 	return ;
1189 
1190 Abort:
1191 	rxvt_print_error("fatal error, aborting...");
1192 	exit(EXIT_FAILURE);
1193 }
1194 
1195 
1196 #ifdef XFT_SUPPORT
1197 /* EXTPROTO */
1198 int
rxvt_change_font_xft(rxvt_t * r,const char * fontname)1199 rxvt_change_font_xft (rxvt_t* r, const char* fontname)
1200 {
1201 	XftPattern*	xp;
1202 	XftFont*	xf;
1203 # ifdef MULTICHAR_SET
1204 	XftPattern*	mxp;
1205 	XftFont*	mxf;
1206 # endif
1207 	int			resize, oldsize = r->TermWin.xftsize;
1208 
1209 
1210 	assert (fontname);
1211 	DBG_MSG(2,(stderr, "rxvt_change_font_xft (%s)\n", fontname));
1212 
1213 	/* we only accept FONT_CMD now for XFT font ;-) */
1214 	if (FONT_CMD != fontname[0])
1215 		return 0;
1216 	if ((char) 0 != fontname[1] &&
1217 		'+' != fontname[1] &&
1218 		'-' != fontname[1] &&
1219 		!isdigit((int) fontname[1]))
1220 		return 0;
1221 	if (('+' == fontname[1]) && ((char) 0 == fontname[2]))
1222 		resize = +1;
1223 	else
1224 	if (('-' == fontname[1]) && ((char) 0 == fontname[2]))
1225 		resize = -1;
1226 	else
1227 		resize = atoi (fontname+1);
1228 	r->TermWin.xftsize += resize;
1229 	/* adjust for minimal font size */
1230 	if (r->TermWin.xftsize < MIN_XFT_FONT_SIZE)
1231 		r->TermWin.xftsize = MIN_XFT_FONT_SIZE;
1232 	/* no change of font size */
1233 	if (r->TermWin.xftsize == oldsize)
1234 		return 0;
1235 # ifdef MULTICHAR_SET
1236 	if (r->h->rs[Rs_xftmsz])	{
1237 		r->TermWin.xftmsize += resize;
1238 		if (r->TermWin.xftmsize < MIN_XFT_FONT_SIZE)
1239 			r->TermWin.xftmsize = MIN_XFT_FONT_SIZE;
1240 	}
1241 # endif
1242 
1243 	/*
1244 	** Now reload xft font with new size using rxvt_init_font_xft.
1245 	** We can reuse it since we have only changed the font size.
1246 	** Before doing so, let us backup the old xft info in case
1247 	** we cannot load new xft font. In that case, we can still
1248 	** fallback to the old font.
1249 	*/
1250 	xp = r->TermWin.xftpattern;	r->TermWin.xftpattern = NULL;
1251 	xf = r->TermWin.xftfont;	r->TermWin.xftfont = NULL;
1252 # ifdef MULTICHAR_SET
1253 	mxp = r->TermWin.xftmpattern;	r->TermWin.xftmpattern = NULL;
1254 	mxf = r->TermWin.xftmfont;		r->TermWin.xftmfont = NULL;
1255 # endif
1256 	if (!rxvt_init_font_xft (r))	{
1257 		/* fallback to old font */
1258 		r->TermWin.xftpattern = xp;
1259 		r->TermWin.xftfont = xf;
1260 # ifdef MULTICHAR_SET
1261 		r->TermWin.xftmpattern = mxp;
1262 		r->TermWin.xftmfont = mxf;
1263 # endif
1264 		return 0;
1265 	}
1266 
1267 	/*
1268 	** It is safe now to free old XftPattern, but apparently there is
1269 	** some problems if we change the font size in reverse direction,
1270 	** e.g., increase font size then decrease it, or decrease font
1271 	** size then increase it. It can crash the terminal.
1272 	**
1273 	** 12-19-2004: Is it because the pattern is got via XftFontMatch,
1274 	** which actually returns a *static* pattern that we should not
1275 	** manually destroy? Anyway, to avoid the crash, let us comment
1276 	** out the XftPatternDestroy calls below. I hope there is a more
1277 	** clear documentation about these Xft functions!!!
1278 	*/
1279 	/*
1280 	DBG_MSG(1, (stderr, "destroy xftpattern = 0x%x\n", (unsigned int) xp));
1281 	FcPatternPrint (xp);
1282 	FcPatternPrint (r->TermWin.xftpattern);
1283 	XftPatternDestroy (xp);
1284 # ifdef MULTICHAR_SET
1285 	if (xp != mxp)
1286 		XftPatternDestroy (mxp);
1287 # endif
1288 	*/
1289 
1290 	return 1;
1291 }
1292 #endif	/* XFT_SUPPORT */
1293 
1294 
1295 /*----------------------------------------------------------------------*/
1296 /* rxvt_change_font_x11 () - Switch to a new font */
1297 /*
1298  * init = 1   - initialize
1299  *
1300  * fontname == FONT_UP  - switch to bigger font
1301  * fontname == FONT_DN  - switch to smaller font
1302  */
1303 /* EXTPROTO */
1304 int
rxvt_change_font_x11(rxvt_t * r,const char * fontname)1305 rxvt_change_font_x11 (rxvt_t* r, const char *fontname)
1306 {
1307 	char*			msg = "can't load font \"%s\"";
1308 	XFontStruct*	xfont;
1309 #ifndef NO_BOLDFONT
1310 	XFontStruct*	bfont;
1311 	int				ckfont;
1312 #endif
1313 	int				fh = 0, fw = 0;
1314 	int				idx = 0;			/* index into rs_font[] */
1315 
1316 
1317 	assert (fontname);
1318 	DBG_MSG(1,(stderr, "rxvt_change_font_x11 (%s)\n", fontname));
1319 
1320 
1321 	switch (fontname[0]) {
1322 	/* special (internal) prefix for font commands */
1323 	case FONT_CMD: /* FONT_CMD =='#' */
1324 		idx = atoi (fontname + 1);
1325 		switch (fontname[1]) {
1326 		case '+':	/* corresponds to FONT_UP */
1327 			r->h->fnum += (idx ? idx : 1);	/* "#+" or "#+3"? */
1328 			r->h->fnum %= MAX_NFONTS;
1329 			break;
1330 
1331 		case '-':	/* corresponds to FONT_DN */
1332 			r->h->fnum += (idx ? idx : -1);	/* "#-" or "#-3"? */
1333 			r->h->fnum %= MAX_NFONTS;
1334 			break;
1335 
1336 		default:
1337 			/* input is not a logical font number */
1338 			if (fontname[1] != '\0' &&
1339 				!isdigit((int) fontname[1]))
1340 				return 0;
1341 			/*
1342 			** input logical font number too big, but don't worry,
1343 			** we will handle it gracefully ;-)
1344 			*/
1345 			r->h->fnum = IDX2FNUM(idx);
1346 			break;
1347 		}
1348 		fontname = NULL;
1349 		break;
1350 
1351 	default:
1352 		/* search for existing fontname */
1353 		for (idx = 0; idx < MAX_NFONTS; idx++) {
1354 			if (!STRCMP (r->h->rs[Rs_font+idx], fontname)) {
1355 				r->h->fnum = IDX2FNUM(idx);
1356 				fontname = NULL;
1357 				break;
1358 			}
1359 		}
1360 		break;
1361 	}
1362 	/* re-position around the normal font */
1363 	if (r->h->fnum < 0)
1364 		r->h->fnum += (-(r->h->fnum / MAX_NFONTS - 1) * MAX_NFONTS);
1365 	idx = FNUM2IDX(r->h->fnum);
1366 
1367 
1368 	/*
1369 	** If fontname != NULL, it's some new font not in the rs_font.
1370 	** We try to load it and replace font in rs_font if succeed.
1371 	*/
1372 	if (NULL != fontname)	{
1373 		xfont = XLoadQueryFont(r->Xdisplay, fontname);
1374 		if (xfont)	{
1375 			/* load new font succeessfully */
1376 			char* ptr = STRDUP (fontname);
1377 			if (ptr) {
1378 				if (r->h->newfont[idx] != NULL)
1379 					free (r->h->newfont[idx]);
1380 				r->h->newfont[idx] = ptr;
1381 				r->h->rs[Rs_font+idx] = r->h->newfont[idx];
1382 			}
1383 			else	{
1384 				assert (0);	/* shouldn't happen */
1385 			}
1386 			/* Free it by now */
1387 			XFreeFont (r->Xdisplay, xfont);
1388 		}
1389 	}
1390 
1391 
1392 	/*
1393 	** OK, now it's time to load font or substitute
1394 	*/
1395 	DBG_MSG(1,(stderr, " load font (%s)\n", r->h->rs[Rs_font+idx]));
1396 	xfont = XLoadQueryFont (r->Xdisplay, r->h->rs[Rs_font+idx]);
1397 	if (!xfont) {
1398 		/* failed to load font */
1399 		rxvt_print_error(msg, r->h->rs[Rs_font+idx]);
1400 
1401 		/* try to load fixed font */
1402 		r->h->rs[Rs_font+idx] = "fixed";
1403 		DBG_MSG(1,(stderr, " load font (%s)\n", r->h->rs[Rs_font+idx]));
1404 		xfont = XLoadQueryFont(r->Xdisplay, r->h->rs[Rs_font+idx]);
1405 		if (!xfont) {
1406 			/* still failed to load font */
1407 			rxvt_print_error(msg, r->h->rs[Rs_font+idx]);
1408 			return 0;
1409 		}
1410 	}
1411 	/* Font loading succeeded */
1412 	if (xfont)	{
1413 		/*
1414 		** if the previous font exists, replace it with new font.
1415 		** otherwise, keep the old font, and do nothing
1416 		*/
1417 		if (r->TermWin.font)
1418 			XFreeFont (r->Xdisplay, r->TermWin.font);
1419 		r->TermWin.font = xfont;
1420 	}
1421 
1422 
1423 	/* set the font sizes */
1424 	fw = rxvt_get_font_widest (r->TermWin.font);
1425 	fh = r->TermWin.font->ascent + r->TermWin.font->descent;
1426 #ifndef NO_LINESPACE
1427 	fh += r->TermWin.lineSpace;
1428 #endif
1429 
1430 	if (fw == r->TermWin.font->min_bounds.width)
1431 		/* Mono-spaced (fixed width) font */
1432 		r->TermWin.propfont &= ~PROPFONT_NORMAL;
1433 	else
1434 		/* Proportional font */
1435 		r->TermWin.propfont |= PROPFONT_NORMAL;
1436 
1437 #ifndef NO_BOLDFONT
1438 	ckfont = !(fw == r->TermWin.fwidth && fh == r->TermWin.fheight);
1439 #endif
1440 
1441 #ifdef XFT_SUPPORT
1442 	/* Set font size when XFT is not enabled */
1443 	if (!((r->Options & Opt_xft) && r->TermWin.xftfont))
1444 #endif
1445 	{
1446 		r->TermWin.fwidth = fw;
1447 		r->TermWin.fheight = fh;
1448 	}
1449 
1450 
1451 #ifndef NO_BOLDFONT
1452 	bfont = NULL;
1453 	if (ckfont)	{
1454 		/* try to load boldFont, fail silently */
1455 		if (NULL == r->TermWin.bfont &&
1456 			NULL != r->h->rs[Rs_boldFont])	{
1457 			DBG_MSG(1,(stderr, " load bfont (%s)\n", r->h->rs[Rs_boldFont]));
1458 			bfont = XLoadQueryFont (r->Xdisplay, r->h->rs[Rs_boldFont]);
1459 		}
1460 
1461 		if (bfont)	{
1462 			/* Loading bold font succeeded */
1463 			fw = rxvt_get_font_widest (bfont);
1464 			fh = bfont->ascent + bfont->descent;
1465 #ifndef NO_LINESPACE
1466 			fh += r->TermWin.lineSpace;
1467 #endif
1468 			if (fw <= r->TermWin.fwidth && fh <= r->TermWin.fheight) {
1469 				if (r->TermWin.bfont)
1470 					XFreeFont (r->Xdisplay, r->TermWin.bfont);
1471 				r->TermWin.bfont = bfont;
1472 				if (fw == r->TermWin.fwidth)
1473 					r->TermWin.propfont &= ~PROPFONT_NORMAL;
1474 				else
1475 					r->TermWin.propfont |= PROPFONT_NORMAL;
1476 			}
1477 			else	{
1478 				XFreeFont (r->Xdisplay, bfont);
1479 			}
1480 		}
1481 	}
1482 #endif /* NO_BOLDFONT */
1483 
1484 
1485 #ifdef MULTICHAR_SET
1486 	/* load font or substitute */
1487 	DBG_MSG(1,(stderr, " load mfont (%s)\n", r->h->rs[Rs_mfont+idx]));
1488 	xfont = XLoadQueryFont(r->Xdisplay, r->h->rs[Rs_mfont+idx]);
1489 	if (!xfont) {
1490 		char*	ptr;
1491 
1492 		/* failed to load font */
1493 		rxvt_print_error(msg, r->h->rs[Rs_mfont+idx]);
1494 
1495 		/* try to load default font */
1496 		ptr = rxvt_fallback_mfont_x11 (r);
1497 		DBG_MSG(1,(stderr, " load mfont (%s)\n", ptr));
1498 		xfont = XLoadQueryFont(r->Xdisplay, ptr);
1499 		if (xfont)
1500 			r->h->rs[Rs_mfont+idx] = ptr;
1501 		else	{
1502 			/* still failed to load font */
1503 			rxvt_print_error(msg, ptr);
1504 			return 0;
1505 		}
1506 	}
1507 	if (xfont)	{
1508 		/*
1509 		** if the previous font exists, replace it with new font.
1510 		** otherwise, keep the old font, and do nothing
1511 		*/
1512 		if (r->TermWin.mfont)
1513 			XFreeFont (r->Xdisplay, r->TermWin.mfont);
1514 		r->TermWin.mfont = xfont;
1515 	}
1516 #endif	/* MULTICHAR_SET */
1517 
1518 	return 1;
1519 }
1520 
1521 
1522 /* INTPROTO */
1523 void
rxvt_font_up_down(rxvt_t * r,int n,int direction)1524 rxvt_font_up_down(rxvt_t* r, int n, int direction)
1525 {
1526 	const char	 *p;
1527 	int				initial, j;
1528 
1529 	for (j = 0; j < n; j++) {
1530 	initial = r->h->fnum;
1531 	for (;;) {
1532 		r->h->fnum += direction;
1533 		if (r->h->fnum == MAX_NFONTS || r->h->fnum == -1) {
1534 		r->h->fnum = initial;
1535 		return;
1536 		}
1537 		p = r->h->rs[Rs_font + FNUM2IDX(r->h->fnum)];
1538 		if (p != NULL && STRLEN(p) > 1)
1539 		break;
1540 	}
1541 	}
1542 }
1543 #undef IDX2FNUM
1544 #undef FNUM2IDX
1545 
1546 
1547 /* INTPROTO */
1548 int
rxvt_get_font_widest(XFontStruct * f)1549 rxvt_get_font_widest(XFontStruct *f)
1550 {
1551 	int				i, cw, fw = 0;
1552 
1553 	if (f->min_bounds.width == f->max_bounds.width)
1554 		return f->min_bounds.width;
1555 	if (f->per_char == NULL)
1556 		return f->max_bounds.width;
1557 	for (i = f->max_char_or_byte2 - f->min_char_or_byte2; --i >= 0;) {
1558 		cw = f->per_char[i].width;
1559 		MAX_IT(fw, cw);
1560 	}
1561 	return fw;
1562 }
1563 
1564 /*----------------------------------------------------------------------*/
1565 /*----------------------------------------------------------------------*/
1566 #ifdef X_HAVE_UTF8_STRING
1567 /* INTPROTO */
1568 void
rxvt_set_utf8_property(rxvt_t * r,Atom prop,Window win,const char * str)1569 rxvt_set_utf8_property (rxvt_t* r, Atom prop, Window win, const char* str)
1570 {
1571 #ifdef HAVE_WCHAR_H && _FreeBSD_version >= 500000
1572 	wchar_t*	ws = rxvt_mbstowcs (str);
1573 	char*		s = rxvt_wcstoutf8 (ws);
1574 
1575 	XChangeProperty (r->Xdisplay, win, prop,
1576 		r->h->xa[XA_UTF8_STRING], 8, PropModeReplace,
1577 		(unsigned char*) s, STRLEN (s));
1578 
1579 	free (s);
1580 	free (ws);
1581 #endif	/* HAVE_WCHAR_H */
1582 }
1583 #endif	/* X_HAVE_UTF8_STRING */
1584 
1585 
1586 /* xterm sequences - title, iconName, color (exptl) */
1587 /* EXTPROTO */
1588 void
rxvt_set_win_title(rxvt_t * r,Window win,const char * str)1589 rxvt_set_win_title (rxvt_t* r, Window win, const char* str)
1590 {
1591 	XChangeProperty (r->Xdisplay, win, XA_WM_NAME,
1592 		XA_STRING, 8, PropModeReplace,
1593 		(unsigned char*) str, STRLEN (str));
1594 #ifdef X_HAVE_UTF8_STRING
1595 	rxvt_set_utf8_property (r, r->h->xa[XA_NET_WM_NAME],
1596 		r->TermWin.parent, str);
1597 #endif
1598 }
1599 
1600 
1601 /* EXTPROTO */
1602 void
rxvt_set_term_title(rxvt_t * r,const unsigned char * str)1603 rxvt_set_term_title (rxvt_t* r, const unsigned char *str)
1604 {
1605 #ifdef SMART_WINDOW_TITLE
1606 	XTextProperty	prop;
1607 
1608 	if (XGetWMName (r->Xdisplay, r->TermWin.parent, &prop) == 0)
1609 		prop.value = NULL;
1610 	if (NULL == prop.value || STRCMP(prop.value, str))
1611 #endif
1612 	{
1613 		rxvt_set_win_title (r, r->TermWin.parent, str);
1614 	}
1615 }
1616 
1617 
1618 /* EXTPROTO */
1619 void
rxvt_set_icon_name(rxvt_t * r,const unsigned char * str)1620 rxvt_set_icon_name (rxvt_t* r, const unsigned char *str)
1621 {
1622 	XTextProperty	prop;
1623 
1624 #ifdef SMART_WINDOW_TITLE
1625 	if (XGetWMIconName(r->Xdisplay, r->TermWin.parent, &prop) == 0)
1626 		prop.value = NULL;
1627 	if (NULL == prop.value || STRCMP(prop.value, str))
1628 #endif
1629 	{
1630 		XChangeProperty (r->Xdisplay, r->TermWin.parent,
1631 			XA_WM_ICON_NAME, XA_STRING, 8, PropModeReplace,
1632 			(unsigned char*) str, STRLEN (str));
1633 #ifdef X_HAVE_UTF8_STRING
1634 		rxvt_set_utf8_property (r, r->h->xa[XA_NET_WM_ICON_NAME],
1635 			r->TermWin.parent, str);
1636 #endif
1637 	}
1638 }
1639 
1640 
1641 #ifdef XTERM_COLOR_CHANGE
1642 /* EXTPROTO */
1643 void
rxvt_set_window_color(rxvt_t * r,int idx,const char * color)1644 rxvt_set_window_color(rxvt_t* r, int idx, const char *color)
1645 {
1646 	XColor			xcol;
1647 	int				ufbg_switched;
1648 #ifdef OFF_FOCUS_FADING
1649 	int				color_switched;
1650 #endif
1651 	int				color_set;
1652 	register int	i;
1653 
1654 
1655 	if (color == NULL || *color == '\0')
1656 		return;
1657 
1658 	color_set = ISSET_PIXCOLOR(r->h, idx);
1659 	/*
1660 	** Restore colors now. Remember to restore ufbg color before
1661 	** PixColors
1662 	*/
1663 	ufbg_switched = rxvt_restore_ufbg_color (r);
1664 #ifdef OFF_FOCUS_FADING
1665 	color_switched = rxvt_restore_pix_color (r);
1666 #endif
1667 
1668 	/* handle color aliases */
1669 	if (isdigit((int) *color)) {
1670 		i = atoi(color);
1671 		if (i >= 8 && i <= 15) {	/* bright colors */
1672 			i -= 8;
1673 # ifndef NO_BRIGHTCOLOR
1674 			r->PixColors[idx] = r->PixColors[minBrightCOLOR + i];
1675 			SET_PIXCOLOR(r->h, idx);
1676 			goto Done;
1677 # endif
1678 		}
1679 		if (i >= 0 && i <= 7) {	/* normal colors */
1680 			r->PixColors[idx] = r->PixColors[minCOLOR + i];
1681 			SET_PIXCOLOR(r->h, idx);
1682 			goto Done;
1683 		}
1684 	}
1685 	if (!rxvt_parse_alloc_color(r, &xcol, color))	{
1686 		/* restore to original state and return */
1687 #ifdef OFF_FOCUS_FADING
1688 		if (color_switched)
1689 			rxvt_switch_pix_color (r);
1690 #endif
1691 		if (ufbg_switched)
1692 			rxvt_switch_ufbg_color (r);
1693 		return;
1694 	}
1695 
1696 /* XStoreColor (r->Xdisplay, XCMAP, XColor*); */
1697 
1698 /*
1699  * FIXME: should free colors here, but no idea how to do it so instead,
1700  * so just keep gobbling up the colormap
1701  */
1702 # if 0
1703 	for (i = Color_Black; i <= Color_White; i++)
1704 	if (r->PixColors[idx] == r->PixColors[i])
1705 		break;
1706 	if (i > Color_White) {
1707 	/* fprintf (stderr, "XFreeColors: r->PixColors [%d] = %lu\n", idx, r->PixColors [idx]); */
1708 	XFreeColors(r->Xdisplay, XCMAP, (r->PixColors + idx), 1,
1709 			DisplayPlanes(r->Xdisplay, XSCREEN));
1710 	}
1711 # endif
1712 
1713 	r->PixColors[idx] = xcol.pixel;
1714 
1715 #ifdef OFF_FOCUS_FADING
1716 	if (r->h->rs[Rs_fade])
1717 		r->PixColorsUnfocus[idx] = rxvt_fade_color (r, xcol.pixel);
1718 #endif
1719 #ifdef XFT_SUPPORT
1720 	if (color_set)	{
1721 		XftColorFree (r->Xdisplay, XVISUAL, XCMAP, &(r->XftColors[idx]));
1722 	}
1723 	rxvt_alloc_xft_color (r, r->PixColors[idx], &(r->XftColors[idx]));
1724 #endif
1725 	SET_PIXCOLOR(r->h, idx);
1726 
1727 Done:
1728 	/*
1729 	** Ok, now return to original state before restoring colors.
1730 	** Remember to change PixColors before ufbg color
1731 	*/
1732 #ifdef OFF_FOCUS_FADING
1733 	if (color_switched)
1734 		rxvt_switch_pix_color (r);
1735 #endif
1736 	if (ufbg_switched)
1737 		rxvt_switch_ufbg_color (r);
1738 
1739 	/* background color has changed */
1740 	if ((idx == Color_bg && ufbg_switched) ||
1741 		(idx == Color_ufbg && ufbg_switched)) {
1742 #ifdef TRANSPARENT
1743 		if (!(r->Options & Opt_transparent))
1744 #endif
1745 		{
1746 			for (i = 0; i <= LTAB(r); i ++)	{
1747 #ifdef BACKGROUND_IMAGE
1748 				if (None == AVTS(r)->pixmap)
1749 #endif
1750 				{
1751 					XSetWindowBackground(r->Xdisplay, PVTS(r, i)->vt,
1752 						r->PixColors[Color_bg]);
1753 				}
1754 			}	/* for */
1755 		}
1756 	}
1757 
1758 	/* handle Color_BD, scrollbar background, etc. */
1759 	rxvt_set_colorfgbg(r);
1760 	rxvt_recolour_cursor(r);
1761 
1762 #if defined(TRANSPARENT) || defined(BACKGROUND_IMAGE)
1763 # ifdef TINTING_SUPPORT
1764 	if (idx == Color_tint)	{
1765 #  ifdef TRANSPARENT
1766 		if (r->Options & Opt_transparent)
1767 			/* reset background */
1768 			rxvt_check_our_parents (r);
1769 		else
1770 #  endif
1771 #  ifdef BACKGROUND_IMAGE
1772 		{	/* reset background */
1773 			for (i = 0; i <= LTAB(r); i ++)
1774 				rxvt_resize_pixmap (r, i);
1775 		}
1776 #  endif
1777 		{	/* empty body to suppress compile error */	}
1778 	}
1779 # endif	/* TINTING_SUPPORT */
1780 #endif	/* TRANSPARENT || BACKGROUND_IMAGE */
1781 
1782 	/* the only reasonable way to enforce a clean update */
1783 	/*
1784 	for (i = 0; i <= LTAB(r); i ++)
1785 		rxvt_scr_poweron(r, i);
1786 	*/
1787 	/*
1788 	** Poweron is not a good idea since other terminal may be using
1789 	** secondary screen, like vim. We should just refresh the screen.
1790 	**
1791 	** And we only need to refresh the current screen. When we switch
1792 	** to other terminals, their screen will be automatically updated.
1793 	*/
1794 	rxvt_scr_clear (r, ATAB(r));
1795 	rxvt_scr_touch (r, ATAB(r), True);
1796 }
1797 
1798 #else
1799 # define rxvt_set_window_color(r, idx,color)	((void)0)
1800 #endif		/* XTERM_COLOR_CHANGE */
1801 
1802 
1803 /* EXTPROTO */
1804 void
rxvt_recolour_cursor(rxvt_t * r)1805 rxvt_recolour_cursor(rxvt_t *r)
1806 {
1807 	XColor			xcol[2];
1808 
1809 	xcol[0].pixel = r->PixColors[Color_pointer];
1810 	xcol[1].pixel = r->PixColors[Color_bg];
1811 	XQueryColors(r->Xdisplay, XCMAP, xcol, 2);
1812 	XRecolorCursor(r->Xdisplay, r->term_pointer, &(xcol[0]), &(xcol[1]));
1813 }
1814 
1815 
1816 /*----------------------------------------------------------------------*/
1817 /*
1818  * find if fg/bg matches any of the normal (low-intensity) colors
1819  */
1820 /* INTPROTO */
1821 void
rxvt_set_colorfgbg(rxvt_t * r)1822 rxvt_set_colorfgbg(rxvt_t *r)
1823 {
1824 	unsigned int	i;
1825 	const char	 *xpmb = "\0";
1826 	char			fstr[sizeof("default") + 1], bstr[sizeof("default") + 1];
1827 
1828 	r->h->env_colorfgbg = rxvt_malloc(sizeof("COLORFGBG=default;default;bg")
1829 						+ 1);
1830 	STRCPY(fstr, "default");
1831 	STRCPY(bstr, "default");
1832 	for (i = Color_Black; i <= Color_White; i++)
1833 		if (r->PixColors[Color_fg] == r->PixColors[i]) {
1834 			sprintf(fstr, "%d", (i - Color_Black));
1835 			break;
1836 		}
1837 	for (i = Color_Black; i <= Color_White; i++)
1838 		if (r->PixColors[Color_bg] == r->PixColors[i]) {
1839 			sprintf(bstr, "%d", (i - Color_Black));
1840 #ifdef BACKGROUND_IMAGE
1841 			xpmb = "default;";
1842 #endif
1843 			break;
1844 		}
1845 	sprintf(r->h->env_colorfgbg, "COLORFGBG=%s;%s%s", fstr, xpmb, bstr);
1846 	putenv(r->h->env_colorfgbg);
1847 
1848 #ifndef NO_BRIGHTCOLOR
1849 	r->h->colorfgbg = DEFAULT_RSTYLE;
1850 	for (i = minCOLOR; i <= maxCOLOR; i++) {
1851 	if (r->PixColors[Color_fg] == r->PixColors[i]
1852 # ifndef NO_BOLD_UNDERLINE_REVERSE
1853 		&& r->PixColors[Color_fg] == r->PixColors[Color_BD]
1854 # endif				/* ! NO_BOLD_UNDERLINE_REVERSE */
1855 		/* if we wanted boldFont to have precedence */
1856 # if 0				/* ifndef NO_BOLDFONT */
1857 		&& r->TermWin.bfont == NULL
1858 # endif				/* NO_BOLDFONT */
1859 		)
1860 		r->h->colorfgbg = SET_FGCOLOR(r->h->colorfgbg, i);
1861 	if (r->PixColors[Color_bg] == r->PixColors[i])
1862 		r->h->colorfgbg = SET_BGCOLOR(r->h->colorfgbg, i);
1863 	}
1864 #endif	/* NO_BRIGHTCOLOR */
1865 }
1866 
1867 /*----------------------------------------------------------------------*/
1868 /*
1869  * Colour determination for low colour displays, routine from
1870  *	 Hans de Goede <hans@highrise.nl>
1871  */
1872 
1873 
1874 #ifdef XFT_SUPPORT
1875 /* EXTPROTO */
1876 int
rxvt_alloc_xft_color(rxvt_t * r,unsigned long pixel,XftColor * xftcolor)1877 rxvt_alloc_xft_color (rxvt_t* r, unsigned long pixel, XftColor* xftcolor)       {
1878 	XColor          xcol;
1879 	XRenderColor    render;
1880 
1881 	assert (xftcolor);
1882 
1883 	xcol.pixel = pixel;
1884 	if (!XQueryColor (r->Xdisplay, XCMAP, &xcol))
1885 		return 0;
1886 
1887 	render.red   = xcol.red;
1888 	render.green = xcol.green;
1889 	render.blue  = xcol.blue;
1890 	render.alpha = 0xFFFF;
1891 	return (XftColorAllocValue (r->Xdisplay, XVISUAL, XCMAP, &render, xftcolor));
1892 }
1893 #endif  /* XFT_SUPPORT */
1894 
1895 
1896 /* EXTPROTO */
1897 int
rxvt_parse_alloc_color(rxvt_t * r,XColor * screen_in_out,const char * colour)1898 rxvt_parse_alloc_color(rxvt_t* r, XColor *screen_in_out, const char *colour)
1899 {
1900 	int				res = 0;
1901 
1902 	if (!XParseColor(r->Xdisplay, XCMAP, colour, screen_in_out))
1903 		rxvt_print_error("can't determine colour: %s", colour);
1904 	else
1905 		res = rxvt_alloc_color(r, screen_in_out, colour);
1906 	return res;
1907 }
1908 
1909 
1910 /* EXTPROTO */
1911 int
rxvt_alloc_color(rxvt_t * r,XColor * screen_in_out,const char * colour)1912 rxvt_alloc_color(rxvt_t* r, XColor *screen_in_out, const char *colour)
1913 {
1914 	int				res;
1915 
1916 	if ((res = XAllocColor(r->Xdisplay, XCMAP, screen_in_out)))
1917 		return res;
1918 
1919 	/* try again with closest match */
1920 	if (XDEPTH >= 4 && XDEPTH <= 8) {
1921 		int				i, numcol;
1922 		int				best_pixel = 0;
1923 		unsigned long   best_diff, diff;
1924 		XColor			*colors;
1925 
1926 #define rSQR(x)		((x)*(x))
1927 
1928 		best_diff = 0;
1929 		numcol = 0x01 << XDEPTH;
1930 		if ((colors = rxvt_malloc(numcol * sizeof(XColor)))) {
1931 			for (i = 0; i < numcol; i++)
1932 			colors[i].pixel = i;
1933 
1934 			XQueryColors(r->Xdisplay, XCMAP, colors, numcol);
1935 			for (i = 0; i < numcol; i++) {
1936 				diff = rSQR(screen_in_out->red - colors[i].red)
1937 					+ rSQR(screen_in_out->green - colors[i].green)
1938 					+ rSQR(screen_in_out->blue - colors[i].blue);
1939 				if (i == 0 || diff < best_diff) {
1940 					best_pixel = colors[i].pixel;
1941 					best_diff = diff;
1942 				}
1943 			}
1944 			*screen_in_out = colors[best_pixel];
1945 			free(colors);
1946 			res = XAllocColor(r->Xdisplay, XCMAP, screen_in_out);
1947 		}
1948 	}
1949 	if (res == 0)
1950 		rxvt_print_error("can't allocate colour: %s", colour);
1951 
1952 	return res;
1953 }
1954 
1955 
1956 
1957 /* -------------------------------------------------------------------- *
1958  * -						X INPUT METHOD ROUTINES						- *
1959  * -------------------------------------------------------------------- */
1960 #ifdef USE_XIM
1961 /* INTPROTO */
1962 void
rxvt_IM_set_size(rxvt_t * r,XRectangle * size)1963 rxvt_IM_set_size(rxvt_t* r, XRectangle *size)
1964 {
1965 	size->x = r->TermWin.int_bwidth;
1966 	size->y = r->TermWin.int_bwidth;
1967 	size->width = Width2Pixel(r->TermWin.ncol);
1968 	size->height = Height2Pixel(r->TermWin.nrow);
1969 }
1970 
1971 /* INTPROTO */
1972 void
rxvt_IM_set_color(rxvt_t * r,unsigned long * fg,unsigned long * bg)1973 rxvt_IM_set_color(rxvt_t* r, unsigned long *fg, unsigned long *bg)
1974 {
1975 	*fg = r->PixColors[Color_fg];
1976 	*bg = r->PixColors[Color_bg];
1977 }
1978 
1979 /* Checking whether input method is running. */
1980 /* INTPROTO */
1981 Bool
rxvt_IM_is_running(rxvt_t * r)1982 rxvt_IM_is_running(rxvt_t *r)
1983 {
1984 	char				*p;
1985 	Atom			atom;
1986 	Window			win;
1987 	char			server[IMBUFSIZ];
1988 
1989 	/* get current locale modifier */
1990 	DBG_MSG(2, (stderr, "rxvt_IM_is_running ()\n"));
1991 	if ((p = XSetLocaleModifiers(NULL)) != NULL) {
1992 		STRCPY(server, "@server=");
1993 		STRNCAT(server, &(p[4]), IMBUFSIZ - 9);	/* skip "@im=" */
1994 		if ((p = STRCHR(server + 1, '@')) != NULL)	/* first one only */
1995 			*p = '\0';
1996 
1997 		atom = XInternAtom(r->Xdisplay, server, False);
1998 		win = XGetSelectionOwner (r->Xdisplay, atom);
1999 		if (win != None)
2000 			return True;
2001 	}
2002 	return False;
2003 }
2004 
2005 
2006 /* EXTPROTO */
2007 void
rxvt_IM_send_spot(rxvt_t * r)2008 rxvt_IM_send_spot (rxvt_t *r)
2009 {
2010 	XPoint			spot;
2011 	XVaNestedList   preedit_attr;
2012 
2013 	if (r->h->Input_Context == NULL ||
2014 		!r->TermWin.focus ||
2015 		!(r->h->input_style & XIMPreeditPosition) ||
2016 		!(r->h->event_type == KeyPress ||
2017 		r->h->event_type == Expose ||
2018 		r->h->event_type == NoExpose ||
2019 		r->h->event_type == SelectionNotify ||
2020 		r->h->event_type == ButtonRelease ||
2021 		r->h->event_type == FocusIn) ||
2022 		!rxvt_IM_is_running(r))
2023 		return;
2024 
2025 	rxvt_setPosition(r, &spot);
2026 
2027 	preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &spot, NULL);
2028 	XSetICValues(r->h->Input_Context, XNPreeditAttributes, preedit_attr, NULL);
2029 	XFree(preedit_attr);
2030 }
2031 
2032 
2033 /* EXTPROTO */
2034 void
rxvt_IM_set_fontset(rxvt_t * r,int idx)2035 rxvt_IM_set_fontset (rxvt_t* r, int idx)
2036 {
2037 	char				*string;
2038 	long			length;
2039 	XFontSet		prev_fontset;
2040 	int				success = 0;
2041 
2042 	if (idx < 0 || idx >= MAX_NFONTS)
2043 		return;
2044 	DBG_MSG(1,(stderr, "rxvt_setTermFontSet()\n"));
2045 	prev_fontset = r->TermWin.fontset;
2046 	r->TermWin.fontset = NULL;
2047 
2048 	length = 0;
2049 	if (r->h->rs[Rs_font + idx])
2050 		length += STRLEN(r->h->rs[Rs_font + idx]) + 1;
2051 # ifdef MULTICHAR_SET
2052 	if (r->h->rs[Rs_mfont + idx])
2053 		length += STRLEN(r->h->rs[Rs_mfont + idx]) + 1;
2054 # endif
2055 	/* possible integer overflow? */
2056 	assert (length >= 0 && length+1 > 0);
2057 	if (length == 0 || (string = rxvt_malloc(length + 1)) == NULL)
2058 		r->TermWin.fontset = NULL;
2059 	else {
2060 		int				missing_charsetcount;
2061 		char			**missing_charsetlist, *def_string;
2062 
2063 		string[0] = '\0';
2064 		if (r->h->rs[Rs_font + idx]) {
2065 			STRCAT(string, r->h->rs[Rs_font + idx]);
2066 			STRCAT(string, ",");
2067 		}
2068 # ifdef MULTICHAR_SET
2069 		if (r->h->rs[Rs_mfont + idx]) {
2070 			STRCAT(string, r->h->rs[Rs_mfont + idx]);
2071 			STRCAT(string, ",");
2072 		}
2073 # endif
2074 		string[STRLEN(string) - 1] = '\0';
2075 		r->TermWin.fontset = XCreateFontSet(r->Xdisplay, string,
2076 						&missing_charsetlist,
2077 						&missing_charsetcount,
2078 						&def_string);
2079 		free(string);
2080 		if (r->TermWin.fontset != NULL)
2081 			success = 1;
2082 	}
2083 
2084 	if (success) {
2085 		if (prev_fontset != NULL)
2086 				XFreeFontSet(r->Xdisplay, prev_fontset);
2087 	}
2088 	else
2089 		r->TermWin.fontset = prev_fontset;
2090 }
2091 
2092 /* INTPROTO */
2093 void
rxvt_IM_set_preedit_area(rxvt_t * r,XRectangle * preedit_rect,XRectangle * status_rect,XRectangle * needed_rect)2094 rxvt_IM_set_preedit_area(rxvt_t* r, XRectangle *preedit_rect, XRectangle *status_rect, XRectangle *needed_rect)
2095 {
2096 	int				mbh = 0, vtx = 0;
2097 
2098 #ifdef HAVE_SCROLLBARS
2099 	if (!(r->Options & Opt_scrollBar_right))
2100 		vtx += rxvt_scrollbar_width(r);
2101 #endif
2102 
2103 #ifdef HAVE_MENUBAR
2104 	mbh += rxvt_menubar_height(r);
2105 #endif
2106 
2107 	mbh += rxvt_tabbar_height(r);
2108 #ifndef NO_LINESPACE
2109 	mbh -= r->TermWin.lineSpace;
2110 #endif
2111 
2112 	preedit_rect->x = needed_rect->width + vtx;
2113 	preedit_rect->y = Height2Pixel(r->TermWin.nrow - 1) + mbh;
2114 
2115 	preedit_rect->width = Width2Pixel(r->TermWin.ncol + 1) - needed_rect->width
2116 					+ vtx;
2117 	preedit_rect->height = Height2Pixel(1);
2118 
2119 	status_rect->x = vtx;
2120 	status_rect->y = Height2Pixel(r->TermWin.nrow - 1) + mbh;
2121 
2122 	status_rect->width = needed_rect->width ? needed_rect->width
2123 						: Width2Pixel(r->TermWin.ncol + 1);
2124 	status_rect->height = Height2Pixel(1);
2125 }
2126 
2127 /* ARGSUSED */
2128 /* INTPROTO */
2129 void
rxvt_IM_destroy_callback(XIM xim,XPointer client_data,XPointer call_data)2130 rxvt_IM_destroy_callback(XIM xim __attribute__((unused)), XPointer client_data __attribute__((unused)), XPointer call_data __attribute__((unused)))
2131 {
2132 	rxvt_t			*r = rxvt_get_r();
2133 
2134 	r->h->Input_Context = NULL;
2135 	/* To avoid Segmentation Fault in C locale: Solaris only? */
2136 	if (STRCMP(r->h->locale, "C"))
2137 		XRegisterIMInstantiateCallback(r->Xdisplay, NULL, NULL, NULL,
2138 			rxvt_IM_init_callback, NULL);
2139 }
2140 
2141 /*
2142  * X manual pages and include files don't match on some systems:
2143  * some think this is an XIDProc and others an XIMProc so we can't
2144  * use the first argument - need to update this to be nice for
2145  * both types via some sort of configure detection
2146  */
2147 /* ARGSUSED */
2148 /* EXTPROTO */
2149 void
rxvt_IM_init_callback(Display * unused,XPointer client_data,XPointer call_data)2150 rxvt_IM_init_callback (Display *unused __attribute__((unused)), XPointer client_data __attribute__((unused)), XPointer call_data __attribute__((unused)))
2151 {
2152 	int				i, found, had_im;
2153 	const char	 *p;
2154 	char			**s;
2155 	rxvt_t			*r = rxvt_get_r();
2156 	char			buf[IMBUFSIZ];
2157 
2158 	DBG_MSG(1,(stderr, "rxvt_IMInstantiateCallback()\n"));
2159 	if (r->h->Input_Context)
2160 		return;
2161 
2162 	found = had_im = 0;
2163 	p = r->h->rs[Rs_inputMethod];
2164 	if (p && *p) {
2165 		had_im = 1;
2166 		s = rxvt_splitcommastring(p);
2167 		for (i = 0; s[i]; i++) {
2168 			if (*s[i]) {
2169 				STRCPY(buf, "@im=");
2170 				STRNCAT(buf, s[i], IMBUFSIZ - 5);
2171 				if ((p = XSetLocaleModifiers(buf)) != NULL &&
2172 					*p &&
2173 					(rxvt_IM_get_IC(r) == True)) {
2174 					found = 1;
2175 					break;
2176 				}
2177 			}
2178 		}
2179 		for (i = 0; s[i]; i++)
2180 			free(s[i]);
2181 		free(s);
2182 	}
2183 	if (found)
2184 		return;
2185 
2186 	/* try with XMODIFIERS env. var. */
2187 	if ((p = XSetLocaleModifiers("")) != NULL && *p) {
2188 		rxvt_IM_get_IC(r);
2189 		return;
2190 	}
2191 
2192 	/* try with no modifiers base IF the user didn't specify an IM */
2193 	if (!had_im &&
2194 		(p = XSetLocaleModifiers("@im=none")) != NULL &&
2195 		*p &&
2196 		rxvt_IM_get_IC(r) == True)
2197 		return;
2198 }
2199 
2200 /*
2201  * Try to open a XIM with the current modifiers, then see if we can
2202  * open a suitable preedit type
2203  */
2204 /* INTPROTO */
2205 Bool
rxvt_IM_get_IC(rxvt_t * r)2206 rxvt_IM_get_IC(rxvt_t *r)
2207 {
2208 	int				i, j, found;
2209 	XIM				xim;
2210 	XPoint			spot;
2211 	XRectangle		rect, status_rect, needed_rect;
2212 	unsigned long   fg, bg;
2213 	const char	 *p;
2214 	char			**s;
2215 	XIMStyles		*xim_styles;
2216 	XVaNestedList   preedit_attr, status_attr;
2217 	XIMCallback	 ximcallback;
2218 	struct rxvt_hidden *h = r->h;
2219 
2220 	DBG_MSG(1,(stderr, "rxvt_IM_get_IC()\n"));
2221 	xim = XOpenIM(r->Xdisplay, NULL, NULL, NULL);
2222 	if (xim == NULL)	{
2223 		DBG_MSG(1,(stderr, "Unalbe to open IM\n"));
2224 		return False;
2225 	}
2226 
2227 	xim_styles = NULL;
2228 	if (XGetIMValues(xim, XNQueryInputStyle, &xim_styles, NULL) ||
2229 		!xim_styles || !xim_styles->count_styles) {
2230 		XCloseIM(xim);
2231 		return False;
2232 	}
2233 
2234 	p = h->rs[Rs_preeditType] ? h->rs[Rs_preeditType]
2235 					: "OverTheSpot,OffTheSpot,Root";
2236 	s = rxvt_splitcommastring(p);
2237 	for (i = found = 0; !found && s[i]; i++) {
2238 		if (!STRCMP(s[i], "OverTheSpot"))
2239 			h->input_style = (XIMPreeditPosition | XIMStatusNothing);
2240 		else if (!STRCMP(s[i], "OffTheSpot"))
2241 			h->input_style = (XIMPreeditArea | XIMStatusArea);
2242 		else if (!STRCMP(s[i], "Root"))
2243 			h->input_style = (XIMPreeditNothing | XIMStatusNothing);
2244 
2245 		for (j = 0; j < xim_styles->count_styles; j++)
2246 			if (h->input_style == xim_styles->supported_styles[j]) {
2247 				found = 1;
2248 				break;
2249 			}
2250 	}
2251 	for (i = 0; s[i]; i++)
2252 		free(s[i]);
2253 	free(s);
2254 	XFree(xim_styles);
2255 
2256 	if (!found) {
2257 		XCloseIM(xim);
2258 		return False;
2259 	}
2260 
2261 	ximcallback.callback = rxvt_IM_destroy_callback;
2262 
2263 	/* XXX: not sure why we need this (as well as IC one below) */
2264 	XSetIMValues(xim, XNDestroyCallback, &ximcallback, NULL);
2265 
2266 	preedit_attr = status_attr = NULL;
2267 
2268 	if (h->input_style & XIMPreeditPosition) {
2269 		rxvt_IM_set_size(r, &rect);
2270 		rxvt_setPosition(r, &spot);
2271 		rxvt_IM_set_color(r, &fg, &bg);
2272 
2273 		preedit_attr = XVaCreateNestedList(0, XNArea, &rect,
2274 							XNSpotLocation, &spot,
2275 							XNForeground, fg,
2276 							XNBackground, bg,
2277 							XNFontSet, r->TermWin.fontset,
2278 							NULL);
2279 	}
2280 	else if (h->input_style & XIMPreeditArea) {
2281 		rxvt_IM_set_color(r, &fg, &bg);
2282 
2283 		/*
2284 		 * The necessary width of preedit area is unknown
2285 		 * until create input context.
2286 		 */
2287 		needed_rect.width = 0;
2288 
2289 		rxvt_IM_set_preedit_area(r, &rect, &status_rect, &needed_rect);
2290 
2291 		preedit_attr = XVaCreateNestedList(0, XNArea, &rect,
2292 							XNForeground, fg,
2293 							XNBackground, bg,
2294 							XNFontSet, r->TermWin.fontset,
2295 							NULL);
2296 		status_attr = XVaCreateNestedList(0, XNArea, &status_rect,
2297 						XNForeground, fg,
2298 						XNBackground, bg,
2299 						XNFontSet, r->TermWin.fontset, NULL);
2300 	}
2301 	h->Input_Context = XCreateIC(xim, XNInputStyle, h->input_style,
2302 					XNClientWindow, r->TermWin.parent,
2303 					XNFocusWindow, r->TermWin.parent,
2304 					XNDestroyCallback, &ximcallback,
2305 					preedit_attr ? XNPreeditAttributes : NULL,
2306 					preedit_attr,
2307 					status_attr ? XNStatusAttributes : NULL,
2308 					status_attr, NULL);
2309 	if (preedit_attr)
2310 		XFree(preedit_attr);
2311 	if (status_attr)
2312 		XFree(status_attr);
2313 	if (h->Input_Context == NULL) {
2314 		rxvt_print_error("failed to create input context");
2315 		XCloseIM(xim);
2316 		return False;
2317 	}
2318 	if (h->input_style & XIMPreeditArea)
2319 		rxvt_IM_set_status_pos (r);
2320 	DBG_MSG(1,(stderr, "rxvt_IM_get_IC() - successful connection\n"));
2321 	return True;
2322 }
2323 
2324 
2325 /* EXTPROTO */
2326 void
rxvt_IM_set_status_pos(rxvt_t * r)2327 rxvt_IM_set_status_pos (rxvt_t *r)
2328 {
2329 	XRectangle		preedit_rect, status_rect, *needed_rect;
2330 	XVaNestedList   preedit_attr, status_attr;
2331 
2332 	if (r->h->Input_Context == NULL ||
2333 		!r->TermWin.focus ||
2334 		!(r->h->input_style & XIMPreeditArea) ||
2335 		!rxvt_IM_is_running(r))
2336 	return;
2337 
2338 	/* Getting the necessary width of preedit area */
2339 	status_attr = XVaCreateNestedList(0, XNAreaNeeded, &needed_rect, NULL);
2340 	XGetICValues(r->h->Input_Context, XNStatusAttributes, status_attr, NULL);
2341 	XFree(status_attr);
2342 
2343 	rxvt_IM_set_preedit_area(r, &preedit_rect, &status_rect, needed_rect);
2344 
2345 	preedit_attr = XVaCreateNestedList(0, XNArea, &preedit_rect, NULL);
2346 	status_attr = XVaCreateNestedList(0, XNArea, &status_rect, NULL);
2347 
2348 	XSetICValues(r->h->Input_Context,
2349 			XNPreeditAttributes, preedit_attr,
2350 			XNStatusAttributes, status_attr, NULL);
2351 
2352 	XFree(preedit_attr);
2353 	XFree(status_attr);
2354 }
2355 #endif				/* USE_XIM */
2356 
2357 /*----------------------------------------------------------------------*/
2358 static rxvt_t  *_rxvt_vars = NULL;
2359 
2360 /* EXTPROTO */
2361 rxvt_t*
rxvt_get_r(void)2362 rxvt_get_r(void)
2363 {
2364 	return _rxvt_vars;
2365 }
2366 /* INTPROTO */
2367 void
rxvt_set_r(rxvt_t * r)2368 rxvt_set_r(rxvt_t *r)
2369 {
2370 	_rxvt_vars = r;
2371 }
2372 
2373 /*----------------------- end-of-file (C source) -----------------------*/
2374