tried to do better scrolling; don't like the result
[k8sterm.git] / src / termswitch.c
blob4b756ca1aa0c55e03a0e166d33494c266275d7f7
1 ////////////////////////////////////////////////////////////////////////////////
2 static const char *get_process_name (int fd) {
3 static char path[4097], res[4097], *c;
4 FILE *fl;
5 pid_t pgrp;
6 //
7 if ((pgrp = tcgetpgrp(fd)) == -1) return NULL;
8 snprintf(path, sizeof(path), "/proc/%d/cmdline", pgrp);
9 if ((fl = fopen(path, "r")) == NULL) return (NULL);
11 memset(res, 0, sizeof(res));
12 fread(res, sizeof(res)-1, 1, fl);
13 fclose(fl);
15 if ((c = strrchr(res, '/')) == NULL) c = res; else ++c;
16 //fprintf(stderr, "proc: [%s]\n", c);
17 return c;
21 static const char *get_process_cwd (int fd) {
22 static char path[4097], res[4097];
23 pid_t pgrp;
24 ssize_t n;
26 if ((pgrp = tcgetpgrp(fd)) == -1) return NULL;
27 snprintf(path, sizeof(path), "/proc/%d/cwd", pgrp);
28 n = readlink(path, res, sizeof(res)-1);
29 if (n > 0) {
30 //fprintf(stderr, "path: [%s]\n", res);
31 res[n] = '\0';
32 return res;
34 return NULL;
38 static void fixWindowTitle (const K8Term *t) {
39 if (t != NULL) {
40 const char *title = t->title;
42 if (title == NULL || !title[0]) {
43 title = opt_title;
44 if (title == NULL) title = "";
46 XStoreName(xw.dpy, xw.win, title);
47 XChangeProperty(xw.dpy, xw.win, XA_NETWM_NAME, XA_UTF8, 8, PropModeReplace, (const unsigned char *)title, strlen(title));
52 static void checkAndFixWindowTitle (K8Term *t, int forceupd) {
53 if (t != NULL && t->cmdfd >= 0) {
54 const char *pname, *ppath;
55 int doupd = 0;
57 if ((pname = get_process_name(t->cmdfd)) != NULL && strcmp(K8T_DATA(t)->lastpname, pname) != 0) {
58 // new process
59 doupd = 1;
60 K8T_DATA(t)->titleset = 0;
62 if (K8T_DATA(t)->lastpname) free(K8T_DATA(t)->lastpname);
63 K8T_DATA(t)->lastpname = strdup(pname);
66 if ((ppath = get_process_cwd(t->cmdfd)) != NULL && strcmp(K8T_DATA(t)->lastppath, ppath) != 0) {
67 // new path
68 if (K8T_DATA(t)->lastppath != NULL) free(K8T_DATA(t)->lastppath);
69 K8T_DATA(t)->lastppath = strdup(ppath);
70 doupd = 1;
73 if (doupd && !K8T_DATA(t)->titleset) {
74 snprintf(t->title, sizeof(t->title), "%s [%s]", K8T_DATA(t)->lastpname, K8T_DATA(t)->lastppath);
75 } else {
76 doupd = 0;
79 if (doupd || forceupd) {
80 if (t == curterm) fixWindowTitle(t);
81 updateTabBar = 1;
87 // find latest active terminal (but not current %-)
88 static int findTermToSwitch (void) {
89 int maxlat = -1, idx = -1;
91 for (int f = 0; f < term_count; ++f) {
92 if (curterm != term_array[f] && term_array[f]->lastActiveTime > maxlat) {
93 maxlat = term_array[f]->lastActiveTime;
94 idx = f;
97 if (idx < 0) {
98 if (termidx == 0) idx = 0; else idx = termidx+1;
99 if (idx > term_count) idx = term_count-1;
101 return idx;
105 static void fixFirstTab (void) {
106 if (termidx < firstVisibleTab) firstVisibleTab = termidx;
107 else if (termidx > firstVisibleTab+opt_tabcount-1) firstVisibleTab = termidx-opt_tabcount+1;
108 if (firstVisibleTab < 0) firstVisibleTab = 0;
109 updateTabBar = 1;
113 static void switchToTerm (int idx, int redraw) {
114 if (idx >= 0 && idx < term_count && term_array[idx] != NULL && term_array[idx] != curterm) {
115 K8TTimeMSec tt = mclock_ticks();
117 if (curterm != NULL) curterm->lastActiveTime = tt;
118 termidx = idx;
119 curterm = term_array[termidx];
120 curterm->curbhidden = 0;
121 curterm->lastBlinkTime = tt;
123 fixFirstTab();
125 xseturgency(0);
126 k8t_tmFullDirty(curterm);
127 fixWindowTitle(curterm);
128 updateTabBar = 1;
129 XSetWindowBackground(xw.dpy, xw.win, getColor(curterm->defbg));
130 xclearunused();
131 if (redraw) {
132 k8t_tmFullDirty(curterm);
133 k8t_drawTerm(curterm, 1);
134 if (!updateTabBar) updateTabBar = 1;
135 xdrawTabBar();
137 //FIXME: optimize memory allocations
138 if (curterm->sel.clip != NULL && curterm->sel.bx >= 0) {
139 if (lastSelStr != NULL) {
140 if (strlen(lastSelStr) >= strlen(curterm->sel.clip)) {
141 strcpy(lastSelStr, curterm->sel.clip);
142 } else {
143 free(lastSelStr);
144 lastSelStr = NULL;
147 if (lastSelStr == NULL) lastSelStr = strdup(curterm->sel.clip);
148 //fprintf(stderr, "newsel: [%s]\n", lastSelStr);
150 xfixsel();
151 //fprintf(stderr, "curterm #%d\n", termidx);
152 //fprintf(stderr, "needConv: %d\n", curterm->needConv);
157 static K8Term *k8t_termalloc (void) {
158 K8Term *t;
160 if (term_count >= term_array_size) {
161 int newsz = ((term_count==0) ? 1 : term_array_size+64);
162 K8Term **n = realloc(term_array, sizeof(K8Term *)*newsz);
164 if (n == NULL && term_count == 0) k8t_die("out of memory!");
165 term_array = n;
166 term_array_size = newsz;
168 if ((t = calloc(1, sizeof(K8Term))) == NULL) return NULL;
170 t->wrbufsize = K8T_WBUFSIZ;
171 t->deffg = defaultFG;
172 t->defbg = defaultBG;
173 t->dead = 1;
174 t->needConv = (needConversion ? 1 : 0);
175 t->belltype = (opt_audiblebell?K8T_BELL_AUDIO:0)|(opt_urgentbell?K8T_BELL_URGENT:0);
176 t->curblink = opt_cursorBlink;
177 t->curblinkinactive = opt_cursorBlinkInactive;
178 t->fastredraw = opt_fastredraw;
180 termSetCallbacks(t);
181 termSetDefaults(t);
183 term_array[term_count++] = t;
185 return t;
189 // newer delete last terminal!
190 static void termfree (int idx) {
191 if (idx >= 0 && idx < term_count && term_array[idx] != NULL) {
192 K8Term *t = term_array[idx];
193 K8TermData *td = K8T_DATA(t);
195 if (K8T_DATA(t)->pid != 0) {
196 kill(K8T_DATA(t)->pid, SIGKILL);
197 return;
200 if (t->cmdfd >= 0) {
201 close(t->cmdfd);
202 t->cmdfd = -1;
205 exitcode = K8T_DATA(t)->exitcode;
207 if (K8T_DATA(t)->waitkeypress) return;
209 if (idx == termidx) {
210 if (term_count > 1) {
211 t->dead = 1;
212 //switchToTerm((idx > 0) ? idx-1 : 1, 0);
213 switchToTerm(findTermToSwitch(), 0);
214 return;
216 curterm = NULL;
219 for (int y = 0; y < t->row; ++y) free(t->alt[y]);
220 for (int y = 0; y < t->linecount; ++y) free(t->line[y]);
221 free(t->dirty);
222 free(t->alt);
223 free(t->line);
225 if (td->lastpname != NULL) free(td->lastpname);
226 if (td->lastppath != NULL) free(td->lastppath);
227 if (td->execcmd != NULL) free(td->execcmd);
228 // condense array
229 if (termidx > idx) --termidx; // it's not current, and current is at the right
230 for (int f = idx+1; f < term_count; ++f) term_array[f-1] = term_array[f];
231 --term_count;
233 //if (td->picalloced) XFreePixmap(xw.dpy, td->picbuf);
234 free(td);
235 free(t);
240 static void termcleanup (void) {
241 int f = 0, needredraw = 0;
243 while (f < term_count) {
244 if (term_array[f]->dead) {
245 termfree(f);
246 needredraw = 1;
247 } else {
248 ++f;
252 if (needredraw) {
253 updateTabBar = 1;
254 k8t_drawTerm(curterm, 1);