1 ////////////////////////////////////////////////////////////////////////////////
2 static const char *get_process_name (int fd
) {
3 static char path
[4097], res
[4097], *c
;
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
);
15 if ((c
= strrchr(res
, '/')) == NULL
) c
= res
; else ++c
;
16 //fprintf(stderr, "proc: [%s]\n", c);
21 static const char *get_process_cwd (int fd
) {
22 static char path
[4097], res
[4097];
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);
30 //fprintf(stderr, "path: [%s]\n", res);
38 static void fixWindowTitle (const K8Term
*t
) {
40 const char *title
= t
->title
;
42 if (title
== NULL
|| !title
[0]) {
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
;
57 if ((pname
= get_process_name(t
->cmdfd
)) != NULL
&& strcmp(K8T_DATA(t
)->lastpname
, pname
) != 0) {
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) {
68 if (K8T_DATA(t
)->lastppath
!= NULL
) free(K8T_DATA(t
)->lastppath
);
69 K8T_DATA(t
)->lastppath
= strdup(ppath
);
73 if (doupd
&& !K8T_DATA(t
)->titleset
) {
74 snprintf(t
->title
, sizeof(t
->title
), "%s [%s]", K8T_DATA(t
)->lastpname
, K8T_DATA(t
)->lastppath
);
79 if (doupd
|| forceupd
) {
80 if (t
== curterm
) fixWindowTitle(t
);
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
;
98 if (termidx
== 0) idx
= 0; else idx
= termidx
+1;
99 if (idx
> term_count
) idx
= term_count
-1;
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;
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
;
119 curterm
= term_array
[termidx
];
120 curterm
->curbhidden
= 0;
121 curterm
->lastBlinkTime
= tt
;
126 k8t_tmFullDirty(curterm
);
127 fixWindowTitle(curterm
);
129 XSetWindowBackground(xw
.dpy
, xw
.win
, getColor(curterm
->defbg
));
132 k8t_tmFullDirty(curterm
);
133 k8t_drawTerm(curterm
, 1);
134 if (!updateTabBar
) updateTabBar
= 1;
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
);
147 if (lastSelStr
== NULL
) lastSelStr
= strdup(curterm
->sel
.clip
);
148 //fprintf(stderr, "newsel: [%s]\n", lastSelStr);
151 //fprintf(stderr, "curterm #%d\n", termidx);
152 //fprintf(stderr, "needConv: %d\n", curterm->needConv);
157 static K8Term
*k8t_termalloc (void) {
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!");
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
;
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
;
183 term_array
[term_count
++] = 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
);
205 exitcode
= K8T_DATA(t
)->exitcode
;
207 if (K8T_DATA(t
)->waitkeypress
) return;
209 if (idx
== termidx
) {
210 if (term_count
> 1) {
212 //switchToTerm((idx > 0) ? idx-1 : 1, 0);
213 switchToTerm(findTermToSwitch(), 0);
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
]);
225 if (td
->lastpname
!= NULL
) free(td
->lastpname
);
226 if (td
->lastppath
!= NULL
) free(td
->lastppath
);
227 if (td
->execcmd
!= NULL
) free(td
->execcmd
);
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
];
233 //if (td->picalloced) XFreePixmap(xw.dpy, td->picbuf);
240 static void termcleanup (void) {
241 int f
= 0, needredraw
= 0;
243 while (f
< term_count
) {
244 if (term_array
[f
]->dead
) {
254 k8t_drawTerm(curterm
, 1);