twind.c - plan9port - [fork] Plan 9 from user space | |
git clone git://src.adamsgaard.dk/plan9port | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
twind.c (14859B) | |
--- | |
1 #include <u.h> | |
2 #include <libc.h> | |
3 #include <draw.h> | |
4 #include <thread.h> | |
5 #include <cursor.h> | |
6 #include <mouse.h> | |
7 #include <keyboard.h> | |
8 #include <frame.h> | |
9 #include <fcall.h> | |
10 #include <plumb.h> | |
11 #include <libsec.h> | |
12 #include "dat.h" | |
13 #include "fns.h" | |
14 | |
15 int winid; | |
16 | |
17 void | |
18 wininit(Window *w, Window *clone, Rectangle r) | |
19 { | |
20 Rectangle r1, br; | |
21 File *f; | |
22 Reffont *rf; | |
23 Rune *rp; | |
24 int nc; | |
25 | |
26 w->tag.w = w; | |
27 w->taglines = 1; | |
28 w->tagexpand = TRUE; | |
29 w->body.w = w; | |
30 w->id = ++winid; | |
31 incref(&w->ref); | |
32 if(globalincref) | |
33 incref(&w->ref); | |
34 w->ctlfid = ~0; | |
35 w->utflastqid = -1; | |
36 r1 = r; | |
37 | |
38 w->tagtop = r; | |
39 w->tagtop.max.y = r.min.y + font->height; | |
40 r1.max.y = r1.min.y + w->taglines*font->height; | |
41 | |
42 incref(&reffont.ref); | |
43 f = fileaddtext(nil, &w->tag); | |
44 textinit(&w->tag, f, r1, &reffont, tagcols); | |
45 w->tag.what = Tag; | |
46 /* tag is a copy of the contents, not a tracked image */ | |
47 if(clone){ | |
48 textdelete(&w->tag, 0, w->tag.file->b.nc, TRUE); | |
49 nc = clone->tag.file->b.nc; | |
50 rp = runemalloc(nc); | |
51 bufread(&clone->tag.file->b, 0, rp, nc); | |
52 textinsert(&w->tag, 0, rp, nc, TRUE); | |
53 free(rp); | |
54 filereset(w->tag.file); | |
55 textsetselect(&w->tag, nc, nc); | |
56 } | |
57 r1 = r; | |
58 r1.min.y += w->taglines*font->height + 1; | |
59 if(r1.max.y < r1.min.y) | |
60 r1.max.y = r1.min.y; | |
61 f = nil; | |
62 if(clone){ | |
63 f = clone->body.file; | |
64 w->body.org = clone->body.org; | |
65 w->isscratch = clone->isscratch; | |
66 rf = rfget(FALSE, FALSE, FALSE, clone->body.reffont->f->… | |
67 }else | |
68 rf = rfget(FALSE, FALSE, FALSE, nil); | |
69 f = fileaddtext(f, &w->body); | |
70 w->body.what = Body; | |
71 textinit(&w->body, f, r1, rf, textcols); | |
72 r1.min.y -= 1; | |
73 r1.max.y = r1.min.y+1; | |
74 draw(screen, r1, tagcols[BORD], nil, ZP); | |
75 textscrdraw(&w->body); | |
76 w->r = r; | |
77 br.min = w->tag.scrollr.min; | |
78 br.max.x = br.min.x + Dx(button->r); | |
79 br.max.y = br.min.y + Dy(button->r); | |
80 draw(screen, br, button, nil, button->r.min); | |
81 w->filemenu = TRUE; | |
82 w->maxlines = w->body.fr.maxlines; | |
83 w->autoindent = globalautoindent; | |
84 if(clone){ | |
85 w->dirty = clone->dirty; | |
86 w->autoindent = clone->autoindent; | |
87 textsetselect(&w->body, clone->body.q0, clone->body.q1); | |
88 winsettag(w); | |
89 } | |
90 } | |
91 | |
92 /* | |
93 * Draw the appropriate button. | |
94 */ | |
95 void | |
96 windrawbutton(Window *w) | |
97 { | |
98 Image *b; | |
99 Rectangle br; | |
100 | |
101 b = button; | |
102 if(!w->isdir && !w->isscratch && (w->body.file->mod || w->body.n… | |
103 b = modbutton; | |
104 br.min = w->tag.scrollr.min; | |
105 br.max.x = br.min.x + Dx(b->r); | |
106 br.max.y = br.min.y + Dy(b->r); | |
107 draw(screen, br, b, nil, b->r.min); | |
108 } | |
109 | |
110 int | |
111 delrunepos(Window *w) | |
112 { | |
113 Rune *r; | |
114 int i; | |
115 | |
116 r = parsetag(w, 0, &i); | |
117 free(r); | |
118 i += 2; | |
119 if(i >= w->tag.file->b.nc) | |
120 return -1; | |
121 return i; | |
122 } | |
123 | |
124 void | |
125 movetodel(Window *w) | |
126 { | |
127 int n; | |
128 | |
129 n = delrunepos(w); | |
130 if(n < 0) | |
131 return; | |
132 moveto(mousectl, addpt(frptofchar(&w->tag.fr, n), Pt(4, w->tag.f… | |
133 } | |
134 | |
135 /* | |
136 * Compute number of tag lines required | |
137 * to display entire tag text. | |
138 */ | |
139 int | |
140 wintaglines(Window *w, Rectangle r) | |
141 { | |
142 int n; | |
143 Rune rune; | |
144 Point p; | |
145 | |
146 if(!w->tagexpand && !w->showdel) | |
147 return 1; | |
148 w->showdel = FALSE; | |
149 w->tag.fr.noredraw = 1; | |
150 textresize(&w->tag, r, TRUE); | |
151 w->tag.fr.noredraw = 0; | |
152 w->tagsafe = FALSE; | |
153 | |
154 if(!w->tagexpand) { | |
155 /* use just as many lines as needed to show the Del */ | |
156 n = delrunepos(w); | |
157 if(n < 0) | |
158 return 1; | |
159 p = subpt(frptofchar(&w->tag.fr, n), w->tag.fr.r.min); | |
160 return 1 + p.y / w->tag.fr.font->height; | |
161 } | |
162 | |
163 /* can't use more than we have */ | |
164 if(w->tag.fr.nlines >= w->tag.fr.maxlines) | |
165 return w->tag.fr.maxlines; | |
166 | |
167 /* if tag ends with \n, include empty line at end for typing */ | |
168 n = w->tag.fr.nlines; | |
169 if(w->tag.file->b.nc > 0){ | |
170 bufread(&w->tag.file->b, w->tag.file->b.nc-1, &rune, 1); | |
171 if(rune == '\n') | |
172 n++; | |
173 } | |
174 if(n == 0) | |
175 n = 1; | |
176 return n; | |
177 } | |
178 | |
179 int | |
180 winresize(Window *w, Rectangle r, int safe, int keepextra) | |
181 { | |
182 int oy, y, mouseintag, mouseinbody; | |
183 Point p; | |
184 Rectangle r1; | |
185 | |
186 mouseintag = ptinrect(mouse->xy, w->tag.all); | |
187 mouseinbody = ptinrect(mouse->xy, w->body.all); | |
188 | |
189 /* tagtop is first line of tag */ | |
190 w->tagtop = r; | |
191 w->tagtop.max.y = r.min.y+font->height; | |
192 | |
193 r1 = r; | |
194 r1.max.y = min(r.max.y, r1.min.y + w->taglines*font->height); | |
195 | |
196 /* If needed, recompute number of lines in tag. */ | |
197 if(!safe || !w->tagsafe || !eqrect(w->tag.all, r1)){ | |
198 w->taglines = wintaglines(w, r); | |
199 r1.max.y = min(r.max.y, r1.min.y + w->taglines*font->hei… | |
200 } | |
201 | |
202 /* If needed, resize & redraw tag. */ | |
203 y = r1.max.y; | |
204 if(!safe || !w->tagsafe || !eqrect(w->tag.all, r1)){ | |
205 textresize(&w->tag, r1, TRUE); | |
206 y = w->tag.fr.r.max.y; | |
207 windrawbutton(w); | |
208 w->tagsafe = TRUE; | |
209 | |
210 /* If mouse is in tag, pull up as tag closes. */ | |
211 if(mouseintag && !ptinrect(mouse->xy, w->tag.all)){ | |
212 p = mouse->xy; | |
213 p.y = w->tag.all.max.y-3; | |
214 moveto(mousectl, p); | |
215 } | |
216 | |
217 /* If mouse is in body, push down as tag expands. */ | |
218 if(mouseinbody && ptinrect(mouse->xy, w->tag.all)){ | |
219 p = mouse->xy; | |
220 p.y = w->tag.all.max.y+3; | |
221 moveto(mousectl, p); | |
222 } | |
223 } | |
224 | |
225 /* If needed, resize & redraw body. */ | |
226 r1 = r; | |
227 r1.min.y = y; | |
228 if(!safe || !eqrect(w->body.all, r1)){ | |
229 oy = y; | |
230 if(y+1+w->body.fr.font->height <= r.max.y){ /* ro… | |
231 r1.min.y = y; | |
232 r1.max.y = y+1; | |
233 draw(screen, r1, tagcols[BORD], nil, ZP); | |
234 y++; | |
235 r1.min.y = min(y, r.max.y); | |
236 r1.max.y = r.max.y; | |
237 }else{ | |
238 r1.min.y = y; | |
239 r1.max.y = y; | |
240 } | |
241 y = textresize(&w->body, r1, keepextra); | |
242 w->r = r; | |
243 w->r.max.y = y; | |
244 textscrdraw(&w->body); | |
245 w->body.all.min.y = oy; | |
246 } | |
247 w->maxlines = min(w->body.fr.nlines, max(w->maxlines, w->body.fr… | |
248 return w->r.max.y; | |
249 } | |
250 | |
251 void | |
252 winlock1(Window *w, int owner) | |
253 { | |
254 incref(&w->ref); | |
255 qlock(&w->lk); | |
256 w->owner = owner; | |
257 } | |
258 | |
259 void | |
260 winlock(Window *w, int owner) | |
261 { | |
262 int i; | |
263 File *f; | |
264 | |
265 f = w->body.file; | |
266 for(i=0; i<f->ntext; i++) | |
267 winlock1(f->text[i]->w, owner); | |
268 } | |
269 | |
270 void | |
271 winunlock(Window *w) | |
272 { | |
273 int i; | |
274 File *f; | |
275 | |
276 /* | |
277 * subtle: loop runs backwards to avoid tripping over | |
278 * winclose indirectly editing f->text and freeing f | |
279 * on the last iteration of the loop. | |
280 */ | |
281 f = w->body.file; | |
282 for(i=f->ntext-1; i>=0; i--){ | |
283 w = f->text[i]->w; | |
284 w->owner = 0; | |
285 qunlock(&w->lk); | |
286 winclose(w); | |
287 } | |
288 } | |
289 | |
290 void | |
291 winmousebut(Window *w) | |
292 { | |
293 moveto(mousectl, addpt(w->tag.scrollr.min, | |
294 divpt(Pt(Dx(w->tag.scrollr), font->height), 2))); | |
295 } | |
296 | |
297 void | |
298 windirfree(Window *w) | |
299 { | |
300 int i; | |
301 Dirlist *dl; | |
302 | |
303 if(w->isdir){ | |
304 for(i=0; i<w->ndl; i++){ | |
305 dl = w->dlp[i]; | |
306 free(dl->r); | |
307 free(dl); | |
308 } | |
309 free(w->dlp); | |
310 } | |
311 w->dlp = nil; | |
312 w->ndl = 0; | |
313 } | |
314 | |
315 void | |
316 winclose(Window *w) | |
317 { | |
318 int i; | |
319 | |
320 if(decref(&w->ref) == 0){ | |
321 xfidlog(w, "del"); | |
322 windirfree(w); | |
323 textclose(&w->tag); | |
324 textclose(&w->body); | |
325 if(activewin == w) | |
326 activewin = nil; | |
327 for(i=0; i<w->nincl; i++) | |
328 free(w->incl[i]); | |
329 free(w->incl); | |
330 free(w->events); | |
331 free(w); | |
332 } | |
333 } | |
334 | |
335 void | |
336 windelete(Window *w) | |
337 { | |
338 Xfid *x; | |
339 | |
340 x = w->eventx; | |
341 if(x){ | |
342 w->nevents = 0; | |
343 free(w->events); | |
344 w->events = nil; | |
345 w->eventx = nil; | |
346 sendp(x->c, nil); /* wake him up */ | |
347 } | |
348 } | |
349 | |
350 void | |
351 winundo(Window *w, int isundo) | |
352 { | |
353 Text *body; | |
354 int i; | |
355 File *f; | |
356 Window *v; | |
357 | |
358 w->utflastqid = -1; | |
359 body = &w->body; | |
360 fileundo(body->file, isundo, &body->q0, &body->q1); | |
361 textshow(body, body->q0, body->q1, 1); | |
362 f = body->file; | |
363 for(i=0; i<f->ntext; i++){ | |
364 v = f->text[i]->w; | |
365 v->dirty = (f->seq != v->putseq); | |
366 if(v != w){ | |
367 v->body.q0 = v->body.fr.p0+v->body.org; | |
368 v->body.q1 = v->body.fr.p1+v->body.org; | |
369 } | |
370 } | |
371 winsettag(w); | |
372 } | |
373 | |
374 void | |
375 winsetname(Window *w, Rune *name, int n) | |
376 { | |
377 Text *t; | |
378 Window *v; | |
379 int i; | |
380 static Rune Lslashguide[] = { '/', 'g', 'u', 'i', 'd', 'e', 0 }; | |
381 static Rune Lpluserrors[] = { '+', 'E', 'r', 'r', 'o', 'r', 's',… | |
382 | |
383 t = &w->body; | |
384 if(runeeq(t->file->name, t->file->nname, name, n) == TRUE) | |
385 return; | |
386 w->isscratch = FALSE; | |
387 if(n>=6 && runeeq(Lslashguide, 6, name+(n-6), 6)) | |
388 w->isscratch = TRUE; | |
389 else if(n>=7 && runeeq(Lpluserrors, 7, name+(n-7), 7)) | |
390 w->isscratch = TRUE; | |
391 filesetname(t->file, name, n); | |
392 for(i=0; i<t->file->ntext; i++){ | |
393 v = t->file->text[i]->w; | |
394 winsettag(v); | |
395 v->isscratch = w->isscratch; | |
396 } | |
397 } | |
398 | |
399 void | |
400 wintype(Window *w, Text *t, Rune r) | |
401 { | |
402 int i; | |
403 | |
404 texttype(t, r); | |
405 if(t->what == Body) | |
406 for(i=0; i<t->file->ntext; i++) | |
407 textscrdraw(t->file->text[i]); | |
408 winsettag(w); | |
409 } | |
410 | |
411 void | |
412 wincleartag(Window *w) | |
413 { | |
414 int i, n; | |
415 Rune *r; | |
416 | |
417 /* w must be committed */ | |
418 n = w->tag.file->b.nc; | |
419 r = parsetag(w, 0, &i); | |
420 for(; i<n; i++) | |
421 if(r[i] == '|') | |
422 break; | |
423 if(i == n) | |
424 return; | |
425 i++; | |
426 textdelete(&w->tag, i, n, TRUE); | |
427 free(r); | |
428 w->tag.file->mod = FALSE; | |
429 if(w->tag.q0 > i) | |
430 w->tag.q0 = i; | |
431 if(w->tag.q1 > i) | |
432 w->tag.q1 = i; | |
433 textsetselect(&w->tag, w->tag.q0, w->tag.q1); | |
434 } | |
435 | |
436 Rune* | |
437 parsetag(Window *w, int extra, int *len) | |
438 { | |
439 static Rune Ldelsnarf[] = { ' ', 'D', 'e', 'l', ' ', 'S', 'n', '… | |
440 static Rune Lspacepipe[] = { ' ', '|', 0 }; | |
441 static Rune Ltabpipe[] = { '\t', '|', 0 }; | |
442 int i; | |
443 Rune *r, *p, *pipe; | |
444 | |
445 r = runemalloc(w->tag.file->b.nc+extra+1); | |
446 bufread(&w->tag.file->b, 0, r, w->tag.file->b.nc); | |
447 r[w->tag.file->b.nc] = '\0'; | |
448 | |
449 /* | |
450 * " |" or "\t|" ends left half of tag | |
451 * If we find " Del Snarf" in the left half of the tag | |
452 * (before the pipe), that ends the file name. | |
453 */ | |
454 pipe = runestrstr(r, Lspacepipe); | |
455 if((p = runestrstr(r, Ltabpipe)) != nil && (pipe == nil || p < p… | |
456 pipe = p; | |
457 if((p = runestrstr(r, Ldelsnarf)) != nil && (pipe == nil || p < … | |
458 i = p - r; | |
459 else { | |
460 for(i=0; i<w->tag.file->b.nc; i++) | |
461 if(r[i]==' ' || r[i]=='\t') | |
462 break; | |
463 } | |
464 *len = i; | |
465 return r; | |
466 } | |
467 | |
468 void | |
469 winsettag1(Window *w) | |
470 { | |
471 int i, j, k, n, bar, dirty, resize; | |
472 Rune *new, *old, *r; | |
473 uint q0, q1; | |
474 static Rune Ldelsnarf[] = { ' ', 'D', 'e', 'l', ' ', | |
475 'S', 'n', 'a', 'r', 'f', 0 }; | |
476 static Rune Lundo[] = { ' ', 'U', 'n', 'd', 'o', 0 }; | |
477 static Rune Lredo[] = { ' ', 'R', 'e', 'd', 'o', 0 }; | |
478 static Rune Lget[] = { ' ', 'G', 'e', 't', 0 }; | |
479 static Rune Lput[] = { ' ', 'P', 'u', 't', 0 }; | |
480 static Rune Llook[] = { ' ', 'L', 'o', 'o', 'k', ' ', 0 }; | |
481 static Rune Lpipe[] = { ' ', '|', 0 }; | |
482 | |
483 /* there are races that get us here with stuff in the tag cache,… | |
484 if(w->tag.ncache!=0 || w->tag.file->mod) | |
485 wincommit(w, &w->tag); /* check file name; also g… | |
486 old = parsetag(w, 0, &i); | |
487 if(runeeq(old, i, w->body.file->name, w->body.file->nname) == FA… | |
488 textdelete(&w->tag, 0, i, TRUE); | |
489 textinsert(&w->tag, 0, w->body.file->name, w->body.file-… | |
490 free(old); | |
491 old = runemalloc(w->tag.file->b.nc+1); | |
492 bufread(&w->tag.file->b, 0, old, w->tag.file->b.nc); | |
493 old[w->tag.file->b.nc] = '\0'; | |
494 } | |
495 | |
496 /* compute the text for the whole tag, replacing current only if… | |
497 new = runemalloc(w->body.file->nname+100); | |
498 i = 0; | |
499 if(w->body.file->nname != 0) | |
500 runemove(new, w->body.file->name, w->body.file->nname); | |
501 i += w->body.file->nname; | |
502 runemove(new+i, Ldelsnarf, 10); | |
503 i += 10; | |
504 if(w->filemenu){ | |
505 if(w->body.needundo || w->body.file->delta.nc>0 || w->bo… | |
506 runemove(new+i, Lundo, 5); | |
507 i += 5; | |
508 } | |
509 if(w->body.file->epsilon.nc > 0){ | |
510 runemove(new+i, Lredo, 5); | |
511 i += 5; | |
512 } | |
513 dirty = w->body.file->nname && (w->body.ncache || w->bod… | |
514 if(!w->isdir && dirty){ | |
515 runemove(new+i, Lput, 4); | |
516 i += 4; | |
517 } | |
518 } | |
519 if(w->isdir){ | |
520 runemove(new+i, Lget, 4); | |
521 i += 4; | |
522 } | |
523 runemove(new+i, Lpipe, 2); | |
524 i += 2; | |
525 r = runestrchr(old, '|'); | |
526 if(r) | |
527 k = r-old+1; | |
528 else{ | |
529 k = w->tag.file->b.nc; | |
530 if(w->body.file->seq == 0){ | |
531 runemove(new+i, Llook, 6); | |
532 i += 6; | |
533 } | |
534 } | |
535 new[i] = 0; | |
536 | |
537 /* replace tag if the new one is different */ | |
538 resize = 0; | |
539 if(runeeq(new, i, old, k) == FALSE){ | |
540 resize = 1; | |
541 n = k; | |
542 if(n > i) | |
543 n = i; | |
544 for(j=0; j<n; j++) | |
545 if(old[j] != new[j]) | |
546 break; | |
547 q0 = w->tag.q0; | |
548 q1 = w->tag.q1; | |
549 textdelete(&w->tag, j, k, TRUE); | |
550 textinsert(&w->tag, j, new+j, i-j, TRUE); | |
551 /* try to preserve user selection */ | |
552 r = runestrchr(old, '|'); | |
553 if(r){ | |
554 bar = r-old; | |
555 if(q0 > bar){ | |
556 bar = (runestrchr(new, '|')-new)-bar; | |
557 w->tag.q0 = q0+bar; | |
558 w->tag.q1 = q1+bar; | |
559 } | |
560 } | |
561 } | |
562 free(old); | |
563 free(new); | |
564 w->tag.file->mod = FALSE; | |
565 n = w->tag.file->b.nc+w->tag.ncache; | |
566 if(w->tag.q0 > n) | |
567 w->tag.q0 = n; | |
568 if(w->tag.q1 > n) | |
569 w->tag.q1 = n; | |
570 textsetselect(&w->tag, w->tag.q0, w->tag.q1); | |
571 windrawbutton(w); | |
572 if(resize){ | |
573 w->tagsafe = 0; | |
574 winresize(w, w->r, TRUE, TRUE); | |
575 } | |
576 } | |
577 | |
578 void | |
579 winsettag(Window *w) | |
580 { | |
581 int i; | |
582 File *f; | |
583 Window *v; | |
584 | |
585 f = w->body.file; | |
586 for(i=0; i<f->ntext; i++){ | |
587 v = f->text[i]->w; | |
588 if(v->col->safe || v->body.fr.maxlines>0) | |
589 winsettag1(v); | |
590 } | |
591 } | |
592 | |
593 void | |
594 wincommit(Window *w, Text *t) | |
595 { | |
596 Rune *r; | |
597 int i; | |
598 File *f; | |
599 | |
600 textcommit(t, TRUE); | |
601 f = t->file; | |
602 if(f->ntext > 1) | |
603 for(i=0; i<f->ntext; i++) | |
604 textcommit(f->text[i], FALSE); /* no-op f… | |
605 if(t->what == Body) | |
606 return; | |
607 r = parsetag(w, 0, &i); | |
608 if(runeeq(r, i, w->body.file->name, w->body.file->nname) == FALS… | |
609 seq++; | |
610 filemark(w->body.file); | |
611 w->body.file->mod = TRUE; | |
612 w->dirty = TRUE; | |
613 winsetname(w, r, i); | |
614 winsettag(w); | |
615 } | |
616 free(r); | |
617 } | |
618 | |
619 void | |
620 winaddincl(Window *w, Rune *r, int n) | |
621 { | |
622 char *a; | |
623 Dir *d; | |
624 Runestr rs; | |
625 | |
626 a = runetobyte(r, n); | |
627 d = dirstat(a); | |
628 if(d == nil){ | |
629 if(a[0] == '/') | |
630 goto Rescue; | |
631 rs = dirname(&w->body, r, n); | |
632 r = rs.r; | |
633 n = rs.nr; | |
634 free(a); | |
635 a = runetobyte(r, n); | |
636 d = dirstat(a); | |
637 if(d == nil) | |
638 goto Rescue; | |
639 r = runerealloc(r, n+1); | |
640 r[n] = 0; | |
641 } | |
642 free(a); | |
643 if((d->qid.type&QTDIR) == 0){ | |
644 free(d); | |
645 warning(nil, "%s: not a directory\n", a); | |
646 free(r); | |
647 return; | |
648 } | |
649 free(d); | |
650 w->nincl++; | |
651 w->incl = realloc(w->incl, w->nincl*sizeof(Rune*)); | |
652 memmove(w->incl+1, w->incl, (w->nincl-1)*sizeof(Rune*)); | |
653 w->incl[0] = runemalloc(n+1); | |
654 runemove(w->incl[0], r, n); | |
655 free(r); | |
656 return; | |
657 | |
658 Rescue: | |
659 warning(nil, "%s: %r\n", a); | |
660 free(r); | |
661 free(a); | |
662 return; | |
663 } | |
664 | |
665 int | |
666 winclean(Window *w, int conservative) | |
667 { | |
668 if(w->isscratch || w->isdir) /* don't whine if it's a gui… | |
669 return TRUE; | |
670 if(!conservative && w->nopen[QWevent]>0) | |
671 return TRUE; | |
672 if(w->dirty){ | |
673 if(w->body.file->nname) | |
674 warning(nil, "%.*S modified\n", w->body.file->nn… | |
675 else{ | |
676 if(w->body.file->b.nc < 100) /* don't whi… | |
677 return TRUE; | |
678 warning(nil, "unnamed file modified\n"); | |
679 } | |
680 w->dirty = FALSE; | |
681 return FALSE; | |
682 } | |
683 return TRUE; | |
684 } | |
685 | |
686 char* | |
687 winctlprint(Window *w, char *buf, int fonts) | |
688 { | |
689 sprint(buf, "%11d %11d %11d %11d %11d ", w->id, w->tag.file->b.n… | |
690 w->body.file->b.nc, w->isdir, w->dirty); | |
691 if(fonts) | |
692 return smprint("%s%11d %q %11d %11d %11d ", buf, Dx(w->b… | |
693 w->body.reffont->f->name, w->body.fr.maxtab, seq… | |
694 return buf; | |
695 } | |
696 | |
697 void | |
698 winevent(Window *w, char *fmt, ...) | |
699 { | |
700 int n; | |
701 char *b; | |
702 Xfid *x; | |
703 va_list arg; | |
704 | |
705 if(w->nopen[QWevent] == 0) | |
706 return; | |
707 if(w->owner == 0) | |
708 error("no window owner"); | |
709 va_start(arg, fmt); | |
710 b = vsmprint(fmt, arg); | |
711 va_end(arg); | |
712 if(b == nil) | |
713 error("vsmprint failed"); | |
714 n = strlen(b); | |
715 w->events = erealloc(w->events, w->nevents+1+n); | |
716 w->events[w->nevents++] = w->owner; | |
717 memmove(w->events+w->nevents, b, n); | |
718 free(b); | |
719 w->nevents += n; | |
720 x = w->eventx; | |
721 if(x){ | |
722 w->eventx = nil; | |
723 sendp(x->c, nil); | |
724 } | |
725 } |