1 /* look-cool.c - look 'n feel type: NeXT
2    Copyright (C) 1996-2002 Paul Sheer
3    Copyright (C) 1999-2002 Sasha Vasko
4 
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9 
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14 
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307, USA.
19  */
20 
21 #include <config.h>
22 #include <stdio.h>
23 #include <my_string.h>
24 #include <stdlib.h>
25 #include <stdarg.h>
26 
27 #include <X11/Intrinsic.h>
28 #include "lkeysym.h"
29 
30 #include "stringtools.h"
31 #include "app_glob.c"
32 #include "coolwidget.h"
33 #include "coollocal.h"
34 
35 #include "mad.h"
36 
37 #ifdef NEXT_LOOK
38 
39 extern struct look *look;
40 
41 /* {{{ search replace dialog */
42 
43 extern int replace_scanf;
44 extern int replace_regexp;
45 extern int replace_all;
46 extern int replace_prompt;
47 extern int replace_whole;
48 extern int replace_case;
49 extern int replace_backwards;
50 extern int search_create_bookmark;
51 
look_next_search_replace_dialog(Window parent,int x,int y,char ** search_text,char ** replace_text,char ** arg_order,const char * heading,int option)52 static void look_next_search_replace_dialog (Window parent, int x, int y, char **search_text, char **replace_text, char **arg_order, const char *heading, int option)
53 {
54     Window win;
55     XEvent xev;
56     CEvent cev;
57     CState s;
58     int xh, yh, h, xb, ys, yc, yb, yr;
59     CWidget *m;
60     int text_input_width ;
61 
62     CBackupState (&s);
63     CDisable ("*");
64 
65     win = CDrawHeadedDialog ("replace", parent, x, y, heading);
66     CGetHintPos (&xh, &h);
67     xh += WINDOW_EXTRA_SPACING ;
68 
69 /* NLS hotkey ? */
70     CIdent ("replace")->position = WINDOW_ALWAYS_RAISED;
71 /* An input line comes after the ':' */
72     (CDrawText ("replace.t1", win, xh, h, _(" Enter search text : ")))->hotkey = 'E';
73 
74     CGetHintPos (0, &yh);
75     (m = CDrawTextInput ("replace.sinp", win, xh, yh, 10, AUTO_HEIGHT, 8192, *search_text))->hotkey = 'E';
76 
77     if (replace_text) {
78 	CGetHintPos (0, &yh);
79 	(CDrawText ("replace.t2", win, xh, yh, _(" Enter replace text : ")))->hotkey = 'n';
80 	CGetHintPos (0, &yh);
81 	(CDrawTextInput ("replace.rinp", win, xh, yh, 10, AUTO_HEIGHT, 8192, *replace_text))->hotkey = 'n';
82 	CSetToolHint ("replace.t2", _("You can enter regexp substrings with %s\n(not \\1, \\2 like sed) then use \"Enter...order\""));
83 	CSetToolHint ("replace.rinp", _("You can enter regexp substrings with %s\n(not \\1, \\2 like sed) then use \"Enter...order\""));
84 	CGetHintPos (0, &yh);
85 	(CDrawText ("replace.t3", win, xh, yh, _(" Enter argument (or substring) order : ")))->hotkey = 'o';
86 	CGetHintPos (0, &yh);
87 	(CDrawTextInput ("replace.ainp", win, xh, yh, 10, AUTO_HEIGHT, 256, *arg_order))->hotkey = 'o';
88 /* Tool hint */
89 	CSetToolHint ("replace.ainp", _("Enter the order of replacement of your scanf\nformat specifiers or regexp substrings, eg 3,1,2"));
90 	CSetToolHint ("replace.t3", _("Enter the order of replacement of your scanf\nformat specifiers or regexp substrings, eg 3,1,2"));
91     }
92     CGetHintPos (0, &yh);
93     ys = yh;
94 /* The following are check boxes */
95     CDrawSwitch ("replace.ww", win, xh, yh, replace_whole, _(" Whole words only "), 0);
96     CGetHintPos (0, &yh);
97     CDrawSwitch ("replace.case", win, xh, yh, replace_case, _(" Case sensitive "), 0);
98     yc = yh;
99     CGetHintPos (0, &yh);
100     CDrawSwitch ("replace.reg", win, xh, yh, replace_regexp, _(" Regular expression "), 1);
101     CSetToolHint ("replace.reg", _("See the regex man page for how\nto compose a regular expression"));
102     CSetToolHint ("replace.reg.label", _("See the regex man page for how\nto compose a regular expression"));
103     yb = yh;
104     CGetHintPos (0, &yh);
105     CGetHintPos (&xb, 0);
106     xb += WINDOW_EXTRA_SPACING ;
107     if (option & SEARCH_DIALOG_OPTION_BACKWARDS) {
108 	CDrawSwitch ("replace.bkwd", win, xh, yh, replace_backwards, _(" Backwards "), 0);
109 /* Tool hint */
110 	CSetToolHint ("replace.bkwd", _("Warning: Searching backward can be slow"));
111 	CSetToolHint ("replace.bkwd.label", _("Warning: Searching backward can be slow"));
112     }
113     if (replace_text) {
114 	yr = ys;
115 	if (option & SEARCH_DIALOG_OPTION_BACKWARDS)
116 	    yr = yc;
117     } else {
118 	if (option & SEARCH_DIALOG_OPTION_BACKWARDS) {
119 	    if (option & SEARCH_DIALOG_OPTION_BOOKMARK)
120 		yr = yb;
121 	    else
122 		yr = yh;
123 	} else {
124 	    if (option & SEARCH_DIALOG_OPTION_BOOKMARK)
125 		yr = yc;
126 	    else
127 		yr = yb;
128 	}
129     }
130 
131     if (replace_text) {
132 	CDrawSwitch ("replace.pr", win, xb, yr, replace_prompt, _(" Prompt on replace "), 0);
133 /* Tool hint */
134 	CSetToolHint ("replace.pr", _("Ask before making each replacement"));
135 	CGetHintPos (0, &yr);
136 	CDrawSwitch ("replace.all", win, xb, yr, replace_all, _(" Replace all "), 0);
137 /* Tool hint */
138 	CSetToolHint ("replace.all", _("Replace repeatedly"));
139 	CGetHintPos (0, &yr);
140     }
141     if (option & SEARCH_DIALOG_OPTION_BOOKMARK) {
142 	CDrawSwitch ("replace.bkmk", win, xb, yr, search_create_bookmark, _(" Bookmarks "), 0);
143 /* Tool hint */
144 	CSetToolHint ("replace.bkmk", _("Create bookmarks at all lines found"));
145 	CSetToolHint ("replace.bkmk.label", _("Create bookmarks at all lines found"));
146 	CGetHintPos (0, &yr);
147     }
148     CDrawSwitch ("replace.scanf", win, xb, yr, replace_scanf, _(" Scanf expression "), 1);
149 /* Tool hint */
150     CSetToolHint ("replace.scanf", _("Allows entering of a C format string,\nsee the scanf man page"));
151 
152     get_hint_limits (&x, &y);
153     {
154       int btn_width, x, y ;
155 	CGetHintPos (&x, &y);
156 
157 	y += WINDOW_EXTRA_SPACING * 2 ;
158 	x += WINDOW_EXTRA_SPACING * 2 ;
159 	CTextSize (&btn_width, 0, " Cancel ");
160 	btn_width += 4 + BUTTON_RELIEF * 2;
161         x -= (btn_width + WINDOW_EXTRA_SPACING) * 2 + WINDOW_EXTRA_SPACING;
162 
163 	CDrawButton ("replace.ok", win, x+btn_width + WINDOW_EXTRA_SPACING * 2, y, AUTO_WIDTH, AUTO_HEIGHT, "   Ok   ");
164 	CDrawButton ("replace.cancel", win, x, y, AUTO_WIDTH, AUTO_HEIGHT, " Cancel ");
165 	CGetHintPos (0, &y);
166 	x += (btn_width + WINDOW_EXTRA_SPACING) * 2 + WINDOW_EXTRA_SPACING;
167 	reset_hint_pos (x, y + WINDOW_EXTRA_SPACING*2);
168     }
169 /* Tool hint */
170     CSetToolHint ("replace.ok", _("Begin search, Enter"));
171     CSetToolHint ("replace.cancel", _("Abort this dialog, Esc"));
172     CSetSizeHintPos ("replace");
173     CMapDialog ("replace");
174 
175     m = CIdent ("replace");
176     text_input_width = m->width - WIDGET_SPACING * 3 - 4 - WINDOW_EXTRA_SPACING*2 ;
177     CSetWidgetSize ("replace.sinp", text_input_width, (CIdent ("replace.sinp"))->height);
178     if (replace_text) {
179 	CSetWidgetSize ("replace.rinp", text_input_width, (CIdent ("replace.rinp"))->height);
180 	CSetWidgetSize ("replace.ainp", text_input_width, (CIdent ("replace.ainp"))->height);
181     }
182     CFocus (CIdent ("replace.sinp"));
183 
184     for (;;) {
185 	CNextEvent (&xev, &cev);
186 	if (!CIdent ("replace")) {
187 	    *search_text = 0;
188 	    break;
189 	}
190 	if (!strcmp (cev.ident, "replace.cancel") || cev.command == CK_Cancel) {
191 	    *search_text = 0;
192 	    break;
193 	}
194 	if (!strcmp (cev.ident, "replace.reg") || !strcmp (cev.ident, "replace.scanf")) {
195 	    if (CIdent ("replace.reg")->keypressed || CIdent ("replace.scanf")->keypressed) {
196 		if (!(CIdent ("replace.case")->keypressed)) {
197 		    CIdent ("replace.case")->keypressed = 1;
198 		    CExpose ("replace.case");
199 		}
200 	    }
201 	}
202 	if (!strcmp (cev.ident, "replace.ok") || cev.command == CK_Enter) {
203 	    if (replace_text) {
204 		replace_all = CIdent ("replace.all")->keypressed;
205 		replace_prompt = CIdent ("replace.pr")->keypressed;
206 		*replace_text = (char *) strdup (CIdent ("replace.rinp")->text);
207 		*arg_order = (char *) strdup (CIdent ("replace.ainp")->text);
208 	    }
209 	    *search_text = (char *) strdup (CIdent ("replace.sinp")->text);
210 	    replace_whole = CIdent ("replace.ww")->keypressed;
211 	    replace_case = CIdent ("replace.case")->keypressed;
212 	    replace_scanf = CIdent ("replace.scanf")->keypressed;
213 	    replace_regexp = CIdent ("replace.reg")->keypressed;
214 
215 	    if (option & SEARCH_DIALOG_OPTION_BACKWARDS) {
216 		replace_backwards = CIdent ("replace.bkwd")->keypressed;
217 	    } else {
218 		replace_backwards = 0;
219 	    }
220 
221 	    if (option & SEARCH_DIALOG_OPTION_BOOKMARK) {
222 		search_create_bookmark = CIdent ("replace.bkmk")->keypressed;
223 	    } else {
224 		search_create_bookmark = 0;
225 	    }
226 
227 	    break;
228 	}
229     }
230     CDestroyWidget ("replace");
231     CRestoreState (&s);
232 }
233 
234 /* }}} search replace dialog */
235 
236 
237 /* {{{ file list stuff */
238 
239 #if 0
240 static char *dname (struct dirent *directentry);
241 #endif
242 
243 #ifdef HAVE_STRFTIME
244 /* We want our own dates for NLS */
245 #undef HAVE_STRFTIME
246 #endif
247 
248 #undef gettext_noop
249 #define gettext_noop(x) x
250 
251 void get_file_time (char *timestr, time_t file_time, int l);
252 
253 #if 0
254 static char **get_filelist_line (void *data, int line_number, int *num_fields, int *tagged)
255 {
256     struct file_entry *directentry;
257     static char *fields[10], size[24], mode[12], timestr[32];
258     static char name[520], *n;
259     mode_t m;
260 
261     *num_fields = 4;		/* name, size, date, mode only (for the mean time) */
262 
263     directentry = (struct file_entry *) data;
264     if (directentry[line_number].options & FILELIST_LAST_ENTRY)
265 	return 0;
266 
267     n = name;
268     strcpy (name, directentry[line_number].name);
269     fields[0] = name;
270     sprintf (size, "\t%u", (unsigned int) directentry[line_number].stat.st_size);
271     fields[1] = size;
272 
273     get_file_time (timestr, directentry[line_number].stat.st_mtime, 0);
274     fields[2] = timestr;
275 
276     memset (mode, ' ', 11);
277     mode[11] = 0;
278     mode[0] = '-';
279     m = directentry[line_number].stat.st_mode;
280     switch ((int) m & S_IFMT) {
281     case S_IFLNK:
282 	mode[0] = 'l';
283 	break;
284     case S_IFDIR:
285 	mode[0] = 'd';
286 	break;
287     case S_IFCHR:
288 	mode[0] = 'c';
289 	break;
290     case S_IFBLK:
291 	mode[0] = 'b';
292 	break;
293     case S_IFIFO:
294 	mode[0] = 'f';
295 	break;
296     case S_IFSOCK:
297 	mode[0] = 's';
298 	break;
299     }
300 
301     mode[1] = m & S_IRUSR ? 'r' : '-';
302     mode[2] = m & S_IWUSR ? 'w' : '-';
303     mode[3] = m & S_IXUSR ? 'x' : '-';
304 
305     mode[4] = m & S_IRGRP ? 'r' : '-';
306     mode[5] = m & S_IWGRP ? 'w' : '-';
307     mode[6] = m & S_IXGRP ? 'x' : '-';
308 
309     mode[7] = m & S_IROTH ? 'r' : '-';
310     mode[8] = m & S_IWOTH ? 'w' : '-';
311     mode[9] = m & S_IXOTH ? 'x' : '-';
312 
313     if (S_ISLNK (m)) {
314 	int l, i;
315 	char *p;
316 	p = directentry[line_number].name;
317 	l = strlen (n);
318 	for (i = 0; i < l; i++) {
319 	    *n++ = '\b';
320 	    *n++ = *p++;
321 	}
322 	*n++ = '\0';
323     } else if (m & (S_IXUSR | S_IXGRP | S_IXOTH)) {
324 	int l, i;
325 	char *p;
326 	p = directentry[line_number].name;
327 	l = strlen (n);
328 	for (i = 0; i < l; i++) {
329 	    *n++ = '\r';
330 	    *n++ = *p++;
331 	}
332 	*n++ = '\0';
333     }
334     fields[3] = mode;
335     fields[*num_fields] = 0;
336     if (directentry[line_number].options & FILELIST_TAGGED_ENTRY)
337 	*tagged = 1;
338     return fields;
339 }
340 #endif
341 
get_filelist_line_short(void * data,int line_number,char buffer[512])342 static char *get_filelist_line_short (void *data, int line_number, char buffer[512])
343 {
344     struct file_entry *directentry;
345     static char ctimestr[32], mtimestr[32];
346     mode_t m;
347     char *ptr;
348     unsigned long size_bytes;
349 
350     directentry = (struct file_entry *) data;
351     if (directentry[line_number].options & FILELIST_LAST_ENTRY)
352 	return 0;
353 
354     buffer[0] = 6;
355     strncpy (&(buffer[1]), directentry[line_number].name, 256);
356     ptr = &(buffer[strlen (buffer)]);
357 
358     sprintf (ptr, "%c\nMode: %c", 27, 9);
359     ptr += strlen (ptr);
360 
361     m = directentry[line_number].stat.st_mode;
362     switch ((int) m & S_IFMT) {
363     case S_IFLNK:
364 	*ptr = 'l';
365 	break;
366     case S_IFDIR:
367 	*ptr = 'd';
368 	break;
369     case S_IFCHR:
370 	*ptr = 'c';
371 	break;
372     case S_IFBLK:
373 	*ptr = 'b';
374 	break;
375     case S_IFIFO:
376 	*ptr = 'f';
377 	break;
378     case S_IFSOCK:
379 	*ptr = 's';
380 	break;
381     default:
382 	*ptr = '-';
383     }
384     ptr++;
385     *(ptr++) = m & S_IRUSR ? 'r' : '-';
386     *(ptr++) = m & S_IWUSR ? 'w' : '-';
387     *(ptr++) = m & S_IXUSR ? 'x' : '-';
388 
389     *(ptr++) = m & S_IRGRP ? 'r' : '-';
390     *(ptr++) = m & S_IWGRP ? 'w' : '-';
391     *(ptr++) = m & S_IXGRP ? 'x' : '-';
392 
393     *(ptr++) = m & S_IROTH ? 'r' : '-';
394     *(ptr++) = m & S_IWOTH ? 'w' : '-';
395     *(ptr++) = m & S_IXOTH ? 'x' : '-';
396 
397 
398     size_bytes = directentry[line_number].stat.st_size;
399     sprintf (ptr, "%c ; Size: [%c%9lu%c] bytes or [%c%6lu%c] KBytes", 27, 7, size_bytes, 27, 7, size_bytes >> 10, 27);
400     ptr += strlen (ptr);
401 
402     get_file_time (ctimestr, directentry[line_number].stat.st_ctime, 0);
403     get_file_time (mtimestr, directentry[line_number].stat.st_mtime, 0);
404 
405     sprintf (ptr, "\nCreated on: %c%s%c ; Modified on: %c%s%c", 1, ctimestr, 27, 1, mtimestr, 27);
406 
407     return buffer;
408 }
409 
is_directory(struct file_entry * directentry,int line_number)410 static Bool is_directory (struct file_entry * directentry, int line_number)
411 {
412     if (directentry[line_number].options & FILELIST_LAST_ENTRY)
413 	return False;
414     switch ((int) (directentry[line_number].stat.st_mode) & S_IFMT) {
415     case S_IFLNK:
416 	/* fixme : add check if it is linked to dir or file */
417 	return True;
418     case S_IFDIR:
419 	return True;
420     }
421     return False;
422 }
423 
424 typedef struct FilelistCache {
425     Pixmap cache;
426     unsigned int width, height;
427     unsigned int firstline, hilited;
428     int current;
429     unsigned int rowheight;
430     unsigned long options;
431 } FilelistCache;
432 
free_filelist_cache(void * vcache)433 static void free_filelist_cache (void *vcache)
434 {
435     if (vcache) {
436 	FilelistCache *cache = (FilelistCache *) vcache;
437 	if (cache->cache) {
438 	    XFreePixmap (CDisplay, cache->cache);
439 	    cache->cache = None;
440 	}
441 	free (vcache);
442     }
443 }
444 
445 #define NEXT_ARROW_SIZE  	8
446 #define NEXT_ARROW_FIELD 	(NEXT_ARROW_SIZE*2)
447 
restrict_text_area(FilelistCache * cache)448 static void restrict_text_area (FilelistCache * cache)
449 {
450     XRectangle clip_rec;
451     clip_rec.x = 1;
452     clip_rec.y = 1;
453     clip_rec.width = cache->width - NEXT_ARROW_FIELD;
454     clip_rec.height = cache->height - 2;
455     XSetClipRectangles (CDisplay, CGC, 0, 0, &clip_rec, 1, YXSorted);
456 }
457 
push_filelist_line(FilelistCache * cache,Bool pushed)458 static void push_filelist_line (FilelistCache * cache, Bool pushed)
459 {
460     int y1, y2;
461     if (cache->current < 0)
462 	return;
463     y1 = (cache->current - cache->firstline) * cache->rowheight;
464     y2 = y1 + cache->rowheight;
465 
466     if (y1 < cache->height && y2 > 0) {
467 	if (pushed)
468 	    CSetColor (COLOR_BLACK);
469 	else
470 	    CSetColor ((cache->hilited == cache->current) ? color_widget (15) : COLOR_FLAT);
471 
472 	CLine (cache->cache, 0, y2, 0, y1);
473 	CLine (cache->cache, 1, y1, cache->width - 2, y1);
474 
475 	if (pushed)
476 	    CSetColor ((cache->hilited == cache->current) ? COLOR_FLAT : color_widget (15));
477 
478 	CLine (cache->cache, 0, y2, cache->width - 2, y2);
479 	CLine (cache->cache, cache->width - 2, y2, cache->width - 2, y1);
480     }
481 }
482 
hilite_filelist_line(FilelistCache * cache,int color,struct file_entry * directentry)483 static void hilite_filelist_line (FilelistCache * cache, int color, struct file_entry *directentry)
484 {
485     int y1, y2, x2;
486     y1 = (cache->hilited - cache->firstline) * cache->rowheight;
487     y2 = y1 + (cache->rowheight / 2 - 4);
488     x2 = cache->width - NEXT_ARROW_FIELD + NEXT_ARROW_SIZE / 2;
489 
490     if (y1 >= 0 && y1 < cache->height - FONT_OVERHEAD) {
491 	CSetColor (color);
492 	CRectangle (cache->cache, 0, y1, cache->width - 1, cache->rowheight - 1);
493 	CSetColor (COLOR_BLACK);
494 	if (!(directentry[cache->hilited].options & FILELIST_LAST_ENTRY) &&
495 	    directentry[cache->hilited].name != NULL) {
496 	    restrict_text_area (cache);
497 	    CSetBackgroundColor (color);
498 	    CImageString (cache->cache, FONT_OFFSET_X + 1, FONT_OFFSET_Y + y1,
499 			  directentry[cache->hilited].name);
500 	    XSetClipMask (CDisplay, CGC, None);
501 	    if (is_directory (directentry, cache->hilited)) {
502 		CSetColor (COLOR_BLACK);
503 		CLine (cache->cache, x2, y2, x2 + 7, y2 + 4);
504 		CLine (cache->cache, x2, y2, x2, y2 + 8);
505 		CSetColor (COLOR_FLAT);
506 		CLine (cache->cache, x2, y2 + 8, x2 + 7, y2 + 4);
507 	    }
508 	}
509     }
510 }
511 
scroll_cache(FilelistCache * cache,unsigned int new_first,int * start,int * end)512 static void scroll_cache (FilelistCache * cache, unsigned int new_first, int *start, int *end)
513 {
514     int good_start, good_end, scroll_to;
515 
516     if (cache->firstline > new_first) {		/* scrolling up */
517 	good_start = 0;
518 	scroll_to = (cache->firstline - new_first) * cache->rowheight;
519 	good_end = cache->height - scroll_to;
520     } else {
521 	good_start = (new_first - cache->firstline) * cache->rowheight;
522 	good_end = cache->height;
523 	scroll_to = 0;
524     }
525     if (good_start < good_end) {
526 	XCopyArea (CDisplay, cache->cache, cache->cache, CGC, 0, good_start, cache->width, good_end, 0, scroll_to);
527 	if (cache->firstline > new_first) {	/* scrolling up */
528 	    *start = 0;
529 	    *end = scroll_to;
530 	} else {
531 	    *start = (cache->height - good_start);
532 	    *end = cache->height;
533 	}
534     } else {
535 	*start = 0;
536 	*end = cache->height;
537     }
538     if (*start < *end) {
539 	CSetColor (COLOR_FLAT);
540 	CRectangle (cache->cache, 0, *start, cache->width, *end);
541     }
542     *start /= cache->rowheight;
543     *end /= cache->rowheight;
544 }
545 
check_filelist_cache(CWidget * wdt,unsigned int w,unsigned int h,FilelistCache * cache)546 static void check_filelist_cache (CWidget * wdt, unsigned int w, unsigned int h, FilelistCache * cache)
547 {
548     struct file_entry *directentry = (struct file_entry *) wdt->hook;
549     int y, x, start_y;
550     int i, start = 0, end = 0;
551 
552     if (cache->cache) {
553 	if (cache->width == w && cache->height == h) {
554 	    if (cache->firstline == wdt->firstline &&
555 		cache->hilited == wdt->cursor &&
556 		cache->options == wdt->options)
557 		return;
558 	} else {
559 	    XFreePixmap (CDisplay, cache->cache);
560 	    cache->cache = None;
561 	}
562     }
563     if (cache->cache == None) {
564 	cache->cache = XCreatePixmap (CDisplay, wdt->winid, w, h, CDepth);
565 	cache->width = w;
566 	cache->height = h;
567 	CTextSize (NULL, (int *) &(cache->rowheight), "Ty~g$V|&^.,/_'I}[@");
568 	if (cache->rowheight == 0)
569 	    cache->rowheight = 1;
570 	cache->rowheight += FONT_OVERHEAD;
571 	CSetColor (COLOR_FLAT);
572 	CRectangle (cache->cache, 0, 0, w, h);
573 	end = h / cache->rowheight;
574     } else {
575 	push_filelist_line (cache, False);
576 	if (cache->hilited != wdt->cursor)
577 	    hilite_filelist_line (cache, COLOR_FLAT, directentry);
578 
579 	if (cache->firstline != wdt->firstline)
580 	    scroll_cache (cache, wdt->firstline, &start, &end);
581     }
582 
583     cache->firstline = wdt->firstline;
584     cache->hilited = wdt->cursor;
585     hilite_filelist_line (cache, (wdt->options & BUTTON_HIGHLIGHT) ? COLOR_WHITE : color_widget (12), directentry);
586     cache->current = wdt->current;
587     push_filelist_line (cache, True);
588 
589     cache->options = wdt->options;
590 
591     start_y = start * cache->rowheight;
592     y = start_y + FONT_OFFSET_Y;
593     start += wdt->firstline;
594     end += wdt->firstline;
595 
596     CSetColor (COLOR_BLACK);
597     restrict_text_area (cache);
598     for (i = start;
599 	 i <= end &&
600 	 i < wdt->numlines && y < cache->height &&
601 	 !(directentry[i].options & FILELIST_LAST_ENTRY); i++) {
602 	if (directentry[i].name && i != cache->hilited) {
603 	    CSetBackgroundColor (COLOR_FLAT);
604 	    CImageString (cache->cache, FONT_OFFSET_X + 1, y,
605 			 directentry[i].name);
606 	}
607 
608 	y += cache->rowheight;
609     }
610     XSetClipMask (CDisplay, CGC, None);
611     /* now drawing  arrows */
612     y = start_y + (cache->rowheight / 2 - 4);
613     x = cache->width - NEXT_ARROW_FIELD + NEXT_ARROW_SIZE / 2;
614     for (i = start;
615 	 i <= end &&
616 	 i < wdt->numlines && y < cache->height &&
617 	 !(directentry[i].options & FILELIST_LAST_ENTRY); i++) {
618 	if (is_directory (directentry, i)) {
619 	    CSetColor (COLOR_BLACK);
620 	    CLine (cache->cache, x, y, x + 7, y + 4);
621 	    CLine (cache->cache, x, y, x, y + 8);
622 	    CSetColor ((i == cache->hilited) ? COLOR_FLAT : COLOR_WHITE);
623 	    CLine (cache->cache, x, y + 8, x + 7, y + 4);
624 	}
625 	y += cache->rowheight;
626     }
627 }
628 
render_NeXT_filelist(CWidget * wdt)629 static void render_NeXT_filelist (CWidget * wdt)
630 {
631     FilelistCache *cache;
632 
633     if (wdt->hook == NULL) {
634 	render_bevel (wdt->winid, 0, 0, wdt->width - 1, wdt->height - 1, 1, 3);
635 	return;
636     }
637     if (wdt->user == NULL) {
638 	wdt->user = calloc (sizeof (FilelistCache), 1);
639 	wdt->free_user = free_filelist_cache;
640     }
641     cache = (FilelistCache *) (wdt->user);
642 
643     CPushFont ("widget", 0);
644     check_filelist_cache (wdt, wdt->width - 3, wdt->height - 3, cache);
645     CPopFont ();
646 
647     render_bevel (wdt->winid, 0, 0, wdt->width - 1, wdt->height - 1, 1, 1);
648 
649     XCopyArea (CDisplay, cache->cache, wdt->winid, CGC, 0, 0, cache->width, cache->height, 2, 2);
650 }
651 
link_scrollbar_to_NeXT_filelist(CWidget * scrollbar,CWidget * w,XEvent * xevent,CEvent * cwevent,int whichscrbutton)652 static void link_scrollbar_to_NeXT_filelist (CWidget * scrollbar, CWidget * w, XEvent * xevent, CEvent * cwevent, int whichscrbutton)
653 {
654     /* fix me : add stuf */
655     int redrawtext = 0;
656     int new_first = w->firstline;
657     FilelistCache *cache;
658     int box_size;
659 
660     if (w->user == NULL)
661 	return;
662     cache = (FilelistCache *) (w->user);
663     box_size = cache->height / cache->rowheight;
664 
665     if ((xevent->type == ButtonRelease || xevent->type == MotionNotify) && whichscrbutton == 3) {
666 	new_first = (double) scrollbar->firstline * w->numlines / 65535.0;
667     } else if (xevent->type == ButtonPress && (cwevent->button == Button1 || cwevent->button == Button2)) {
668 	new_first = w->firstline;
669 	switch (whichscrbutton) {
670 	case 1:
671 	    new_first -= box_size - 1;
672 	    break;
673 	case 2:
674 	    new_first--;
675 	    break;
676 	case 5:
677 	    new_first++;
678 	    break;
679 	case 4:
680 	    new_first += box_size - 1;
681 	    break;
682 	}
683     }
684     if (new_first < 0)
685 	new_first = 0;
686     else if (new_first > w->numlines - box_size)
687 	new_first = w->numlines - box_size;
688     redrawtext = (new_first != w->firstline);
689     w->firstline = new_first;
690 
691     if (xevent->type == ButtonRelease ||
692 	(redrawtext && !CCheckWindowEvent (xevent->xany.window, ButtonReleaseMask | ButtonMotionMask, 0)))
693 	render_NeXT_filelist (w);
694 
695     scrollbar->firstline = (double) 65535.0 *w->firstline / (w->numlines ? w->numlines : 1);
696     scrollbar->numlines = (double) 65535.0 *box_size / (w->numlines ? w->numlines : 1);
697 
698 }
699 
700 static int eh_NeXT_filelist (CWidget * w, XEvent * xevent, CEvent * cwevent);
701 
look_next_draw_file_list(const char * identifier,Window parent,int x,int y,int width,int height,int line,int column,struct file_entry * directentry,long options)702 static CWidget *look_next_draw_file_list (const char *identifier, Window parent, int x, int y,
703 			int width, int height, int line, int column,
704 			struct file_entry *directentry,
705 			long options)
706 {
707     struct file_entry e;
708     CWidget *w;
709     int x_hint;
710     int lines = 0;
711     unsigned int prop;
712 
713     if (!directentry) {
714 	memset (&e, 0, sizeof (e));
715 	e.options = FILELIST_LAST_ENTRY;
716 	directentry = &e;
717     } else {
718 	while (!(directentry[lines].options & FILELIST_LAST_ENTRY))
719 	    lines++;
720     }
721 
722     if (height == AUTO_HEIGHT)
723 	height = max (1, lines) * FONT_PIX_PER_LINE + 6;
724 
725     if (width == AUTO_WIDTH)
726 	width = (FONT_MEAN_WIDTH * 24 + 15);
727 
728     w = CSetupWidget (identifier, parent, x, y,
729 	      width, height, C_TEXTBOX_WIDGET, INPUT_KEY, COLOR_FLAT, 1);
730 
731     x_hint = x + width + WIDGET_SPACING;
732     prop = (double) 65535.0 *(height / FONT_PIX_PER_LINE) / (lines ? lines : 1);
733     w->vert_scrollbar = CDrawVerticalScrollbar (catstrs (identifier, ".vsc", NULL), parent,
734 				 x_hint, y, height, AUTO_WIDTH, 0, prop);
735     w->vert_scrollbar->position |= POSITION_HEIGHT;
736     CSetScrollbarCallback (w->vert_scrollbar->ident, w->ident, link_scrollbar_to_NeXT_filelist);
737     CGetHintPos (&x_hint, 0);
738 
739     set_hint_pos (x_hint, y + height + WIDGET_SPACING);
740     w->eh = eh_NeXT_filelist;
741     w->current = -1;
742     w->cursor = -1;
743     w->firstline = 0;
744     w->numlines = lines;
745     w->hook = directentry;
746     return w;
747 }
748 
look_next_redraw_file_list(const char * identifier,struct file_entry * directentry,int preserve)749 CWidget *look_next_redraw_file_list (const char *identifier, struct file_entry * directentry, int preserve)
750 {
751     CWidget *w = CIdent (identifier);
752 
753     if (w) {
754 	w->hook = directentry;
755 	if (!directentry)
756 	    w->numlines = 1;
757 	else {
758 	    register int i = 0;
759 	    while (!(directentry[i].options & FILELIST_LAST_ENTRY))
760 		i++;
761 	    w->numlines = i;
762 	}
763 	w->current = -1;
764 	w->cursor = -1;
765 	w->firstline = 0;
766 
767 	free_filelist_cache (w->user);
768 	w->user = NULL;
769 	render_NeXT_filelist (w);
770 	if (w->user) {
771 	    FilelistCache *cache;
772 	    int box_size;
773 	    cache = (FilelistCache *) (w->user);
774 	    box_size = cache->height / cache->rowheight;
775 	    w->vert_scrollbar->firstline = (double) 65535.0 *w->firstline / (w->numlines ? w->numlines : 1);
776 	    w->vert_scrollbar->numlines = (double) 65535.0 *box_size / (w->numlines ? w->numlines : 1);
777 	    render_scrollbar (w->vert_scrollbar);
778 	}
779     }
780     return w;
781 }
782 
CSetFilelistPosition(const char * identifier,long current,long cursor,long firstline)783 void CSetFilelistPosition (const char *identifier, long current, long cursor, long firstline)
784 {
785     CWidget *w = CIdent (identifier);
786 
787     if (w) {
788 	FilelistCache *cache;
789 	int redraw_scrollbar = 0;
790 	if (current >= w->numlines)
791 	    current = w->numlines - 1;
792 	if (cursor >= w->numlines)
793 	    cursor = w->numlines - 1;
794 	w->current = current;
795 	w->cursor = cursor;
796 	if (firstline >= 0 && (cache = (FilelistCache *) (w->user))) {
797 	    long max_fline = w->numlines - cache->height / cache->rowheight;
798 	    if (max_fline <= 0)
799 		if (firstline >= max_fline)
800 		    firstline = max_fline - 1;
801 	    /* if our window is larger then numlines : */
802 	    if (firstline < 0)
803 		firstline = 0;
804 	    redraw_scrollbar = (w->firstline != firstline);
805 	    w->firstline = firstline;
806 	}
807 	render_NeXT_filelist (w);
808 	if (redraw_scrollbar) {
809 	    w->vert_scrollbar->firstline = (double) 65535.0 *w->firstline / (w->numlines ? w->numlines : 1);
810 	    render_scrollbar (w->vert_scrollbar);
811 	}
812     }
813 }
814 
look_next_get_file_list_line(CWidget * w,int line)815 struct file_entry *look_next_get_file_list_line (CWidget * w, int line)
816 {
817     struct file_entry *e;
818     static struct file_entry r;
819 
820     memset (&r, 0, sizeof (r));
821     e = (struct file_entry *) w->hook;
822     if (e[line].options & FILELIST_LAST_ENTRY)
823 	r.options = FILELIST_LAST_ENTRY;
824     else
825 	r = e[line];
826     return &r;
827 }
828 
filelist_handle_mouse(CWidget * wdt,FilelistCache * cache,int y)829 int filelist_handle_mouse (CWidget * wdt, FilelistCache * cache, int y)
830 {
831     int new_hilite;
832     new_hilite = (int) (wdt->firstline) + y / (int) (cache->rowheight);
833     if (y < 0)
834 	new_hilite--;
835     /* we don't want to remove hilite even if user wants to go
836        beyound the beginning */
837     if (new_hilite < 0)
838 	new_hilite = 0;
839 
840     return new_hilite;
841 }
842 
filelist_handle_keypress(CWidget * wdt,FilelistCache * cache,KeySym key)843 int filelist_handle_keypress (CWidget * wdt, FilelistCache * cache, KeySym key)
844 {
845     int new_cursor = wdt->cursor;
846 
847 /* when text is highlighted, the cursor must be off */
848     switch ((int) key) {
849     case CK_Up:
850 	new_cursor--;
851 	break;
852     case CK_Down:
853 	new_cursor++;
854 	break;
855     case CK_Page_Up:
856 	new_cursor -= cache->height / cache->rowheight - 1;
857 	break;
858     case CK_Page_Down:
859 	new_cursor += cache->height / cache->rowheight - 1;
860 	break;
861     case CK_Home:
862 	new_cursor = 0;
863 	break;
864     case CK_End:
865 	new_cursor = wdt->numlines;
866 	break;
867     default:
868 	return -1;
869     }
870     /* we don't want to remove hilite even if user wants to go
871        beyound the beginning */
872     if (new_cursor < 0)
873 	new_cursor = 0;
874     return new_cursor;
875 }
876 
change_hilite(CWidget * w,int new_hilite)877 int change_hilite (CWidget * w, int new_hilite)
878 {
879     FilelistCache *cache = (FilelistCache *) (w->user);
880     if (new_hilite >= w->numlines)
881 	new_hilite = w->numlines - 1;
882     if (new_hilite != w->cursor) {
883 	int new_firstline = w->firstline;
884 #if 0
885 	struct file_entry *directentry = (struct file_entry *) w->hook;
886 #endif
887 	if (new_hilite < w->firstline && new_hilite >= 0)
888 	    new_firstline = new_hilite;
889 	if (new_hilite >= w->firstline + w->height / cache->rowheight)
890 	    new_firstline = new_hilite - w->height / cache->rowheight + 1;
891 	if (new_firstline != w->firstline) {
892 	    w->cursor = new_hilite;
893 	    w->firstline = new_firstline;
894 	    w->vert_scrollbar->firstline = (double) 65535.0 *w->firstline / (w->numlines ? w->numlines : 1);
895 	    render_scrollbar (w->vert_scrollbar);
896 	}
897 	w->cursor = new_hilite;
898 	return 1;
899     }
900     return 0;
901 }
902 
903 void selection_send (XSelectionRequestEvent * rq);
904 
eh_NeXT_filelist(CWidget * w,XEvent * xevent,CEvent * cwevent)905 int eh_NeXT_filelist (CWidget * w, XEvent * xevent, CEvent * cwevent)
906 {
907 #if 0
908     int xevent_xbutton_y;
909 #endif
910     int need_redraw = 0;
911     FilelistCache *cache = (FilelistCache *) (w->user);
912     int handled = 0;
913 
914     if ((w == NULL || w->hook == NULL || cache == NULL) &&
915 	xevent->type != Expose)
916 	return handled;
917 
918     switch (xevent->type) {
919     case SelectionRequest:
920 /* fixme: later
921    {
922    int type;
923    if (selection.text)  free (selection.text);
924    selection.text = (unsigned char *) get_block (w, 0, 0, &type, &selection.len);
925    selection_send (&(xevent->xselectionrequest));
926    }
927    return 1;
928      */ case Expose:
929 	handled = 1;
930 	break;
931     case ButtonPress:
932 	resolve_button (xevent, cwevent);
933 	need_redraw = change_hilite (w, filelist_handle_mouse (w, cache, cwevent->y));
934 	handled = 1;
935 	break;
936     case ButtonRelease:
937 	resolve_button (xevent, cwevent);
938 	need_redraw = change_hilite (w, filelist_handle_mouse (w, cache, cwevent->y));
939 	handled = 1;
940 	break;
941     case MotionNotify:
942 	resolve_button (xevent, cwevent);
943 	if (cwevent->state & (Button1Mask | Button2Mask)) {
944 	    need_redraw = change_hilite (w, filelist_handle_mouse (w, cache, cwevent->y));
945 	    handled = 1;
946 	}
947 	break;
948     case FocusIn:
949 	w->options |= BUTTON_HIGHLIGHT;
950 	need_redraw = 1;
951 	handled = 1;
952 	break;
953     case FocusOut:
954 	w->options &= ~BUTTON_HIGHLIGHT;
955 	need_redraw = 1;
956 	handled = 1;
957 	break;
958     case EnterNotify:		/* we simply let our parent to process it */
959     case LeaveNotify:
960 	cwevent->ident = w->ident;
961 	break;
962     case KeyPress:
963 	{
964 	    int move_to = filelist_handle_keypress (w, cache, cwevent->command);
965 
966 	    if (move_to >= 0) {
967 		need_redraw = change_hilite (w, move_to);
968 		handled = 1;
969 	    } else {
970 		switch (cwevent->command) {
971 		case CK_Left:
972 		case CK_Right:
973 		case CK_Home:
974 		case CK_End:
975 		case CK_Enter:
976 		case CK_BackSpace:
977 		    cwevent->ident = w->ident;
978 		    return 1;
979 		default:
980 		    if (cwevent->insert > 0) {
981 			cwevent->ident = w->ident;
982 			return 1;
983 		    }
984 		}
985 	    }
986 	}
987 	break;
988 
989     default:
990 	return handled;
991     }
992 
993     if (need_redraw || cwevent->double_click)
994 	cwevent->ident = w->ident;
995 
996     if ((xevent->type == Expose && !xevent->xexpose.count) || need_redraw)
997 	render_NeXT_filelist (w);
998 
999     return handled;
1000 }
1001 
1002 
1003 /* }}} file list stuff */
1004 
1005 /* {{{ file browser stuff */
1006 
1007 /*****************************************************************/
1008 /*     Miscellaneous read only text widget for dynamic text      */
1009 /*****************************************************************/
1010 
render_dyn_text(CWidget * wdt)1011 static void render_dyn_text (CWidget * wdt)
1012 {
1013     Window win = wdt->winid;
1014     char text[1024], *p, *q;
1015     int y, x = 0, w = wdt->width;
1016     int color = 0;
1017     int new_line = 1;
1018 
1019     CSetColor (COLOR_LIGHT);
1020     CRectangle (win, 1, 1, w - 2, wdt->height - 2);
1021     CSetColor (COLOR_BLACK);
1022     CSetBackgroundColor (COLOR_LIGHT);
1023 
1024     y = 1;			/* bevel */
1025     if ((q = wdt->text) == NULL)
1026 	return;
1027     CPushFont ("widget", 0);
1028     for (;;) {
1029 	long len;
1030 
1031 	CSetColor (color_palette (color));
1032 	/* looking for control characters */
1033 	for (p = q; *p && *p >= ' '; p++);
1034 
1035 	len = min ((unsigned long) p - (unsigned long) q, 1023);
1036 
1037 	if (new_line) {
1038 	    if (wdt->options & TEXT_CENTRED)
1039 		x = (w - (TEXT_RELIEF + 1) * 2 - CImageTextWidth (q, len)) / 2;
1040 	    else
1041 		x = 0;
1042 	    new_line = 0;
1043 	}
1044 	if (!*p) {		/* last line */
1045 	    drawstring_xy (win, TEXT_RELIEF + 1 + x, TEXT_RELIEF + y, q);
1046 	    break;
1047 	} else {
1048 	    memcpy (text, q, len);
1049 	    text[len] = 0;
1050 	    drawstring_xy (win, TEXT_RELIEF + 1 + x,
1051 			   TEXT_RELIEF + y, text);
1052 	    x += CImageTextWidth (q, len);
1053 	}
1054 
1055 	if (*p == '\n') {
1056 	    new_line = 1;
1057 	    y += FONT_PIX_PER_LINE;	/* next line */
1058 	} else if (*p == 28)
1059 	    color = (int) '\n';
1060 	else
1061 	    color = *p;
1062 
1063 	color %= 27;
1064 	q = p + 1;
1065     }
1066     CPopFont ();
1067     render_bevel (win, 0, 0, w - 1, wdt->height - 1, 1, 1);
1068 }
1069 
1070 
1071 /*-----------------------------------------------------------------------*/
eh_dyn_text(CWidget * w,XEvent * xevent,CEvent * cwevent)1072 static int eh_dyn_text (CWidget * w, XEvent * xevent, CEvent * cwevent)
1073 {
1074     switch (xevent->type) {
1075     case Expose:
1076 	if (!xevent->xexpose.count)
1077 	    render_dyn_text (w);
1078 	break;
1079     }
1080     return 0;
1081 }
1082 
CDrawDynText(const char * identifier,Window parent,int x,int y,int width,int rows,const char * fmt,...)1083 static CWidget *CDrawDynText (const char *identifier, Window parent,
1084 		  int x, int y, int width, int rows, const char *fmt,...)
1085 {
1086     va_list pa;
1087     char *str;
1088     int w, h;
1089     CWidget *wdt;
1090 
1091     va_start (pa, fmt);
1092     str = vsprintf_alloc (fmt, pa);
1093     va_end (pa);
1094 
1095     CPushFont ("widget", 0);
1096     CTextSize (&w, &h, str);
1097     if (width != AUTO_WIDTH && width)
1098 	w = width;
1099     else
1100 	w += TEXT_RELIEF * 2 + 2;
1101 
1102     if (rows != AUTO_HEIGHT && rows) {
1103 	CTextSize (0, &h, "Ty~g$V|&^.,/_'I}[@");
1104 	h = (h + FONT_OVERHEAD) * rows;
1105     }
1106     h += TEXT_RELIEF * 2 + 2;
1107 
1108     wdt = CSetupWidget (identifier, parent, x, y,
1109 			w, h, C_TEXT_WIDGET, INPUT_EXPOSE, COLOR_FLAT, 0);
1110     wdt->text = (char *) strdup (str);
1111     wdt->eh = eh_dyn_text;
1112     free (str);
1113     set_hint_pos (x + w + WIDGET_SPACING, y + h + WIDGET_SPACING);
1114     CPopFont ();
1115     return wdt;
1116 }
1117 
CRedrawDynText(const char * identifier,const char * fmt,...)1118 static CWidget *CRedrawDynText (const char *identifier, const char *fmt,...)
1119 {
1120     va_list pa;
1121     char *str;
1122     CWidget *wdt;
1123 #if 0
1124     int w, h;
1125 #endif
1126 
1127     wdt = CIdent (identifier);
1128     if (!wdt)
1129 	return 0;
1130 
1131     va_start (pa, fmt);
1132     str = vsprintf_alloc (fmt, pa);
1133     va_end (pa);
1134 
1135     if (wdt->text)
1136 	free (wdt->text);
1137     wdt->text = (char *) strdup (str);
1138 
1139     render_dyn_text (wdt);
1140     free (str);
1141     return wdt;
1142 }
1143 
1144 
1145 /******************************************************************/
1146 /*                   NeXT Directory Tree stuff                    */
1147 /******************************************************************/
1148 typedef struct NeXTDir {
1149     struct NeXTDir *next, *prev;
1150 
1151     char *name;
1152     char *filter;
1153     long cursor;
1154     long current;
1155     long firstline;
1156     struct file_entry *list;
1157 
1158 } NeXTDir;
1159 
1160 typedef struct NeXTDirTree {
1161     NeXTDir *first, *last, *selected;
1162     NeXTDir *discarded;		/* when we chdir - it will store previos tail */
1163     int pos;
1164     int numdirs;
1165     int numpanes;
1166     char *path;
1167     int path_length;
1168 
1169     int dirty;			/* can't change dirs - need to redraw widgets first */
1170 } NeXTDirTree;
1171 
1172 extern Bool is_directory (struct file_entry *directentry, int line_number);
1173 
create_dir_elem(char * name,int name_len)1174 static NeXTDir *create_dir_elem (char *name, int name_len)
1175 {
1176     NeXTDir *dir;
1177     dir = (NeXTDir *) calloc (sizeof (NeXTDir), 1);
1178     dir->prev = dir->next = NULL;
1179     dir->filter = (char *) strdup ("*");
1180     dir->current = -1;
1181     dir->list = NULL;
1182     if (name == NULL || name_len == 0) {	/* root directory then */
1183 	dir->name = (char *) strdup ("");
1184     } else {
1185 	dir->name = malloc (name_len + 1);
1186 	strncpy (dir->name, name, name_len);
1187 	dir->name[name_len] = '\0';
1188     }
1189     return dir;
1190 }
1191 
destroy_dir_elem(NeXTDir ** dir)1192 static void destroy_dir_elem (NeXTDir ** dir)
1193 {
1194     if (dir) {
1195 	if (*dir) {
1196 	    if ((*dir)->filter)
1197 		free ((*dir)->filter);
1198 	    if ((*dir)->name)
1199 		free ((*dir)->name);
1200 	    if ((*dir)->list)
1201 		free ((*dir)->list);
1202 	    memset (*dir, 0x00, sizeof (NeXTDir));	/* just in case */
1203 	    free (*dir);
1204 	    *dir = NULL;
1205 	}
1206     }
1207 }
1208 
create_dir_tree(const char * path,int numpanes)1209 static NeXTDirTree *create_dir_tree (const char *path, int numpanes)
1210 {
1211     NeXTDirTree *tree = NULL;
1212     char *ptr = 0;
1213 
1214     tree = (NeXTDirTree *) calloc (sizeof (NeXTDirTree), 1);
1215 
1216     if (path == NULL) {		/* defaulting to the root */
1217 	tree->path_length = 1;
1218 	tree->path = (char *) strdup ("/");
1219 	tree->first = tree->last = tree->selected = create_dir_elem ("", 0);
1220         tree->numdirs++;
1221     } else {
1222 	tree->path_length = strlen (path);
1223 	tree->path = malloc (tree->path_length + 1);
1224 	strcpy (tree->path, path);
1225 
1226 	ptr = tree->path;
1227 
1228 	if (*ptr == '/') {
1229 	    tree->first = tree->last = tree->selected = create_dir_elem ("", 0);
1230 	    tree->numdirs++;
1231 	}
1232 	while (*ptr) {
1233 	    int len = 0;
1234 	    while (*(ptr + len) && *(ptr + len) != '/')
1235 		len++;
1236 	    if (len) {
1237 		tree->selected = create_dir_elem (ptr, len);
1238 		if (tree->last == NULL)
1239 		    tree->first = tree->last = tree->selected;
1240 		else {
1241 		    tree->selected->prev = tree->last;
1242 		    tree->last->next = tree->selected;
1243 		    tree->last = tree->selected;
1244 		}
1245 		tree->numdirs++;
1246 	    }
1247 	    ptr += len;
1248 	    if (*ptr)
1249 		ptr++;		/* skipping / */
1250 	}
1251     }
1252     tree->numpanes = numpanes;
1253     tree->discarded = NULL;
1254 
1255     if (tree->selected == NULL)
1256 	tree->selected = tree->last;
1257     tree->pos = tree->numdirs - tree->numpanes;
1258     if (tree->pos < 0)
1259 	tree->pos = 0;
1260     return tree;
1261 }
1262 
destroy_dir_chain(NeXTDir ** start)1263 static void destroy_dir_chain (NeXTDir ** start)
1264 {
1265     NeXTDir *dir;
1266     for (dir = *start; dir; dir = *start) {
1267 	*start = dir->next;
1268 	destroy_dir_elem (&dir);
1269     }
1270 }
1271 
destroy_dir_tree(NeXTDirTree ** tree)1272 static void destroy_dir_tree (NeXTDirTree ** tree)
1273 {
1274     if (tree) {
1275 	destroy_dir_chain (&((*tree)->first));
1276 	destroy_dir_chain (&((*tree)->discarded));
1277 	free (*tree);
1278 	*tree = NULL;
1279     }
1280 }
1281 
get_dir_path(NeXTDirTree * tree,NeXTDir * dir,char * buffer)1282 static char *get_dir_path (NeXTDirTree * tree, NeXTDir * dir, char *buffer)
1283 {
1284     register NeXTDir *d;
1285     register char *ptr1 = buffer, *ptr2;
1286     if (!ptr1 || !tree || !dir)
1287 	return NULL;
1288 
1289     for (d = tree->first; d && d != dir; d = d->next) {
1290 	*(ptr1++) = '/';
1291 	ptr2 = d->name;
1292 	if (*ptr2)
1293 	    while (*ptr2)
1294 		*(ptr1++) = *(ptr2++);
1295 	else			/* we don't really want //, even thou it is not a violation */
1296 	    ptr1--;
1297     }
1298     *ptr1 = '\0';
1299     return buffer;
1300 }
1301 
read_dir_filelist(NeXTDir * dir,char * path)1302 static struct file_entry *read_dir_filelist (NeXTDir * dir, char *path)
1303 {
1304     if (dir && path) {
1305 	register int k;
1306 	char *next_dir = NULL;
1307 	CHourGlass (CFirstWindow);
1308 	if (dir->list)
1309 	    free (dir->list);
1310 	dir->list = get_file_entry_list (path, FILELIST_ALL_FILES, (dir->filter) ? dir->filter : "*");
1311 	if (dir->next)
1312 	    next_dir = dir->next->name;
1313 	dir->current = -1;
1314 	if (dir->list && next_dir) {
1315 	    for (k = 0; !(dir->list[k].options & FILELIST_LAST_ENTRY); k++)
1316 		if (is_directory (dir->list, k))
1317 		    if (strcmp (dir->list[k].name, next_dir) == 0) {
1318 			dir->current = k;
1319 			break;
1320 		    }
1321 	}
1322 	dir->cursor = dir->firstline = (dir->current >= 0) ? dir->current : 0;
1323 	CUnHourGlass (CFirstWindow);
1324     }
1325     return dir->list;
1326 }
1327 
update_tree_integrity(NeXTDirTree * tree,NeXTDir * selected)1328 static void update_tree_integrity (NeXTDirTree * tree, NeXTDir * selected)
1329 {
1330     NeXTDir *t;
1331     tree->selected = NULL;
1332     tree->numdirs = 0;
1333     tree->path_length = 0;
1334 
1335     for (t = tree->first; t; t = t->next) {
1336 	tree->last = t;
1337 	if (selected == t)
1338 	    tree->selected = selected;
1339 	tree->numdirs++;
1340 	tree->path_length += 1 + strlen (t->name);
1341     }
1342 
1343     tree->path_length++;
1344 
1345     tree->pos = tree->numdirs - tree->numpanes;
1346     if (tree->pos < 0)
1347 	tree->pos = 0;
1348 
1349     if (tree->selected == NULL)
1350 	tree->selected = tree->last;
1351 }
1352 
change_dir(NeXTDirTree * tree,NeXTDir * dir,long item_num)1353 static void change_dir (NeXTDirTree * tree, NeXTDir * dir, long item_num)
1354 {
1355     struct file_entry *item;
1356     NeXTDir *tmp;
1357 
1358     if (!tree || tree->dirty || !dir || item_num < 0)
1359 	return;
1360     item = &(dir->list[item_num]);
1361 
1362     if (item->name[0] == '.') {
1363 	if (item->name[1] == '\0')
1364 	    return;
1365 	else if (item->name[1] == '.' && item->name[2] == '\0') {	/* poping Up */
1366 	    if (dir->prev == NULL)
1367 		return;
1368 	    dir = dir->prev;
1369 	    if (tree->discarded)
1370 		destroy_dir_chain (&(tree->discarded));
1371 	    tree->discarded = dir->next;
1372 	    dir->next = NULL;
1373 	    tree->dirty = 1;
1374 	    update_tree_integrity (tree, dir);
1375 	    return;
1376 	}
1377     }
1378     if (tree->discarded) {
1379 	if (tree->discarded->prev == dir &&
1380 	    strcmp (tree->discarded->name, item->name) == 0) {
1381 	    tmp = dir->next;
1382 	    dir->next = tree->discarded;
1383 	    tree->discarded = tmp;
1384 	} else {
1385 	    destroy_dir_chain (&(tree->discarded));
1386 	    tree->discarded = dir->next;
1387 	    dir->next = NULL;
1388 	}
1389     } else {
1390 	tree->discarded = dir->next;
1391 	dir->next = NULL;
1392     }
1393 
1394     if (dir->next == NULL) {
1395 	dir->next = create_dir_elem (item->name, strlen (item->name));
1396 	dir->next->prev = dir;
1397     }
1398     tree->dirty = 1;
1399 
1400     dir->current = item_num;
1401     /* taking some precautions so not to destroy tree integrity */
1402     update_tree_integrity (tree, dir);
1403 }
1404 
get_full_filename(NeXTDirTree * tree,NeXTDir * dir,long item)1405 static char *get_full_filename (NeXTDirTree * tree, NeXTDir * dir, long item)
1406 {
1407     char *buffer, *path_tail;
1408     if (!tree || item < 0 || !dir || !(dir->list))
1409 	return NULL;
1410     buffer = malloc (tree->path_length + 1 + strlen (dir->list[item].name) + 1);
1411     get_dir_path (tree, dir, buffer);
1412     path_tail = buffer + strlen (buffer);
1413     sprintf (path_tail, "/%s/%s", dir->name, dir->list[item].name);
1414     return buffer;
1415 }
1416 
commit(NeXTDirTree * tree,NeXTDir * dir)1417 static char *commit (NeXTDirTree * tree, NeXTDir * dir)
1418 {				/* when user presses Enter on selected item or dobleclicks */
1419     if (tree) {
1420 	if (dir) {
1421 	    if (dir->list && dir->cursor >= 0) {
1422 		if (is_directory (dir->list, dir->cursor))
1423 		    change_dir (tree, dir, dir->cursor);
1424 		else
1425 		    return get_full_filename (tree, dir, dir->cursor);
1426 	    }
1427 	}
1428     }
1429     return NULL;
1430 }
1431 
1432 /******************************************************************/
1433 /*                   NeXT Browser widget stuff                    */
1434 /******************************************************************/
1435 
1436 #define FILEBROWSER_PANES 		2
1437 #define STANDALONE_FILEBROWSER_PANES 	3
1438 
1439 static char *mime_majors[3] =
1440 {"url", "text", 0};
1441 
1442 typedef struct NeXTFileBrowser {
1443     int numpanes;
1444     int focused;
1445 
1446 #define MAX_PARTIAL_NAME 32
1447     char partial_name[MAX_PARTIAL_NAME];
1448     int partial_end;
1449 
1450     char **labels;
1451     char **lists;
1452     char *hscroll;
1453     char *fileattr;
1454     char *name;
1455     char *filter;
1456     NeXTDirTree *tree;
1457 } NeXTFileBrowser;
1458 
clear_partial_buffer(NeXTFileBrowser * browser)1459 static void clear_partial_buffer (NeXTFileBrowser * browser)
1460 {
1461     if (browser) {
1462 	browser->partial_end = 0;
1463     }
1464 }
1465 
1466 
1467 extern void CSetFilelistPosition (const char *identifier, long current, long cursor, long firstline);
1468 
dir_save_position(NeXTDir * dir,long cursor,long current,long firstline)1469 static void dir_save_position (NeXTDir * dir, long cursor, long current, long firstline)
1470 {
1471     dir->cursor = cursor;
1472     dir->current = current;
1473     dir->firstline = firstline;
1474 }
1475 
destroy_next_filebrowser(CWidget * w)1476 static void destroy_next_filebrowser (CWidget * w)
1477 {
1478     if (w->hook) {
1479 	NeXTFileBrowser *browser = (NeXTFileBrowser *) w->hook;
1480 	int i;
1481 	destroy_dir_tree (&(browser->tree));
1482 	if (browser->labels) {
1483 	    for (i = 0; i < browser->numpanes; i++)
1484 		if (browser->labels[i])
1485 		    free (browser->labels[i]);
1486 	    free (browser->labels);
1487 	}
1488 	if (browser->lists) {
1489 	    for (i = 0; i < browser->numpanes; i++)
1490 		if (browser->lists[i])
1491 		    free (browser->lists[i]);
1492 	    free (browser->lists);
1493 	}
1494 	if (browser->fileattr)
1495 	    free (browser->fileattr);
1496 	if (browser->name)
1497 	    free (browser->name);
1498 	if (browser->filter)
1499 	    free (browser->filter);
1500 	/* just in case */
1501 	memset (browser, 0x00, sizeof (NeXTFileBrowser));
1502 
1503 	free (browser);
1504 	w->hook = 0;
1505     }
1506 }
1507 
get_dir_by_num(NeXTDirTree * tree,int num)1508 static NeXTDir *get_dir_by_num (NeXTDirTree * tree, int num)
1509 {
1510     NeXTDir *dir = NULL;
1511     register int i;
1512     if (tree)
1513 	dir = tree->first;
1514     for (i = 0; dir && i < num; i++)
1515 	dir = dir->next;
1516     return dir;
1517 }
1518 
1519 static void update_filter (NeXTFileBrowser * browser, NeXTDir * dir);
1520 
link_browser_to_data(NeXTFileBrowser * browser,int start)1521 static void link_browser_to_data (NeXTFileBrowser * browser, int start)
1522 {
1523     NeXTDir *dir;
1524     char *path = NULL, *path_tail = 0;
1525     int i, todo = browser->numpanes;
1526     if (browser == NULL)
1527 	return;
1528     if (start < 0 || start >= browser->numpanes)
1529 	start = 0;
1530 
1531     if (start == 0)
1532 	browser->tree->dirty = 0;
1533 
1534     if (browser->tree) {
1535 	todo -= start;
1536 	start += browser->tree->pos;
1537 	dir = get_dir_by_num (browser->tree, start);
1538     } else
1539 	dir = NULL;
1540 
1541     if (dir) {
1542 	path = malloc (browser->tree->path_length + 1);
1543 	get_dir_path (browser->tree, dir, path);
1544 	path_tail = path + strlen (path);
1545     }
1546     for (i = 0; i < todo; i++) {
1547 	if (!dir) {
1548 	    CRedrawDynText (browser->labels[i], "");
1549 	    CRedrawFilelist (browser->lists[i], 0, 0);
1550 	} else {
1551 
1552 	    if (dir->name) {
1553 		*(path_tail++) = '/';
1554 		strcpy (path_tail, dir->name);
1555 		path_tail += strlen (dir->name);
1556 		CRedrawDynText (browser->labels[i], "%s/%s", dir->name, dir->filter);
1557 	    } else
1558 		CRedrawDynText (browser->labels[i], "/%s", dir->filter);	/* root */
1559 
1560 	    if (dir->list == NULL)
1561 		read_dir_filelist (dir, path);
1562 	    CRedrawFilelist (browser->lists[i], dir->list, 0);
1563 	    CSetFilelistPosition (browser->lists[i], dir->current, dir->cursor, dir->firstline);
1564 	    dir = dir->next;
1565 	}
1566     }
1567 }
1568 
update_scrollbar(CWidget * scrollbar,NeXTFileBrowser * browser,int redraw)1569 static void update_scrollbar (CWidget * scrollbar, NeXTFileBrowser * browser, int redraw)
1570 {
1571     scrollbar->firstline = (double) 65535.0 *browser->tree->pos / (browser->tree->numdirs ? browser->tree->numdirs : 1);
1572     scrollbar->numlines = (double) 65535.0 *browser->numpanes / (browser->tree->numdirs ? browser->tree->numdirs : 1);
1573     if (redraw)
1574 	render_scrollbar (scrollbar);
1575 }
1576 
link_scrollbar_to_NeXT_browser(CWidget * scrollbar,CWidget * w,XEvent * xevent,CEvent * cwevent,int whichscrbutton)1577 static void link_scrollbar_to_NeXT_browser (CWidget * scrollbar, CWidget * w, XEvent * xevent, CEvent * cwevent, int whichscrbutton)
1578 {
1579     /* fix me : add stuf */
1580     int redraw = 0;
1581     int new_first = w->firstline;
1582     NeXTFileBrowser *browser;
1583 #if 0
1584     static int r = 0;
1585     NeXTDir *dir;
1586 #endif
1587 
1588     if (w->hook == NULL)
1589 	return;
1590     browser = (NeXTFileBrowser *) (w->hook);
1591     new_first = browser->tree->pos;
1592 
1593     if ((xevent->type == ButtonRelease || xevent->type == MotionNotify) && whichscrbutton == 3) {
1594 	new_first = (double) scrollbar->firstline * browser->tree->numdirs / 65535.0;
1595     } else if (xevent->type == ButtonPress && (cwevent->button == Button1 || cwevent->button == Button2)) {
1596 	switch (whichscrbutton) {
1597 	case 1:
1598 	    new_first -= browser->numpanes - 1;
1599 	    break;
1600 	case 2:
1601 	    new_first--;
1602 	    break;
1603 	case 5:
1604 	    new_first++;
1605 	    break;
1606 	case 4:
1607 	    new_first += browser->numpanes - 1;
1608 	    break;
1609 	}
1610     }
1611     if (new_first > browser->tree->numdirs - browser->numpanes)
1612 	new_first = browser->tree->numdirs - browser->numpanes;
1613     if (new_first < 0)
1614 	new_first = 0;
1615 
1616     redraw = (new_first != browser->tree->pos);
1617     browser->tree->pos = new_first;
1618 
1619     if (xevent->type == ButtonRelease ||
1620 	(redraw && !CCheckWindowEvent (xevent->xany.window, ButtonReleaseMask | ButtonMotionMask, 0)))
1621 	link_browser_to_data (browser, 0);
1622 
1623     update_scrollbar (w->hori_scrollbar, browser, 0);
1624 }
1625 
update_input(NeXTFileBrowser * browser,NeXTDir * dir)1626 static void update_input (NeXTFileBrowser * browser, NeXTDir * dir)
1627 {
1628     char *text = NULL;
1629     CWidget *inp_w = CIdent (browser->name);
1630 
1631     clear_partial_buffer (browser);
1632 
1633     text = get_full_filename (browser->tree, dir, dir->cursor);
1634 
1635     CDrawTextInput (browser->name, inp_w->parentid, inp_w->x, inp_w->y,
1636 		    inp_w->width, inp_w->height, 256, text);
1637     if (text)
1638 	free (text);
1639 
1640 }
1641 
filter_changed(NeXTFileBrowser * browser,NeXTDir * dir)1642 static void filter_changed (NeXTFileBrowser * browser, NeXTDir * dir)
1643 {
1644     CWidget *inp_w = CIdent (browser->filter);
1645     char *new_filter = "*";
1646     if (inp_w->text)
1647 	new_filter = inp_w->text;
1648 
1649     if (strcmp (dir->filter, new_filter)) {
1650 	struct file_entry *list;
1651 	if (dir->filter)
1652 	    free (dir->filter);
1653 	dir->filter = (char *) strdup (new_filter);
1654 	list = dir->list;
1655 	dir->list = NULL;
1656 	link_browser_to_data (browser, browser->focused - browser->tree->pos);
1657 	/* now after all filelists has updated its information
1658 	   we no longer need old data */
1659 	if (list)
1660 	    free (list);
1661     }
1662 }
1663 
update_filter(NeXTFileBrowser * browser,NeXTDir * dir)1664 static void update_filter (NeXTFileBrowser * browser, NeXTDir * dir)
1665 {
1666     CWidget *inp_w = CIdent (browser->filter);
1667 
1668     if (strcmp (dir->filter, inp_w->text) == 0)
1669 	return;
1670     if (strlen (inp_w->text))
1671 	CAddToTextInputHistory (browser->name, inp_w->text);
1672 
1673     CDrawTextInput (browser->filter, inp_w->parentid, inp_w->x, inp_w->y,
1674 		    inp_w->width, inp_w->height, 256, dir->filter);
1675 
1676 }
1677 
1678 /* returns 0 on fail */
goto_partial_file_name(NeXTFileBrowser * browser,NeXTDir * dir,int new_char)1679 static int goto_partial_file_name (NeXTFileBrowser * browser, NeXTDir * dir, int new_char)
1680 {
1681     int success = 0;
1682     if (browser && dir && dir->list && browser->partial_end < MAX_PARTIAL_NAME - 1) {
1683 	register int i;
1684 	if (new_char != 0) {
1685 	    browser->partial_name[browser->partial_end] = (char) new_char;
1686 	    browser->partial_end++;
1687 	} else if (browser->partial_end <= 0)
1688 	    return success;
1689 	else
1690 	    browser->partial_end--;
1691 
1692 	for (i = 0; !(dir->list[i].options & FILELIST_LAST_ENTRY); i++)
1693 	    if (strncmp (dir->list[i].name, browser->partial_name, browser->partial_end) == 0) {
1694 		dir->cursor = i;
1695 		dir->firstline = dir->cursor;
1696 		CSetFilelistPosition (browser->lists[browser->focused], dir->current, dir->cursor, dir->firstline);
1697 		success++;
1698 		break;
1699 	    }
1700 	if (!success)
1701 	    browser->partial_end--;
1702 
1703     }
1704     return success;
1705 }
1706 
draw_file_browser(const char * identifier,Window parent,int x,int y,const char * directory,const char * file,const char * label)1707 static Window draw_file_browser (const char *identifier, Window parent, int x, int y,
1708 	      const char *directory, const char *file, const char *label)
1709 {
1710     CWidget *w, *tmp = 0;
1711     int y2, x2, x3, btn_width, btn_height;
1712     int text_w1, text_w2;
1713     Window win;
1714     NeXTFileBrowser *browser;
1715     int i;
1716     char *ident, *ctrl_name;
1717     int panes = FILEBROWSER_PANES;
1718 
1719     if (strcmp (identifier, "browser") == 0)
1720 	panes = STANDALONE_FILEBROWSER_PANES;
1721 
1722     if (parent == CRoot)
1723 	win = CDrawMainWindow (identifier, label);
1724     else
1725 	win = CDrawHeadedDialog (identifier, parent, x, y, label);
1726 
1727     w = CIdent (identifier);
1728     w->options |= WINDOW_ALWAYS_RAISED;
1729     CHourGlass (CFirstWindow);
1730 /* allocating, initializing and storing our data */
1731     browser = (NeXTFileBrowser *) calloc (sizeof (NeXTFileBrowser), 1);
1732     w->hook = browser;
1733     w->destroy = destroy_next_filebrowser;
1734     browser->tree = create_dir_tree (directory, panes);
1735     browser->numpanes = 0;
1736     CUnHourGlass (CFirstWindow);
1737 
1738     if (browser->tree->numdirs == 0) {
1739 	CErrorDialog (parent, 20, 20, _ (" File browser "), _ (" Unable to read directory "));
1740 	CDestroyWidget (identifier);
1741 	return None;
1742     }
1743     browser->labels = (char **) calloc (sizeof (char *), panes);
1744     browser->lists = (char **) calloc (sizeof (char *), panes);
1745     browser->numpanes = panes;
1746 
1747     CGetHintPos (&x, &y);
1748     x += WINDOW_EXTRA_SPACING;
1749     y += WINDOW_EXTRA_SPACING;
1750 #define FILE_BOX_WIDTH (FONT_MEAN_WIDTH * 32 + 7)
1751     /* we'll use it to construct our widget names */
1752     ident = malloc (strlen (identifier) + 20);
1753     strcpy (ident, identifier);
1754     ctrl_name = ident + strlen (identifier);
1755     y2 = 0;
1756     for (i = 0; i < browser->numpanes; i++) {
1757 	CGetHintPos (&x2, 0);
1758 	x2 += WINDOW_EXTRA_SPACING;
1759 	sprintf (ctrl_name, ".label%3.3d", i);
1760 	browser->labels[i] = (char *) strdup (ident);
1761 	tmp = CDrawDynText (ident, win, x2, y, FILE_BOX_WIDTH, 1, "");
1762 	tmp->options |= TEXT_CENTRED;
1763 
1764 	/* only first time */
1765 	if (y2 == 0) {
1766 	    CGetHintPos (0, &y2);
1767 	    /* y2+=WINDOW_EXTRA_SPACING ; */
1768 	}
1769 	sprintf (ctrl_name, ".flist%3.3d", i);
1770 	browser->lists[i] = (char *) strdup (ident);
1771 	tmp = CDrawFilelist (ident, win, x2, y2,
1772 			     FILE_BOX_WIDTH, FONT_PIX_PER_LINE * 10, 0, 0, NULL, TEXTBOX_FILE_LIST);
1773 	tmp->position |= POSITION_HEIGHT;
1774 	xdnd_set_type_list (CDndClass, tmp->winid, xdnd_typelist_send[DndFiles]);
1775 	/* Toolhint */
1776 	CSetToolHint (ident, _ ("Double click to enter dir or open file."));
1777     }
1778     /* we want to automagically resize rightmost filelist */
1779     tmp->position |= POSITION_WIDTH;
1780     if (tmp->vert_scrollbar)
1781 	tmp->vert_scrollbar->position |= POSITION_RIGHT;
1782     tmp = CIdent (browser->labels[browser->numpanes - 1]);
1783     tmp->position |= POSITION_WIDTH;
1784 
1785     /* the right end of dialog */
1786     CGetHintPos (&x3, &y2);
1787 
1788     strcpy (ctrl_name, ".hsc");
1789     i = (double) 65535.0 *browser->tree->numpanes / (browser->tree->numdirs ? browser->tree->numdirs : 1);
1790     w->hori_scrollbar = CDrawHorizontalScrollbar (ident, win,
1791 			x, y2 + WINDOW_EXTRA_SPACING, x3 - x, AUTO_HEIGHT, i, i);
1792     CSetScrollbarCallback (ident, w->ident, link_scrollbar_to_NeXT_browser);
1793     w->hori_scrollbar->position = POSITION_BOTTOM | POSITION_WIDTH;
1794     update_scrollbar (w->hori_scrollbar, browser, 1);
1795 
1796     CPushFont ("widget", 0);
1797 
1798     CGetHintPos (0, &y2);
1799     strcpy (ctrl_name, ".fileattr");
1800     browser->fileattr = (char *) strdup (ident);
1801     tmp = CDrawDynText (ident, win, x, y2 + WINDOW_EXTRA_SPACING, x3 - x, 3, "");
1802     tmp->position |= POSITION_FILL | POSITION_BOTTOM;
1803 
1804     CTextSize (&text_w1, 0, "Name : ");
1805     CTextSize (&text_w2, 0, "Filter : ");
1806 /* filename input stuff: */
1807     CGetHintPos (0, &y2);
1808     y2 += WINDOW_EXTRA_SPACING;
1809     /* label */
1810     strcpy (ctrl_name, ".namex");
1811     x2 = x;
1812     if (text_w1 < text_w2)
1813 	x2 += text_w2 - text_w1;
1814     tmp = CDrawText (ident, win, x2, y2, _ ("Name : "));
1815     tmp->position |= POSITION_BOTTOM;
1816     /* we want filter and name inputs to be right underneath of each other */
1817     x2 += text_w1 + WINDOW_EXTRA_SPACING;
1818     /* input */
1819     strcpy (ctrl_name, ".finp");
1820     browser->name = (char *) strdup (ident);
1821     tmp = CDrawTextInput (ident, win, x2, y2, AUTO_WIDTH, AUTO_HEIGHT, 256, file);
1822     tmp->position |= POSITION_FILL | POSITION_BOTTOM;
1823     /* Toolhint */
1824     CSetToolHint (ident, _ ("Filename of the file to load."));
1825     /* DnD stuff */
1826     xdnd_set_type_list (CDndClass, tmp->winid, xdnd_typelist_send[DndFile]);
1827     tmp->funcs->types = DndFile;
1828     tmp->funcs->mime_majors = mime_majors;
1829 
1830 /* file filter input stuff */
1831     CGetHintPos (0, &y2);
1832     y2 += WINDOW_EXTRA_SPACING;
1833     /* label */
1834     x2 = x;
1835     if (text_w2 < text_w1)
1836 	x2 += text_w1 - text_w2;
1837     strcpy (ctrl_name, ".filtx");
1838     (CDrawText (ident, win, x2, y2, _ ("Filter :")))->position |= POSITION_BOTTOM;
1839     x2 += text_w2 + WINDOW_EXTRA_SPACING;
1840     /* input (we already know where to place it - right under filename input ) */
1841     strcpy (ctrl_name, ".filtinp");
1842     browser->filter = (char *) strdup (ident);
1843     tmp = CDrawTextInput (ident, win, x2, y2, AUTO_WIDTH, AUTO_HEIGHT, 256, TEXTINPUT_LAST_INPUT);
1844     tmp->position |= POSITION_FILL | POSITION_BOTTOM;
1845     /* Toolhint */
1846     CSetToolHint (ident, _ ("List only files matching this shell filter"));
1847 
1848 /* buttons stuff */
1849     CGetHintPos (0, &y2);
1850     y2 += WINDOW_EXTRA_SPACING * 2;
1851     /* determining buttons size */
1852     CTextSize (&btn_width, &btn_height, " Cancel ");
1853     btn_height += 5 + BUTTON_RELIEF * 2;
1854     btn_width += 4 + BUTTON_RELIEF * 2;
1855     /* cancel button */
1856     x2 = x3 - (btn_width + WINDOW_EXTRA_SPACING) * 2 - WINDOW_EXTRA_SPACING;
1857     strcpy (ctrl_name, ".cancel");
1858     tmp = CDrawButton (ident, win, x2, y2, btn_width, btn_height, " Cancel ");
1859     tmp->position |= POSITION_RIGHT | POSITION_BOTTOM;
1860     CSetToolHint (ident, _ ("Abort this dialog, Escape"));
1861     /* ok button */
1862     x2 += btn_width + WINDOW_EXTRA_SPACING * 2;
1863     strcpy (ctrl_name, ".ok");
1864     tmp = CDrawButton (ident, win, x2, y2, btn_width, btn_height, "   Ok   ");
1865     tmp->position |= POSITION_RIGHT | POSITION_BOTTOM;
1866     CSetToolHint (ident, _ ("Accept, Enter"));
1867 
1868     CPopFont ();
1869 
1870 /* all done - no longer need that : */
1871     free (ident);
1872 
1873 /* make us real ! */
1874     link_browser_to_data (browser, 0);
1875     /* that will be our width/height : */
1876     y2 += btn_height + WINDOW_EXTRA_SPACING * 2;
1877     reset_hint_pos (x3, y2);
1878     CSetSizeHintPos (identifier);
1879     /* map us */
1880     CMapDialog (identifier);
1881     /* enable resizing */
1882     CSetWindowResizable (identifier, FONT_MEAN_WIDTH * 40, min (FONT_PIX_PER_LINE * 5 + 230, w->height), 1600, 1200);	/* minimum and maximum sizes */
1883 
1884     return win;
1885 }
1886 
1887 /* options */
1888 #define GETFILE_GET_DIRECTORY		1
1889 #define GETFILE_GET_EXISTING_FILE	2
1890 #define GETFILE_BROWSER			4
1891 
1892 void input_insert (CWidget * w, int c);
1893 
1894 #if 0
1895 static char *file_error (void)
1896 {
1897     if (errno) {
1898 	char *error_msg;
1899 #ifdef HAVE_STRERROR
1900 	error_msg = _ (strerror (errno));
1901 #else
1902 	extern int sys_nerr;
1903 	extern char *sys_errlist[];
1904 	if ((0 <= errno) && (errno < sys_nerr))
1905 	    error_msg = _ (sys_errlist[errno]);
1906 	else
1907 /* The returned value, 'errno' has an unknown meaning */
1908 	    error_msg = _ ("strange errno");
1909 #endif
1910 	return catstrs ("[", error_msg, "]", NULL);
1911     }
1912     return "";
1913 }
1914 #endif
1915 
run_cmd(const char * fmt,...)1916 static void run_cmd (const char *fmt,...)
1917 {
1918     signal (SIGCHLD, SIG_IGN);
1919     if (!fork ()) {		/* child process */
1920 	va_list pa;
1921 	char *str;
1922 
1923 	va_start (pa, fmt);
1924 	str = vsprintf_alloc (fmt, pa);
1925 	va_end (pa);
1926 
1927 	execlp ("/bin/sh", "/bin/sh", "-c", str, (char *) NULL);
1928 
1929 	/* if all is fine then the thread will exit here */
1930 	/* so displaying error if not                    */
1931 	fprintf (stderr, "\nBad luck running command [%s].\n", str);
1932 	exit (0);		/*thread completed */
1933     }
1934 }
1935 
1936 static char *empty_line = "";
1937 
item_selected(const char * identifier,NeXTFileBrowser * browser,NeXTDir * dir)1938 static char *item_selected (const char *identifier, NeXTFileBrowser * browser, NeXTDir * dir)
1939 {
1940     char *ptr = NULL;
1941     CWidget *w;
1942 
1943     if (!browser || !identifier)
1944 	return 0;		/* something terrible has happen ! */
1945     if (dir == NULL) {
1946 	if ((w = CIdent (browser->name)) && w->text)
1947 	{
1948 	    ptr = strdup (w->text);
1949 	    if (strlen (w->text))
1950 		CAddToTextInputHistory (browser->name, w->text);
1951 	}
1952     } else {
1953 	ptr = commit (browser->tree, dir);
1954 	if (browser->tree->dirty)
1955 	    link_browser_to_data (browser, 0);
1956     }
1957 
1958     if (ptr == NULL)
1959 	ptr = empty_line;
1960     else if (strcmp (identifier, "browser") == 0) {
1961 	struct file_entry *item = &(dir->list[dir->cursor]);
1962 
1963 	if ((item->stat.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) {
1964 	    run_cmd (ptr);
1965 	} else {
1966 	    static char *default_editor = "smalledit";
1967 	    static char *editor = NULL;
1968 	    if (editor == NULL) {
1969 		editor = getenv ("EDITOR");
1970 		if (editor == NULL)
1971 		    editor = default_editor;
1972 	    }
1973 	    run_cmd ("%s %s", editor, ptr);
1974 	}
1975 	free (ptr);
1976 	ptr = empty_line;
1977     }
1978     return ptr;
1979 }
1980 
1981 char *get_filelist_line_short (void *data, int line_number, char buffer[1024]);
1982 
cursor_moved(NeXTFileBrowser * browser,NeXTDir * dir,CWidget * list_w)1983 static void cursor_moved (NeXTFileBrowser * browser, NeXTDir * dir, CWidget * list_w)
1984 {
1985     if (browser && dir && list_w) {
1986 	dir_save_position (dir, list_w->cursor, list_w->current, list_w->firstline);
1987 	if (dir->cursor >= 0) {
1988 	    char buffer[512];
1989 #if 0
1990 	    struct file_entry *item = &(dir->list[dir->cursor]);
1991 	    char *tail;
1992 #endif
1993 	    if (get_filelist_line_short (dir->list, dir->cursor, buffer))
1994 		CRedrawDynText (browser->fileattr, buffer);
1995 	}
1996     }
1997 }
1998 
1999 /*
2000    Returns "" on no file entered and NULL on exit (i.e. Cancel button pushed)
2001    else returns the file or directory. Result must be immediately copied.
2002    Result must not be free'd.
2003  */
handle_browser(const char * identifier,CEvent * cwevent,int options)2004 static char *handle_browser (const char *identifier, CEvent * cwevent, int options)
2005 {
2006 #if 0
2007     int i;
2008 #endif
2009     CWidget *w = CIdent (identifier);
2010     NeXTFileBrowser *browser;
2011     int flist = -1;
2012     char *ptr;
2013 
2014     if (!w)
2015 	return empty_line;
2016 
2017     if (cwevent->command == CK_Cancel)
2018 	return 0;
2019     if ((browser = (NeXTFileBrowser *) w->hook) == NULL)
2020 	return empty_line;
2021 
2022     /* that will be our subwidget name : */
2023     if ((ptr = strrchr (cwevent->ident, '.')) == NULL)
2024 	/* nothing to do here - messege for self */
2025 	return empty_line;
2026 
2027     ptr++;
2028     /* lets find out which one we have (starting from the shortest) */
2029     if (strcmp (ptr, "ok") == 0)
2030 	/* we take text from text input and use it as filename */
2031 	return item_selected (identifier, browser, NULL);
2032     else if (strncmp (ptr, "flist", 5) == 0)
2033 	/* all filelists ends with flistNNN */
2034 	flist = atoi (ptr + 5);	/* will process them later */
2035     else if (strcmp (ptr, "cancel") == 0)
2036 	return 0;
2037     else if (strcmp (ptr, "finp") == 0) {
2038 	if (cwevent->type == KeyPress && cwevent->command == CK_Enter)
2039 	    return item_selected (identifier, browser, NULL);
2040 	return empty_line;
2041     } else if (strcmp (ptr, "filtinp") == 0) {
2042 	if (cwevent->type == KeyPress && cwevent->command == CK_Enter)
2043 	    filter_changed (browser, browser->tree->selected);
2044 	return empty_line;
2045     }
2046     if (flist >= 0 && flist < browser->numpanes) {	/* filelist event */
2047 	NeXTDir *dir = get_dir_by_num (browser->tree, flist + browser->tree->pos);
2048 	CWidget *list_w = CIdent (browser->lists[flist]);
2049 
2050 	/* saving status */
2051 	browser->focused = flist;
2052 	browser->tree->selected = dir;
2053 
2054 	switch (cwevent->type) {
2055 	case EnterNotify:
2056 	    CFocus (list_w);
2057 	    update_filter (browser, dir);
2058 	    break;
2059 /*          case LeaveNotify :
2060    fprintf(stderr, "LeaveNotify\n");
2061    browser->focused = -1 ;
2062    CFocus( CIdent(browser->name));
2063    break ;
2064  */
2065 	case ButtonPress:
2066 	case ButtonRelease:
2067 	case MotionNotify:
2068 	    cursor_moved (browser, dir, list_w);
2069 	    if (cwevent->type != ButtonRelease)
2070 		update_input (browser, dir);
2071 	    else if (cwevent->double_click)
2072 		return item_selected (identifier, browser, dir);
2073 	    break;
2074 	case KeyPress:
2075 	    {
2076 		int scroll = 0;
2077 		switch (cwevent->command) {
2078 		case CK_Enter:
2079 		    update_input (browser, dir);
2080 		    return item_selected (identifier, browser, dir);
2081 		case CK_Up:
2082 		case CK_Down:
2083 		case CK_Page_Up:
2084 		case CK_Page_Down:
2085 		    cursor_moved (browser, dir, list_w);
2086 		    break;
2087 		case CK_Left:
2088 		    if (browser->tree->pos > 0)
2089 			scroll = -1;
2090 		    break;
2091 		case CK_Right:
2092 		    if (browser->tree->pos < browser->tree->numdirs - browser->numpanes)
2093 			scroll = 1;
2094 		    break;
2095 		case CK_Home:
2096 		    scroll = -(browser->tree->pos);
2097 		    break;
2098 		case CK_End:
2099 		    scroll = (browser->tree->numdirs - browser->numpanes) - browser->tree->pos;
2100 		    break;
2101 		case CK_BackSpace:
2102 		    /* remove last typed partial filename char */
2103 		    goto_partial_file_name (browser, dir, 0);
2104 		    break;
2105 		default:
2106 		    if (cwevent->insert > 0) {
2107 			if (cwevent->key == ' ')
2108 			    update_input (browser, dir);
2109 			else if (isprint (cwevent->key)) {
2110 			    goto_partial_file_name (browser, dir, cwevent->key);
2111 			    cursor_moved (browser, dir, list_w);
2112 			}
2113 		    }
2114 		}
2115 		if (scroll != 0) {
2116 		    browser->tree->pos += scroll;
2117 		    link_browser_to_data (browser, 0);
2118 		    dir = get_dir_by_num (browser->tree, browser->tree->pos + flist);
2119 		    update_filter (browser, dir);
2120 		    update_scrollbar (w->hori_scrollbar, browser, 1);
2121 		}
2122 	    }
2123 	    break;
2124 	default:
2125 	    break;
2126 	}
2127     }
2128     return empty_line;
2129 }
2130 
2131 Window find_mapped_window (Window w);
2132 
2133 /* result must be free'd */
look_next_get_file_or_dir(Window parent,int x,int y,const char * dir,const char * file,const char * label,int options)2134 static char *look_next_get_file_or_dir (Window parent, int x, int y,
2135        const char *dir, const char *file, const char *label, int options)
2136 {
2137     CEvent cwevent;
2138     XEvent xevent;
2139     CState s;
2140     CWidget *w;
2141 
2142     CBackupState (&s);
2143     CDisable ("*");
2144     CEnable ("_cfileBr*");
2145 
2146     parent = find_mapped_window (parent);
2147     if (!(x | y)) {
2148 	x = 20;
2149 	y = 20;
2150     }
2151     draw_file_browser ("CGetFile", parent, x, y, dir, file, label);
2152 
2153     CFocus (CIdent ("CGetFile.finp"));
2154 
2155     file = "";
2156     do {
2157 	CNextEvent (&xevent, &cwevent);
2158 	if (xevent.type == Expose || !xevent.type
2159 	    || xevent.type == InternalExpose || xevent.type == TickEvent)
2160 	    continue;
2161 	if (!CIdent ("CGetFile")) {
2162 	    file = 0;
2163 	    break;
2164 	}
2165 	if (xevent.type == Expose || !xevent.type || xevent.type == AlarmEvent
2166 	  || xevent.type == InternalExpose || xevent.type == TickEvent) {
2167 	    file = "";
2168 	    continue;
2169 	}
2170 	file = handle_browser ("CGetFile", &cwevent, options);
2171 	if (!file)
2172 	    break;
2173     } while (!(*file));
2174 
2175 /* here we want to add the complete path to the text-input history: */
2176     w = CIdent ("CGetFile.finp");
2177     if (w) {
2178 	if (w->text) {
2179 	    free (w->text);
2180 	    w->text = 0;
2181 	}
2182 	if (file)
2183 	    w->text = (char *) strdup (file);
2184     }
2185     CDestroyWidget ("CGetFile");	/* text is added to history
2186 					   when text-input widget is destroyed */
2187     CRestoreState (&s);
2188 
2189     if (file)
2190 	return (char *) ((*file) ? file : 0);
2191     else
2192 	return 0;
2193 }
2194 
2195 /*
2196    cb_browser():
2197    1) if filelist has decided that browser should be notifyed about event
2198    it sets CEvent.ident member, and we get into handle_browser.
2199    That includes events external for filelist (Left, Right, Home,
2200    End, Space, Enter, Esc) even thou filelist does no processing of it.
2201    Note also that if user types in some characters while in filelist -
2202    filelist will do search for filename, not the browser, as it was
2203    happening in original version.
2204    2) handle_browser do all the neccessary processing of received events -
2205    updates edit boxes, updates NexTDirTree status, changes dir if needed,
2206    scrolls left, right, home and end.
2207    Sasha.
2208  */
2209 
get_browser_name(char * ident,char * buffer)2210 static char *get_browser_name (char *ident, char *buffer)
2211 {
2212     char *start = buffer;
2213     while (*ident && *ident != '.')
2214 	*(buffer++) = *(ident++);
2215     *buffer = '\0';
2216 
2217     return start;
2218 }
2219 
cb_browser(CWidget * w,XEvent * x,CEvent * c)2220 static int cb_browser (CWidget * w, XEvent * x, CEvent * c)
2221 {
2222     char id[32];
2223     get_browser_name (w->ident, id);
2224     if (!handle_browser (id, c, GETFILE_BROWSER)) {
2225 	w = CIdent (catstrs (id, ".finp", NULL));
2226 	if (w)
2227 	    if (w->text) {
2228 		free (w->text);
2229 		w->text = 0;
2230 	    }
2231 	CDestroyWidget (id);
2232     }
2233     return 0;
2234 }
2235 
look_next_draw_browser(const char * ident,Window parent,int x,int y,const char * dir,const char * file,const char * label)2236 static void look_next_draw_browser (const char *ident, Window parent, int x, int y,
2237 		   const char *dir, const char *file, const char *label)
2238 {
2239     CWidget *w;
2240 
2241     if (!(parent | x | y)) {
2242 	parent = CFirstWindow;
2243 	x = 20;
2244 	y = 20;
2245     }
2246     draw_file_browser (ident, parent, x, y, dir, file, label);
2247     if ((w = CIdent (ident))) {
2248 	NeXTFileBrowser *browser = w->hook;
2249 	int i;
2250 	if (browser) {
2251 	    for (i = 0; i < browser->numpanes; i++)
2252 		CAddCallback (browser->lists[i], cb_browser);
2253 
2254 	    CAddCallback (browser->name, cb_browser);
2255 	    CAddCallback (browser->filter, cb_browser);
2256 	    CAddCallback (catstrs (ident, ".ok", NULL), cb_browser);
2257 	    CAddCallback (catstrs (ident, ".cancel", NULL), cb_browser);
2258 
2259 	    CFocus (CIdent (catstrs (ident, ".finp", NULL)));
2260 	}
2261     }
2262 }
2263 
2264 
2265 /* }}} file browser stuff */
2266 
2267 /* {{{ scrollbar extras  */
2268 
2269 #define PURENEXT
2270 /*****************************************/
2271 /* start NeXT scrollbar specific fetures */
2272 /* could be anything from 13 to 19  but the true NeXT is 17 */
2273 #define SB_WIDTH		17
2274 /* this will define somemore parameters for shaping NeXTish scrollbars */
2275 /* NEXT_SCROLL_CLEAN if defined removes shades of grey from buttons */
2276 #undef NEXT_SCROLL_CLEAN
2277 #define NEXT_SCROLL_SQUARE_ARROWS
2278 #define SB_BORDER_WIDTH 1
2279 /* this makes buttons thinner then scrollbar's base ( if more then 0 ) */
2280 #define SIDE_STEP_WIDTH 1
2281 /*  end NeXT scrollbar specific fetures  */
2282 /*****************************************/
2283 
2284 /*****************************************/
2285 /* scrollbarr configuration stuff        */
2286 
2287 #define Xdisplay CDisplay
2288 #define Xroot    CRoot
2289 #define Xdepth   CDepth
2290 
2291 static char *SCROLLER_DIMPLE[] =
2292 {
2293     ".%###.",
2294     "%#%%%%",
2295     "#%%...",
2296     "#%..  ",
2297     "#%.   ",
2298     ".%.  ."
2299 };
2300 
2301 #define SCROLLER_DIMPLE_WIDTH   6
2302 #define SCROLLER_DIMPLE_HEIGHT  6
2303 
2304 static char *SCROLLER_ARROW[4][13] =
2305 {
2306     {".............",
2307      ".............",
2308      "......%......",
2309      "......#......",
2310      ".....%#%.....",
2311      ".....###.....",
2312      "....%###%....",
2313      "....#####....",
2314      "...%#####%...",
2315      "...#######...",
2316      "..%#######%..",
2317      ".............",
2318      "............."
2319     },
2320     {".............",
2321      ".............",
2322      "..%#######%..",
2323      "...#######...",
2324      "...%#####%...",
2325      "....#####....",
2326      "....%###%....",
2327      ".....###.....",
2328      ".....%#%.....",
2329      "......#......",
2330      "......%......",
2331      ".............",
2332      "............."
2333     },
2334     {"             ",
2335      "             ",
2336      "      %      ",
2337      "      %      ",
2338      "     %%%     ",
2339      "     %%%     ",
2340      "    %%%%%    ",
2341      "    %%%%%    ",
2342      "   %%%%%%%   ",
2343      "   %%%%%%%   ",
2344      "  %%%%%%%%%  ",
2345      "             ",
2346      "             "
2347     },
2348     {"             ",
2349      "             ",
2350      "  %%%%%%%%%  ",
2351      "   %%%%%%%   ",
2352      "   %%%%%%%   ",
2353      "    %%%%%    ",
2354      "    %%%%%    ",
2355      "     %%%     ",
2356      "     %%%     ",
2357      "      %      ",
2358      "      %      ",
2359      "             ",
2360      "             "
2361     }};
2362 
2363 #define ARROW_SOURCE_WIDTH   13
2364 #define ARROW_SOURCE_HEIGHT  13
2365 
2366 typedef struct {
2367     Pixmap icon;
2368     Pixmap icon_mask;
2369     int origin_x, origin_y, width, height;
2370 } Icon;
2371 
2372 typedef struct {
2373     unsigned arrow_width, arrow_height;
2374     int bValid;
2375     Icon dimple;
2376     Icon Arrows[8];
2377     Pixmap stipple;
2378     /* this stuff is related to cache */
2379     XRectangle thumb;
2380     XRectangle buttons[2];
2381     unsigned int button_arrow[2];
2382     unsigned int width, height;
2383     int work_length;
2384     Pixmap cache;
2385 } ScrollIcons;
2386 
2387 #define UP_ARROW	(next_icons->Arrows[0])
2388 #define UP_ARROW_HI	(next_icons->Arrows[1])
2389 #define DOWN_ARROW	(next_icons->Arrows[2])
2390 #define DOWN_ARROW_HI	(next_icons->Arrows[3])
2391 
2392 #define ARROW_WIDTH   (next_icons->arrow_width)
2393 #define ARROW_HEIGHT  (next_icons->arrow_height)
2394 
2395 #define BEVEL_HI_WIDTH 1
2396 #define BEVEL_LO_WIDTH 2
2397 #define BEVEL_SIZE (BEVEL_HI_WIDTH+BEVEL_LO_WIDTH)
2398 
2399 #define SB_BUTTON_HEIGHT (BEVEL_SIZE+ARROW_HEIGHT)
2400 #define SB_BUTTONS_HEIGHT ((SB_BUTTON_HEIGHT<<1)-SIDE_STEP_WIDTH)
2401 
2402 #ifndef SB_BORDER_WIDTH
2403 #define SB_BORDER_WIDTH 1
2404 #endif
2405 #define SB_BORDER_SIZE  (SB_BORDER_WIDTH<<1)
2406 
2407 #ifndef SIDE_STEP_WIDTH
2408 #define SIDE_STEP_WIDTH 0
2409 #endif
2410 
2411 #define SB_MIN_THUMB_SIZE  (SCROLLER_DIMPLE_WIDTH+2+BEVEL_SIZE)
2412 
2413 /* end NeXT unconfigurable stuff */
2414 /*********************************/
2415 
2416 #define stp_width 8
2417 #define stp_height 8
2418 
2419 #if 0
2420 static unsigned char stp_bits[] =
2421 {
2422     0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa};
2423 #endif
2424 
2425 #undef  TRANSPARENT
2426 #define IS_TRANSP_SCROLL 0
2427 
2428 
2429 typedef struct {
2430     GC blackGC;
2431     GC whiteGC;
2432     GC darkGC;
2433     GC maskGC;
2434     GC maskGC_0;
2435 } IconGC;
2436 
init_scroll_size(ScrollIcons * next_icons)2437 static void init_scroll_size (ScrollIcons * next_icons)
2438 {
2439     ARROW_WIDTH = (SB_WIDTH - BEVEL_SIZE - SB_BORDER_SIZE - SIDE_STEP_WIDTH);
2440     ARROW_WIDTH = min (ARROW_WIDTH, ARROW_SOURCE_WIDTH);
2441 
2442 #ifdef NEXT_SCROLL_SQUARE_ARROWS
2443     ARROW_HEIGHT = ARROW_WIDTH;
2444 #else
2445     ARROW_HEIGHT = ARROW_SOURCE_HEIGHT;
2446 #endif
2447     next_icons->bValid = 1;
2448 }
2449 
2450 /* PROTO */
GetScrollArrowsHeight(ScrollIcons * next_icons)2451 unsigned GetScrollArrowsHeight (ScrollIcons * next_icons)
2452 {
2453     if (!next_icons->bValid)
2454 	init_scroll_size (next_icons);
2455     return (SB_BUTTONS_HEIGHT);
2456 }
2457 
CheckIconGC(IconGC * igc,Pixmap icon,Pixmap icon_mask)2458 static void CheckIconGC (IconGC * igc, Pixmap icon, Pixmap icon_mask)
2459 {
2460     XGCValues values;
2461     unsigned long valuemask = GCForeground | GCGraphicsExposures;
2462 
2463     values.graphics_exposures = False;
2464 
2465     if (igc == NULL)
2466 	return;
2467     if (igc->maskGC == None) {
2468 	values.foreground = 1;
2469 	igc->maskGC = XCreateGC (Xdisplay, icon_mask, valuemask, &values);
2470     }
2471     if (igc->maskGC_0 == None) {
2472 	values.foreground = 0;
2473 	igc->maskGC_0 = XCreateGC (Xdisplay, icon_mask, valuemask, &values);
2474     }
2475     if (igc->whiteGC == None) {
2476 	values.foreground = COLOR_WHITE;
2477 	igc->whiteGC = XCreateGC (Xdisplay, icon, valuemask, &values);
2478     }
2479     if (igc->darkGC == None) {
2480 	values.foreground = COLOR_DARK;
2481 	igc->darkGC = XCreateGC (Xdisplay, icon, valuemask, &values);
2482     }
2483     if (igc->blackGC == None) {
2484 	values.foreground = COLOR_BLACK;
2485 	igc->blackGC = XCreateGC (Xdisplay, icon, valuemask, &values);
2486     }
2487 }
2488 
FreeIconGC(IconGC * igc)2489 static void FreeIconGC (IconGC * igc)
2490 {
2491     if (igc) {
2492 	if (igc->maskGC != None) {
2493 	    XFreeGC (Xdisplay, igc->maskGC);
2494 	    igc->maskGC = None;
2495 	}
2496 	if (igc->maskGC_0 != None) {
2497 	    XFreeGC (Xdisplay, igc->maskGC_0);
2498 	    igc->maskGC_0 = None;
2499 	}
2500 	if (igc->whiteGC == None) {
2501 	    XFreeGC (Xdisplay, igc->whiteGC);
2502 	    igc->whiteGC = None;
2503 	}
2504 	if (igc->darkGC == None) {
2505 	    XFreeGC (Xdisplay, igc->darkGC);
2506 	    igc->darkGC = None;
2507 	}
2508 	if (igc->blackGC != None) {
2509 	    XFreeGC (Xdisplay, igc->blackGC);
2510 	    igc->blackGC = None;
2511 	}
2512     }
2513 }
2514 
renderIcon(Window win,char ** data,Icon * pIcon,IconGC * igc,Bool rotate)2515 static void renderIcon (Window win, char **data, Icon * pIcon, IconGC * igc, Bool rotate)
2516 {
2517     Pixmap d, mask;
2518     register int i, k;
2519     int x, y, max_x, max_y;
2520     GC maskgc, paintgc;
2521     char pixel;
2522 
2523     d = XCreatePixmap (Xdisplay, win, pIcon->width, pIcon->height, Xdepth);
2524     mask = XCreatePixmap (Xdisplay, win, pIcon->width, pIcon->height, 1);
2525 
2526     if (rotate) {
2527 	max_x = pIcon->height;
2528 	max_y = pIcon->width;
2529     } else {
2530 	max_x = pIcon->width;
2531 	max_y = pIcon->height;
2532     }
2533 
2534     CheckIconGC (igc, d, mask);
2535     y = pIcon->origin_y;
2536 
2537     for (i = 0; i < max_y; y++, i++) {
2538 	x = pIcon->origin_x;
2539 	for (k = 0; k < max_x; k++, x++) {
2540 	    maskgc = igc->maskGC;
2541 	    if (rotate)
2542 		pixel = data[x][y];
2543 	    else
2544 		pixel = data[y][x];
2545 	    switch (pixel) {
2546 	    case ' ':
2547 	    case 'w':
2548 		paintgc = igc->whiteGC;
2549 		break;
2550 	    case '%':
2551 	    case 'd':
2552 		paintgc = igc->darkGC;
2553 		break;
2554 	    case '#':
2555 	    case 'b':
2556 		paintgc = igc->blackGC;
2557 		break;
2558 	    case '.':
2559 	    case 'l':
2560 	    default:
2561 		paintgc = CGC;
2562 		maskgc = igc->maskGC_0;
2563 		break;
2564 	    }
2565 	    XDrawPoint (Xdisplay, d, paintgc, k, i);
2566 	    XDrawPoint (Xdisplay, mask, maskgc, k, i);
2567 	}
2568     }
2569 
2570     pIcon->icon = d;
2571     pIcon->icon_mask = mask;
2572 }
2573 
2574 static ScrollIcons *
init_next_icons(Window win)2575  init_next_icons (Window win)
2576 {
2577     unsigned arrow_x_offset, arrow_y_offset;
2578     IconGC icongc =
2579     {None, None, None, None};
2580     int i;
2581     ScrollIcons *next_icons = calloc (1, sizeof (ScrollIcons));
2582 
2583     if (next_icons == NULL)
2584 	return next_icons;
2585 
2586     CSetColor (COLOR_FLAT);
2587 
2588     next_icons->dimple.width = SCROLLER_DIMPLE_WIDTH;
2589     next_icons->dimple.height = SCROLLER_DIMPLE_WIDTH;
2590     renderIcon (win, SCROLLER_DIMPLE, &(next_icons->dimple), &icongc, False);
2591 
2592     init_scroll_size (next_icons);
2593     arrow_x_offset = (ARROW_SOURCE_WIDTH - ARROW_WIDTH) >> 1;
2594 #ifdef NEXT_SCROLL_SQUARE_ARROWS
2595     arrow_y_offset = arrow_x_offset;
2596 #else
2597     arrow_y_offset = 0;		/* not implemented yet */
2598 #endif
2599 
2600     for (i = 0; i < 4; i++) {
2601 	next_icons->Arrows[i].origin_x = arrow_x_offset;
2602 	next_icons->Arrows[i].origin_y = arrow_y_offset;
2603 	next_icons->Arrows[i].width = ARROW_WIDTH;
2604 	next_icons->Arrows[i].height = ARROW_HEIGHT;
2605 	renderIcon (win, SCROLLER_ARROW[i], &(next_icons->Arrows[i]), &icongc, False);
2606     }
2607     for (; i < 8; i++) {
2608 	next_icons->Arrows[i].origin_x = arrow_y_offset;
2609 	next_icons->Arrows[i].origin_y = arrow_x_offset;
2610 	next_icons->Arrows[i].width = ARROW_HEIGHT;
2611 	next_icons->Arrows[i].height = ARROW_WIDTH;
2612 	renderIcon (win, SCROLLER_ARROW[i - 4], &(next_icons->Arrows[i]), &icongc, True);
2613     }
2614 
2615     FreeIconGC (&icongc);
2616 
2617     next_icons->stipple = XCreatePixmap (Xdisplay, win, 2, 2, Xdepth);
2618     XDrawPoint (Xdisplay, next_icons->stipple, CGC, 0, 0);
2619     XDrawPoint (Xdisplay, next_icons->stipple, CGC, 1, 1);
2620 
2621     CSetColor (COLOR_DARK);
2622     XDrawPoint (Xdisplay, next_icons->stipple, CGC, 0, 1);
2623     XDrawPoint (Xdisplay, next_icons->stipple, CGC, 1, 0);
2624 
2625     return next_icons;
2626 }
2627 
free_next_icons(void * ptr)2628 void free_next_icons (void *ptr)
2629 {
2630     ScrollIcons *next_icons = (ScrollIcons *) ptr;
2631     if (next_icons) {
2632 	register int i;
2633 	if (next_icons->dimple.icon) {
2634 	    XFreePixmap (Xdisplay, next_icons->dimple.icon);
2635 	    next_icons->dimple.icon = None;
2636 	}
2637 	if (next_icons->stipple) {
2638 	    XFreePixmap (Xdisplay, next_icons->stipple);
2639 	    next_icons->stipple = None;
2640 	}
2641 	for (i = 0; i < 4; i++)
2642 	    if (next_icons->Arrows[i].icon) {
2643 		XFreePixmap (Xdisplay, next_icons->Arrows[i].icon);
2644 		next_icons->Arrows[i].icon = None;
2645 	    }
2646 	if (next_icons->cache) {
2647 	    XFreePixmap (Xdisplay, next_icons->cache);
2648 	    next_icons->cache = None;
2649 	}
2650     }
2651 }
2652 
render_next_icon(Drawable d,Icon * i,int x,int y)2653 static void render_next_icon (Drawable d, Icon * i, int x, int y)
2654 {
2655 #ifdef TRANSPARENT
2656     if (IS_TRANSP_SCROLL) {
2657 	XSetClipMask (Xdisplay, CGC, i->icon_mask);
2658 	XSetClipOrigin (Xdisplay, CGC, x, y);
2659     }
2660 #endif
2661     XCopyArea (Xdisplay, i->icon, d, CGC, 0, 0,
2662 	       i->width, i->height, x, y);
2663 
2664 #ifdef TRANSPARENT
2665     if (IS_TRANSP_SCROLL)
2666 	XSetClipMask (Xdisplay, CGC, None);
2667 #endif
2668 }
2669 
2670 
2671 /* Draw bezel & arrows */
render_next_button(Drawable d,XRectangle * rec,Icon * icon,Bool pressed)2672 static void render_next_button (Drawable d, XRectangle * rec, Icon * icon, Bool pressed)
2673 {
2674     int x2 = rec->x + rec->width - 1, y2 = rec->y + rec->height - 1;
2675     CSetColor ((pressed) ? COLOR_BLACK : COLOR_WHITE);
2676 
2677     CLine (d, rec->x, rec->y, rec->x, y2);
2678     CLine (d, rec->x, rec->y, x2, rec->y);
2679 
2680     CSetColor ((pressed) ? COLOR_WHITE : COLOR_BLACK);
2681     CLine (d, rec->x, y2, x2, y2);
2682     CLine (d, x2, y2, x2, rec->y);
2683 
2684     if (!pressed)
2685 	CSetColor (COLOR_FLAT);
2686 
2687     CRectangle (d, rec->x + 1, rec->y + 1, rec->width - 3, rec->height - 3);
2688 
2689     render_next_icon (d, icon, rec->x + ((rec->width - icon->width) / 2),
2690 		      rec->y + ((rec->height - icon->height) / 2));
2691 }
2692 
check_cache(ScrollIcons * next_icons,Window win,int width,int height,int pos,int prop,int flags)2693 Bool check_cache (ScrollIcons * next_icons, Window win, int width, int height, int pos, int prop, int flags)
2694 {
2695     unsigned int l, wl, thumb_start, thumb_length;
2696     unsigned int button_arrow[2];
2697 #if 0
2698     int cache_valid = 0;
2699 #endif
2700 
2701     if (width > height) {
2702 	if (height > SB_WIDTH + SB_BORDER_SIZE)		/* vertical */
2703 	    height = SB_WIDTH + SB_BORDER_SIZE;
2704 	l = width;
2705     } else {
2706 	if (width > SB_WIDTH + SB_BORDER_SIZE)
2707 	    width = SB_WIDTH + SB_BORDER_SIZE;
2708 	l = height;
2709     }
2710     wl = l - SB_BORDER_SIZE - SB_BUTTONS_HEIGHT - SIDE_STEP_WIDTH;
2711 
2712     button_arrow[0] = 0;
2713     button_arrow[1] = 1;
2714 
2715     if (prop == 65535 || prop == 0) {
2716 	thumb_length = 0;
2717 	thumb_start = 0;
2718     } else {
2719 	thumb_length = (double) (wl * prop) / 65535.0;
2720 	if (thumb_length < SB_MIN_THUMB_SIZE) {
2721 	    wl -= SB_MIN_THUMB_SIZE - thumb_length;
2722 	    thumb_length = SB_MIN_THUMB_SIZE;
2723 	} else if (thumb_length > wl)
2724 	    thumb_length = wl;
2725 
2726 	if (pos >= 65535 - prop - 1)
2727 	    thumb_start = l - thumb_length - SB_BUTTONS_HEIGHT;
2728 	else
2729 	    thumb_start = ((double) (wl * pos) / 65535.0) + SB_BORDER_WIDTH;
2730 
2731 	if (thumb_start - SB_BORDER_WIDTH > wl - thumb_length)
2732 	    thumb_start = SB_BORDER_WIDTH + wl - thumb_length;
2733 	if (thumb_start < SB_BORDER_WIDTH)
2734 	    thumb_start = SB_BORDER_WIDTH;
2735 
2736 	next_icons->work_length = wl;
2737 
2738 	if (!(flags & 0x20)) {
2739 	    if ((flags & 0x0f) == 2)
2740 		button_arrow[0] = 2;
2741 	    if ((flags & 0x0f) == 5)
2742 		button_arrow[1] = 3;
2743 	}
2744     }
2745     if (l != height) {
2746 	button_arrow[0] += 4;
2747 	button_arrow[1] += 4;
2748     }
2749     if (next_icons->cache) {
2750 	if (width == next_icons->width && height == next_icons->height) {
2751 	    if (button_arrow[0] == next_icons->button_arrow[0] &&
2752 		button_arrow[1] == next_icons->button_arrow[1]) {
2753 		if (l == height) {
2754 		    if (next_icons->thumb.height == thumb_length &&
2755 			next_icons->thumb.y == thumb_start)
2756 			return True;
2757 		} else if (next_icons->thumb.width == thumb_length &&
2758 			   next_icons->thumb.x == thumb_start)
2759 		    return True;
2760 	    }
2761 	} else {
2762 	    XFreePixmap (Xdisplay, next_icons->cache);
2763 	    next_icons->cache = None;
2764 	}
2765     }
2766     next_icons->button_arrow[0] = button_arrow[0];
2767     next_icons->button_arrow[1] = button_arrow[1];
2768 
2769     if (l == height) {
2770 	next_icons->thumb.height = thumb_length;
2771 	next_icons->thumb.y = thumb_start;
2772 	next_icons->thumb.width = SB_WIDTH;
2773 	next_icons->thumb.x = SB_BORDER_WIDTH;
2774     } else {
2775 	next_icons->thumb.width = thumb_length;
2776 	next_icons->thumb.x = thumb_start;
2777 	next_icons->thumb.height = SB_WIDTH;
2778 	next_icons->thumb.y = SB_BORDER_WIDTH;
2779     }
2780     if (next_icons->cache == None) {	/* create double buffer */
2781 	next_icons->cache = XCreatePixmap (Xdisplay, win, width, height, Xdepth);
2782 	next_icons->width = width;
2783 	next_icons->height = height;
2784 	if (l == height) {
2785 	    next_icons->buttons[0].x = next_icons->buttons[1].x = SB_BORDER_WIDTH;
2786 	    next_icons->buttons[0].width = next_icons->buttons[1].width = SB_WIDTH;
2787 	    next_icons->buttons[0].height = next_icons->buttons[1].height = SB_BUTTON_HEIGHT;
2788 	    next_icons->buttons[1].y = l - next_icons->buttons[1].height - SIDE_STEP_WIDTH;
2789 	    next_icons->buttons[0].y = next_icons->buttons[1].y - next_icons->buttons[0].height;
2790 	} else {
2791 	    next_icons->buttons[0].y = next_icons->buttons[1].y = SB_BORDER_WIDTH;
2792 	    next_icons->buttons[0].height = next_icons->buttons[1].height = SB_WIDTH;
2793 	    next_icons->buttons[0].width = next_icons->buttons[1].width = SB_BUTTON_HEIGHT;
2794 	    next_icons->buttons[1].x = l - next_icons->buttons[1].width - SIDE_STEP_WIDTH;
2795 	    next_icons->buttons[0].x = next_icons->buttons[1].x - next_icons->buttons[0].width;
2796 	}
2797     }
2798     return False;
2799 }
2800 
scrollbar_fill_back(ScrollIcons * next_icons)2801 void scrollbar_fill_back (ScrollIcons * next_icons)
2802 {
2803     int x2, y2;
2804     register int i;
2805 
2806     /* draw the background */
2807     XSetTile (Xdisplay, CGC, next_icons->stipple);
2808     XSetFillStyle (Xdisplay, CGC, FillTiled);
2809     XSetTSOrigin (Xdisplay, CGC, 0, 0);
2810 
2811     CSetColor (COLOR_WHITE);
2812     CRectangle (next_icons->cache,
2813 		SB_BORDER_WIDTH, SB_BORDER_WIDTH,
2814 		(next_icons->width) - SB_BORDER_SIZE,
2815 		(next_icons->height) - SB_BORDER_SIZE);
2816 
2817     XSetTile (Xdisplay, CGC, None);
2818     XSetFillStyle (Xdisplay, CGC, FillSolid);
2819 
2820     x2 = next_icons->width - 1;
2821     y2 = next_icons->height - 1;
2822 
2823     CSetColor (COLOR_WHITE);
2824     for (i = 0; i < SB_BORDER_WIDTH; i++) {
2825 	CLine (next_icons->cache, i, y2 - i, x2 - i, y2 - i);
2826 	CLine (next_icons->cache, x2 - i, y2 - i, x2 - i, i);
2827     }
2828     CSetColor (COLOR_BLACK);
2829     for (i = 0; i < SB_BORDER_WIDTH; i++) {
2830 	CLine (next_icons->cache, i, y2 - i, i, i);
2831 	CLine (next_icons->cache, i, i, x2 - i, i);
2832     }
2833 
2834 
2835 }
2836 
render_next_scrollbar(ScrollIcons * next_icons,Window win,int x,int y,int width,int height,int pos,int prop,int flags)2837 int render_next_scrollbar (ScrollIcons * next_icons, Window win, int x, int y, int width, int height, int pos, int prop, int flags)
2838 {
2839     int cache_valid;
2840 
2841     cache_valid = check_cache (next_icons, win, width, height, pos, prop, flags);
2842 /*fprintf( stderr, "%dx%d,pos: %d, prop: %d ->%s, whole: %dx%d, thumb: %dx%d%+d%+d\n",
2843    width, height, pos, prop,
2844    (cache_valid)?"Cached":"Redrawing",
2845    next_icons->width, next_icons->height,
2846    next_icons->thumb.width, next_icons->thumb.height,
2847    next_icons->thumb.x, next_icons->thumb.y );
2848  */ if (!cache_valid) {
2849 	int i;
2850 	scrollbar_fill_back (next_icons);
2851 	if (next_icons->thumb.width > 0 &&
2852 	    next_icons->thumb.height > 0) {
2853 	    render_next_button (next_icons->cache,
2854 				&(next_icons->thumb),
2855 				&(next_icons->dimple),
2856 				False);
2857 	    for (i = 0; i < 2; i++) {
2858 		render_next_button (next_icons->cache,
2859 				    &(next_icons->buttons[i]),
2860 		      &(next_icons->Arrows[next_icons->button_arrow[i]]),
2861 				    (next_icons->button_arrow[i] & 0x02));
2862 	    }
2863 	}
2864     }
2865     XCopyArea (Xdisplay, next_icons->cache, win, CGC, 0, 0, next_icons->width, next_icons->height, 0, 0);
2866     return 1;
2867 }
2868 
2869 /* }}} end scrollbar extras */
2870 
2871 int find_menu_hotkey (struct menu_item m[], int this, int num);
2872 
2873 /* outermost bevel */
2874 #define BEVEL_MAIN	1
2875 /* next-outermost bevel */
2876 #define BEVEL_IN 	1
2877 #define BEVEL_OUT	1
2878 /* between items, and between items and next-outermost bevel */
2879 #define SPACING		0
2880 
2881 /* between items rectangle and text */
2882 #define RELIEF		4
2883 
2884 #define S		SPACING
2885 /* between window border and items */
2886 #define O		(BEVEL_OUT + SPACING)
2887 /* total height of an item */
2888 
2889 /* size of bar item */
2890 #define BAR_HEIGHT	H
2891 #define ITEM_BEVEL_TYPE 0
2892 #define ITEM_BEVEL      1
2893 
2894 #define H		(FONT_PIX_PER_LINE + RELIEF * 2 + 1)
2895 
2896 #define B		BAR_HEIGHT
2897 
look_next_get_default_widget_font(void)2898 static char *look_next_get_default_widget_font (void)
2899 {
2900     return "-*-fixed-medium-r-normal--%d-*-*-*-*-*-*";
2901 }
2902 
look_next_get_menu_item_extents(int n,int j,struct menu_item m[],int * border,int * relief,int * y1,int * y2)2903 static void look_next_get_menu_item_extents (int n, int j, struct menu_item m[], int *border, int *relief, int *y1, int *y2)
2904 {
2905     int i, n_items = 0, n_bars = 0;
2906 
2907     *border = O;
2908     *relief = RELIEF;
2909 
2910     if (!n || j < 0) {
2911 	*y1 = O;
2912 	*y2 = *y1 + H;
2913     } else {
2914 	int not_bar;
2915 	not_bar = 1;
2916 	for (i = 0; i < j; i++)
2917 	    if (m[i].text[2])
2918 		n_items++;
2919 	    else
2920 		n_bars++;
2921 	*y1 = O + n_items * (H + S) + n_bars * (B + S) + (not_bar ? 0 : 2);
2922 	*y2 = *y1 + (not_bar ? H : (B - 4));
2923     }
2924 }
2925 
look_next_menu_draw(Window win,int w,int h,struct menu_item m[],int n,int light)2926 static void look_next_menu_draw (Window win, int w, int h, struct menu_item m[], int n, int light)
2927 {
2928     int i, y1, y2, offset = 0;
2929     static int last_light = 0, last_n = 0;
2930     static Window last_win = 0;
2931 
2932     if (last_win == win && last_n != n) {
2933 	XClearWindow (CDisplay, win);
2934 	render_bevel (win, 0, 0, w - 1, h - 1, BEVEL_MAIN, 0);
2935 	render_bevel (win, BEVEL_IN, BEVEL_IN, w - 1 - BEVEL_IN, h - 1 - BEVEL_IN, BEVEL_OUT - BEVEL_IN, 1);
2936     } else if (last_light >= 0 && last_light < n) {
2937 	int border, relief;
2938 	look_next_get_menu_item_extents (n, last_light, m, &border, &relief, &y1, &y2);
2939 	CSetColor (COLOR_FLAT);
2940 	CRectangle (win, O + 1, y1 - 1, w - O * 2 + 2, y2 - y1 + 2);
2941     }
2942     last_win = win;
2943     last_n = n;
2944     CPushFont ("widget", 0);
2945     for (i = 0; i < n; i++) {
2946 	int border, relief;
2947 	look_next_get_menu_item_extents (n, i, m, &border, &relief, &y1, &y2);
2948 	render_bevel (win, O, y1, w - O - 1, y2 - 1, ITEM_BEVEL, ITEM_BEVEL_TYPE);
2949 	if (i == light && m[i].text[2]) {
2950 	    CSetColor (color_widget (14));
2951 	    CRectangle (win, O + 1, y1 + 1, w - O * 2 - 4, y2 - y1 - 4);
2952 	}
2953 	if (m[i].text[2]) {
2954 	    char *u;
2955 	    u = strrchr (m[i].text, '\t');
2956 	    if (u)
2957 		*u = 0;
2958 	    CSetColor (COLOR_BLACK);
2959 	    if (m[i].hot_key == '~')
2960 		m[i].hot_key = find_menu_hotkey (m, i, n);
2961 	    if (i == light)
2962 		CSetBackgroundColor (color_widget (14));
2963 	    else
2964 		CSetBackgroundColor (COLOR_FLAT);
2965 	    drawstring_xy_hotkey (win, RELIEF + O - offset, RELIEF + y1 - offset, m[i].text, m[i].hot_key);
2966 	    if (u) {
2967 		drawstring_xy (win, RELIEF + O + (w - (O + RELIEF) * 2 - CImageStringWidth (u + 1)) - offset,
2968 			       RELIEF + y1 - offset, u + 1);
2969 		*u = '\t';
2970 	    }
2971 	}
2972     }
2973     last_light = light;
2974     CPopFont ();
2975 }
2976 
look_next_render_menu_button(CWidget * wdt)2977 static void look_next_render_menu_button (CWidget * wdt)
2978 {
2979     int w = wdt->width, h = wdt->height;
2980     int x = 0, y = 0;
2981 
2982     Window win = wdt->winid;
2983 
2984     if (wdt->disabled || !((wdt->droppedmenu) ||
2985 		 (wdt->options & (BUTTON_PRESSED | BUTTON_HIGHLIGHT)))) {
2986 	CSetColor (COLOR_FLAT);
2987 	CRectangle (win, x, y, x + w, y + h);
2988 	CSetColor (COLOR_BLACK);
2989 	CSetBackgroundColor (COLOR_FLAT);
2990     } else {
2991 	CSetColor (COLOR_DARK);
2992 	CRectangle (win, x, y, x + w - 1, y + h - 1);
2993 	if (wdt->options & BUTTON_PRESSED)
2994 	    render_bevel (win, x, y, x + w - 1, y + h - 1, 2, 1);
2995 	CSetColor (COLOR_WHITE);
2996 	CSetBackgroundColor (COLOR_DARK);
2997     }
2998     if (!wdt->label)
2999 	return;
3000     if (!(*(wdt->label)))
3001 	return;
3002     CPushFont ("widget", 0);
3003     drawstring_xy_hotkey (win, x + 2 + BUTTON_RELIEF, y + 2 + BUTTON_RELIEF, wdt->label, wdt->hotkey);
3004     CPopFont ();
3005 }
3006 
look_next_render_button(CWidget * wdt)3007 static void look_next_render_button (CWidget * wdt)
3008 {
3009     int w = wdt->width, h = wdt->height;
3010     int x = 0, y = 0;
3011 
3012     Window win = wdt->winid;
3013 #define BUTTON_BEVEL 1
3014 
3015     if((wdt->options & BUTTON_HIGHLIGHT) && !wdt->disabled)
3016     {
3017 	CSetColor (COLOR_BLACK);
3018 	XDrawRectangle (CDisplay, win, CGC, x, y, w-1, h-1);
3019     } else
3020         render_bevel (win, x, y, x + w - 1, y + h - 1, BUTTON_BEVEL, ( wdt->options & BUTTON_PRESSED )?1:0);
3021 
3022     if (!wdt->label)
3023 	return;
3024     if (!(*(wdt->label)))
3025 	return;
3026     CSetColor (COLOR_BLACK);
3027     CSetBackgroundColor (COLOR_FLAT);
3028     CPushFont ("widget", 0);
3029     drawstring_xy_hotkey (win, x + 2 + BUTTON_RELIEF, y + 2 + BUTTON_RELIEF, wdt->label, wdt->hotkey);
3030     CPopFont ();
3031 }
3032 
look_next_render_bar(CWidget * wdt)3033 static void look_next_render_bar (CWidget * wdt)
3034 {
3035     int w = wdt->width, h = wdt->height;
3036 
3037     Window win = wdt->winid;
3038 
3039     CSetColor (COLOR_FLAT);
3040     CLine (win, 1, 1, w - 2, 1);
3041     render_bevel (win, 0, 0, w - 1, h - 1, 1, 1);
3042 }
3043 
look_next_render_sunken_bevel(Window win,int x1,int y1,int x2,int y2,int thick,int sunken)3044 static void look_next_render_sunken_bevel (Window win, int x1, int y1, int x2, int y2, int thick,
3045 					   int sunken)
3046 {
3047     int i;
3048     if ((sunken & 2) && (y2 - y1 - 2 * thick + 1 > 0) && (x2 - x1 - 2 * thick + 1 > 0)) {
3049 	CSetColor (COLOR_FLAT);
3050 	CRectangle (win, x1 + thick, y1 + thick, x2 - x1 - 2 * thick + 1, y2 - y1 - 2 * thick + 1);
3051     }
3052     CSetColor (COLOR_BLACK);
3053     CLine (win, x1, y1, x2, y1);
3054     CLine (win, x1, y1, x1, y2);
3055 
3056     CSetColor (COLOR_WHITE);
3057     for (i = 0; i < thick; i++) {
3058 	CLine (win, x2 - i, y1 + i, x2 - i, y2 - i);
3059 	CLine (win, x1 + i, y2 - i, x2 - i, y2 - i);
3060     }
3061     if (x2 - x1 - i > 0)
3062 	XClearArea (CDisplay, win, x1 + i, y1 + i, x2 - x1 - i, 1, False);
3063     if (y2 - y1 - i > 0)
3064 	XClearArea (CDisplay, win, x1 + i, y1 + i, 1, y2 - y1 - i, False);
3065 
3066     CSetColor (COLOR_DARK);
3067     XDrawPoint (CDisplay, win, CGC, x1, y2);
3068     XDrawPoint (CDisplay, win, CGC, x2, y1);
3069     x1++;
3070     x2--;
3071     y1++;
3072     y2--;
3073     for (i = 0; i < thick; i++) {
3074 	CLine (win, x1 + i, y2 - i, x1 + i, y1 + i);
3075 	CLine (win, x1 + i, y1 + i, x2 - i, y1 + i);
3076     }
3077 }
3078 
look_next_render_raised_bevel(Window win,int x1,int y1,int x2,int y2,int thick,int sunken)3079 static void look_next_render_raised_bevel (Window win, int x1, int y1, int x2, int y2, int thick,
3080 					   int sunken)
3081 {
3082     int i;
3083     if ((sunken & 2) && (y2 - y1 - 2 * thick + 1 > 0) && (x2 - x1 - 2 * thick + 1 > 0)) {
3084 	CSetColor (COLOR_FLAT);
3085 	CRectangle (win, x1 + thick, y1 + thick, x2 - x1 - 2 * thick + 1, y2 - y1 - 2 * thick + 1);
3086     }
3087     CSetColor (COLOR_WHITE);
3088     for (i = 0; i < thick; i++) {
3089 	CLine (win, x1 + i, y1 + i, x2 - i, y1 + i);
3090 	CLine (win, x1 + i, y1 + i, x1 + i, y2 - i);
3091     }
3092 
3093     if (x2 - x1 - i > 0)
3094 	XClearArea (CDisplay, win, x1 + i, y1 + i, x2 - x1 - i, 1, False);
3095     if (y2 - y1 - i > 0)
3096 	XClearArea (CDisplay, win, x1 + i, y1 + i, 1, y2 - y1 - i, False);
3097 
3098     CSetColor (COLOR_BLACK);
3099     CLine (win, x2, y1, x2, y2);
3100     CLine (win, x1, y2, x2, y2);
3101     CSetColor (COLOR_DARK);
3102     XDrawPoint (CDisplay, win, CGC, x1, y2);
3103     XDrawPoint (CDisplay, win, CGC, x2, y1);
3104     x1++;
3105     x2--;
3106     y1++;
3107     y2--;
3108     for (i = 0; i < thick; i++) {
3109 	CLine (win, x1 + i, y2 - i, x2 - i, y2 - i);
3110 	CLine (win, x2 - i, y1 + i, x2 - i, y2 - i);
3111     }
3112 }
3113 
look_next_draw_hotkey_understroke(Window win,int x,int y,int hotkey)3114 static void look_next_draw_hotkey_understroke (Window win, int x, int y, int hotkey)
3115 {
3116     CLine (win, x+1, y , x + FONT_PER_CHAR (hotkey) - 2, y);
3117     y++;
3118     CLine (win, x+1, y, x + FONT_PER_CHAR (hotkey) - 2, y);
3119 }
3120 
look_next_render_text(CWidget * wdt)3121 static void look_next_render_text (CWidget * wdt)
3122 {
3123     Window win = wdt->winid;
3124     char text[1024], *p, *q;
3125     int hot, y, w = wdt->width, center = 0;
3126     int releif = 1 ;
3127 
3128     releif += TEXT_RELIEF ;
3129     CSetColor (COLOR_FLAT);
3130     CRectangle (win, 1, 1, w - 2, wdt->height - 2);
3131     CSetColor (COLOR_BLACK);
3132 
3133     hot = wdt->hotkey;		/* a letter that needs underlining */
3134     y = 1;			/* bevel */
3135     q = wdt->text;
3136     CPushFont ("widget", 0);
3137     CSetBackgroundColor (COLOR_FLAT);
3138     for (;;) {
3139 	p = strchr (q, '\n');
3140 	if (!p) {		/* last line */
3141 	    if (wdt->options & TEXT_CENTRED)
3142 		center = (wdt->width - releif * 2 - CImageTextWidth (q, strlen (q))) / 2;
3143 	    drawstring_xy_hotkey (win, releif + center, releif + y - 1, q, hot);
3144 	    break;
3145 	} else {
3146 	    int l;
3147 	    l = min (1023, (unsigned long) p - (unsigned long) q);
3148 	    memcpy (text, q, l);
3149 	    text[l] = 0;
3150 	    if (wdt->options & TEXT_CENTRED)
3151 		center = (wdt->width - releif * 2 - CImageTextWidth (q, l)) / 2;
3152 	    drawstring_xy_hotkey (win, releif + center, releif + y - 1, text, hot);
3153 	}
3154 	y += FONT_PIX_PER_LINE;
3155 	hot = 0;		/* only for first line */
3156 	q = p + 1;		/* next line */
3157     }
3158     CPopFont ();
3159 }
3160 
3161 #define NEXT_HANDLE	  25
3162 #define NEXT_LOWBAR       7
3163 
look_next_render_window(CWidget * wdt)3164 static void look_next_render_window (CWidget * wdt)
3165 {
3166     int w = wdt->width, h = wdt->height;
3167 
3168     Window win = wdt->winid;
3169 
3170     if (wdt->options & WINDOW_NO_BORDER)
3171 	return;
3172     if ((wdt->position & WINDOW_RESIZABLE) && CRoot != wdt->parentid) {
3173 	CSetColor (COLOR_FLAT);
3174 	CRectangle (win, 0, 0, w - 1, h - 1);
3175 	render_bevel (win, 1, h - NEXT_LOWBAR - 1, NEXT_HANDLE + 1, h - 1, 1, 0);
3176 	render_bevel (win, NEXT_HANDLE + 2, h - NEXT_LOWBAR - 1, w - NEXT_HANDLE - 3, h - 1, 1, 0);
3177 	render_bevel (win, w - NEXT_HANDLE - 2, h - NEXT_LOWBAR - 1, w - 1, h - 1, 1, 0);
3178     }
3179     render_bevel (win, 0, 0, w - 1, h - 1, 2, 0);
3180     if (CRoot != wdt->parentid)
3181 	if (win == CGetFocus ())
3182 	    render_bevel (win, 4, 4, w - 5, h - 5, 3, 1);
3183 }
3184 
look_next_render_scrollbar(CWidget * wdt)3185 static void look_next_render_scrollbar (CWidget * wdt)
3186 {
3187     int pos, prop;
3188     int flags = wdt->options;
3189     if (!wdt)
3190 	return;
3191 
3192     pos = wdt->firstline;
3193     prop = wdt->numlines;
3194 
3195     if (prop < 0)
3196 	prop = 0;
3197     if (pos < 0)
3198 	pos = 0;
3199     if (pos > 65535)
3200 	pos = 65535;
3201     if (pos + prop >= 65535)
3202 	prop = 65535 - pos;
3203 
3204     render_next_scrollbar ((ScrollIcons *) wdt->user, wdt->winid,
3205 			   wdt->x, wdt->y, wdt->width, wdt->height,
3206 			   pos, prop, flags);
3207 
3208     if (wdt->scroll_bar_extra_render)
3209 	(*wdt->scroll_bar_extra_render) (wdt);
3210 }
3211 
3212 /*
3213    Which scrollbar button was pressed: 3 is the middle button ?
3214  */
look_next_which_scrollbar_button(int bx,int by,CWidget * wdt)3215 static int look_next_which_scrollbar_button (int bx, int by, CWidget * wdt)
3216 {
3217 #if 0
3218     int pos;
3219     int prop;
3220 #endif
3221     ScrollIcons *next_icons = (ScrollIcons *) wdt->user;
3222 /*
3223    fprintf( stderr, "button: (%d,%d) thumb: (%d,%d)\n",bx, by, next_icons->thumb.x, next_icons->thumb.y  );
3224  */
3225     if (wdt->kind == C_VERTSCROLL_WIDGET) {
3226 	if (by > 0 && by < next_icons->thumb.y)
3227 	    return 1;
3228 	if (by >= next_icons->thumb.y &&
3229 	    by <= next_icons->thumb.y + next_icons->thumb.height)
3230 	    return 3;
3231 	if (by > next_icons->thumb.y + next_icons->thumb.height &&
3232 	    by < next_icons->buttons[0].y)
3233 	    return 4;
3234 	if (by >= next_icons->buttons[0].y &&
3235 	  by <= next_icons->buttons[0].y + next_icons->buttons[0].height)
3236 	    return 2;
3237 	if (by >= next_icons->buttons[1].y &&
3238 	  by <= next_icons->buttons[1].y + next_icons->buttons[1].height)
3239 	    return 5;
3240     } else {
3241 	if (bx > 0 && bx < next_icons->thumb.x)
3242 	    return 1;
3243 	if (bx >= next_icons->thumb.x &&
3244 	    bx <= next_icons->thumb.x + next_icons->thumb.width)
3245 	    return 3;
3246 	if (bx > next_icons->thumb.x + next_icons->thumb.width &&
3247 	    bx < next_icons->buttons[0].x)
3248 	    return 4;
3249 	if (bx >= next_icons->buttons[0].x &&
3250 	    bx <= next_icons->buttons[0].x + next_icons->buttons[0].width)
3251 	    return 2;
3252 	if (bx >= next_icons->buttons[1].x &&
3253 	    bx <= next_icons->buttons[1].x + next_icons->buttons[1].width)
3254 	    return 5;
3255 
3256     }
3257     return 0;
3258 }
3259 
look_next_scrollbar_handler(CWidget * w,XEvent * xevent,CEvent * cwevent)3260 static int look_next_scrollbar_handler (CWidget * w, XEvent * xevent, CEvent * cwevent)
3261 {
3262     static int buttonypos, y, offset, whichscrbutton = 0;	/* which of the five scroll bar buttons was pressed */
3263     int xevent_xbutton_y, length, width, thumb_pos;
3264     ScrollIcons *next_icons = (ScrollIcons *) w->user;
3265 
3266     if (w->kind == C_VERTSCROLL_WIDGET) {
3267 	xevent_xbutton_y = xevent->xbutton.y;
3268 	length = w->height - SB_BUTTONS_HEIGHT - SB_BORDER_SIZE - next_icons->thumb.height;
3269 	width = w->width;
3270 	thumb_pos = next_icons->thumb.y;
3271     } else {
3272 	xevent_xbutton_y = xevent->xbutton.x;
3273 	length = w->width - SB_BUTTONS_HEIGHT - SB_BORDER_SIZE - next_icons->thumb.width;
3274 	width = w->height;
3275 	thumb_pos = next_icons->thumb.x;
3276     }
3277 
3278     if (next_icons->thumb.width == 0 || next_icons->thumb.height == 0) {
3279 	if (xevent->type == Expose && !xevent->xexpose.count)
3280 	    render_scrollbar (w);
3281 	return 0;
3282     }
3283     switch (xevent->type) {
3284 /*    case LeaveNotify:
3285  */
3286     case Expose:
3287 	w->options = whichscrbutton = 0;
3288 	break;
3289     case ButtonRepeat:
3290 	resolve_button (xevent, cwevent);
3291 	if (whichscrbutton != 3 &&
3292 	    (cwevent->button == Button1 || cwevent->button == Button2)) {
3293 	    int b;
3294 	    b = look_next_which_scrollbar_button (cwevent->x, cwevent->y, w);
3295 	    if (b != 3 && b > 0) {
3296 		y = w->firstline;
3297 		buttonypos = xevent_xbutton_y;
3298 		w->options = whichscrbutton = b;
3299 		cwevent->ident = w->ident;
3300 		xevent->type = cwevent->type = ButtonPress;
3301 	    }
3302 	}
3303 	break;
3304     case ButtonPress:
3305 	resolve_button (xevent, cwevent);
3306 	if (cwevent->button == Button1 || cwevent->button == Button2) {
3307 	    buttonypos = xevent_xbutton_y;
3308 	    y = w->firstline;
3309 	    w->options = whichscrbutton = look_next_which_scrollbar_button (cwevent->x, cwevent->y, w);
3310 	    if (whichscrbutton == 3) {
3311 		offset = thumb_pos - buttonypos + SB_BORDER_WIDTH;
3312 	    } else
3313 		offset = 0;
3314 	    cwevent->ident = w->ident;
3315 	    w->search_start = w->firstline;
3316 	    w->search_len = w->numlines;
3317 	}
3318 	break;
3319     case ButtonRelease:
3320 	resolve_button (xevent, cwevent);
3321 	if (whichscrbutton == 3) {
3322 	    w->options = 0x20 + whichscrbutton;
3323 	    y = (double) (xevent_xbutton_y + offset) * (double) 65535.0 / next_icons->work_length;
3324 	    w->firstline = y;
3325 	    buttonypos = xevent_xbutton_y;
3326 	}
3327 	break;
3328     case MotionNotify:
3329 	if (whichscrbutton == 0)
3330 	    return 0;
3331 	resolve_button (xevent, cwevent);
3332 	if (cwevent->state & (Button1Mask | Button2Mask)) {
3333 	    w->options = whichscrbutton;
3334 	    if (whichscrbutton == 3) {
3335 		y = (double) (xevent_xbutton_y + offset) * (double) 65535.0 / (next_icons->work_length);
3336 		w->firstline = y;
3337 		buttonypos = xevent_xbutton_y;
3338 	    }
3339 	}
3340 	break;
3341     default:
3342 	return 0;
3343     }
3344 
3345     if (w->firstline > 65535)
3346 	w->firstline = 65535;
3347     if (cwevent->state & (Button1Mask | Button2Mask) || cwevent->type == ButtonPress || cwevent->type == ButtonRelease)
3348 	if (w->scroll_bar_link && w->vert_scrollbar)
3349 	    (*w->scroll_bar_link) (w, w->vert_scrollbar, xevent, cwevent, whichscrbutton);
3350 
3351     if (cwevent->type == ButtonRelease)
3352 	w->options = whichscrbutton = 0;
3353     if (xevent->type != Expose || !xevent->xexpose.count)
3354 	look_next_render_scrollbar (w);
3355 
3356     return 0;
3357 }
3358 
look_next_init_scrollbar_icons(CWidget * w)3359 static void look_next_init_scrollbar_icons (CWidget * w)
3360 {
3361     w->user = init_next_icons (w->winid);
3362     w->free_user = free_next_icons;
3363 }
3364 
look_next_get_scrollbar_size(int type)3365 static int look_next_get_scrollbar_size (int type)
3366 {
3367     return SB_WIDTH + SB_BORDER_SIZE;
3368 }
3369 
look_next_get_button_color(XColor * color,int i)3370 static void look_next_get_button_color (XColor * color, int i)
3371 {
3372     color->red = color->green = (i * 4) * 65535 / 63;
3373     color->blue = (i * 4) * 65535 / 63;
3374     color->flags = DoRed | DoBlue | DoGreen;
3375 }
3376 
look_next_window_handler(CWidget * w,XEvent * xevent,CEvent * cwevent)3377 static int look_next_window_handler (CWidget * w, XEvent * xevent, CEvent * cwevent)
3378 {
3379     static Window window_is_resizing = 0;
3380     static int windowx, windowy;
3381     static int wx = 0, wy = 0;
3382     static int wwidth = 0, wheight = 0;
3383     static int allowwindowmove = 0;
3384     static int allowwindowresize = 0;
3385 
3386     switch (xevent->type) {
3387     case ClientMessage:
3388 	if (!w->disabled)
3389 	    cwevent->ident = w->ident;
3390 	break;
3391     case Expose:
3392 	if (!xevent->xexpose.count)
3393 	    render_window (w);
3394 	break;
3395     case ButtonRelease:
3396 	strcpy (cwevent->ident, w->ident);
3397 	window_is_resizing = 0;
3398 	resolve_button (xevent, cwevent);
3399 	allowwindowmove = 0;
3400 	allowwindowresize = 0;
3401 	break;
3402     case ButtonPress:
3403 	strcpy (cwevent->ident, w->ident);
3404 	resolve_button (xevent, cwevent);
3405 	if (cwevent->double_click == 1) {
3406 	    CWidget *c = CChildFocus (w);
3407 	    if (c)
3408 		CFocus (c);
3409 	}
3410 	if (cwevent->button == Button1 && !(w->position & WINDOW_ALWAYS_LOWERED)) {
3411 	    XRaiseWindow (CDisplay, w->winid);
3412 	    CRaiseWindows ();
3413 	} else if (cwevent->button == Button2 && !(w->position & WINDOW_ALWAYS_RAISED)) {
3414 	    XLowerWindow (CDisplay, w->winid);
3415 	    CLowerWindows ();
3416 	}
3417 	windowx = xevent->xbutton.x_root - w->x;
3418 	windowy = xevent->xbutton.y_root - w->y;
3419 	wx = xevent->xbutton.x;
3420 	wy = xevent->xbutton.y;
3421 	wwidth = w->width;
3422 	wheight = w->height;
3423 	if (wy > w->height - NEXT_LOWBAR && w->position & WINDOW_RESIZABLE) {
3424 	    allowwindowresize = 1;
3425 	    if (wx < NEXT_HANDLE) {
3426 		allowwindowresize++;
3427 		if (w->position & WINDOW_UNMOVEABLE)
3428 		    allowwindowresize++;
3429 	    } else if (wx < w->width - NEXT_HANDLE - 1)
3430 		allowwindowresize = 3;
3431 	} else
3432 	    allowwindowmove = 1;
3433 	break;
3434     case MotionNotify:
3435 	resolve_button (xevent, cwevent);
3436 	if ((w->position & WINDOW_RESIZABLE) && allowwindowresize
3437 	    && (cwevent->state & (Button1Mask | Button2Mask))) {
3438 	    int wi, he;
3439 #if 0
3440 	    int new_x, new_y;
3441 #endif
3442 	    int dx = xevent->xmotion.x_root - windowx - w->x;
3443 	    int dy = xevent->xmotion.y_root - windowy - w->y;
3444 	    window_is_resizing = w->winid;
3445 	    he = wheight + dy;
3446 	    wi = wwidth;
3447 
3448 	    if (allowwindowresize == 1)
3449 		wi += dx;
3450 	    else if (allowwindowresize == 2)
3451 		wi -= dx;
3452 
3453 /* this is actually for the edit windows, and needs to be generalized */
3454 	    if (wi < w->mark1)
3455 		wi = w->mark1;
3456 	    if (he < w->mark2)
3457 		he = w->mark2;
3458 
3459 	    wi -= w->firstcolumn;
3460 	    wi -= wi % w->textlength;
3461 	    wi += w->firstcolumn;
3462 	    he -= w->firstline;
3463 	    he -= he % w->numlines;
3464 	    he += w->firstline;
3465 	    w->position &= ~WINDOW_MAXIMISED;
3466 	    dx = wi - w->width;
3467 	    CSetSize (w, wi, he);
3468 	    if (allowwindowresize == 2 && dx != 0) {
3469 		w->x -= dx;
3470 		wwidth = w->width;
3471 		XMoveWindow (CDisplay, w->winid, w->x, w->y);
3472 	    }
3473 	}
3474 	if (!(w->position & WINDOW_UNMOVEABLE) && allowwindowmove
3475 	    && (cwevent->state & (Button1Mask | Button2Mask))) {
3476 	    w->x = xevent->xmotion.x_root - windowx;
3477 	    w->y = xevent->xmotion.y_root - windowy;
3478 	    if (w->x + xevent->xmotion.x < 2)
3479 		w->x = -wx + 2;
3480 	    if (w->y + xevent->xmotion.y < 2)
3481 		w->y = -wy + 2;
3482 	    XMoveWindow (CDisplay, w->winid, w->x, w->y);
3483 	}
3484 	break;
3485     }
3486     return 0;
3487 }
3488 
3489 extern Pixmap Cswitchon;
3490 extern Pixmap Cswitchoff;
3491 
look_next_render_switch(CWidget * wdt)3492 static void look_next_render_switch (CWidget * wdt)
3493 {
3494     int w = wdt->width, h = wdt->height;
3495     Window win = wdt->winid;
3496     int x = 0, y = 0;
3497 
3498     CSetColor (COLOR_FLAT);
3499     CRectangle (win, x+2, y+2, w - 4, h - 4);
3500 
3501     CSetColor (wdt->fg);
3502     CSetBackgroundColor (wdt->bg);
3503     if (wdt->options & SWITCH_PICTURE_TYPE) {
3504 	if (wdt->keypressed)
3505 	    XCopyPlane (CDisplay, Cswitchon, win, CGC, 0, 0,
3506 			w, h, x, y, 1);
3507 	else
3508 	    XCopyPlane (CDisplay, Cswitchoff, win, CGC, 0, 0,
3509 			w, h, x, y, 1);
3510     } else {
3511 	if (wdt->keypressed)
3512 	{
3513 	    render_bevel (win, x + 1, y + 1, x + w - 1, y + h - 1, 1, 0);
3514 	    CSetColor (COLOR_DARK);
3515 	    CLine( win, x+1+3, y+1+11, x+1+10, y+1+3 );
3516 	    CSetColor( COLOR_BLACK );
3517 	    CLine( win, x+1+4, y+1+5, x+1+4, y+1+8 );
3518 	    CLine( win, x+1+4, y+1+11, x+1+10, y+1+4 );
3519 	    CSetColor( COLOR_WHITE );
3520 	    CLine(win, x+1+3, y+1+5, x+1+3, y+1+10 );
3521 	    CLine(win, x+1+3, y+1+10, x+1+9, y+1+3 );
3522 	}else
3523 	    render_bevel (win, x + 1, y + 1, x + w - 2, y + h - 2, 1, 0);
3524 
3525     }
3526     if (wdt->options & (BUTTON_HIGHLIGHT | BUTTON_PRESSED))
3527     	CSetColor(COLOR_BLACK);
3528     else
3529     	CSetColor(COLOR_FLAT);
3530     XDrawRectangle (CDisplay, win, CGC, x, y, w-1, h-1);
3531 }
3532 
look_next_edit_render_tidbits(CWidget * wdt)3533 static void look_next_edit_render_tidbits (CWidget * wdt)
3534 {
3535     int isfocussed;
3536     int w = wdt->width, h = wdt->height;
3537     Window win;
3538 
3539     win = wdt->winid;
3540     isfocussed = (win == CGetFocus ());
3541     CSetColor (COLOR_FLAT);
3542     render_bevel (win, 0, 0, w - 1, h - 1, 1, 1);	/*most outer border bevel */
3543 }
3544 
look_next_draw_cancel_button(char * ident,Window win,int x,int y)3545 static CWidget *look_next_draw_cancel_button (char *ident, Window win, int x, int y)
3546 {
3547     CWidget *wdt;
3548 #if 0
3549     CGetHintPos (&x, 0);
3550 #endif
3551     wdt = CDrawButton (ident, win, x, y, AUTO_WIDTH, AUTO_HEIGHT, _(" Cancel "));
3552 #if 0
3553     CGetHintPos (0, &y);
3554     reset_hint_pos (x + WINDOW_EXTRA_SPACING, y + 2 * WINDOW_EXTRA_SPACING);
3555 #endif
3556     return wdt;
3557 }
3558 
look_next_draw_ok_button(char * ident,Window win,int x,int y)3559 static CWidget *look_next_draw_ok_button (char *ident, Window win, int x, int y)
3560 {
3561     CWidget *wdt;
3562 #if 0
3563     CGetHintPos (&x, 0);
3564 #endif
3565     wdt = CDrawButton (ident, win, x, y, AUTO_WIDTH, AUTO_HEIGHT, _("   Ok   "));
3566 #if 0
3567     CGetHintPos (0, &y);
3568     reset_hint_pos (x + WINDOW_EXTRA_SPACING, y + 2 * WINDOW_EXTRA_SPACING);
3569 #endif
3570     return wdt;
3571 }
3572 
look_next_render_fielded_textbox_tidbits(CWidget * w,int isfocussed)3573 static void look_next_render_fielded_textbox_tidbits (CWidget *w, int isfocussed)
3574 {
3575     render_bevel (w->winid, 0, 0, w->width - 1, w->height - 1, 1, 1);	/*most outer border bevel */
3576 }
3577 
look_next_render_textbox_tidbits(CWidget * w,int isfocussed)3578 static void look_next_render_textbox_tidbits (CWidget * w, int isfocussed)
3579 {
3580     if (isfocussed) {
3581 	render_bevel (w->winid, 0, 0, w->width - 1, w->height - 1, 1, 1);	/*most outer border bevel */
3582     } else {
3583 	render_bevel (w->winid, 0, 0, w->width - 1, w->height - 1, 1, 0);	/*most outer border bevel */
3584     }
3585 }
3586 
look_next_render_passwordinput_tidbits(CWidget * wdt,int isfocussed)3587 static void look_next_render_passwordinput_tidbits (CWidget * wdt, int isfocussed)
3588 {
3589     int w = wdt->width, h = wdt->height;
3590     Window win = wdt->winid;
3591     CSetColor (COLOR_WHITE);
3592     XDrawRectangle (CDisplay, win, CGC, 1, 1, w - 2, h - 2);
3593     XDrawRectangle (CDisplay, win, CGC, 2, 2, w - 4, h - 4);
3594     if (win == CGetFocus ()) {
3595 	render_bevel (win, 0, 0, w - 1, h - 1, 1, 1);
3596     } else {
3597 	render_bevel (win, 0, 0, w - 1, h - 1, 1, 1);
3598     }
3599 }
3600 
look_next_render_textinput_tidbits(CWidget * wdt,int isfocussed)3601 static void look_next_render_textinput_tidbits (CWidget * wdt, int isfocussed)
3602 {
3603     int w = wdt->width, h = wdt->height;
3604     Window win = wdt->winid;
3605     CSetColor (COLOR_WHITE);
3606     XDrawRectangle (CDisplay, win, CGC, 1, 1, w - h - 3, h - 3);
3607     XDrawRectangle (CDisplay, win, CGC, 2, 2, w - h - 5, h - 5);
3608     if (isfocussed) {
3609 	render_bevel (win, 0, 0, w - h - 1, h - 1, 1, 1);	/*most outer border bevel */
3610     } else {
3611 	render_bevel (win, 0, 0, w - h - 1, h - 1, 1, 1);	/*most outer border bevel */
3612     }
3613     /* history button to the right */
3614     if (wdt->options & BUTTON_PRESSED) {
3615 	CRectangle (win, w - h + 2, 2, h - 4, h - 4);
3616 	render_bevel (win, w - h, 0, w - 1, h - 1, 2, 3);
3617     } else if (wdt->options & BUTTON_HIGHLIGHT) {
3618 	CRectangle (win, w - h + 1, 1, h - 2, h - 2);
3619 	render_bevel (win, w - h, 0, w - 1, h - 1, 1, 2);
3620     } else {
3621 	CRectangle (win, w - h + 2, 2, h - 4, h - 4);
3622 	render_bevel (win, w - h, 0, w - 1, h - 1, 2, 2);
3623     }
3624 }
3625 
3626 extern struct focus_win focus_border;
3627 
render_focus_border_n(Window win,int i)3628 static void render_focus_border_n (Window win, int i)
3629 {
3630     int j;
3631     j = (i > 3) + 1;
3632     if (win == focus_border.top) {
3633 	render_bevel (win, 0, 0, focus_border.width + 2 * WIDGET_FOCUS_RING - 1, focus_border.height + 2 * WIDGET_FOCUS_RING - 1, j, 0);
3634 	render_bevel (win, i, i, focus_border.width + 2 * WIDGET_FOCUS_RING - 1 - i, focus_border.height + 2 * WIDGET_FOCUS_RING - 1 - i, 2, 1);
3635     } else if (win == focus_border.bottom) {
3636 	render_bevel (win, 0, 0 - focus_border.height, focus_border.width + 2 * WIDGET_FOCUS_RING - 1, WIDGET_FOCUS_RING - 1, j, 0);
3637 	render_bevel (win, i, i - focus_border.height, focus_border.width + 2 * WIDGET_FOCUS_RING - 1 - i, WIDGET_FOCUS_RING - 1 - i, 2, 1);
3638     } else if (win == focus_border.left) {
3639 	render_bevel (win, 0, 0 - WIDGET_FOCUS_RING, focus_border.width + 2 * WIDGET_FOCUS_RING - 1, focus_border.height + WIDGET_FOCUS_RING - 1, j, 0);
3640 	render_bevel (win, i, i - WIDGET_FOCUS_RING, focus_border.width + 2 * WIDGET_FOCUS_RING - 1 - i, focus_border.height + WIDGET_FOCUS_RING - 1 - i, 2, 1);
3641     } else if (win == focus_border.right) {
3642 	render_bevel (win, 0 + WIDGET_FOCUS_RING - focus_border.width, 0 - WIDGET_FOCUS_RING, WIDGET_FOCUS_RING - 1, focus_border.height + WIDGET_FOCUS_RING - 1, j, 0);
3643 	render_bevel (win, i + WIDGET_FOCUS_RING - focus_border.width, i - WIDGET_FOCUS_RING, WIDGET_FOCUS_RING - 1 - i, focus_border.height + WIDGET_FOCUS_RING - 1 - i, 2, 1);
3644     }
3645 }
3646 
look_next_render_focus_border(Window win)3647 static void look_next_render_focus_border (Window win)
3648 {
3649     render_focus_border_n (win, focus_border.border);
3650 }
3651 
look_next_get_extra_window_spacing(void)3652 static int look_next_get_extra_window_spacing (void)
3653 {
3654     return 3;
3655 }
3656 
look_next_get_default_interwidget_spacing(void)3657 static int look_next_get_default_interwidget_spacing (void)
3658 {
3659     return 1;
3660 }
3661 
look_next_get_focus_ring_size(void)3662 static int look_next_get_focus_ring_size (void)
3663 {
3664     return 1;
3665 }
3666 
look_next_get_window_resize_bar_thickness(void)3667 static int look_next_get_window_resize_bar_thickness (void)
3668 {
3669     return 7;
3670 }
3671 
look_next_get_button_flat_color(void)3672 static unsigned long look_next_get_button_flat_color (void)
3673 {
3674     return color_widget(10);
3675 }
3676 
look_next_get_switch_size(void)3677 static int look_next_get_switch_size (void)
3678 {
3679     return 16;
3680 }
3681 
look_next_get_fielded_textbox_hscrollbar_width(void)3682 static int look_next_get_fielded_textbox_hscrollbar_width (void)
3683 {
3684     return AUTO_WIDTH;
3685 }
3686 
3687 struct look look_next = {
3688     look_next_get_default_interwidget_spacing,
3689     look_next_menu_draw,
3690     look_next_get_menu_item_extents,
3691     look_next_render_menu_button,
3692     look_next_render_button,
3693     look_next_render_bar,
3694     look_next_render_raised_bevel,
3695     look_next_render_sunken_bevel,
3696     look_next_draw_hotkey_understroke,
3697     look_next_get_default_widget_font,
3698     look_next_render_text,
3699     look_next_render_window,
3700     look_next_render_scrollbar,
3701     look_next_get_scrollbar_size,
3702     look_next_init_scrollbar_icons,
3703     look_next_which_scrollbar_button,
3704     look_next_scrollbar_handler,
3705     look_next_get_button_color,
3706     look_next_get_extra_window_spacing,
3707     look_next_window_handler,
3708     look_next_get_focus_ring_size,
3709     look_next_get_button_flat_color,
3710     look_next_get_window_resize_bar_thickness,
3711     look_next_render_switch,
3712     look_next_get_switch_size,
3713     look_next_draw_browser,
3714     look_next_get_file_or_dir,
3715     look_next_draw_file_list,
3716     look_next_redraw_file_list,
3717     look_next_get_file_list_line,
3718     look_next_search_replace_dialog,
3719     look_next_edit_render_tidbits,
3720     look_next_draw_cancel_button,
3721     look_next_draw_cancel_button,
3722     look_next_draw_cancel_button,
3723     look_next_draw_ok_button,
3724     look_next_render_fielded_textbox_tidbits,
3725     look_next_render_textbox_tidbits,
3726     look_next_get_fielded_textbox_hscrollbar_width,
3727     look_next_render_textinput_tidbits,
3728     look_next_render_passwordinput_tidbits,
3729     look_next_render_focus_border,
3730 };
3731 
3732 #endif			/* NEXT_LOOK */
3733 
3734 
3735