1 #define k8stx_output(buf_,buflen_) do { \
2 if (!xw.paste_term || xw.paste_term->dead) { \
3 xw.paste_term = NULL; \
6 if ((buflen_) <= 0) break; \
7 if (K8T_DATA(xw.paste_term)->cmdline.cmdMode != K8T_CMDMODE_NONE) { \
8 if (K8T_DATA(xw.paste_term)->cmdline.cmdMode == K8T_CMDMODE_INPUT) { \
9 tcmdput(xw.paste_term, &K8T_DATA(xw.paste_term)->cmdline, (buf_), (buflen_)); \
12 if (!xw.past_wasbrcp && K8T_ISSET(xw.paste_term, K8T_MODE_BRACPASTE)) { \
13 xw.past_wasbrcp = 1; \
14 k8t_ttyWriteStrNoEnc(xw.paste_term, "\x1b[200~"); \
16 k8t_ttyWrite(xw.paste_term, (buf_), (buflen_)); \
21 #define k8stx_finish_paste() do { \
22 if (xw.paste_term && xw.past_wasbrcp && !xw.paste_term->dead) { \
23 k8t_ttyWriteStrNoEnc(xw.paste_term, "\x1b[201~"); \
25 xw.paste_term = NULL; \
29 ////////////////////////////////////////////////////////////////////////////////
30 static const char *get_process_name (int pfd
) {
31 static char path
[256], res
[4097], *c
;
34 if ((pgrp
= tcgetpgrp(pfd
)) == -1) return NULL
;
35 snprintf(path
, sizeof(path
), "/proc/%d/cmdline", pgrp
);
36 if ((fd
= open(path
, O_RDONLY
|O_CLOEXEC
)) < 0) return NULL
;
37 res
[sizeof(res
)-1] = 0;
38 read(fd
, res
, sizeof(res
)-1);
40 if ((c
= strrchr(res
, '/')) == NULL
) c
= res
; else ++c
;
45 static const char *get_process_cwd (int pfd
) {
46 static char path
[256], res
[4097];
49 if ((pgrp
= tcgetpgrp(pfd
)) == -1) return NULL
;
50 snprintf(path
, sizeof(path
), "/proc/%d/cwd", pgrp
);
51 n
= readlink(path
, res
, sizeof(res
)-1);
60 static void fixWindowTitle (const K8Term
*t
) {
62 const char *title
= t
->title
;
64 if (title
== NULL
|| !title
[0]) {
66 if (title
== NULL
) title
= "";
68 XStoreName(xw
.dpy
, xw
.win
, title
);
69 XChangeProperty(xw
.dpy
, xw
.win
, XA_NETWM_NAME
, XA_UTF8
, 8, PropModeReplace
, (const unsigned char *)title
, strlen(title
));
74 static void checkAndFixWindowTitle (K8Term
*t
, int forceupd
) {
75 if (t
!= NULL
&& t
->cmdfd
>= 0) {
76 const char *pname
, *ppath
;
78 if ((pname
= get_process_name(t
->cmdfd
)) && strcmp(K8T_DATA(t
)->lastpname
, pname
) != 0) {
82 //fprintf(stderr, "new process: [%s]\n", pname);
83 K8T_DATA(t
)->titleset
= 0;
84 if (K8T_DATA(t
)->lastpname
) free(K8T_DATA(t
)->lastpname
);
85 K8T_DATA(t
)->lastpname
= strdup(pname
);
86 is_mc
= (strcmp(pname
, "mc") == 0 || strcmp(pname
, "mcedit") == 0 || strcmp(pname
, "mcview") == 0);
87 if (K8T_DATA(t
)->mc_hack_active
&& !is_mc
) {
88 K8T_DATA(t
)->mc_hack_active
= 0;
89 t
->clearOnPartialScrollMode
= K8T_DATA(t
)->old_scroll_mode
;
90 } else if (!K8T_DATA(t
)->mc_hack_active
&& is_mc
) {
91 K8T_DATA(t
)->mc_hack_active
= 1;
92 t
->clearOnPartialScrollMode
= 2;
95 if ((ppath
= get_process_cwd(t
->cmdfd
)) != NULL
&& strcmp(K8T_DATA(t
)->lastppath
, ppath
) != 0) {
97 if (K8T_DATA(t
)->lastppath
!= NULL
) free(K8T_DATA(t
)->lastppath
);
98 K8T_DATA(t
)->lastppath
= strdup(ppath
);
101 if (doupd
&& !K8T_DATA(t
)->titleset
) {
102 snprintf(t
->title
, sizeof(t
->title
), "%s [%s]", K8T_DATA(t
)->lastpname
, K8T_DATA(t
)->lastppath
);
106 if (doupd
|| forceupd
) {
107 if (t
== curterm
) fixWindowTitle(t
);
114 // find latest active terminal (but not current %-)
115 static int findTermToSwitch (void) {
117 K8TTimeMSec maxlat
= 0;
118 for (int f
= 0; f
< term_count
; ++f
) {
119 if (curterm
!= term_array
[f
] && term_array
[f
]->lastActiveTime
> maxlat
) {
120 maxlat
= term_array
[f
]->lastActiveTime
;
125 if (termidx
== 0) idx
= 0; else idx
= termidx
+1;
126 if (idx
> term_count
) idx
= term_count
-1;
132 static void fixFirstTab (void) {
133 if (termidx
< firstVisibleTab
) firstVisibleTab
= termidx
;
134 else if (termidx
> firstVisibleTab
+opt_tabcount
-1) firstVisibleTab
= termidx
-opt_tabcount
+1;
135 if (firstVisibleTab
< 0) firstVisibleTab
= 0;
140 static void switchToTerm (int idx
, int redraw
) {
141 if (idx
>= 0 && idx
< term_count
&& term_array
[idx
] != NULL
&& term_array
[idx
] != curterm
) {
142 K8TTimeMSec tt
= mclock_ticks();
144 if (curterm
!= NULL
) curterm
->lastActiveTime
= tt
;
146 curterm
= term_array
[termidx
];
147 curterm
->curbhidden
= 0;
148 curterm
->lastBlinkTime
= tt
;
149 if (xw
.paste_term
&& xw
.paste_term
!= curterm
) k8stx_finish_paste();
154 k8t_tmFullDirty(curterm
);
155 fixWindowTitle(curterm
);
157 XSetWindowBackground(xw
.dpy
, xw
.win
, getColor(curterm
->defbg
));
160 k8t_tmFullDirty(curterm
);
161 k8t_drawTerm(curterm
, 1);
162 if (!updateTabBar
) updateTabBar
= 1;
165 //FIXME: optimize memory allocations
166 if (curterm
->sel
.clip
!= NULL
&& curterm
->sel
.bx
>= 0) {
167 if (lastSelStr
!= NULL
) {
168 if (strlen(lastSelStr
) >= strlen(curterm
->sel
.clip
)) {
169 strcpy(lastSelStr
, curterm
->sel
.clip
);
175 if (lastSelStr
== NULL
) lastSelStr
= strdup(curterm
->sel
.clip
);
176 //fprintf(stderr, "newsel: [%s]\n", lastSelStr);
179 //fprintf(stderr, "curterm #%d\n", termidx);
180 //fprintf(stderr, "needConv: %d\n", curterm->needConv);
185 static K8Term
*k8t_termalloc (void) {
188 if (term_count
>= term_array_size
) {
189 int newsz
= ((term_count
==0) ? 1 : term_array_size
+64);
190 K8Term
**n
= realloc(term_array
, sizeof(K8Term
*)*newsz
);
192 if (n
== NULL
&& term_count
== 0) k8t_die("out of memory!");
194 term_array_size
= newsz
;
196 if ((t
= calloc(1, sizeof(K8Term
))) == NULL
) return NULL
;
198 t
->wrbufsize
= K8T_WBUFSIZ
;
199 t
->deffg
= defaultFG
;
200 t
->defbg
= defaultBG
;
202 t
->needConv
= (needConversion
? 1 : 0);
203 t
->belltype
= (opt_audiblebell
?K8T_BELL_AUDIO
:0)|(opt_urgentbell
?K8T_BELL_URGENT
:0);
204 t
->curblink
= opt_cursorBlink
;
205 t
->curblinkinactive
= opt_cursorBlinkInactive
;
206 t
->fastredraw
= opt_fastredraw
;
207 t
->clearOnPartialScrollMode
= opt_scrollclear
;
212 term_array
[term_count
++] = t
;
218 // newer delete last terminal!
219 static void termfree (int idx
) {
220 if (idx
>= 0 && idx
< term_count
&& term_array
[idx
] != NULL
) {
221 K8Term
*t
= term_array
[idx
];
222 K8TermData
*td
= K8T_DATA(t
);
223 // abort pasting, if there was any
224 if (xw
.paste_term
== t
) xw
.paste_term
= NULL
;
226 if (K8T_DATA(t
)->pid
!= 0) {
227 kill(K8T_DATA(t
)->pid
, SIGKILL
);
236 exitcode
= K8T_DATA(t
)->exitcode
;
238 if (K8T_DATA(t
)->waitkeypress
) return;
240 if (idx
== termidx
) {
241 if (term_count
> 1) {
243 //switchToTerm((idx > 0) ? idx-1 : 1, 0);
244 switchToTerm(findTermToSwitch(), 0);
246 fprintf(stderr
, "FATAL: cannot find good terminal to switch onto.\n");
254 for (int y
= 0; y
< t
->row
; ++y
) free(t
->alt
[y
]);
255 for (int y
= 0; y
< t
->linecount
; ++y
) free(t
->line
[y
]);
260 if (td
->lastpname
!= NULL
) free(td
->lastpname
);
261 if (td
->lastppath
!= NULL
) free(td
->lastppath
);
262 if (td
->execcmd
!= NULL
) free(td
->execcmd
);
264 if (termidx
> idx
) --termidx
; // it's not current, and current is at the right
265 for (int f
= idx
+1; f
< term_count
; ++f
) term_array
[f
-1] = term_array
[f
];
268 //if (td->picalloced) XFreePixmap(xw.dpy, td->picbuf);
275 static void termcleanup (void) {
276 int f
= 0, needredraw
= 0;
278 while (f
< term_count
) {
279 if (term_array
[f
]->dead
) {
280 //fprintf(stderr, "found dead term #%d of %d\n", f, term_count);
282 //fprintf(stderr, "terms left: %d (curterm=%p)\n", term_count, curterm);
290 K8TTimeMSec stt
= mclock_ticks();
291 if (stt
< xw
.paste_last_activity
|| stt
-xw
.paste_last_activity
>= 13000) {
292 //fprintf(stderr, "SELECTION PASTE ABORTED DUE TO TIMEOUT.\n");
293 k8stx_finish_paste();
299 k8t_drawTerm(curterm
, 1);