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