added some callbacks
[k8sterm.git] / src / sterm.c
blobf97b0073d3ae770f1913438b544413d01d21b94b
1 /* See LICENSE for licence details. */
2 #ifndef GIT_VERSION
3 # define VERSION "0.3.1.beta9"
4 #else
5 # define VERSION GIT_VERSION
6 #endif
8 #ifdef _XOPEN_SOURCE
9 # undef _XOPEN_SOURCE
10 #endif
11 #define _XOPEN_SOURCE 600
13 #include <alloca.h>
14 #include <ctype.h>
15 #include <errno.h>
16 #include <fcntl.h>
17 #include <iconv.h>
18 #include <limits.h>
19 #include <locale.h>
20 #include <pty.h>
21 #include <stdarg.h>
22 #include <stdint.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <strings.h>
27 #include <signal.h>
28 #include <sys/ioctl.h>
29 #include <sys/select.h>
30 #include <sys/stat.h>
31 #include <sys/time.h>
32 #include <sys/types.h>
33 #include <sys/wait.h>
34 #include <time.h>
35 #include <unistd.h>
36 #include <X11/Xatom.h>
37 #include <X11/Xlib.h>
38 #include <X11/Xutil.h>
39 #include <X11/cursorfont.h>
40 #include <X11/keysym.h>
42 //#include "dbglog.h"
45 // uncomment the following to use XCreateGlyphCursor() instead of XCreatePixmapCursor()
46 //#define BLANKPTR_USE_GLYPH_CURSOR
49 //#define PASTE_SELECTION_DEBUG
51 //#define DUMP_KEYSYMS
53 //#define KEYPAD_DUMP
55 //#define DUMP_PROG_OUTPUT
56 //#define DUMP_PROG_INPUT
58 //#define DUMP_IO_READ
59 //#define DUMP_IO_WRITE
61 #if defined(DUMP_IO_READ) || defined(DUMP_IO_WRITE)
62 # define DUMP_IO
63 #endif
65 #ifdef KEYPAD_DUMP
66 # define DUMP_KEYPAD_SWITCH(strflag,strstate) do { fprintf(stderr, "KEYPAD %s (%s)\n", (strstate), (strflag)); } while (0)
67 #else
68 # define DUMP_KEYPAD_SWITCH(strflag,strstate) ((void)(sizeof(strflag)+sizeof(strstate)))
69 #endif
72 ////////////////////////////////////////////////////////////////////////////////
73 #include "defaults.c"
74 #include "getticks.c"
77 ////////////////////////////////////////////////////////////////////////////////
78 #define USAGE_VERSION "k8sterm " VERSION "\n(c) 2010-2012 st engineers and Ketmar // Vampire Avalon\n"
79 #define USAGE \
80 "usage: sterm [options]\n" \
81 "options:\n" \
82 "-v show version and exit\n" \
83 "-h show this help and exit\n" \
84 "-S disable tabs\n" \
85 "-t title set window title\n" \
86 "-c class set window class\n" \
87 "-w windowid embed in window id given id\n" \
88 "-T termname set TERM name\n" \
89 "-C config_file use custom config file\n" \
90 "-l langiconv use given locale\n" \
91 "-R stcmd run this INTERNAL k8sterm command\n" \
92 "-e command... run given command and pass all following args to it\n"
95 ////////////////////////////////////////////////////////////////////////////////
96 /* masks for key translation */
97 #define XK_NO_MOD (UINT_MAX)
98 #define XK_ANY_MOD (0)
101 /* misc utility macros */
102 #ifdef K8T_MAX
103 # undef K8T_MAX
104 #endif
105 #define K8T_MAX(__a,__b) \
106 ({ typeof(__a)_a = (__a); \
107 typeof(__b)_b = (__b); \
108 _a > _b ? _a : _b; })
110 #ifdef K8T_MIN
111 # undef K8T_MIN
112 #endif
113 #define K8T_MIN(__a,__b) \
114 ({ typeof(__a)_a = (__a); \
115 typeof(__b)_b = (__b); \
116 _a < _b ? _a : _b; })
118 #define K8T_ARRLEN(a) (sizeof(a)/sizeof(a[0]))
119 #define K8T_DEFAULT(a, b) (a) = ((a) ? (a) : (b))
120 #define K8T_BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b))
121 #define K8T_LIMIT(x, a, b) ((x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x))
122 #define K8T_ATTRCMP(a, b) ((a).attr != (b).attr || (a).fg != (b).fg || (a).bg != (b).bg)
123 #define K8T_ISSET(_tr,flag) ((_tr)->mode&(flag))
124 #define K8T_X2COL(x) ((x)/xw.cw)
125 #define K8T_Y2ROW(_tr, y) ((y-(opt_tabposition==1 ? xw.tabheight : 0))/xw.ch-((_tr) != NULL ? (_tr)->topline : 0))
126 #define K8T_ISGFX(mode) ((mode)&K8T_ATTR_GFX)
129 ////////////////////////////////////////////////////////////////////////////////
130 enum {
131 K8T_BELL_AUDIO = 0x01,
132 K8T_BELL_URGENT = 0x02
135 enum {
136 K8T_CMDMODE_NONE,
137 K8T_CMDMODE_INPUT,
138 K8T_CMDMODE_MESSAGE
141 // glyph attributes (bitmask)
142 enum {
143 K8T_ATTR_NULL = 0x00,
144 K8T_ATTR_REVERSE = 0x01,
145 K8T_ATTR_UNDERLINE = 0x02,
146 K8T_ATTR_BOLD = 0x04,
147 K8T_ATTR_GFX = 0x08,
148 K8T_ATTR_DEFFG = 0x10,
149 K8T_ATTR_DEFBG = 0x20,
152 // cursor operations for k8t_tmCursor()
153 enum cursor_movement {
154 K8T_CURSOR_SAVE,
155 K8T_CURSOR_LOAD
158 // cursor state (bitmask)
159 enum {
160 K8T_CURSOR_DEFAULT = 0x00,
161 K8T_CURSOR_HIDE = 0x01,
162 K8T_CURSOR_WRAPNEXT = 0x02
165 // glyph state (bitmask)
166 enum {
167 K8T_GLYPH_SET = 0x01, /* for selection only */
168 K8T_GLYPH_DIRTY = 0x02,
169 K8T_GLYPH_WRAP = 0x10, /* can be set for the last line glyph */
172 // terminal mode flags (bitmask)
173 enum {
174 K8T_MODE_WRAP = 0x01,
175 K8T_MODE_INSERT = 0x02,
176 K8T_MODE_APPKEYPAD = 0x04,
177 K8T_MODE_ALTSCREEN = 0x08,
178 K8T_MODE_CRLF = 0x10,
179 K8T_MODE_MOUSEBTN = 0x20,
180 K8T_MODE_MOUSEMOTION = 0x40,
181 K8T_MODE_MOUSE = 0x20|0x40,
182 K8T_MODE_REVERSE = 0x80,
183 K8T_MODE_BRACPASTE = 0x100,
184 K8T_MODE_FOCUSEVT = 0x200,
185 K8T_MODE_DISPCTRL = 0x400, //TODO: not implemented yet
186 K8T_MODE_GFX0 = 0x1000,
187 K8T_MODE_GFX1 = 0x2000,
190 // escape sequence processor state
191 enum {
192 K8T_ESC_START = 0x01,
193 K8T_ESC_CSI = 0x02,
194 K8T_ESC_OSC = 0x04,
195 K8T_ESC_TITLE = 0x08,
196 K8T_ESC_ALTCHARSET = 0x10,
197 K8T_ESC_HASH = 0x20,
198 K8T_ESC_PERCENT = 0x40,
199 K8T_ESC_ALTG1 = 0x80,
202 // X11 window state flags
203 enum {
204 K8T_WIN_VISIBLE = 0x01,
205 K8T_WIN_REDRAW = 0x02,
206 K8T_WIN_FOCUSED = 0x04
210 ////////////////////////////////////////////////////////////////////////////////
211 typedef struct __attribute__((packed)) {
212 /* character code */
213 union __attribute__((packed)) {
214 uint32_t uc;
215 char c[UTF_SIZ];
217 uint8_t attr; /* attribute flags */
218 uint16_t fg; /* foreground */
219 uint16_t bg; /* background */
220 uint8_t state; /* state flags */
221 } K8TGlyph;
223 typedef K8TGlyph *K8TLine;
226 typedef struct {
227 K8TGlyph attr; /* current char attributes */
228 int x;
229 int y;
230 char state;
231 } K8TCursor;
234 /* CSI Escape sequence structs */
235 /* ESC '[' [[ [<priv>] <arg> [;]] <mode>] */
236 typedef struct {
237 char buf[K8T_ESC_BUF_SIZ]; /* raw string */
238 int len; /* raw string length */
239 char priv;
240 int arg[K8T_ESC_ARG_SIZ];
241 int narg; /* nb of args */
242 char mode;
243 } K8TCSIEscape;
246 /* Purely graphic info */
247 typedef struct {
248 Display *dpy;
249 Colormap cmap;
250 Window win;
251 Cursor cursor;
252 Cursor blankPtr;
253 Atom xembed;
254 XIM xim;
255 XIC xic;
256 int scr;
257 int w; /* window width */
258 int h; /* window height */
259 int bufw; /* pixmap width */
260 int bufh; /* pixmap height */
261 int ch; /* char height */
262 int cw; /* char width */
263 char state; /* focus, redraw, visible */
265 int tch; /* tab text char height */
266 Pixmap pictab;
267 int tabheight;
268 //struct timeval lastdraw;
269 } K8TXWindow;
272 /* TODO: use better name for vars... */
273 typedef struct {
274 int mode;
275 int bx, by;
276 int ex, ey;
277 struct { int x, y; } b, e;
278 char *clip;
279 Atom xtarget;
280 MSTime tclick1;
281 MSTime tclick2;
282 } K8TSelection;
285 /* Drawing Context */
286 typedef struct {
287 uint32_t *ncol; // normal colors
288 uint32_t *bcol; // b/w colors
289 uint32_t *gcol; // green colors
290 uint32_t *clrs[3];
291 GC gc;
292 struct {
293 int ascent;
294 int descent;
295 short lbearing;
296 short rbearing;
297 XFontSet set;
298 Font fid;
299 } font[3];
300 } K8TXDC;
303 typedef struct K8TCmdLine K8TCmdLine;
304 typedef struct K8Term K8Term;
306 typedef void (*CmdLineExecFn) (K8Term *term, K8TCmdLine *cmdline, int cancelled);
308 struct K8TCmdLine {
309 int cmdMode; // K8T_CMDMODE_xxx
310 char cmdline[UTF_SIZ*CMDLINE_SIZE];
311 int cmdreslen; // byte length of 'reserved' (read-only) part
312 int cmdofs; // byte offset of the first visible UTF-8 char in cmdline
313 char cmdc[UTF_SIZ+1]; // buffer to collect UTF-8 char
314 int cmdcl; // index in cmdc, used to collect UTF-8 chars
315 int cmdtabpos; // # of bytes (not UTF-8 chars!) used in autocompletion or -1
316 const char *cmdcurtabc; // current autocompleted command
317 CmdLineExecFn cmdexecfn;
318 void *udata;
322 /* Internal representation of the screen */
323 struct K8Term {
324 int cmdfd;
325 int dead;
326 int exitcode;
327 int waitkeypress; /* child is dead, awaiting for keypress */
328 char *exitmsg; /* message for waitkeypress */
329 int needConv; /* 0: utf-8 locale */
330 int belltype;
331 int blackandwhite;
332 int fastredraw;
333 int justSwapped;
335 int curblink;
336 int curbhidden;
337 MSTime lastBlinkTime;
338 int curblinkinactive;
340 int row; /* nb row */
341 int col; /* nb col */
342 int topline; /* top line for drawing (0: no history; 1: show one history line; etc) */
343 int linecount; /* full, with history */
344 int maxhistory;/* max history lines; 0: none; <0: infinite */
345 K8TLine *line; /* screen */
346 K8TLine *alt; /* alternate screen */
347 char *dirty; /* dirtyness of lines */
348 K8TCursor c; /* cursor */
349 int top; /* top scroll limit */
350 int bot; /* bottom scroll limit */
351 int mode; /* terminal mode flags */
352 int mousemode; /* mouse mode: 1000, 1005, 1006, 1015 */
353 int esc; /* escape state flags */
354 int charset; /* K8T_MODE_GFX0 or K8T_MODE_GFX1 */
355 int ignoredecpad; /* ignore DEC keypad switching sequences */
357 K8TCursor csaved; /* saved cursor info */
358 // old cursor position
359 int oldcx;
360 int oldcy;
362 char title[K8T_ESC_TITLE_SIZ+1];
363 int titlelen;
365 int mouseob;
366 int mouseox;
367 int mouseoy;
369 char obuf[OBUFSIZ];
370 #ifdef DUMP_PROG_OUTPUT
371 int xobuflen;
372 #endif
373 int obuflen;
375 char ubuf[UTF_SIZ];
376 int ubufpos;
378 char drawbuf[DRAW_BUF_SIZ];
380 char wrbuf[WBUFSIZ];
381 int wrbufsize;
382 int wrbufused;
383 int wrbufpos;
385 K8TCSIEscape escseq;
386 K8TSelection sel;
387 pid_t pid;
388 MSTime lastDrawTime;
390 char *execcmd;
392 Pixmap picbuf;
393 int picbufw;
394 int picbufh;
396 uint16_t deffg;
397 uint16_t defbg;
399 int wantRedraw;
401 MSTime lastActiveTime;
403 K8TCmdLine cmdline;
405 int dumpescapes;
406 int dumpeskeys;
407 // callbacks
408 // locale conversions
409 // returns new length
410 int (*loc2utf) (K8Term *term, char *dest, const char *src, int len);
411 int (*utf2loc) (K8Term *term, char *dest, const char *src, int len);
412 // draws
413 void (*drawSetFG) (K8Term *term, int clr);
414 void (*drawSetBG) (K8Term *term, int clr);
415 // coords in chars
416 void (*drawRect) (K8Term *term, int x0, int y0, int cols, int rows); // use FG
417 void (*drawFillRect) (K8Term *term, int x0, int y0, int cols, int rows); // use FG
418 void (*drawCopyArea) (K8Term *term, int x0, int y0, int cols, int rows); // copy pixmap to screen
419 void (*drawString) (K8Term *term, int x, int y, int cols, const K8TGlyph *base, int fontset, const char *s, int bytelen);
423 ////////////////////////////////////////////////////////////////////////////////
424 #include "globals.c"
427 ////////////////////////////////////////////////////////////////////////////////
428 #include "utf8.c"
429 #include "utils.c"
430 #include "keymaps.c"
433 ////////////////////////////////////////////////////////////////////////////////
434 static void executeCommands (const char *str);
435 static const char *findCommandCompletion (const char *str, int slen, const char *prev);
438 static void k8t_ttyResize (K8Term *term);
439 static void k8t_tmSetAttr (K8Term *term, int *attr, int l);
440 static void k8t_tmResetAttrs (K8Term *term);
441 static int k8t_tmDoWrap (K8Term *term);
442 static void k8t_tmPutC (K8Term *term, const char *c); // `c` is utf-8
443 static void k8t_ttyWrite (K8Term *term, const char *s, size_t n);
444 static void k8t_ttyWriteNoEnc (K8Term *term, const char *s, size_t n);
445 static void k8t_tmDirty (K8Term *term, int top, int bot);
446 static void k8t_tmFullDirty (K8Term *term);
449 static void tdrawfatalmsg (K8Term *term, const char *msg);
451 static void xclearunused (void);
452 static void xseturgency (int add);
453 static void xfixsel (void);
454 static void xblankPointer (void);
455 static void xunblankPointer (void);
456 static void xdrawTabBar (void);
459 static void k8t_Draw (K8Term *term, int forced);
462 static void tcmdput (K8Term *term, K8TCmdLine *cmdline, const char *s, int len);
464 #include "decls.c"
467 ////////////////////////////////////////////////////////////////////////////////
468 static inline void k8t_ttyWriteStr (K8Term *term, const char *s) { if (s != NULL && s[0]) k8t_ttyWrite(term, s, strlen(s)); }
469 static inline void k8t_ttyWriteStrNoEnc (K8Term *term, const char *s) { if (s != NULL && s[0]) k8t_ttyWriteNoEnc(term, s, strlen(s)); }
471 //FIXME: do utf-8!
472 static inline void k8t_ttyPutStr (K8Term *term, const char *s) { if (s != NULL) while (*s) { k8t_tmPutC(term, s); ++s; } }
475 static inline uint32_t getColor (int idx) {
476 if (globalBW && (curterm == NULL || !curterm->blackandwhite)) return dc.clrs[globalBW][idx];
477 if (curterm != NULL) return dc.clrs[curterm->blackandwhite%3][idx];
478 return dc.clrs[0][idx];
482 ////////////////////////////////////////////////////////////////////////////////
483 #include "iniparse.c"
484 #include "locales.c"
487 ////////////////////////////////////////////////////////////////////////////////
488 #include "x11CB.c"
491 ////////////////////////////////////////////////////////////////////////////////
492 #include "termswitch.c"
495 ////////////////////////////////////////////////////////////////////////////////
496 #include "selection.c"
497 #include "tabmouseutils.c"
498 #include "mouseevents.c"
501 ////////////////////////////////////////////////////////////////////////////////
502 #include "ttyinit.c"
503 #include "ttyrw.c"
504 #include "ttyutils.c"
505 #include "ttyputc.c"
506 #include "ttyresize.c"
509 ////////////////////////////////////////////////////////////////////////////////
510 #include "tcmdline.c"
511 #include "tfatalbox.c"
514 ////////////////////////////////////////////////////////////////////////////////
515 #include "x11misc.c"
516 #include "x11drawstr.c"
517 #include "x11drawcur.c"
518 #include "x11drawtabs.c"
519 #include "x11drawcmdline.c"
520 #include "x11draw.c"
523 ////////////////////////////////////////////////////////////////////////////////
524 #include "x11evtvis.c"
525 #include "x11evtkbd.c"
528 ////////////////////////////////////////////////////////////////////////////////
529 // xembed?
530 static void xevtcbcmessage (XEvent *e) {
531 /* See xembed specs http://standards.freedesktop.org/xembed-spec/xembed-spec-latest.html */
532 if (e->xclient.message_type == xw.xembed && e->xclient.format == 32) {
533 if (e->xclient.data.l[1] == XEMBED_FOCUS_IN) {
534 xw.state |= K8T_WIN_FOCUSED;
535 xseturgency(0);
536 k8t_tmSendFocusEvent(curterm, 1);
537 } else if (e->xclient.data.l[1] == XEMBED_FOCUS_OUT) {
538 xw.state &= ~K8T_WIN_FOCUSED;
539 k8t_tmSendFocusEvent(curterm, 0);
541 k8t_DrawCursor(curterm);
542 xdrawTabBar();
543 k8t_DrawCopy(curterm, 0, 0, curterm->col, curterm->row);
544 return;
547 if (e->xclient.data.l[0] == XA_WM_DELETE_WINDOW) {
548 closeRequestComes = 1;
549 return;
554 ////////////////////////////////////////////////////////////////////////////////
555 static inline int last_draw_too_old (void) {
556 MSTime tt = mclock_ticks();
558 if (curterm != NULL) {
559 if (curterm->dead || !curterm->wantRedraw) return 0;
561 return
562 (tt-curterm->lastDrawTime >= opt_drawtimeout ||
563 tt-lastDrawTime >= (curterm->justSwapped ? opt_swapdrawtimeout : opt_maxdrawtimeout));
565 return (tt-lastDrawTime >= opt_maxdrawtimeout);
569 ////////////////////////////////////////////////////////////////////////////////
570 // main loop
571 static void (*handler[LASTEvent])(XEvent *) = {
572 [KeyPress] = xevtcbkpress,
573 [ClientMessage] = xevtcbcmessage,
574 [ConfigureNotify] = xevtcbresise,
575 [VisibilityNotify] = xevtcbvisibility,
576 [UnmapNotify] = xevtcbunmap,
577 [Expose] = xevtcbexpose,
578 [FocusIn] = xevtcbfocus,
579 [FocusOut] = xevtcbfocus,
580 [MotionNotify] = xevtcbbmotion,
581 [ButtonPress] = xevtcbbpress,
582 [ButtonRelease] = xevtcbbrelease,
583 [SelectionNotify] = xevtcbselnotify,
584 [SelectionRequest] = xevtcbselrequest,
585 [SelectionClear] = xevtcbselclear,
589 static void run (void) {
590 //int stuff_to_print = 0;
591 int xfd = XConnectionNumber(xw.dpy);
593 ptrLastMove = mclock_ticks();
594 while (term_count > 0) {
595 XEvent ev;
596 fd_set rfd, wfd;
597 struct timeval timeout;
598 int maxfd = xfd;
599 int dodraw;
601 FD_ZERO(&rfd);
602 FD_ZERO(&wfd);
603 FD_SET(xfd, &rfd);
604 //FD_SET(curterm->cmdfd, &rfd);
605 // have something to write?
606 for (int f = 0; f < term_count; ++f) {
607 K8Term *t = term_array[f];
609 if (!t->dead && t->cmdfd >= 0) {
610 if (t->cmdfd > maxfd) maxfd = t->cmdfd;
611 FD_SET(t->cmdfd, &rfd);
612 if (t->pid != 0 && t->wrbufpos < t->wrbufused) FD_SET(t->cmdfd, &wfd);
616 timeout.tv_sec = 0;
617 timeout.tv_usec = (opt_drawtimeout+2)*1000;
618 //fprintf(stderr, "before select...\n");
619 if (select(maxfd+1, &rfd, &wfd, NULL, &timeout) < 0) {
620 if (errno == EINTR) continue;
621 k8t_die("select failed: %s", strerror(errno));
623 //fprintf(stderr, "after select...\n");
624 // process terminals i/o
625 for (int f = 0; f < term_count; ++f) {
626 K8Term *t = term_array[f];
628 if (!t->dead && t->cmdfd >= 0) {
629 int rd = -1;
631 if (t->pid != 0 && FD_ISSET(t->cmdfd, &wfd)) k8t_ttyFlushWriteBuf(t);
632 if (FD_ISSET(t->cmdfd, &rfd)) rd = k8t_ttyRead(t);
634 if (t->waitkeypress && t->exitmsg != NULL && rd < 0) {
635 // there will be no more data
636 close(t->cmdfd);
637 t->cmdfd = -1;
639 tdrawfatalmsg(t, t->exitmsg);
640 free(t->exitmsg);
641 t->exitmsg = NULL;
642 k8t_tmWantRedraw(t, 1);
647 //fprintf(stderr, "000: term=%p; dead=%d; waitkeypress=%d\n", term, (term ? term->dead : 666), (term ? term->waitkeypress : 666));
648 termcleanup();
649 //fprintf(stderr, "001: term=%p; dead=%d; waitkeypress=%d\n", term, (term ? term->dead : 666), (term ? term->waitkeypress : 666));
650 if (term_count == 0) exit(exitcode);
652 dodraw = 0;
653 if (curterm != NULL && curterm->curblink > 0) {
654 MSTime tt = mclock_ticks();
656 if (tt-curterm->lastBlinkTime >= curterm->curblink) {
657 curterm->lastBlinkTime = tt;
658 if ((xw.state&K8T_WIN_FOCUSED) || curterm->curblinkinactive) {
659 curterm->curbhidden = (curterm->curbhidden ? 0 : -1);
660 dodraw = 1;
661 } else {
662 curterm->curbhidden = 0;
666 if (updateTabBar) xdrawTabBar();
667 if (dodraw || last_draw_too_old()) k8t_Draw(curterm, 0);
669 if (XPending(xw.dpy)) {
670 while (XPending(xw.dpy)) {
671 XNextEvent(xw.dpy, &ev);
672 switch (ev.type) {
673 //case VisibilityNotify:
674 //case UnmapNotify:
675 //case FocusIn:
676 //case FocusOut:
677 case MotionNotify:
678 case ButtonPress:
679 case ButtonRelease:
680 xunblankPointer();
681 ptrLastMove = mclock_ticks();
682 break;
683 default: ;
685 if (XFilterEvent(&ev, xw.win)) continue;
686 if (handler[ev.type]) (handler[ev.type])(&ev);
690 if (curterm != NULL) {
691 switch (closeRequestComes) {
692 case 1: // just comes
693 if (opt_ignoreclose == 0) {
694 tcmdlinehide(curterm, &curterm->cmdline);
695 tcmdlineinitex(curterm, &curterm->cmdline, "Do you really want to close sterm [Y/n]? ");
696 curterm->cmdline.cmdexecfn = cmdline_closequeryexec;
697 } else if (opt_ignoreclose < 0) {
698 //FIXME: kill all clients?
699 return;
701 closeRequestComes = 0;
702 break;
703 case 2: // ok, die now
704 //FIXME: kill all clients?
705 return;
709 if (!ptrBlanked && opt_ptrblank > 0 && mclock_ticks()-ptrLastMove >= opt_ptrblank) {
710 xblankPointer();
716 ////////////////////////////////////////////////////////////////////////////////
717 #include "inifile.c"
718 #include "commands.c"
721 ////////////////////////////////////////////////////////////////////////////////
722 #include "childkiller.c"
725 ////////////////////////////////////////////////////////////////////////////////
726 int main (int argc, char *argv[]) {
727 char *configfile = NULL;
728 char *runcmd = NULL;
730 //dbgLogInit();
732 for (int f = 1; f < argc; f++) {
733 if (strcmp(argv[f], "-name") == 0) { ++f; continue; }
734 if (strcmp(argv[f], "-into") == 0) { ++f; continue; }
735 if (strcmp(argv[f], "-embed") == 0) { ++f; continue; }
736 switch (argv[f][0] != '-' || argv[f][2] ? -1 : argv[f][1]) {
737 case 'e': f = argc+1; break;
738 case 't':
739 case 'c':
740 case 'w':
741 case 'b':
742 case 'R':
743 ++f;
744 break;
745 case 'T':
746 if (++f < argc) {
747 free(opt_term);
748 opt_term = strdup(argv[f]);
749 opt_term_locked = 1;
751 break;
752 case 'C':
753 if (++f < argc) {
754 if (configfile != NULL) free(configfile);
755 configfile = strdup(argv[f]);
757 break;
758 case 'l':
759 if (++f < argc) cliLocale = argv[f];
760 break;
761 case 'S': // single-tab mode
762 opt_disabletabs = 1;
763 break;
764 case 'v':
765 fprintf(stderr, "%s", USAGE_VERSION);
766 exit(EXIT_FAILURE);
767 case 'h':
768 default:
769 fprintf(stderr, "%s%s", USAGE_VERSION, USAGE);
770 exit(EXIT_FAILURE);
774 initDefaultOptions();
775 if (configfile == NULL) {
776 const char *home = getenv("HOME");
778 if (home != NULL) {
779 configfile = SPrintf("%s/.sterm.rc", home);
780 if (loadConfig(configfile) == 0) goto cfgdone;
781 free(configfile); configfile = NULL;
783 configfile = SPrintf("%s/.config/sterm.rc", home);
784 if (loadConfig(configfile) == 0) goto cfgdone;
785 free(configfile); configfile = NULL;
788 configfile = SPrintf("/etc/sterm.rc");
789 if (loadConfig(configfile) == 0) goto cfgdone;
790 free(configfile); configfile = NULL;
792 configfile = SPrintf("/etc/sterm/sterm.rc");
793 if (loadConfig(configfile) == 0) goto cfgdone;
794 free(configfile); configfile = NULL;
796 configfile = SPrintf("./.sterm.rc");
797 if (loadConfig(configfile) == 0) goto cfgdone;
798 free(configfile); configfile = NULL;
799 // no config
800 } else {
801 if (loadConfig(configfile) < 0) k8t_die("config file '%s' not found!", configfile);
803 cfgdone:
804 if (configfile != NULL) free(configfile); configfile = NULL;
806 for (int f = 1; f < argc; f++) {
807 if (strcmp(argv[f], "-name") == 0) { ++f; continue; }
808 if (strcmp(argv[f], "-into") == 0 || strcmp(argv[f], "-embed") == 0) {
809 if (opt_embed) free(opt_embed);
810 opt_embed = strdup(argv[f]);
811 continue;
813 switch (argv[f][0] != '-' || argv[f][2] ? -1 : argv[f][1]) {
814 case 't':
815 if (++f < argc) {
816 free(opt_title);
817 opt_title = strdup(argv[f]);
819 break;
820 case 'c':
821 if (++f < argc) {
822 free(opt_class);
823 opt_class = strdup(argv[f]);
825 break;
826 case 'w':
827 if (++f < argc) {
828 if (opt_embed) free(opt_embed);
829 opt_embed = strdup(argv[f]);
831 break;
832 case 'R':
833 if (++f < argc) runcmd = argv[f];
834 break;
835 case 'e':
836 /* eat all remaining arguments */
837 if (++f < argc) opt_cmd = &argv[f];
838 f = argc+1;
839 case 'T':
840 case 'C':
841 case 'l':
842 ++f;
843 break;
844 case 'S':
845 break;
849 setenv("TERM", opt_term, 1);
850 mclock_init();
851 setlocale(LC_ALL, "");
852 initLCConversion();
853 summonChildKiller();
854 updateTabBar = 1;
855 termidx = 0;
856 curterm = k8t_termalloc();
857 if (curterm->execcmd != NULL) { free(curterm->execcmd); curterm->execcmd = NULL; }
858 k8t_tmInitialize(curterm, 80, 25);
859 if (k8t_ttyNew(curterm) != 0) k8t_die("can't run process");
860 opt_cmd = NULL;
861 xinit();
862 k8t_selInit(curterm);
863 if (runcmd != NULL) executeCommands(runcmd);
864 run();
865 return 0;