added "amber tint" mode for selection (default)
[yterm.git] / src / x11_xrm.inc.c
blobbb64d556c36135b254efc839474e1ae39f788ad4
1 /*
2 * YTerm -- (mostly) GNU/Linux X11 terminal emulator
4 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
5 * Understanding is not required. Only obedience.
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, version 3 of the License ONLY.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 Xrdb options parsing.
21 included directly into the main file.
25 #define XRM_BAD_COLOR (0xffffffffU)
27 static char xrm_key_value[1024];
30 //==========================================================================
32 // strEquCI
34 //==========================================================================
35 static yterm_bool strEquCI (const char *s0, const char *s1) {
36 if (s0 == NULL) s0 = "";
37 if (s1 == NULL) s1 = "";
38 while (*s0 != 0 && *s1 != 0) {
39 char c0 = *s0++;
40 if (c0 >= 'A' && c0 <= 'Z') c0 = c0 - 'A' + 'a';
41 char c1 = *s1++;
42 if (c1 >= 'A' && c1 <= 'Z') c1 = c1 - 'A' + 'a';
43 if (c0 != c1) return 0;
45 return (s0[0] == 0 && s1[0] == 0);
49 //==========================================================================
51 // parse_keybind
53 //==========================================================================
54 static yterm_bool parse_keybind (KeyBind *kb, const char *str) {
55 yterm_bool res = 0;
56 KeySym keysym = NoSymbol;
57 uint32_t modmask = 0;
58 while (*str > 0 && *str <= 32) str += 1;
59 if (str && str[0]) {
60 while (*str) {
61 if (str[0] == 'C' && str[1] == '-') {
62 modmask = modmask | ControlMask;
63 str += 2;
64 } else if (str[0] == 'M' && str[1] == '-') {
65 modmask = modmask | Mod1Mask;
66 str += 2;
67 } else if (str[0] == 'H' && str[1] == '-') {
68 modmask = modmask | Mod4Mask;
69 str += 2;
70 } else if (str[0] == 'S' && str[1] == '-') {
71 modmask = modmask | ShiftMask;
72 str += 2;
73 } else {
74 break;
77 if (str[0]) {
78 keysym = XStringToKeysym(str);
79 // this is what X.org returns from `XLookupKeysym()` even if shift is pressed
80 if (keysym >= XK_A && keysym <= XK_Z) keysym = keysym - XK_A + XK_a;
84 if (keysym != NoSymbol) {
85 if (kb) {
86 kb->mods = modmask;
87 kb->ksym = keysym;
88 res = 1;
92 return res;
96 //==========================================================================
98 // parse_signal_name
100 //==========================================================================
101 static int parse_signal_name (const char *str) {
102 if ((str[0] == 's' || str[0] == 'S') &&
103 (str[1] == 'i' || str[1] == 'I') &&
104 (str[2] == 'g' || str[2] == 'G'))
106 str += 3;
108 while (*str == '_') str += 1;
109 if (strEquCI(str, "HUP")) return 1;
110 if (strEquCI(str, "INT")) return 2;
111 if (strEquCI(str, "QUIT")) return 3;
112 if (strEquCI(str, "ILL")) return 4;
113 if (strEquCI(str, "TRAP")) return 5;
114 if (strEquCI(str, "ABRT")) return 6;
115 if (strEquCI(str, "ABORT")) return 6;
116 //if (strEquCI(str, "IOT")) return 6;
117 if (strEquCI(str, "BUS")) return 7;
118 if (strEquCI(str, "FPE")) return 8;
119 if (strEquCI(str, "KILL")) return 9;
120 if (strEquCI(str, "USR1")) return 10;
121 if (strEquCI(str, "SEGV")) return 11;
122 if (strEquCI(str, "USR2")) return 12;
123 //if (strEquCI(str, "PIPE")) return 13;
124 if (strEquCI(str, "ALRM")) return 14;
125 if (strEquCI(str, "ALARM")) return 14;
126 if (strEquCI(str, "TERM")) return 15;
127 if (strEquCI(str, "STKFLT")) return 16;
128 //if (strEquCI(str, "CHLD")) return 17;
129 if (strEquCI(str, "CONT")) return 18;
130 if (strEquCI(str, "STOP")) return 19;
131 //if (strEquCI(str, "TSTP")) return 20;
132 //if (strEquCI(str, "TTIN")) return 21;
133 //if (strEquCI(str, "TTOU")) return 22;
134 if (strEquCI(str, "URG")) return 23;
135 //if (strEquCI(str, "XCPU")) return 24;
136 //if (strEquCI(str, "XFSZ")) return 25;
137 //if (strEquCI(str, "VTALRM")) return 26;
138 //if (strEquCI(str, "PROF")) return 27;
139 //if (strEquCI(str, "WINCH")) return 28;
140 return 0;
144 //==========================================================================
146 // xrm_val_to_val
148 //==========================================================================
149 static char *xrm_val_to_val (XrmValue *val) {
150 char *res = NULL;
151 if (val != NULL) {
152 const char *str = (const char *)val->addr;
153 size_t slen = (val->size > 0 && str != NULL ? strlen(str) : 0);
154 // trim leading spaces
155 while (slen > 0 && str[0] > 0 && str[0] <= 32) {
156 str += 1; slen -= 1;
158 // trim trailing spaces
159 while (slen > 0 && str[slen - 1] > 0 && str[slen - 1] <= 32) {
160 slen -= 1;
162 if (slen > 0 && slen < sizeof(xrm_key_value)) {
163 memcpy(xrm_key_value, str, slen);
164 xrm_key_value[slen] = 0;
165 res = xrm_key_value;
168 return res;
172 //==========================================================================
174 // parse_bool
176 //==========================================================================
177 static int parse_bool (const char *val) {
178 int res = -1;
179 if (val != NULL) {
180 if (strEquCI(val, "tan")) res = 1;
181 else if (strEquCI(val, "yes")) res = 1;
182 else if (strEquCI(val, "true")) res = 1;
183 else if (strEquCI(val, "on")) res = 1;
184 else if (strEquCI(val, "1")) res = 1;
185 else if (strEquCI(val, "ona")) res = 0;
186 else if (strEquCI(val, "no")) res = 0;
187 else if (strEquCI(val, "false")) res = 0;
188 else if (strEquCI(val, "off")) res = 0;
189 else if (strEquCI(val, "0")) res = 0;
191 return res;
195 //==========================================================================
197 // hex_digit
199 //==========================================================================
200 static int hex_digit (char ch) {
201 return
202 ch >= '0' && ch <= '9' ? ch - '0' :
203 ch >= 'A' && ch <= 'F' ? ch - 'A' + 10 :
204 ch >= 'a' && ch <= 'f' ? ch - 'a' + 10 :
209 //==========================================================================
211 // parse_hex_color
213 //==========================================================================
214 static uint32_t parse_hex_color (const char *cname) {
215 if (cname == NULL) return XRM_BAD_COLOR;
216 while (*cname > 0 && *cname <= 32) cname += 1;
217 if (cname[0] != '#') return XRM_BAD_COLOR;
218 cname += 1;
219 while (*cname > 0 && *cname <= 32) cname += 1;
220 uint32_t vals[6] = {0, 0, 0, 0, 0, 0};
221 int ccnt = 0;
222 while (ccnt < 6 && *cname > 32) {
223 const int dig = hex_digit(*cname); cname += 1;
224 if (dig < 0) return XRM_BAD_COLOR;
225 vals[ccnt] = (unsigned)dig;
226 ccnt += 1;
228 if (ccnt != 3 && ccnt != 6) return XRM_BAD_COLOR;
229 while (*cname > 0 && *cname <= 32) cname += 1;
230 if (cname[0]) return XRM_BAD_COLOR;
231 if (ccnt == 3) {
232 vals[4] = vals[2]; vals[5] = vals[2];
233 vals[2] = vals[1]; vals[3] = vals[1];
234 vals[1] = vals[0];
236 return
237 (vals[0] << 20) | (vals[1] << 16) |
238 (vals[2] << 12) | (vals[3] << 8) |
239 (vals[4] << 4) | vals[5];
243 // ////////////////////////////////////////////////////////////////////////// //
244 static char xrm_errmenu_str[128];
245 static int xrm_errmenu_strpos = 0;
248 //==========================================================================
250 // xrm_errmenu_put
252 //==========================================================================
253 static void xrm_errmenu_put (const char *str) {
254 if (str && str[0]) {
255 int slen = (int)strlen(str);
256 if (xrm_errmenu_strpos + slen >= (int)sizeof(xrm_errmenu_str) - 1 - 4) {
257 xrm_errmenu_str[xrm_errmenu_strpos] = '.'; xrm_errmenu_strpos += 1;
258 xrm_errmenu_str[xrm_errmenu_strpos] = '.'; xrm_errmenu_strpos += 1;
259 xrm_errmenu_str[xrm_errmenu_strpos] = '.'; xrm_errmenu_strpos += 1;
260 xrm_errmenu_str[xrm_errmenu_strpos] = 0;
261 xrm_errmenu_strpos = (int)sizeof(xrm_errmenu_str);
262 } else {
263 strcpy(xrm_errmenu_str + xrm_errmenu_strpos, str);
264 xrm_errmenu_strpos += slen;
270 //==========================================================================
272 // show_error_menu
274 //==========================================================================
275 static void show_error_menu (const char *errmsg, XrmQuarkList quarks) {
276 MenuWindow *menu = menu_new_window(0, 0, "Config Error!", 0, 0);
278 // error message
279 xrm_errmenu_strpos = 0; xrm_errmenu_str[0] = 0;
280 xrm_errmenu_put("Error: ");
281 xrm_errmenu_put(errmsg);
282 menu_add_label(menu, xrm_errmenu_str, NULL);
284 // key
285 xrm_errmenu_strpos = 0; xrm_errmenu_str[0] = 0;
286 xrm_errmenu_put(" Key: ");
287 int f = 0;
288 while (quarks[f] != NULLQUARK) {
289 const char *qq = XrmQuarkToString(quarks[f]);
290 if (f != 0) xrm_errmenu_put(".");
291 xrm_errmenu_put(qq);
292 f += 1;
294 menu_add_label(menu, xrm_errmenu_str, NULL);
295 menu_add_label(menu, NULL, NULL);
297 menu->curr_item = menu->items_count;
298 menu_add_label(menu, "&Close", &menu_msgbox_close_cb);
299 menu_center(menu);
300 open_menu(menu);
304 //==========================================================================
306 // xrm_keybind_cb
308 //==========================================================================
309 static Bool xrm_keybind_cb (XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks,
310 XrmRepresentation *type, XrmValue *value, XPointer udata)
312 (void)db; (void)bindings; (void)quarks; (void)type; (void)value; (void)udata;
313 //fprintf(stderr, "=====\n");
315 const char *errmsg = NULL;
317 if (quarks[0] == NULLQUARK || strcmp(XrmQuarkToString(quarks[0]), xrm_app_name) != 0) return False;
318 if (quarks[1] == NULLQUARK || strcmp(XrmQuarkToString(quarks[1]), "keybind") != 0) {
319 errmsg = "invalid key name";
320 goto error;
322 if (quarks[2] == NULLQUARK || quarks[3] == NULLQUARK || quarks[4] != NULLQUARK) {
323 errmsg = "invalid key format";
324 goto error;
327 if (!type || strcmp(XrmQuarkToString(*type), "String") != 0) {
328 errmsg = "invalid key type";
329 goto error;
332 if (value->size == 0 || value->addr == NULL) {
333 errmsg = "empty key value";
334 goto error;
337 KeyBind *kb = keybinds;
338 while (kb != NULL && strcmp(kb->bindname, XrmQuarkToString(quarks[2])) != 0) {
339 kb = kb->next;
342 if (!kb) {
343 // create new empty keybind
344 kb = malloc(sizeof(KeyBind));
345 if (!kb) { fprintf(stderr, "FATAL: out of memory!\n"); abort(); }
346 memset(kb, 0, sizeof(KeyBind));
347 kb->ksym = NoSymbol;
348 kb->bindname = strdup(XrmQuarkToString(quarks[2]));
349 kb->colorMode = -1;
350 kb->killsignal = 0;
351 kb->allow_history = -1;
352 kb->next = keybinds;
353 keybinds = kb;
356 const char *key = XrmQuarkToString(quarks[3]);
357 const char *val = (const char *)value->addr;
359 #if 0
361 fprintf(stderr, "name: ");
362 int qc = 0;
363 while (quarks[qc] != NULLQUARK) {
364 const char *qs = XrmQuarkToString(quarks[qc]);
365 if (qc != 0) fputc('.', stderr);
366 fprintf(stderr, "%s", qs);
367 qc += 1;
369 fputc('\n', stderr);
370 fprintf(stderr, " key: %s\n", key);
371 fprintf(stderr, " value: %s\n", val);
373 #endif
375 if (strcmp(key, "bind") == 0) {
376 // key binding, parse it
377 if (strEquCI(val, "none") || strEquCI(val, "disable") ||
378 strEquCI(val, "disabled"))
380 kb->killsignal = KB_CMD_IGNORE;
381 } else if (!parse_keybind(kb, val)) {
382 errmsg = "invalid binding string";
383 goto error;
385 } else if (strcmp(key, "path") == 0) {
386 if (strcmp(val, "$CWD") == 0) val = "$PWD";
387 else if (strcmp(val, "$PWD") == 0) {}
388 else if (strcmp(val, "$HOME") == 0) {}
389 else if (val[0] == '/') {}
390 else {
391 errmsg = "invalid path";
392 goto error;
394 free(kb->path);
395 kb->path = strdup(val);
396 if (!kb->path) { fprintf(stderr, "FATAL: out of memory!\n"); abort(); }
397 } else if (strcmp(key, "color") == 0) {
398 if (strEquCI(val, "bw") || strEquCI(val, "mono")) kb->colorMode = CMODE_BW;
399 else if (strEquCI(val, "green")) kb->colorMode = CMODE_GREEN;
400 else if (strEquCI(val, "normal")) kb->colorMode = CMODE_NORMAL;
401 else if (strEquCI(val, "color")) kb->colorMode = CMODE_NORMAL;
402 else if (strEquCI(val, "default")) kb->colorMode = -1;
403 else {
404 errmsg = "invalid color mode";
405 goto error;
407 } else if (strcmp(key, "kill") == 0) {
408 int sig = parse_signal_name(val);
409 if (sig == 0) {
410 errmsg = "invalid signal name";
411 goto error;
413 free(kb->exec); kb->exec = NULL;
414 if (kb->killsignal != KB_CMD_IGNORE) kb->killsignal = sig;
415 } else if (strcmp(key, "exec") == 0) {
416 free(kb->exec);
417 kb->exec = strdup(val);
418 if (!kb->exec) { fprintf(stderr, "FATAL: out of memory!\n"); abort(); }
419 if (kb->killsignal != KB_CMD_IGNORE) kb->killsignal = 0;
420 } else if (strcmp(key, "paste") == 0) {
421 free(kb->exec); kb->exec = NULL;
422 if (strEquCI(val, "primary")) kb->killsignal = KB_CMD_PASTE_PRIMARY;
423 else if (strEquCI(val, "secondary")) kb->killsignal = KB_CMD_PASTE_SECONDARY;
424 else if (strEquCI(val, "clipboard")) kb->killsignal = KB_CMD_PASTE_CLIPBOARD;
425 else {
426 errmsg = "invalid selection name";
427 goto error;
429 } else if (strcmp(key, "copy-to") == 0 || strcmp(key, "copyto") == 0) {
430 free(kb->exec); kb->exec = NULL;
431 if (strEquCI(val, "primary")) kb->killsignal = KB_CMD_COPY_TO_PRIMARY;
432 else if (strEquCI(val, "secondary")) kb->killsignal = KB_CMD_COPY_TO_SECONDARY;
433 else if (strEquCI(val, "clipboard")) kb->killsignal = KB_CMD_COPY_TO_CLIPBOARD;
434 else {
435 errmsg = "invalid selection name";
436 goto error;
438 } else if (strcmp(key, "tab") == 0) {
439 free(kb->exec); kb->exec = NULL;
440 if (strEquCI(val, "prev")) kb->killsignal = KB_CMD_TAB_PREV;
441 else if (strEquCI(val, "next")) kb->killsignal = KB_CMD_TAB_NEXT;
442 else if (strEquCI(val, "first")) kb->killsignal = KB_CMD_TAB_FIRST;
443 else if (strEquCI(val, "last")) kb->killsignal = KB_CMD_TAB_LAST;
444 else if (strEquCI(val, "move-left")) kb->killsignal = KB_CMD_TAB_MOVE_LEFT;
445 else if (strEquCI(val, "move-right")) kb->killsignal = KB_CMD_TAB_MOVE_RIGHT;
446 else {
447 errmsg = "invalid tab command";
448 goto error;
450 } else if (strcmp(key, "history") == 0) {
451 // for "exec"
452 if (strEquCI(val, "default")) {
453 kb->allow_history = -1;
454 } else {
455 int bval = parse_bool(val);
456 if (bval < 0) {
457 errmsg = "invalid history command";
458 goto error;
460 kb->allow_history = bval;
462 } else if (strcmp(key, "selection") == 0) {
463 free(kb->exec); kb->exec = NULL;
464 if (strEquCI(val, "start")) kb->killsignal = KB_CMD_START_SELECTION;
465 else {
466 errmsg = "invalid selection command";
467 goto error;
469 } else if (strcmp(key, "mouse-report") == 0 || strcmp(key, "mouse-reports") == 0) {
470 free(kb->exec); kb->exec = NULL;
471 if (strEquCI(val, "toggle")) kb->killsignal = KB_CMD_MREPORTS_TOGGLE;
472 else {
473 int bval = parse_bool(val);
474 if (bval < 0) {
475 errmsg = "invalid mouse-report command";
476 goto error;
478 kb->killsignal = KB_CMD_MREPORTS_OFF + bval;
480 } else if (strcmp(key, "escesc") == 0 || strcmp(key, "esc-esc") == 0) {
481 free(kb->exec); kb->exec = NULL;
482 if (strEquCI(val, "toggle")) kb->killsignal = KB_CMD_ESCESC_TOGGLE;
483 else {
484 int bval = parse_bool(val);
485 if (bval < 0) {
486 errmsg = "invalid escesc command";
487 goto error;
489 kb->killsignal = KB_CMD_ESCESC_OFF + bval;
491 } else if (strcmp(key, "cursor") == 0) {
492 free(kb->exec); kb->exec = NULL;
493 if (strEquCI(val, "toggle")) kb->killsignal = KB_CMD_CURSOR_TOGGLE;
494 else {
495 int bval = parse_bool(val);
496 if (bval < 0) {
497 errmsg = "invalid escesc command";
498 goto error;
500 kb->killsignal = KB_CMD_CURSOR_OFF + bval;
502 } else if (strcmp(key, "history-mode") == 0) {
503 free(kb->exec); kb->exec = NULL;
504 if (strEquCI(val, "toggle")) kb->killsignal = KB_CMD_HISTORY_TOGGLE;
505 else {
506 int bval = parse_bool(val);
507 if (bval < 0) {
508 errmsg = "invalid history-mode command";
509 goto error;
511 kb->killsignal = KB_CMD_HISTORY_OFF + bval;
513 } else if (strcmp(key, "color-mode") == 0) {
514 free(kb->exec); kb->exec = NULL;
515 if (strEquCI(val, "normal")) kb->killsignal = KB_CMD_COLOR_NORMAL;
516 else if (strEquCI(val, "color")) kb->killsignal = KB_CMD_COLOR_NORMAL;
517 else if (strEquCI(val, "default")) kb->killsignal = KB_CMD_COLOR_DEFAULT;
518 else if (strEquCI(val, "bw") || strEquCI(val, "mono")) kb->killsignal = KB_CMD_COLOR_BW;
519 else if (strEquCI(val, "green")) kb->killsignal = KB_CMD_COLOR_GREEN;
520 else {
521 errmsg = "invalid color-mode command";
522 goto error;
524 } else if (strcmp(key, "menu") == 0) {
525 free(kb->exec); kb->exec = NULL;
526 if (strEquCI(val, "tab-options")) kb->killsignal = KB_CMD_MENU_TAB_OPTIONS;
527 else if (strEquCI(val, "global-options")) kb->killsignal = KB_CMD_MENU_OPTIONS;
528 else {
529 errmsg = "invalid menu command";
530 goto error;
532 } else {
533 errmsg = "unknown keybind option";
534 goto error;
537 return False;
539 error:
540 if (xrm_reloading) {
541 show_error_menu(errmsg, quarks);
544 fprintf(stderr, "CONFIG ERROR: %s!\n", errmsg);
545 fprintf(stderr, " key: ");
546 int f = 0;
547 while (quarks[f] != NULLQUARK) {
548 const char *qq = XrmQuarkToString(quarks[f]);
549 if (f != 0) fputc('.', stderr);
550 fprintf(stderr, "%s", qq);
551 f += 1;
553 fputc('\n', stderr);
555 if (type) {
556 fprintf(stderr, " type: %s\n", XrmQuarkToString(*type));
557 if (strcmp(XrmQuarkToString(*type), "String") == 0) {
558 fprintf(stderr, " value: <%.*s>\n", (unsigned)value->size, (const char *)value->addr);
562 if (!xrm_reloading) exit(1);
563 return False;
567 // ////////////////////////////////////////////////////////////////////////// //
568 enum {
569 XRM_BOOL,
570 XRM_MSTIME, // positive
571 XRM_TABCOUNT,
572 XRM_FPS,
573 XRM_FONT,
574 XRM_FONTGFX,
575 XRM_COLOR,
576 XRM_COLOR_OR_NONE,
577 XRM_SHADOW_OFS,
578 XRM_STRING, // never empty
579 XRM_TERMTYPE,
582 typedef struct {
583 const char *key;
584 int type;
585 yterm_bool once; // load only once?
586 yterm_bool sealed;
587 void *varptr;
588 XrmQuarkList quarks; // will be sorted
589 } IniKey;
592 static IniKey inikeys[] = {
593 {.key="window.title", .type=XRM_STRING, .varptr=&opt_title, .once=1},
595 {.key="term.name", .type=XRM_STRING, .varptr=&opt_term, .once=1},
596 {.key="term.type", .type=XRM_TERMTYPE, .varptr=&opt_term_type, .once=1},
597 {.key="term.font", .type=XRM_FONT, .varptr=&opt_mono_font, .once=1},
599 {.key="term.font.gfx", .type=XRM_FONTGFX, .varptr=&opt_terminus_gfx, .once=1},
600 {.key="term.winch.delay", .type=XRM_MSTIME, .varptr=&opt_winch_delay},
602 {.key="tabs.font", .type=XRM_FONT, .varptr=&opt_tabs_font, .once=1},
603 {.key="tabs.visible", .type=XRM_TABCOUNT, .varptr=&opt_tabs_visible, .once=1},
605 {.key="paste.primary", .type=XRM_STRING, .varptr=&opt_paste_from[0]},
606 {.key="paste.secondary", .type=XRM_STRING, .varptr=&opt_paste_from[1]},
607 {.key="paste.clipboard", .type=XRM_STRING, .varptr=&opt_paste_from[2]},
609 {.key="copyto.primary", .type=XRM_STRING, .varptr=&opt_copy_to[0]},
610 {.key="copyto.secondary", .type=XRM_STRING, .varptr=&opt_copy_to[1]},
611 {.key="copyto.clipboard", .type=XRM_STRING, .varptr=&opt_copy_to[2]},
613 {.key="refresh.fps", .type=XRM_FPS, .varptr=&opt_fps},
615 {.key="history.enabled", .type=XRM_BOOL, .varptr=&opt_history_enabled},
617 {.key="esc-esc.fix", .type=XRM_BOOL, .varptr=&opt_esc_twice},
618 {.key="mouse.reports", .type=XRM_BOOL, .varptr=&opt_mouse_reports},
620 {.key="cursor.blink.time", .type=XRM_MSTIME, .varptr=&opt_cur_blink_time},
621 {.key="cursor.color0.fg", .type=XRM_COLOR_OR_NONE, .varptr=&curColorsFG[0]},
622 {.key="cursor.color0.bg", .type=XRM_COLOR_OR_NONE, .varptr=&curColorsBG[0]},
623 {.key="cursor.color1.fg", .type=XRM_COLOR_OR_NONE, .varptr=&curColorsFG[1]},
624 {.key="cursor.color1.bg", .type=XRM_COLOR_OR_NONE, .varptr=&curColorsBG[1]},
625 {.key="cursor.color.inactive", .type=XRM_COLOR_OR_NONE, .varptr=&curColorsBG[2]},
627 {.key="color.default.fg", .type=XRM_COLOR, .varptr=&colorsTTY[CIDX_DEFAULT_FG]},
628 {.key="color.default.bg", .type=XRM_COLOR, .varptr=&colorsTTY[CIDX_DEFAULT_BG]},
629 {.key="color.default.fg.high", .type=XRM_COLOR, .varptr=&colorsTTY[CIDX_DEFAULT_HIGH_FG]},
630 {.key="color.default.bg.high", .type=XRM_COLOR, .varptr=&colorsTTY[CIDX_DEFAULT_HIGH_BG]},
632 {.key="color.bold.fg", .type=XRM_COLOR, .varptr=&colorsTTY[CIDX_BOLD_FG]},
633 {.key="color.underline.fg", .type=XRM_COLOR, .varptr=&colorsTTY[CIDX_UNDER_FG]},
634 {.key="color.bold.underline.fg", .type=XRM_COLOR, .varptr=&colorsTTY[CIDX_BOLD_UNDER_FG]},
636 {.key="color.high.bold.fg", .type=XRM_COLOR, .varptr=&colorsTTY[CIDX_BOLD_HIGH_FG]},
637 {.key="color.high.underline.fg", .type=XRM_COLOR, .varptr=&colorsTTY[CIDX_UNDER_HIGH_FG]},
638 {.key="color.high.bold.underline.fg", .type=XRM_COLOR, .varptr=&colorsTTY[CIDX_BOLD_UNDER_HIGH_FG]},
640 {.key="tab.color.frame.fg", .type=XRM_COLOR, .varptr=&tab_frame_fg},
641 {.key="tab.color.frame.bg", .type=XRM_COLOR, .varptr=&tab_frame_bg},
643 {.key="tab.color.normal.bg", .type=XRM_COLOR, .varptr=&tab_colors[TABC_NORMAL].bg},
644 {.key="tab.color.normal.text", .type=XRM_COLOR, .varptr=&tab_colors[TABC_NORMAL].text},
645 {.key="tab.color.normal.index", .type=XRM_COLOR, .varptr=&tab_colors[TABC_NORMAL].index},
646 {.key="tab.color.normal.ellipsis", .type=XRM_COLOR, .varptr=&tab_colors[TABC_NORMAL].ellipsis},
648 {.key="tab.color.active.bg", .type=XRM_COLOR, .varptr=&tab_colors[TABC_ACTIVE].bg},
649 {.key="tab.color.active.text", .type=XRM_COLOR, .varptr=&tab_colors[TABC_ACTIVE].text},
650 {.key="tab.color.active.index", .type=XRM_COLOR, .varptr=&tab_colors[TABC_ACTIVE].index},
651 {.key="tab.color.active.ellipsis", .type=XRM_COLOR, .varptr=&tab_colors[TABC_ACTIVE].ellipsis},
653 {.key="tab.color.dead.bg", .type=XRM_COLOR, .varptr=&tab_colors[TABC_DEAD].bg},
654 {.key="tab.color.dead.text", .type=XRM_COLOR, .varptr=&tab_colors[TABC_DEAD].text},
655 {.key="tab.color.dead.index", .type=XRM_COLOR, .varptr=&tab_colors[TABC_DEAD].index},
656 {.key="tab.color.dead.ellipsis", .type=XRM_COLOR, .varptr=&tab_colors[TABC_DEAD].ellipsis},
658 {.key="tab.color.dead.active.bg", .type=XRM_COLOR, .varptr=&tab_colors[TABC_DEAD_ACTIVE].bg},
659 {.key="tab.color.dead.active.text", .type=XRM_COLOR, .varptr=&tab_colors[TABC_DEAD_ACTIVE].text},
660 {.key="tab.color.dead.active.index", .type=XRM_COLOR, .varptr=&tab_colors[TABC_DEAD_ACTIVE].index},
661 {.key="tab.color.dead.active.ellipsis", .type=XRM_COLOR, .varptr=&tab_colors[TABC_DEAD_ACTIVE].ellipsis},
663 {.key="selection.color.fg", .type=XRM_COLOR, .varptr=&colorAmberFG},
664 {.key="selection.color.bg", .type=XRM_COLOR, .varptr=&colorAmberBG},
665 {.key="selection.block.color.fg", .type=XRM_COLOR, .varptr=&colorSelectionFG},
666 {.key="selection.block.color.bg", .type=XRM_COLOR, .varptr=&colorSelectionBG},
668 {.key="selection.tint", .type=XRM_BOOL, .varptr=&opt_amber_tint},
670 {.key="osd-menu.shadow.color", .type=XRM_COLOR_OR_NONE, .varptr=&opt_osd_menu_shadow_color},
671 {.key="osd-menu.shadow.x-ofs", .type=XRM_SHADOW_OFS, .varptr=&opt_osd_menu_shadow_xofs},
672 {.key="osd-menu.shadow.y-ofs", .type=XRM_SHADOW_OFS, .varptr=&opt_osd_menu_shadow_yofs},
673 {.key="osd-menu.shadow.xofs", .type=XRM_SHADOW_OFS, .varptr=&opt_osd_menu_shadow_xofs},
674 {.key="osd-menu.shadow.yofs", .type=XRM_SHADOW_OFS, .varptr=&opt_osd_menu_shadow_yofs},
676 {.key="osd-menu.color.passive.bg", .type=XRM_COLOR_OR_NONE, .varptr=&osd_menu_bg[0]},
677 {.key="osd-menu.color.passive.fg", .type=XRM_COLOR_OR_NONE, .varptr=&osd_menu_fg[0]},
679 {.key="osd-menu.color.active.bg", .type=XRM_COLOR_OR_NONE, .varptr=&osd_menu_bg[OSD_CSCHEME_ACTIVE]},
680 {.key="osd-menu.color.active.fg", .type=XRM_COLOR_OR_NONE, .varptr=&osd_menu_fg[OSD_CSCHEME_ACTIVE]},
682 {.key="osd-menu.color.passive.cursor.bg", .type=XRM_COLOR_OR_NONE, .varptr=&osd_menu_bg[OSD_CSCHEME_CURSOR]},
683 {.key="osd-menu.color.passive.cursor.fg", .type=XRM_COLOR_OR_NONE, .varptr=&osd_menu_fg[OSD_CSCHEME_CURSOR]},
685 {.key="osd-menu.color.active.cursor.bg", .type=XRM_COLOR_OR_NONE, .varptr=&osd_menu_bg[OSD_CSCHEME_CURSOR | OSD_CSCHEME_ACTIVE]},
686 {.key="osd-menu.color.active.cursor.fg", .type=XRM_COLOR_OR_NONE, .varptr=&osd_menu_fg[OSD_CSCHEME_CURSOR | OSD_CSCHEME_ACTIVE]},
688 {.key="osd-menu.color.passive.hotkey.bg", .type=XRM_COLOR_OR_NONE, .varptr=&osd_menu_bg[OSD_CSCHEME_HOTKEY]},
689 {.key="osd-menu.color.passive.hotkey.fg", .type=XRM_COLOR_OR_NONE, .varptr=&osd_menu_fg[OSD_CSCHEME_HOTKEY]},
691 {.key="osd-menu.color.active.hotkey.bg", .type=XRM_COLOR_OR_NONE, .varptr=&osd_menu_bg[OSD_CSCHEME_HOTKEY | OSD_CSCHEME_ACTIVE]},
692 {.key="osd-menu.color.active.hotkey.fg", .type=XRM_COLOR_OR_NONE, .varptr=&osd_menu_fg[OSD_CSCHEME_HOTKEY | OSD_CSCHEME_ACTIVE]},
694 {.key="osd-menu.color.passive.cursor.hotkey.bg", .type=XRM_COLOR_OR_NONE, .varptr=&osd_menu_bg[OSD_CSCHEME_CURSOR | OSD_CSCHEME_HOTKEY]},
695 {.key="osd-menu.color.passive.cursor.hotkey.fg", .type=XRM_COLOR_OR_NONE, .varptr=&osd_menu_fg[OSD_CSCHEME_CURSOR | OSD_CSCHEME_HOTKEY]},
697 {.key="osd-menu.color.active.cursor.hotkey.bg", .type=XRM_COLOR_OR_NONE, .varptr=&osd_menu_bg[OSD_CSCHEME_CURSOR | OSD_CSCHEME_HOTKEY | OSD_CSCHEME_ACTIVE]},
698 {.key="osd-menu.color.active.cursor.hotkey.fg", .type=XRM_COLOR_OR_NONE, .varptr=&osd_menu_fg[OSD_CSCHEME_CURSOR | OSD_CSCHEME_HOTKEY | OSD_CSCHEME_ACTIVE]},
700 {.key=NULL},
704 //==========================================================================
706 // xq_cmp_cb
708 //==========================================================================
709 static int xq_cmp_cb (const void *aa, const void *bb) {
710 XrmQuark a = *(const XrmQuark *)aa;
711 XrmQuark b = *(const XrmQuark *)bb;
712 return (a < b ? -1 : a > b ? +1 : 0);
716 //==========================================================================
718 // prepare_ikey_name
720 //==========================================================================
721 static void prepare_ikey_name (IniKey *ikey) {
722 yterm_assert(ikey != NULL);
723 if (ikey->quarks == NULL) {
724 // parse key name
725 char ktemp[128];
726 yterm_assert(strlen(ikey->key) < sizeof(ktemp));
727 strcpy(ktemp, ikey->key);
728 int pqcount = 2;
729 for (const char *tmp = ikey->key; *tmp; tmp += 1) {
730 if (*tmp == '.') pqcount += 1;
732 ikey->quarks = malloc((unsigned)pqcount * sizeof(ikey->quarks[0]));
733 pqcount = 0;
734 const char *kstr = ikey->key;
735 while (*kstr) {
736 if (*kstr == '.') {
737 kstr += 1;
738 } else {
739 const char *ep = strchr(kstr, '.');
740 if (ep == NULL) ep = kstr + strlen(kstr);
741 const size_t klen = (size_t)(ptrdiff_t)(ep - kstr);
742 yterm_assert(klen != 0);
743 if (klen >= sizeof(ktemp)) abort();
744 memcpy(ktemp, kstr, klen);
745 ktemp[klen] = 0;
746 kstr = ep;
747 ikey->quarks[pqcount] = XrmStringToQuark(ktemp);
748 pqcount += 1;
751 yterm_assert(pqcount != 0);
752 qsort(&ikey->quarks[0], (size_t)pqcount, sizeof(ikey->quarks[0]), xq_cmp_cb);
753 ikey->quarks[pqcount] = NULLQUARK;
754 #if 0
755 fprintf(stderr, "PARSED: ");
756 for (int cc = 0; ikey->quarks[cc]; cc += 1) {
757 if (cc != 0) fputc('.', stderr);
758 fprintf(stderr, "%s", XrmQuarkToString(ikey->quarks[cc]));
760 fputc('\n', stderr);
761 #endif
766 #define DUMP_KEY_NAME() do { \
767 int qnn = 0; \
768 while (quarks[qnn] != NULLQUARK) { \
769 if (qnn != 0) fputc('.', stderr); \
770 fprintf(stderr, "%s", XrmQuarkToString(quarks[qnn])); \
771 qnn += 1; \
773 } while (0)
776 #define DUMP_SKKEY_NAME() do { \
777 int qnn = 0; \
778 while (qlist[qnn] != NULLQUARK) { \
779 if (qnn != 0) fputc('.', stderr); \
780 fprintf(stderr, "%s", XrmQuarkToString(qlist[qnn])); \
781 qnn += 1; \
783 } while (0)
786 //==========================================================================
788 // xrm_load_inis_cb
790 //==========================================================================
791 static Bool xrm_load_inis_cb (XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks,
792 XrmRepresentation *type, XrmValue *value, XPointer udata)
794 (void)db; (void)bindings; (void)quarks; (void)type; (void)value; (void)udata;
795 //fprintf(stderr, "=====\n");
797 const char *errmsg = NULL;
799 if (quarks[0] == NULLQUARK || quarks[1] == NULLQUARK) {
800 errmsg = "invalid key name";
801 goto error;
804 XrmQuark qlist[16];
805 int count = 0;
806 while (count < 16 && quarks[count + 1] != NULLQUARK) {
807 // keybind?
808 if (strcmp(XrmQuarkToString(quarks[count + 1]), "keybind") == 0) {
809 return xrm_keybind_cb(db, bindings, quarks, type, value, udata);
811 qlist[count] = quarks[count + 1];
812 count += 1;
815 if (count < 1 || count > 15) return False;
816 qlist[count] = NULLQUARK;
818 qsort(&qlist[0], (size_t)count, sizeof(qlist[0]), xq_cmp_cb);
820 #if 0
821 fprintf(stderr, "***: "); DUMP_SKKEY_NAME(); fputc('\n', stderr);
822 #endif
824 for (IniKey *ikey = inikeys; ikey->key != NULL; ikey += 1) {
825 prepare_ikey_name(ikey);
826 // compare
827 int pos = 0;
828 while (qlist[pos] != NULLQUARK && ikey->quarks[pos] != NULLQUARK &&
829 qlist[pos] == ikey->quarks[pos])
831 pos += 1;
833 if (qlist[pos] == NULLQUARK && ikey->quarks[pos] == NULLQUARK) {
834 if (ikey->sealed) return False; // this option is sealed
835 if (type == NULL || strcmp(XrmQuarkToString(*type), "String") != 0) {
836 errmsg = "invalid key type";
837 goto error;
839 char *sval = xrm_val_to_val(value);
840 if (sval == NULL) {
841 errmsg = "invalid key value";
842 goto error;
844 switch (ikey->type) {
845 case XRM_BOOL:
847 int bval = parse_bool(sval);
848 if (bval < 0) {
849 errmsg = "invalid boolean value";
850 goto error;
852 *(yterm_bool *)ikey->varptr = bval;
854 break;
855 case XRM_MSTIME: // positive
857 int bval = parse_bool(sval);
858 if (bval == 0) {
859 *(int *)ikey->varptr = 0;
860 } else {
861 char *end;
862 long v = strtol(sval, &end, 10);
863 if (*end || v < 0 || v > 2666) {
864 errmsg = "invalid time value";
865 goto error;
867 *(int *)ikey->varptr = (int)v;
870 break;
871 case XRM_FPS:
873 char *end;
874 long v = strtol(sval, &end, 10);
875 if (*end || v < 1 || v > 120) {
876 errmsg = "invalid FPS value";
877 goto error;
879 *(int *)ikey->varptr = (int)v;
881 break;
882 case XRM_SHADOW_OFS:
884 char *end;
885 long v = strtol(sval, &end, 10);
886 if (*end || v < 1 || v > 64) {
887 errmsg = "invalid shadow offset value";
888 goto error;
890 *(int *)ikey->varptr = (int)v;
892 break;
893 case XRM_TABCOUNT:
895 char *end;
896 long v = strtol(sval, &end, 10);
897 if (*end || v < 0 || v > 32) {
898 int bval = parse_bool(sval);
899 if (bval < 0) {
900 errmsg = "invalid tab count value";
901 goto error;
903 opt_enable_tabs = bval;
904 } else {
905 if (v == 0) {
906 opt_enable_tabs = 0;
907 } else {
908 *(int *)ikey->varptr = (int)v;
912 break;
913 case XRM_FONT:
915 char **sptr = (char **)ikey->varptr;
916 free(*sptr);
917 *sptr = strdup(sval);
918 if (*sptr == NULL) { fprintf(stderr, "FATAL: out of memory!\n"); abort(); }
920 break;
921 case XRM_COLOR:
923 uint32_t clr = parse_hex_color(sval);
924 if (clr == XRM_BAD_COLOR) {
925 errmsg = "invalid color value";
926 goto error;
928 *(uint32_t *)ikey->varptr = clr;
930 break;
931 case XRM_COLOR_OR_NONE:
933 if (strEquCI(sval, "none")) {
934 *(uint32_t *)ikey->varptr = 0xff000000U;
935 } else {
936 uint32_t clr = parse_hex_color(sval);
937 if (clr == XRM_BAD_COLOR) {
938 errmsg = "invalid color value";
939 goto error;
941 *(uint32_t *)ikey->varptr = clr;
944 break;
945 case XRM_STRING: // never empty
947 char **sptr = (char **)ikey->varptr;
948 free(*sptr);
949 *sptr = strdup(sval);
950 if (*sptr == NULL) { fprintf(stderr, "FATAL: out of memory!\n"); abort(); }
952 break;
953 case XRM_TERMTYPE:
954 if (strEquCI(sval, "rxvt")) opt_term_type = TT_RXVT;
955 else if (strEquCI(sval, "xterm")) opt_term_type = TT_XTERM;
956 else {
957 errmsg = "invalid terminal type";
958 goto error;
960 break;
961 case XRM_FONTGFX:
962 if (strEquCI(sval, "terminus")) opt_terminus_gfx = 1;
963 else if (strEquCI(sval, "unicode")) opt_terminus_gfx = 0;
964 else {
965 errmsg = "invalid font gfx type";
966 goto error;
968 break;
969 default:
970 fprintf(stderr, "INTERNAL ERROR: ketmar forgot to handle some ini type!\n");
971 abort();
973 #if 0
974 fprintf(stderr, "OK KEY: "); DUMP_KEY_NAME(); fputc('\n', stderr);
975 fprintf(stderr, " type: %d; val=<%s>\n", ikey->type, sval);
976 #endif
977 return False;
981 // terminal colors?
982 if (count == 1) {
983 const char *qn = XrmQuarkToString(qlist[0]);
984 int idx = -1;
985 for (int f = 0; idx == -1 && f < 16; f += 1) {
986 char kname[16];
987 snprintf(kname, sizeof(kname), "color%d", f);
988 if (strcmp(qn, kname) == 0) idx = f;
989 else if (f < 10) {
990 snprintf(kname, sizeof(kname), "color0%d", f);
991 if (strcmp(qn, kname) == 0) idx = f;
994 if (idx != -1) {
995 yterm_assert(idx >= 0 && idx <= 15);
996 #if 0
997 fprintf(stderr, "TTYCOLOR %d KEY: ", idx); DUMP_KEY_NAME(); fputc('\n', stderr);
998 #endif
999 char *sval = xrm_val_to_val(value);
1000 if (sval == NULL) {
1001 errmsg = "invalid key value";
1002 goto error;
1004 uint32_t clr = parse_hex_color(sval);
1005 if (clr == XRM_BAD_COLOR) {
1006 errmsg = "invalid color value";
1007 goto error;
1009 colorsTTY[idx] = clr;
1010 return False;
1014 fprintf(stderr, "UNKNOWN KEY: "); DUMP_KEY_NAME(); fputc('\n', stderr);
1016 return False;
1018 error:
1019 if (xrm_reloading) {
1020 show_error_menu(errmsg, quarks);
1023 fprintf(stderr, "CONFIG ERROR: %s!\n", errmsg);
1024 fprintf(stderr, " key: ");
1025 int f = 0;
1026 while (quarks[f] != NULLQUARK) {
1027 const char *qq = XrmQuarkToString(quarks[f]);
1028 if (f != 0) fputc('.', stderr);
1029 fprintf(stderr, "%s", qq);
1030 f += 1;
1032 fputc('\n', stderr);
1034 if (type) {
1035 fprintf(stderr, " type: %s\n", XrmQuarkToString(*type));
1036 if (strcmp(XrmQuarkToString(*type), "String") == 0) {
1037 fprintf(stderr, " value: <%.*s>\n", (unsigned)value->size, (const char *)value->addr);
1041 if (!xrm_reloading) exit(1);
1042 return False;
1046 //==========================================================================
1048 // xrm_load_inis
1050 //==========================================================================
1051 static void xrm_load_inis (XrmDatabase db) {
1052 XrmQuark names[2];
1053 XrmQuark classes[2];
1055 names[0] = XrmPermStringToQuark(xrm_app_name);
1056 names[1] = NULLQUARK;
1057 // class
1058 classes[0] = NULLQUARK;
1060 XrmEnumerateDatabase(db, names, classes, XrmEnumAllLevels, xrm_load_inis_cb, NULL);
1064 //==========================================================================
1066 // xrm_seal_option_by_ptr
1068 //==========================================================================
1069 static void xrm_seal_option_by_ptr (const void *ptr) {
1070 for (IniKey *ikey = inikeys; ikey->key != NULL; ikey += 1) {
1071 if (ikey->varptr == ptr && ikey->sealed == 0) {
1072 ikey->sealed = -1;
1078 //==========================================================================
1080 // xrm_is_option_sealed_by_ptr
1082 //==========================================================================
1083 static yterm_bool xrm_is_option_sealed_by_ptr (const void *ptr) {
1084 yterm_bool res = 0;
1085 for (IniKey *ikey = inikeys; res == 0 && ikey->key != NULL; ikey += 1) {
1086 res = (ikey->varptr == ptr && ikey->sealed == -1);
1088 return res;
1092 //==========================================================================
1094 // xrm_unseal_ptr_options
1096 //==========================================================================
1097 static void xrm_unseal_ptr_options (void) {
1098 for (IniKey *ikey = inikeys; ikey->key != NULL; ikey += 1) {
1099 if (ikey->sealed == -1) ikey->sealed = 0;
1104 //==========================================================================
1106 // xrm_new_command_keybind
1108 //==========================================================================
1109 static void xrm_new_command_keybind (const char *name, const char *keys, int cmd) {
1110 yterm_assert(name != NULL);
1111 yterm_assert(keys != NULL);
1112 KeyBind *kb = malloc(sizeof(KeyBind));
1113 if (!kb) { fprintf(stderr, "FATAL: out of memory!\n"); abort(); }
1114 memset(kb, 0, sizeof(KeyBind));
1115 kb->bindname = strdup(name);
1116 if (!kb->bindname) abort();
1117 if (!parse_keybind(kb, keys)) abort();
1118 kb->colorMode = -1;
1119 kb->killsignal = cmd;
1120 kb->allow_history = -1;
1121 kb->next = keybinds;
1122 keybinds = kb;
1126 //==========================================================================
1128 // xrm_new_exec_keybind
1130 //==========================================================================
1131 static void xrm_new_exec_keybind (const char *name, const char *keys,
1132 const char *exec, const char *path)
1134 yterm_assert(name != NULL);
1135 yterm_assert(keys != NULL);
1136 yterm_assert(exec != NULL);
1137 yterm_assert(path != NULL);
1138 KeyBind *kb = malloc(sizeof(KeyBind));
1139 if (!kb) { fprintf(stderr, "FATAL: out of memory!\n"); abort(); }
1140 memset(kb, 0, sizeof(KeyBind));
1141 kb->bindname = strdup(name);
1142 if (!kb->bindname) abort();
1143 if (!parse_keybind(kb, keys)) abort();
1144 kb->colorMode = -1;
1145 kb->killsignal = 0;
1146 kb->allow_history = -1;
1147 kb->exec = strdup(exec);
1148 if (!kb->exec) abort();
1149 kb->path = strdup(path);
1150 if (!kb->path) abort();
1151 kb->next = keybinds;
1152 keybinds = kb;
1156 //==========================================================================
1158 // xrm_add_default_keybinds
1160 //==========================================================================
1161 static void xrm_add_default_keybinds (void) {
1162 fprintf(stderr, "adding default keybindings...\n");
1164 xrm_new_command_keybind("start-selection", "C-space", KB_CMD_START_SELECTION);
1165 xrm_new_command_keybind("start-selection1", "C-KP_Insert", KB_CMD_START_SELECTION);
1166 xrm_new_command_keybind("start-selection2", "M-KP_Insert", KB_CMD_START_SELECTION);
1168 xrm_new_command_keybind("paste-primary", "S-Insert", KB_CMD_PASTE_PRIMARY);
1169 xrm_new_command_keybind("paste-secondary", "M-Insert", KB_CMD_PASTE_SECONDARY);
1170 xrm_new_command_keybind("paste-clipboard", "M-S-Insert", KB_CMD_PASTE_CLIPBOARD);
1172 xrm_new_command_keybind("copy-to-primary", "S-Insert", KB_CMD_COPY_TO_PRIMARY);
1173 xrm_new_command_keybind("copy-to-secondary", "M-Insert", KB_CMD_COPY_TO_SECONDARY);
1174 xrm_new_command_keybind("copy-to-clipboard", "M-S-Insert", KB_CMD_COPY_TO_CLIPBOARD);
1175 xrm_new_command_keybind("copy-to-primary", "M-S-c", KB_CMD_COPY_TO_PRIMARY);
1177 xrm_new_command_keybind("prev-tab", "C-M-Left", KB_CMD_TAB_PREV);
1178 xrm_new_command_keybind("next-tab", "C-M-Right", KB_CMD_TAB_NEXT);
1179 xrm_new_command_keybind("first-tab", "C-M-Home", KB_CMD_TAB_FIRST);
1180 xrm_new_command_keybind("last-tab", "C-M-End", KB_CMD_TAB_LAST);
1181 xrm_new_command_keybind("tab-to-left", "M-S-Left", KB_CMD_TAB_MOVE_LEFT);
1182 xrm_new_command_keybind("tab-to-right", "M-S-Right", KB_CMD_TAB_MOVE_RIGHT);
1184 xrm_new_command_keybind("kill-process", "C-H-k", SIGKILL);
1186 xrm_new_exec_keybind("newtab", "C-M-t", "$SHELL", "$PWD");
1187 xrm_new_exec_keybind("root-shell", "C-M-r", "suka -F -", "$PWD");
1188 keybinds->colorMode = CMODE_GREEN;
1189 xrm_new_exec_keybind("mc", "C-M-m", "mc", "$PWD");
1191 xrm_new_command_keybind("menu-tab-options", "Menu", KB_CMD_MENU_TAB_OPTIONS);
1195 //==========================================================================
1197 // xrm_load_options
1199 //==========================================================================
1200 static void xrm_load_options (void) {
1201 XrmInitialize();
1203 // some idiotic X11 instances doesn't have a system-wide resources
1204 // WARNING! don't free `sysdbstr()`! that's how it works.
1205 char *sysdbstr = XResourceManagerString(x11_dpy);
1206 XrmDatabase db = XrmGetStringDatabase(sysdbstr != NULL ? sysdbstr : "");
1208 // clear keybinds
1209 while (keybinds != NULL) {
1210 KeyBind *kb = keybinds;
1211 keybinds = keybinds->next;
1212 free(kb->bindname);
1213 free(kb->exec);
1214 free(kb->path);
1217 // load local settings
1219 const char *home = getenv("HOME");
1220 if (home && home[0]) {
1221 char *fname = malloc(strlen(home) + 128);
1222 strcpy(fname, home);
1223 if (home[strlen(home) - 1] != '/') strcat(fname, "/");
1224 strcat(fname, ".k8-yterm.Xresources");
1225 //fprintf(stderr, "<%s>\n", fname);
1226 if (db) {
1227 if (XrmCombineFileDatabase(fname, &db, True) == 0) {
1228 //fprintf(stderr, "SHIT!\n");
1230 } else {
1231 db = XrmGetFileDatabase(fname);
1233 free(fname);
1237 if (db) {
1238 //xrm_load_keybinds(db);
1239 xrm_load_inis(db);
1241 for (IniKey *ikey = inikeys; ikey->key != NULL; ikey += 1) {
1242 free(ikey->quarks);
1243 ikey->quarks = NULL;
1246 XrmDestroyDatabase(db);
1248 yterm_assert(opt_tabs_visible > 0);
1249 // check if we have more than one tab open, and don't disable tabs in this case
1250 if (!opt_enable_tabs) {
1251 Term *tt = termlist;
1252 while (tt != NULL && tt->deadstate == DS_DEAD) tt = tt->next;
1253 if (tt != NULL) opt_enable_tabs = 1;
1256 // seal options
1257 for (IniKey *ikey = inikeys; ikey->key != NULL; ikey += 1) {
1258 if (ikey->once) ikey->sealed = 1;
1261 // remove dead keybinds
1262 KeyBind *prev = NULL;
1263 KeyBind *cc = NULL;
1264 KeyBind *kb = keybinds;
1265 while (kb != NULL) {
1266 if (kb->ksym == NoSymbol || kb->killsignal == KB_CMD_IGNORE ||
1267 (kb->killsignal <= 0 && kb->exec == NULL))
1269 fprintf(stderr, "XRM: removed empty/disabled keybind '%s'\n", kb->bindname);
1270 free(kb->bindname);
1271 free(kb->exec);
1272 free(kb->path);
1273 if (prev != NULL) prev->next = kb->next; else keybinds = kb->next;
1274 cc = kb;
1275 kb = kb->next;
1276 free(cc);
1277 } else {
1278 prev = kb; kb = kb->next;
1282 // if we have no keybinds, add default
1283 if (keybinds == NULL) xrm_add_default_keybinds();
1285 // check for keybind conflicts
1286 for (kb = keybinds; kb != NULL; kb = kb->next) {
1287 for (KeyBind *nkb = kb->next; nkb != NULL; nkb = nkb->next) {
1288 if (nkb != kb && nkb->ksym == kb->ksym && nkb->mods == kb->mods) {
1289 yterm_bool bad = 1;
1290 if (kb->killsignal == KB_CMD_PASTE_PRIMARY ||
1291 kb->killsignal == KB_CMD_PASTE_SECONDARY ||
1292 kb->killsignal == KB_CMD_PASTE_CLIPBOARD)
1294 bad = nkb->killsignal != KB_CMD_COPY_TO_PRIMARY &&
1295 nkb->killsignal != KB_CMD_COPY_TO_SECONDARY &&
1296 nkb->killsignal != KB_CMD_COPY_TO_CLIPBOARD;
1297 } else if (kb->killsignal == KB_CMD_COPY_TO_PRIMARY ||
1298 kb->killsignal == KB_CMD_COPY_TO_SECONDARY ||
1299 kb->killsignal == KB_CMD_COPY_TO_CLIPBOARD)
1301 bad = nkb->killsignal != KB_CMD_PASTE_PRIMARY &&
1302 nkb->killsignal != KB_CMD_PASTE_SECONDARY &&
1303 nkb->killsignal != KB_CMD_PASTE_CLIPBOARD;
1305 if (bad) {
1306 fprintf(stderr, "WARNING! keybind '%s' conflicts with '%s'!\n",
1307 kb->bindname, nkb->bindname);
1313 #if 0
1314 // dump keybinds
1315 if (keybinds != NULL) {
1316 fprintf(stderr, "=== KEYBINDS ===\n");
1317 for (kb = keybinds; kb != NULL; kb = kb->next) {
1318 const char *ksname = XKeysymToString(kb->ksym);
1319 fprintf(stderr, "--- %s ---\n", kb->bindname);
1320 fprintf(stderr, " key: ");
1321 if (kb->mods & ControlMask) fprintf(stderr, "C-");
1322 if (kb->mods & Mod1Mask) fprintf(stderr, "M-");
1323 if (kb->mods & Mod4Mask) fprintf(stderr, "H-");
1324 if (kb->mods & ShiftMask) fprintf(stderr, "S-");
1325 fprintf(stderr, "%s\n", ksname);
1326 fprintf(stderr, " path: %s\n", (kb->path != NULL ? kb->path : "<default>"));
1327 fprintf(stderr, " exec: %s\n", (kb->exec != NULL ? kb->exec : "<none>"));
1328 if (kb->killsignal >= 600) {
1329 fprintf(stderr, " command: %d\n", kb->killsignal);
1330 } else if (kb->killsignal > 0) {
1331 fprintf(stderr, " kill: %d\n", kb->killsignal);
1332 } else {
1333 fprintf(stderr, " kill: <none>\n");
1337 #endif
1339 } else {
1340 fprintf(stderr, "NOTE: cannot load X resources database (meh).\n");