1 /* look-cool.c - look 'n feel type: COOL
2    Copyright (C) 1996-2017 Paul Sheer
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2 of the License, or
7    (at your option) any later version.
8 
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17    02111-1307, USA.
18  */
19 
20 #include <config.h>
21 #include <stdio.h>
22 #include <my_string.h>
23 #include <stdlib.h>
24 #include <stdarg.h>
25 
26 #include <X11/Intrinsic.h>
27 #include "lkeysym.h"
28 
29 #include "stringtools.h"
30 #include "app_glob.c"
31 #include "coolwidget.h"
32 #include "coollocal.h"
33 
34 #include "mad.h"
35 
36 extern struct look *look;
37 
38 /* {{{ search replace dialog */
39 
40 extern int replace_scanf;
41 extern int replace_regexp;
42 extern int replace_all;
43 extern int replace_prompt;
44 extern int replace_whole;
45 extern int replace_case;
46 extern int replace_backwards;
47 extern int search_create_bookmark;
48 
49 struct look_cool_list {
50     struct file_entry *l;
51     int n;
52 };
53 
look_cool_search_replace_dialog(Window parent,int x,int y,char ** search_text,char ** replace_text,char ** arg_order,const char * heading,int option)54 void look_cool_search_replace_dialog (Window parent, int x, int y, char **search_text, char **replace_text, char **arg_order, const char *heading, int option)
55 {
56     Window win;
57     XEvent xev;
58     CEvent cev;
59     CState s;
60     int xh, yh, h, xb, ys, yc, yb, yr;
61     CWidget *m;
62     int text_input_width ;
63 
64     CBackupState (&s);
65     CDisable ("*");
66 
67     win = CDrawHeadedDialog ("replace", parent, x, y, heading);
68     CGetHintPos (&xh, &h);
69 
70 /* NLS hotkey ? */
71     CIdent ("replace")->position = WINDOW_ALWAYS_RAISED;
72 /* An input line comes after the ':' */
73     (CDrawText ("replace.t1", win, xh, h, _(" Enter search text : ")))->hotkey = 'E';
74 
75     CGetHintPos (0, &yh);
76     (m = CDrawTextInput ("replace.sinp", win, xh, yh, 10, AUTO_HEIGHT, 8192, *search_text))->hotkey = 'E';
77 
78     if (replace_text) {
79 	CGetHintPos (0, &yh);
80 	(CDrawText ("replace.t2", win, xh, yh, _(" Enter replace text : ")))->hotkey = 'n';
81 	CGetHintPos (0, &yh);
82 	(CDrawTextInput ("replace.rinp", win, xh, yh, 10, AUTO_HEIGHT, 8192, *replace_text))->hotkey = 'n';
83 	CSetToolHint ("replace.t2", _("You can enter regexp substrings with %s\n(not \\1, \\2 like sed) then use \"Enter...order\""));
84 	CSetToolHint ("replace.rinp", _("You can enter regexp substrings with %s\n(not \\1, \\2 like sed) then use \"Enter...order\""));
85 	CGetHintPos (0, &yh);
86 	(CDrawText ("replace.t3", win, xh, yh, _(" Enter argument (or substring) order : ")))->hotkey = 'o';
87 	CGetHintPos (0, &yh);
88 	(CDrawTextInput ("replace.ainp", win, xh, yh, 10, AUTO_HEIGHT, 256, *arg_order))->hotkey = 'o';
89 /* Tool hint */
90 	CSetToolHint ("replace.ainp", _("Enter the order of replacement of your scanf\nformat specifiers or regexp substrings, eg 3,1,2"));
91 	CSetToolHint ("replace.t3", _("Enter the order of replacement of your scanf\nformat specifiers or regexp substrings, eg 3,1,2"));
92     }
93     CGetHintPos (0, &yh);
94     ys = yh;
95 /* The following are check boxes */
96     CDrawSwitch ("replace.ww", win, xh, yh, replace_whole, _(" Whole words only "), 0);
97     CGetHintPos (0, &yh);
98     CDrawSwitch ("replace.case", win, xh, yh, replace_case, _(" Case sensitive "), 0);
99     yc = yh;
100     CGetHintPos (0, &yh);
101     CDrawSwitch ("replace.reg", win, xh, yh, replace_regexp, _(" Regular expression "), 1);
102     CSetToolHint ("replace.reg", _("See the regex man page for how\nto compose a regular expression"));
103     CSetToolHint ("replace.reg.label", _("See the regex man page for how\nto compose a regular expression"));
104     yb = yh;
105     CGetHintPos (0, &yh);
106     CGetHintPos (&xb, 0);
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     CDrawPixmapButton ("replace.ok", win, x - WIDGET_SPACING - TICK_BUTTON_WIDTH, h, PIXMAP_BUTTON_TICK);
154     CDrawPixmapButton ("replace.cancel", win, x - WIDGET_SPACING - TICK_BUTTON_WIDTH, h + WIDGET_SPACING + TICK_BUTTON_WIDTH, PIXMAP_BUTTON_CROSS);
155 /* Tool hint */
156     CSetToolHint ("replace.ok", _("Begin search, Enter"));
157     CSetToolHint ("replace.cancel", _("Abort this dialog, Esc"));
158     CSetSizeHintPos ("replace");
159     CMapDialog ("replace");
160 
161     m = CIdent ("replace");
162     text_input_width = m->width - WIDGET_SPACING * 3 - 4 - TICK_BUTTON_WIDTH ;
163     CSetWidgetSize ("replace.sinp", text_input_width, (CIdent ("replace.sinp"))->height);
164     if (replace_text) {
165 	CSetWidgetSize ("replace.rinp", text_input_width, (CIdent ("replace.rinp"))->height);
166 	CSetWidgetSize ("replace.ainp", text_input_width, (CIdent ("replace.ainp"))->height);
167     }
168     CFocus (CIdent ("replace.sinp"));
169 
170     for (;;) {
171 	CNextEvent (&xev, &cev);
172 	if (!CIdent ("replace")) {
173 	    *search_text = 0;
174 	    break;
175 	}
176 	if (!strcmp (cev.ident, "replace.cancel") || cev.command == CK_Cancel) {
177 	    *search_text = 0;
178 	    break;
179 	}
180 	if (!strcmp (cev.ident, "replace.reg") || !strcmp (cev.ident, "replace.scanf")) {
181 	    if (CIdent ("replace.reg")->keypressed || CIdent ("replace.scanf")->keypressed) {
182 		if (!(CIdent ("replace.case")->keypressed)) {
183 		    CIdent ("replace.case")->keypressed = 1;
184 		    CExpose ("replace.case");
185 		}
186 	    }
187 	}
188 	if (!strcmp (cev.ident, "replace.ok") || cev.command == CK_Enter) {
189 	    if (replace_text) {
190 		replace_all = CIdent ("replace.all")->keypressed;
191 		replace_prompt = CIdent ("replace.pr")->keypressed;
192 		*replace_text = (char *) strdup (CIdent ("replace.rinp")->text);
193 		*arg_order = (char *) strdup (CIdent ("replace.ainp")->text);
194 	    }
195 	    *search_text = (char *) strdup (CIdent ("replace.sinp")->text);
196 	    replace_whole = CIdent ("replace.ww")->keypressed;
197 	    replace_case = CIdent ("replace.case")->keypressed;
198 	    replace_scanf = CIdent ("replace.scanf")->keypressed;
199 	    replace_regexp = CIdent ("replace.reg")->keypressed;
200 
201 	    if (option & SEARCH_DIALOG_OPTION_BACKWARDS) {
202 		replace_backwards = CIdent ("replace.bkwd")->keypressed;
203 	    } else {
204 		replace_backwards = 0;
205 	    }
206 
207 	    if (option & SEARCH_DIALOG_OPTION_BOOKMARK) {
208 		search_create_bookmark = CIdent ("replace.bkmk")->keypressed;
209 	    } else {
210 		search_create_bookmark = 0;
211 	    }
212 
213 	    break;
214 	}
215     }
216     CDestroyWidget ("replace");
217     CRestoreState (&s);
218 }
219 
220 /* }}} search replace dialog */
221 
222 /* {{{ file list stuff */
223 
destroy_filelist(CWidget * w)224 static void destroy_filelist (CWidget * w)
225 {
226     if (w->hook) {
227         struct look_cool_list *fe = (struct look_cool_list *) w->hook;
228         if (fe->l)
229             free (fe->l);
230 	free (w->hook);
231 	w->hook = 0;
232     }
233 }
234 
235 /* This doesn't apply to solaris: */
236 /*
237  * struct dirent {
238  * 	long		d_ino;
239  * 	__kernel_off_t	d_off;
240  * 	unsigned short	d_reclen;
241  * 	char		d_name[256];
242  * };
243  */
244 
245 /*
246  *
247  * #define S_ISLNK(m)	(((m) & S_IFMT) == S_IFLNK)
248  * #define S_ISREG(m)	(((m) & S_IFMT) == S_IFREG)
249  * #define S_ISDIR(m)	(((m) & S_IFMT) == S_IFDIR)
250  * #define S_ISCHR(m)	(((m) & S_IFMT) == S_IFCHR)
251  * #define S_ISBLK(m)	(((m) & S_IFMT) == S_IFBLK)
252  * #define S_ISFIFO(m)	(((m) & S_IFMT) == S_IFIFO)
253  * #define S_ISSOCK(m)	(((m) & S_IFMT) == S_IFSOCK)
254  *
255  * #define S_IRWXU 00700
256  * #define S_IRUSR 00400
257  * #define S_IWUSR 00200
258  * #define S_IXUSR 00100
259  *
260  * #define S_IRWXG 00070
261  * #define S_IRGRP 00040
262  * #define S_IWGRP 00020
263  * #define S_IXGRP 00010
264  *
265  * #define S_IRWXO 00007
266  * #define S_IROTH 00004
267  * #define S_IWOTH 00002
268  * #define S_IXOTH 00001
269  */
270 
271 #if 0
272 static char *dname (struct dirent *directentry);
273 #endif
274 
275 #ifdef HAVE_STRFTIME
276 /* We want our own dates for NLS */
277 #undef HAVE_STRFTIME
278 #endif
279 
280 #undef gettext_noop
281 #define gettext_noop(x) x
282 
283 void get_file_time (char *timestr, time_t file_time, int l);
284 
get_filelist_line(void * data,int line_number,int * num_fields,int * tagged)285 static char **get_filelist_line (void *data, int line_number, int *num_fields, int *tagged)
286 {
287     struct file_entry *directentry;
288     struct look_cool_list *fe;
289     static char *fields[10], size[24], mode[12], timestr[32];
290     static char name[520], *n;
291     mode_t m;
292 
293     *num_fields = 4;		/* name, size, date, mode only (for the mean time) */
294 
295     fe = (struct look_cool_list *) data;
296     if (line_number >= fe->n)
297 	return 0;
298     directentry = fe->l;
299 
300     n = name;
301     strcpy (name, directentry[line_number].name);
302     fields[0] = name;
303     sprintf (size, "\t%u", (unsigned int) directentry[line_number].stat.st_size);
304     fields[1] = size;
305 
306     get_file_time (timestr, directentry[line_number].stat.st_mtime, 0);
307     fields[2] = timestr;
308 
309     memset (mode, ' ', 11);
310     mode[11] = 0;
311     mode[0] = '-';
312     m = directentry[line_number].stat.st_mode;
313     switch ((int) m & S_IFMT) {
314     case S_IFLNK:
315 	mode[0] = 'l';
316 	break;
317     case S_IFDIR:
318 	mode[0] = 'd';
319 	break;
320     case S_IFCHR:
321 	mode[0] = 'c';
322 	break;
323     case S_IFBLK:
324 	mode[0] = 'b';
325 	break;
326     case S_IFIFO:
327 	mode[0] = 'f';
328 	break;
329     case S_IFSOCK:
330 	mode[0] = 's';
331 	break;
332     }
333 
334     mode[1] = m & S_IRUSR ? 'r' : '-';
335     mode[2] = m & S_IWUSR ? 'w' : '-';
336     mode[3] = m & S_IXUSR ? 'x' : '-';
337 
338     mode[4] = m & S_IRGRP ? 'r' : '-';
339     mode[5] = m & S_IWGRP ? 'w' : '-';
340     mode[6] = m & S_IXGRP ? 'x' : '-';
341 
342     mode[7] = m & S_IROTH ? 'r' : '-';
343     mode[8] = m & S_IWOTH ? 'w' : '-';
344     mode[9] = m & S_IXOTH ? 'x' : '-';
345 
346     if (S_ISLNK (m)) {
347 	int l, i;
348 	char *p;
349 	p = directentry[line_number].name;
350 	l = strlen (n);
351 	for (i = 0; i < l; i++) {
352 	    *n++ = '\b';
353 	    *n++ = *p++;
354 	}
355 	*n++ = '\0';
356     } else if (m & (S_IXUSR | S_IXGRP | S_IXOTH)) {
357 	int l, i;
358 	char *p;
359 	p = directentry[line_number].name;
360 	l = strlen (n);
361 	for (i = 0; i < l; i++) {
362 	    *n++ = '\r';
363 	    *n++ = *p++;
364 	}
365 	*n++ = '\0';
366     }
367     fields[3] = mode;
368     fields[*num_fields] = 0;
369     if (directentry[line_number].options & FILELIST_TAGGED_ENTRY)
370 	*tagged = 1;
371     return fields;
372 }
373 
374 
look_cool_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)375 CWidget *look_cool_draw_file_list (const char *identifier, Window parent, int x, int y,
376 			int width, int height, int line, int column,
377 			struct file_entry *directentry,
378 			long options)
379 {
380     struct file_entry e;
381     struct look_cool_list *fe;
382     CWidget *w;
383     int n;
384 
385     for (n = 0; directentry && !(directentry[n].options & FILELIST_LAST_ENTRY); n++);	/* count entries */
386 
387     fe = CMalloc (sizeof (struct look_cool_list));
388     fe->l = CMalloc (sizeof (struct file_entry) * (n + 1));
389     memcpy (fe->l, directentry, sizeof (struct file_entry) * n);
390     fe->n = n;
391 
392     w = CDrawFieldedTextbox (identifier, parent, x, y,
393 			     width, height, line, column,
394 			     get_filelist_line,
395 			     options, fe);
396     w->hook = (void *) fe;
397     w->destroy = destroy_filelist;
398 
399     return w;
400 }
401 
look_cool_redraw_file_list(const char * identifier,struct file_entry * directentry,int preserve)402 CWidget *look_cool_redraw_file_list (const char *identifier, struct file_entry *directentry, int preserve)
403 {
404     struct file_entry e;
405     struct look_cool_list *fe;
406     CWidget *w;
407     int n;
408 
409     for (n = 0; directentry && !(directentry[n].options & FILELIST_LAST_ENTRY); n++);	/* count entries */
410 
411     w = CIdent (identifier);
412     fe = (struct look_cool_list *) w->hook;
413     free (fe->l);
414     fe->l = CMalloc (sizeof (struct file_entry) * (n + 1));
415     memcpy (fe->l, directentry, sizeof (struct file_entry) * n);
416     fe->n = n;
417 
418     w = CRedrawFieldedTextbox (identifier, preserve);
419 
420     return w;
421 }
422 
look_cool_get_file_list_line(CWidget * w,int line)423 struct file_entry *look_cool_get_file_list_line (CWidget * w, int line)
424 {
425     struct look_cool_list *fe;
426     static struct file_entry r;
427     memset (&r, 0, sizeof (r));
428     fe = (struct look_cool_list *) w->hook;
429     if (line >= fe->n)
430 	r.options = FILELIST_LAST_ENTRY;
431     else
432 	r = fe->l[line];
433     return &r;
434 }
435 
436 
437 
438 /* }}} file list stuff */
439 
440 /* {{{ file browser stuff */
441 
442 extern int option_file_browser_width;
443 extern int option_file_browser_height;
444 
445 static char *mime_majors[3] =
446 {"url", "text", 0};
447 
draw_file_browser(const char * identifier,Window parent,int x,int y,const char * directory,const char * file,const char * label)448 static Window draw_file_browser (const char *identifier, Window parent, int x, int y,
449 		    const char *directory, const char *file, const char *label)
450 {
451     CWidget * w;
452     struct file_entry *filelist = 0, *directorylist = 0;
453     char *dir;
454     char *resolved_path, *p;
455     int y2, x2, x3, y3;
456     Window win;
457 
458     dir = (char *) strdup (directory);
459 
460     if (parent == CRoot)
461 	win = CDrawMainWindow (identifier, label);
462     else
463 	win = CDrawHeadedDialog (identifier, parent, x, y, label);
464     (CIdent (identifier))->options |= WINDOW_ALWAYS_RAISED;
465     CHourGlass (CFirstWindow);
466     for (;;) {
467 	filelist = get_file_entry_list (dir, FILELIST_FILES_ONLY, CLastInput (catstrs (identifier, ".filt", NULL)));
468 	if (!filelist) {
469 	    char *s;
470 	    s = strrchr (dir, '/');
471 	    if (s) {
472 		*s = '\0';
473 		continue;
474 	    }
475 	}
476 	break;
477     }
478     CUnHourGlass (CFirstWindow);
479     if (!filelist || !(directorylist = get_file_entry_list (dir, FILELIST_DIRECTORIES_ONLY, ""))) {
480 	CErrorDialog (parent, 20, 20, _(" File browser "), _(" Unable to read directory "));
481 	CDestroyWidget (identifier);
482 	goto error;
483     }
484     CGetHintPos (&x, &y);
485     resolved_path = pathdup (dir);
486     p = resolved_path + strlen (resolved_path) - 1;
487     if (*p != '/') {
488 	*++p = '/';
489 	*++p = '\0';
490     }
491     (CDrawText (catstrs (identifier, ".dir", NULL), win, x, y, "%s", resolved_path))->position |= POSITION_FILL;
492     free (resolved_path);
493     CGetHintPos (0, &y);
494     reset_hint_pos (x, y);
495     y3 = y;
496     (w = CDrawFilelist (catstrs (identifier, ".fbox", NULL), win, x, y,
497 		  FONT_MEAN_WIDTH * option_file_browser_width + 7, FONT_PIX_PER_LINE * option_file_browser_height + 6, 0, 0, filelist, TEXTBOX_FILE_LIST))->position |= POSITION_WIDTH | POSITION_HEIGHT;
498     xdnd_set_type_list (CDndClass, w->winid, xdnd_typelist_send[DndFiles]);
499     (CIdent (catstrs (identifier, ".fbox", NULL)))->options |= TEXTBOX_MARK_WHOLE_LINES;
500 
501 /* the vertical scroll bar is named the same as the text box, with a ".vsc" at the end: */
502     CSetMovement (catstrs (identifier, ".fbox.vsc", NULL), POSITION_HEIGHT | POSITION_RIGHT);
503     CSetMovement (catstrs (identifier, ".fbox.hsc", NULL), POSITION_WIDTH | POSITION_BOTTOM);
504     CGetHintPos (&x2, &y2);
505     x3 = x2;
506     (w = CDrawFilelist (catstrs (identifier, ".dbox", NULL), win, x2, y + TICK_BUTTON_WIDTH + WIDGET_SPACING,
507 		  FONT_MEAN_WIDTH * 24 + 7, y2 - WIDGET_SPACING * 3 - 12 - y - TICK_BUTTON_WIDTH, 0, 0, directorylist, TEXTBOX_FILE_LIST))->position |= POSITION_HEIGHT | POSITION_RIGHT;
508     xdnd_set_type_list (CDndClass, w->winid, xdnd_typelist_send[DndFiles]);
509 
510 /* Toolhint */
511     CSetToolHint (catstrs (identifier, ".dbox", NULL), _("Double click to enter directories"));
512     (CIdent (catstrs (identifier, ".dbox", NULL)))->options |= TEXTBOX_MARK_WHOLE_LINES;
513     CSetMovement (catstrs (identifier, ".dbox.vsc", NULL), POSITION_HEIGHT | POSITION_RIGHT);
514     CSetMovement (catstrs (identifier, ".dbox.hsc", NULL), POSITION_RIGHT | POSITION_BOTTOM);
515     CGetHintPos (&x2, &y2);
516     (CDrawText (catstrs (identifier, ".msg", NULL), win, x, y2, _("Ctrl-Tab to complete, Alt-Ins for clip history, Shift-Up for history")))->position |= POSITION_FILL | POSITION_BOTTOM;
517     CGetHintPos (0, &y2);
518     (w = CDrawTextInput (catstrs (identifier, ".finp", NULL), win, x, y2,
519 		    WIDGET_SPACING * 2 - 2, AUTO_HEIGHT, 256, file))->position |= POSITION_FILL | POSITION_BOTTOM;
520     xdnd_set_type_list (CDndClass, w->winid, xdnd_typelist_send[DndFile]);
521     w->funcs->types = DndFile;
522     w->funcs->mime_majors = mime_majors;
523 
524     CGetHintPos (0, &y2);
525 /* Label for file filter input line. For example, to list files matching '*.c' */
526     (CDrawText (catstrs (identifier, ".filx", NULL), win, x, y2, _("Filter : ")))->position |= POSITION_BOTTOM;
527     CGetHintPos (&x, 0);
528     (CDrawTextInput (catstrs (identifier, ".filt", NULL), win, x, y2,
529 		    WIDGET_SPACING * 2 - 2, AUTO_HEIGHT, 256, TEXTINPUT_LAST_INPUT))->position |= POSITION_FILL | POSITION_BOTTOM;
530 /* Toolhint */
531     CSetToolHint (catstrs (identifier, ".filt", NULL), _("List only files matching this shell filter"));
532     CSetToolHint (catstrs (identifier, ".filx", NULL), _("List only files matching this shell filter"));
533     (CDrawPixmapButton (catstrs (identifier, ".ok", NULL), win, x3, y3,
534 		       PIXMAP_BUTTON_TICK))->position |= POSITION_RIGHT;
535 /* Toolhint */
536     CSetToolHint (catstrs (identifier, ".ok", NULL), _("Accept, Enter"));
537 
538     (CDrawPixmapButton (catstrs (identifier, ".cancel", NULL), win, x2 - WIDGET_SPACING * 2 - TICK_BUTTON_WIDTH - 20, y3,
539 		       PIXMAP_BUTTON_CROSS))->position |= POSITION_RIGHT;
540 /* Toolhint */
541     CSetToolHint (catstrs (identifier, ".cancel", NULL), _("Abort this dialog, Escape"));
542     CSetSizeHintPos (identifier);
543     CMapDialog (identifier);
544     y = (CIdent (identifier))->height;
545     CSetWindowResizable (identifier, FONT_MEAN_WIDTH * 40, min (FONT_PIX_PER_LINE * 5 + 210, y), 1600, 1200);	/* minimum and maximum sizes */
546 
547   error:
548     if (directorylist)
549 	free (directorylist);
550     if (filelist)
551 	free (filelist);
552     free (dir);
553     return win;
554 }
555 
how_much_matches(const char * a,const char * b)556 static int how_much_matches (const char *a, const char *b)
557 {
558     int n = 0;
559     while (*a && *b && *a++ == *b++)
560         n++;
561     return n;
562 }
563 
564 /* returns 0 on fail */
goto_partial_file_name(CWidget * list,char * text)565 static int goto_partial_file_name (CWidget * list, char *text)
566 {
567     int i = 0;
568     struct file_entry *fe = 0;
569     char *e;
570     int max_match = -1;
571     int found_matchiest = -1;
572 
573     for (;;) {
574         int n;
575 	if (!strlen (text))
576 	    break;
577 	if (list->kind == C_FIELDED_TEXTBOX_WIDGET) {
578 	    fe = CGetFilelistLine (list, i);
579 	    e = fe->name;
580 	} else {
581 	    e = CGetTextBoxLine (list, i);
582 	    if (e)
583 		while (*e == '/')
584 		    e++;
585 	}
586 	if (!e)
587 	    break;
588         n = how_much_matches (e, text);
589         if (max_match < n) {
590             max_match = n;
591             found_matchiest = i;
592         }
593 	if (list->kind == C_FIELDED_TEXTBOX_WIDGET) {
594 	    if (fe->options & FILELIST_LAST_ENTRY)
595 		break;
596 	} else {
597 	    if (i >= list->numlines - 1)
598 		break;
599 	}
600 	i++;
601     }
602     if (max_match >= 1) {
603         CSetTextboxPos (list, TEXT_SET_CURSOR_LINE, found_matchiest);
604         CSetTextboxPos (list, TEXT_SET_LINE, found_matchiest);
605         return 1;
606     }
607     return 0;
608 }
609 
610 /* options */
611 #define GETFILE_GET_DIRECTORY		1
612 #define GETFILE_GET_EXISTING_FILE	2
613 #define GETFILE_BROWSER			4
614 
615 void input_insert (CWidget * w, int c);
616 
file_error(void)617 static char *file_error (void)
618 {
619     if (errno) {
620 	const char *error_msg;
621 #ifdef HAVE_STRERROR
622 	error_msg = _ (strerror (errno));
623 #else
624 	extern int sys_nerr;
625 	extern char *sys_errlist[];
626 	if ((0 <= errno) && (errno < sys_nerr))
627 	    error_msg = _ (sys_errlist[errno]);
628 	else
629 /* The returned value, 'errno' has an unknown meaning */
630 	    error_msg = _ ("strange errno");
631 #endif
632 	return catstrs ("[", error_msg, "]", NULL);
633     }
634     return "";
635 }
636 
637 
638 /*
639    Returns "" on no file entered and NULL on exit (i.e. Cancel button pushed)
640    else returns the file or directory. Result must be immediately copied.
641    Result must not be free'd.
642  */
handle_browser(const char * identifier,CEvent * cwevent,int options)643 static char *handle_browser (const char *identifier, CEvent * cwevent, int options)
644 {
645     struct stat st;
646     char *q;
647     char *idd = catstrs (identifier, ".dbox", NULL);
648     char *idf = catstrs (identifier, ".fbox", NULL);
649     static char estr[MAX_PATH_LEN + 1];
650     CWidget *directory = CIdent (catstrs (identifier, ".dir", NULL));
651     CWidget *filelist = CIdent (idf);
652     CWidget *directorylist = CIdent (idd);
653     CWidget *textinput = CIdent (catstrs (identifier, ".finp", NULL));
654     CWidget *filterinput = CIdent (catstrs (identifier, ".filt", NULL));
655 
656     CSetDndDirectory (directory->text);
657 
658     if (cwevent->type == ButtonPress || cwevent->type == KeyPress)
659 	CRedrawText (catstrs (identifier, ".msg", NULL), "%s", file_error());
660 
661     if (!strcmp (cwevent->ident, filterinput->ident) && cwevent->command == CK_Enter) {
662 	struct file_entry *f;
663 	if (!(*(filterinput->text))) {
664 	    filterinput->text[0] = '*';
665 	    filterinput->text[1] = '\0';
666 	    CExpose (filterinput->ident);
667 	}
668 	CHourGlass (CFirstWindow);
669 	CRedrawFilelist (catstrs (identifier, ".fbox", NULL),
670 			 f = get_file_entry_list (directory->text, FILELIST_FILES_ONLY, filterinput->text),
671 			 0);
672 	if (f)
673 	    free (f);
674 	CUnHourGlass (CFirstWindow);
675 	return "";
676     }
677     if (!strcmp (cwevent->ident, idf) && !(options & (GETFILE_GET_DIRECTORY | GETFILE_BROWSER))) {
678 	if (cwevent->button == Button1 || cwevent->command == CK_Enter) {
679 	    q = (CGetFilelistLine (filelist, filelist->cursor))->name;
680 	    CDrawTextInput (textinput->ident, CIdent (identifier)->winid, textinput->x, textinput->y,
681 			    textinput->width, textinput->height, 256, q);
682 	} else if (cwevent->insert > 0) {
683 	    input_insert (textinput, cwevent->insert);
684 	    if (goto_partial_file_name (filelist, textinput->text))
685 		CExpose (filelist->ident);
686 	    CExpose (textinput->ident);
687 	} else if (cwevent->command == CK_BackSpace && textinput->cursor > 0) {
688 	    textinput->text[--textinput->cursor] = '\0';
689 	    if (goto_partial_file_name (filelist, textinput->text))
690 		CExpose (filelist->ident);
691 	    CExpose (textinput->ident);
692 	}
693     }
694     if (!strcmp (cwevent->ident, idd)) {
695 	if (cwevent->button == Button1 || cwevent->command == CK_Enter) {
696 	    q = (CGetFilelistLine (directorylist, directorylist->cursor))->name;
697 	    CDrawTextInput (catstrs (identifier, ".finp", NULL), CIdent (identifier)->winid, textinput->x, textinput->y,
698 			textinput->width, textinput->height, 256, q);
699 	} else if (cwevent->insert > 0) {
700 	    input_insert (textinput, cwevent->insert);
701 	    if (goto_partial_file_name (directorylist, textinput->text))
702 		CExpose (directorylist->ident);
703 	    CExpose (textinput->ident);
704 	} else if (cwevent->command == CK_BackSpace && textinput->cursor > 0) {
705 	    textinput->text[--textinput->cursor] = '\0';
706 	    if (goto_partial_file_name (directorylist, textinput->text))
707 		CExpose (directorylist->ident);
708 	    CExpose (textinput->ident);
709 	}
710     }
711     if (!strcmp (cwevent->ident, textinput->ident)) {
712 	switch ((int) cwevent->command) {
713 	case CK_Enter:
714 	    if (!(options & (GETFILE_GET_DIRECTORY | GETFILE_BROWSER)))
715 		if (!strncmp ((CGetFilelistLine (filelist, filelist->cursor))->name, textinput->text, strlen (textinput->text))) {
716 		    CFocus (filelist);
717 		    CExpose (filelist->ident);
718 		    return "";
719 		}
720 	    break;
721 	case CK_Down:
722 	    if (textinput->keypressed) {
723 		if (goto_partial_file_name (filelist, textinput->text)) {
724 		    CFocus (filelist);
725 		    CExpose (filelist->ident);
726 		    break;
727 		}
728 	    }
729 	    CFocus (filelist);
730 	    CSetTextboxPos (filelist, TEXT_SET_CURSOR_LINE, 0);
731 	    CExpose (filelist->ident);
732 	    break;
733 	case CK_Up:
734 	    if (textinput->keypressed) {
735 		if (goto_partial_file_name (filelist, textinput->text)) {
736 		    CFocus (filelist);
737 		    CExpose (filelist->ident);
738 		    break;
739 		}
740 	    }
741 	    CFocus (filelist);
742 	    CSetTextboxPos (filelist, TEXT_SET_CURSOR_LINE, 999999);
743 	    CExpose (filelist->ident);
744 	    break;
745 	case CK_Page_Down:
746 	    CFocus (filelist);
747 	    CSetTextboxPos (filelist, TEXT_SET_CURSOR_LINE, filelist->height / FONT_PIX_PER_LINE - 1);
748 	    CExpose (filelist->ident);
749 	    break;
750 	case CK_Page_Up:
751 	    CFocus (filelist);
752 	    CSetTextboxPos (filelist, TEXT_SET_CURSOR_LINE, filelist->numlines - filelist->height / FONT_PIX_PER_LINE + 1);
753 	    CExpose (filelist->ident);
754 	    break;
755 	default:
756 	    if (cwevent->insert > 0)
757 		if (goto_partial_file_name (filelist, textinput->text))
758 		    CExpose (filelist->ident);
759 	    break;
760 	}
761     }
762     if (cwevent->command == CK_Cancel || !strcmp (cwevent->ident, catstrs (identifier, ".cancel", NULL)))
763 	return 0;
764 
765     if (options & GETFILE_GET_DIRECTORY) {
766 	if (!strcmp (cwevent->ident, catstrs (identifier, ".ok", NULL))) {
767 	    char *resolved_path;
768 	    resolved_path = pathdup (directory->text);
769 	    strcpy (estr, resolved_path);
770 	    free (resolved_path);
771 	    return estr;
772 	}
773     }
774     if (!strcmp (cwevent->ident, catstrs (identifier, ".ok", NULL))
775 	|| cwevent->command == CK_Enter
776 	|| (cwevent->double_click && !strcmp (cwevent->ident, catstrs (identifier, ".finp", NULL)))
777 	|| (cwevent->double_click && !strcmp (cwevent->ident, catstrs (identifier, ".dbox", NULL)))
778 	|| (cwevent->double_click && !strcmp (cwevent->ident, catstrs (identifier, ".fbox", NULL)))) {
779 	char *resolved_path;
780 	if (*textinput->text == '/' || *textinput->text == '~')
781 	    *estr = '\0';
782 	else {
783 	    strcpy (estr, directory->text);
784 	    strcat (estr, "/");
785 	}
786 	strcat (estr, textinput->text);
787 	resolved_path = pathdup (estr);
788 	strcpy (estr, resolved_path);
789 	free (resolved_path);
790 	textinput->keypressed = 0;
791 	q = estr + strlen (estr) - 1;
792 	if (!estr[0])
793 	    return "";
794 	if (stat (estr, &st)) {
795 	    if (errno == ENOENT) {
796 /* The user wanted a directory, but typed in one that doesn't exist */
797 		if (*q != '/' && !(options & GETFILE_GET_EXISTING_FILE) && !(options & (GETFILE_GET_DIRECTORY | GETFILE_BROWSER)))
798 /* user wants a new file */
799 		    return estr;
800 	    }
801 /* ********* */
802 	    CRedrawText (catstrs (identifier, ".msg", NULL), "%s", file_error());
803 	    return "";
804 	}
805 	if (S_ISDIR (st.st_mode)) {
806 	    struct file_entry *g = 0, *f = 0;
807 	    CHourGlass (CFirstWindow);
808 	    g = get_file_entry_list (estr, FILELIST_FILES_ONLY, filterinput->text);
809 	    CUnHourGlass (CFirstWindow);
810 	    if (g) {
811 		CRedrawFilelist (catstrs (identifier, ".fbox", NULL), g, 0);
812 		CRedrawFilelist (catstrs (identifier, ".dbox", NULL), f = get_file_entry_list (estr, FILELIST_DIRECTORIES_ONLY, ""), 0);
813 		if (*q != '/') {
814 		    *++q = '/';
815 		    *++q = '\0';
816 		}
817 		CRedrawText (catstrs (identifier, ".dir", NULL), "%s", estr);
818 		if (options & GETFILE_BROWSER)
819 		    CAddToTextInputHistory (textinput->ident, estr);
820 	    }
821 	    if (g)
822 		free (g);
823 	    if (f)
824 		free (f);
825 	    return "";
826 	} else {
827 	    if (options & (GETFILE_GET_DIRECTORY | GETFILE_BROWSER)) {
828 		CRedrawText (catstrs (identifier, ".msg", NULL), "%s", file_error());
829 		return "";
830 	    }
831 	    return estr;	/* entry exists and is a file */
832 	}
833     }
834     return "";
835 }
836 
837 Window find_mapped_window (Window w);
838 
839 /* result must be free'd */
look_cool_get_file_or_dir(Window parent,int x,int y,const char * dir,const char * file,const char * label,int options)840 char *look_cool_get_file_or_dir (Window parent, int x, int y,
841        const char *dir, const char *file, const char *label, int options)
842 {
843     CEvent cwevent;
844     XEvent xevent;
845     CState s;
846     CWidget *w;
847 
848     CBackupState (&s);
849     CDisable ("*");
850     CEnable ("_cfileBr*");
851 
852     parent = find_mapped_window (parent);
853     if (!(x | y)) {
854 	x = 20;
855 	y = 20;
856     }
857     draw_file_browser ("CGetFile", parent, x, y, dir, file, label);
858 
859     CFocus (CIdent ("CGetFile.finp"));
860 
861     file = "";
862     do {
863 	CNextEvent (&xevent, &cwevent);
864 	if (xevent.type == Expose || !xevent.type
865 	    || xevent.type == InternalExpose || xevent.type == TickEvent)
866 	    continue;
867 	if (!CIdent ("CGetFile")) {
868 	    file = 0;
869 	    break;
870 	}
871 	if (xevent.type == Expose || !xevent.type || xevent.type == AlarmEvent
872 	  || xevent.type == InternalExpose || xevent.type == TickEvent) {
873 	    file = "";
874 	    continue;
875 	}
876 	file = handle_browser ("CGetFile", &cwevent, options);
877 	if (!file)
878 	    break;
879     } while (!(*file));
880 
881 /* here we want to add the complete path to the text-input history: */
882     w = CIdent ("CGetFile.finp");
883     if (w) {
884 	if (w->text) {
885 	    free (w->text);
886 	    w->text = 0;
887 	}
888 	if (file)
889 	    w->text = (char *) strdup (file);
890     }
891     w = CIdent ("CGetFile.fbox");
892     if (w) {
893 	option_file_browser_width = (w->width - 7) / FONT_MEAN_WIDTH;
894 	if (option_file_browser_width < 10)
895 	    option_file_browser_width = 10;
896 	option_file_browser_height = (w->height - 6) / FONT_PIX_PER_LINE;
897 	if (option_file_browser_height < 10)
898 	    option_file_browser_height = 10;
899     }
900     CDestroyWidget ("CGetFile");	/* text is added to history
901 					   when text-input widget is destroyed */
902 
903     CRestoreState (&s);
904 
905     if (file) {
906 	return (char *) strdup (file);
907     } else
908 	return 0;
909 }
910 
cb_browser(CWidget * w,XEvent * x,CEvent * c)911 static int cb_browser (CWidget * w, XEvent * x, CEvent * c)
912 {
913     char id[32], *s;
914     strcpy (id, w->ident);
915     s = strchr (id, '.');
916     if (s)
917 	*s = 0;
918     if (!handle_browser (id, c, GETFILE_BROWSER)) {
919 	w = CIdent (catstrs (id, ".finp", NULL));
920 	if (w)
921 	    if (w->text) {
922 		free (w->text);
923 		w->text = 0;
924 	    }
925 	CDestroyWidget (id);
926     }
927     return 0;
928 }
929 
look_cool_draw_browser(const char * ident,Window parent,int x,int y,const char * dir,const char * file,const char * label)930 void look_cool_draw_browser (const char *ident, Window parent, int x, int y,
931 		   const char *dir, const char *file, const char *label)
932 {
933     if (!(parent | x | y)) {
934 	parent = CFirstWindow;
935 	x = 20;
936 	y = 20;
937     }
938 
939     draw_file_browser (ident, parent, x, y, dir, file, label);
940 
941     CAddCallback (catstrs (ident, ".dbox", NULL), cb_browser);
942     CAddCallback (catstrs (ident, ".fbox", NULL), cb_browser);
943     CAddCallback (catstrs (ident, ".finp", NULL), cb_browser);
944     CAddCallback (catstrs (ident, ".filt", NULL), cb_browser);
945     CAddCallback (catstrs (ident, ".ok", NULL), cb_browser);
946     CAddCallback (catstrs (ident, ".cancel", NULL), cb_browser);
947 
948     CFocus (CIdent (catstrs (ident, ".finp", NULL)));
949 }
950 
951 
952 /* }}} file browser stuff */
953 
954 int find_menu_hotkey (struct menu_item m[], int this, int num);
955 
956 /* outermost bevel */
957 #define BEVEL_MAIN	2
958 /* next-outermost bevel */
959 #define BEVEL_IN 	4
960 #define BEVEL_OUT	5
961 /* between items, and between items and next-outermost bevel */
962 #define SPACING		4
963 /* between items rectangle and text */
964 #define RELIEF		(TEXT_RELIEF + 1)
965 
966 #define S		SPACING
967 /* between window border and items */
968 #define O		(BEVEL_OUT + SPACING)
969 /* total height of an item */
970 
971 /* size of bar item */
972 #define BAR_HEIGHT	8
973 #define ITEM_BEVEL_TYPE 1
974 #define ITEM_BEVEL      1
975 
976 #define H		(FONT_PIX_PER_LINE + RELIEF * 2)
977 
978 #define B		BAR_HEIGHT
979 
look_cool_get_default_widget_font(void)980 static char *look_cool_get_default_widget_font (void)
981 {
982     return "-*-helvetica-bold-r-*--%d-*-*-*-*-*-*";
983 }
984 
look_cool_get_menu_item_extents(int n,int j,struct menu_item m[],int * border,int * relief,int * y1,int * y2)985 static void look_cool_get_menu_item_extents (int n, int j, struct menu_item m[], int *border, int *relief, int *y1, int *y2)
986 {
987     int i, n_items = 0, n_bars = 0;
988 
989     *border = O;
990     *relief = RELIEF;
991 
992     if (!n || j < 0) {
993 	*y1 = O;
994 	*y2 = *y1 + H;
995     } else {
996 	int not_bar;
997 	not_bar = (m[j].text[2] != '\0');
998 	for (i = 0; i < j; i++)
999 	    if (m[i].text[2])
1000 		n_items++;
1001 	    else
1002 		n_bars++;
1003 	*y1 = O + n_items * (H + S) + n_bars * (B + S) + (not_bar ? 0 : 2);
1004 	*y2 = *y1 + (not_bar ? H : (B - 4));
1005     }
1006 }
1007 
look_cool_menu_draw(Window win,int w,int h,struct menu_item m[],int n,int light)1008 static void look_cool_menu_draw (Window win, int w, int h, struct menu_item m[], int n, int light)
1009 {
1010     int i, y1, y2, offset = 0;
1011     static int last_light = 0, last_n = 0;
1012     static Window last_win = 0;
1013 
1014     render_bevel (win, 0, 0, w - 1, h - 1, BEVEL_MAIN, 0);
1015     render_bevel (win, BEVEL_IN, BEVEL_IN, w - 1 - BEVEL_IN, h - 1 - BEVEL_IN, BEVEL_OUT - BEVEL_IN, 1);
1016 
1017     if (last_win == win && last_n != n) {
1018 	XClearWindow (CDisplay, win);
1019     } else if (last_light >= 0 && last_light < n) {
1020 	int border, relief;
1021 	look_cool_get_menu_item_extents (n, last_light, m, &border, &relief, &y1, &y2);
1022 	CSetColor (COLOR_FLAT);
1023 	CRectangle (win, O - 1, y1 - 1, w - O * 2 + 2, y2 - y1 + 2);
1024     }
1025     last_win = win;
1026     last_n = n;
1027     CPushFont ("widget", 0);
1028     for (i = 0; i < n; i++) {
1029 	int border, relief;
1030 	look_cool_get_menu_item_extents (n, i, m, &border, &relief, &y1, &y2);
1031 	if (i == light && m[i].text[2]) {
1032 	    offset = 1;
1033 	    CSetColor (color_widget (11));
1034 	    CRectangle (win, O + 1, y1 + 1, w - O * 2 - 2, y2 - y1 - 2);
1035 	    render_bevel (win, O - 1, y1 - 1, w - O, y2, 2, 0);
1036 	} else {
1037 	    if (!(m[i].text[2]))
1038 		render_bevel (win, O + 6, y1, w - O - 1 - 6, y2 - 1, 2, 0);
1039 	    else
1040 		render_bevel (win, O, y1, w - O - 1, y2 - 1, ITEM_BEVEL, ITEM_BEVEL_TYPE);
1041 	    offset = 0;
1042 	}
1043 	if (m[i].text[2]) {
1044 
1045 	    char *u;
1046 	    u = strrchr (m[i].text, '\t');
1047 	    if (u)
1048 		*u = 0;
1049 	    CSetColor (COLOR_BLACK);
1050 	    if (m[i].hot_key == '~')
1051 		m[i].hot_key = find_menu_hotkey (m, i, n);
1052 	    if (i == light)
1053 		CSetBackgroundColor (color_widget (11));
1054 	    else
1055 		CSetBackgroundColor (COLOR_FLAT);
1056 	    drawstring_xy_hotkey (win, RELIEF + O - offset,
1057 			  RELIEF + y1 - offset, m[i].text, m[i].hot_key);
1058 	    if (u) {
1059 		drawstring_xy (win, RELIEF + O + (w - (O + RELIEF) * 2 - CImageStringWidth (u + 1)) - offset,
1060 			       RELIEF + y1 - offset, u + 1);
1061 		*u = '\t';
1062 	    }
1063 	}
1064     }
1065     last_light = light;
1066     CPopFont ();
1067 }
1068 
look_cool_render_menu_button(CWidget * wdt)1069 static void look_cool_render_menu_button (CWidget * wdt)
1070 {
1071     int w = wdt->width, h = wdt->height;
1072     int x = 0, y = 0;
1073 
1074     Window win = wdt->winid;
1075 
1076     if (wdt->disabled)
1077 	goto disabled;
1078     if (wdt->options & BUTTON_PRESSED) {
1079 	render_bevel (win, x, y, x + w - 1, y + h - 1, 2, 1);
1080     } else if (wdt->options & BUTTON_HIGHLIGHT) {
1081 	CSetColor (COLOR_FLAT);
1082 	XDrawRectangle (CDisplay, win, CGC, x + 1, y + 1, w - 3, h - 3);
1083 	render_bevel (win, x, y, x + w - 1, y + h - 1, 1, 0);
1084     } else {
1085   disabled:
1086 	CSetColor (COLOR_FLAT);
1087 	XDrawRectangle (CDisplay, win, CGC, x, y, w - 1, h - 1);
1088 	XDrawRectangle (CDisplay, win, CGC, x + 1, y + 1, w - 3, h - 3);
1089     }
1090 
1091     if (!wdt->label)
1092 	return;
1093     if (!(*(wdt->label)))
1094 	return;
1095     CSetColor (COLOR_BLACK);
1096     CPushFont ("widget", 0);
1097     CSetBackgroundColor (COLOR_FLAT);
1098     drawstring_xy_hotkey (win, x + 2 + BUTTON_RELIEF, y + 2 + BUTTON_RELIEF, wdt->label, wdt->hotkey);
1099     CPopFont ();
1100 }
1101 
look_cool_render_button(CWidget * wdt)1102 static void look_cool_render_button (CWidget * wdt)
1103 {
1104     int w = wdt->width, h = wdt->height;
1105     int x = 0, y = 0;
1106 
1107     Window win = wdt->winid;
1108 #define BUTTON_BEVEL 2
1109 
1110     if (wdt->disabled)
1111 	goto disabled;
1112     if (wdt->options & BUTTON_PRESSED) {
1113 	render_bevel (win, x, y, x + w - 1, y + h - 1, BUTTON_BEVEL, 1);
1114     } else if (wdt->options & BUTTON_HIGHLIGHT) {
1115 	CSetColor (COLOR_FLAT);
1116 	XDrawRectangle (CDisplay, win, CGC, x + 1, y + 1, w - 3, h - 3);
1117 	render_bevel (win, x, y, x + w - 1, y + h - 1, 1, 0);
1118     } else {
1119       disabled:
1120 	render_bevel (win, x, y, x + w - 1, y + h - 1, BUTTON_BEVEL, 0);
1121     }
1122 
1123     if (!wdt->label)
1124 	return;
1125     if (!(*(wdt->label)))
1126 	return;
1127     CSetColor (COLOR_BLACK);
1128     CSetBackgroundColor (COLOR_FLAT);
1129     CPushFont ("widget", 0);
1130     drawstring_xy_hotkey (win, x + 2 + BUTTON_RELIEF, y + 2 + BUTTON_RELIEF, wdt->label, wdt->hotkey);
1131     CPopFont ();
1132 }
1133 
look_cool_render_bar(CWidget * wdt)1134 static void look_cool_render_bar (CWidget * wdt)
1135 {
1136     int w = wdt->width, h = wdt->height;
1137 
1138     Window win = wdt->winid;
1139 
1140     CSetColor (COLOR_FLAT);
1141     CLine (win, 1, 1, w - 2, 1);
1142     render_bevel (win, 0, 0, w - 1, h - 1, 1, 1);
1143 }
1144 
look_cool_render_sunken_bevel(Window win,int x1,int y1,int x2,int y2,int thick,int sunken)1145 void look_cool_render_sunken_bevel (Window win, int x1, int y1, int x2, int y2, int thick, int sunken)
1146 {
1147     int i;
1148 
1149     if ((sunken & 2)) {
1150 	CSetColor (COLOR_FLAT);
1151 	CRectangle (win, x1 + thick, y1 + thick, x2 - x1 - 2 * thick + 1, y2 - y1 - 2 * thick + 1);
1152     }
1153 
1154     i = /* thick - 1 */ 0;
1155 
1156     CSetColor (color_widget (11));
1157     CLine (win, x1 + i, y2 - i, x2 - 1 - i, y2 - i);
1158     CLine (win, x2 - i, y1 + i, x2 - i, y2 - i - 1);
1159 
1160     CSetColor (color_widget (7));
1161     CLine (win, x1, y1, x1, y2 - 1);
1162     CLine (win, x1, y1, x2 - 1, y1);
1163 
1164     if (thick > 1) {
1165 	CSetColor (color_widget (4));
1166 	for (i = 1; i < thick; i++) {
1167 	    CLine (win, x1 + i + 1, y1 + i, x2 - 1 - i, y1 + i);
1168 	    CLine (win, x1 + i, y1 + i, x1 + i, y2 - 1 - i);
1169 	}
1170 	CSetColor (color_widget (13));
1171 	for (i = 1; i < thick; i++) {
1172 	    CLine (win, x2 - i, y1 + i, x2 - i, y2 - i - 1);
1173 	    CLine (win, x1 + i, y2 - i, x2 - i - 1, y2 - i);
1174 	}
1175     }
1176     CSetColor (color_widget (14));
1177     for (i = 0; i < thick; i++)
1178 	XDrawPoint (CDisplay, win, CGC, x2 - i, y2 - i);
1179 }
1180 
look_cool_render_raised_bevel(Window win,int x1,int y1,int x2,int y2,int thick,int sunken)1181 static void look_cool_render_raised_bevel (Window win, int x1, int y1, int x2, int y2, int thick, int sunken)
1182 {
1183     int i;
1184 
1185     if ((sunken & 2)) {
1186 	CSetColor (COLOR_FLAT);
1187 	CRectangle (win, x1 + thick, y1 + thick, x2 - x1 - 2 * thick + 1, y2 - y1 - 2 * thick + 1);
1188     }
1189 
1190     i = thick - 1;
1191 
1192     CSetColor (color_widget (7));
1193     CLine (win, x1 + i, y2 - i, x2 - i - 1, y2 - i);
1194     CLine (win, x2 - i, y1 + i, x2 - i, y2 - i);
1195 
1196     CSetColor (color_widget (12));
1197     CLine (win, x1 + i, y1 + i, x1 + i, y2 - 1 - i);
1198     CLine (win, x1 + 1 + i, y1 + i, x2 - 1 - i, y1 + i);
1199 
1200     if (thick > 1) {
1201 	CSetColor (color_widget (11));
1202 	for (i = 0; i < thick - 1; i++) {
1203 	    CLine (win, x1 + i + 1, y1 + i, x2 - 1 - i, y1 + i);
1204 	    CLine (win, x1 + i, y1 + i + 1, x1 + i, y2 - 1 - i);
1205 	}
1206 	CSetColor (color_widget (4));
1207 	for (i = 0; i < thick - 1; i++) {
1208 	    CLine (win, x2 - i, y1 + i, x2 - i, y2 - i);
1209 	    CLine (win, x1 + i, y2 - i, x2 - i - 1, y2 - i);
1210 	}
1211     }
1212     CSetColor (color_widget (15));
1213     for (i = 0; i < thick; i++)
1214 	XDrawPoint (CDisplay, win, CGC, x1 + i, y1 + i);
1215 }
1216 
look_cool_draw_hotkey_understroke(Window win,int x,int y,int hotkey)1217 static void look_cool_draw_hotkey_understroke (Window win, int x, int y, int hotkey)
1218 {
1219     CLine (win, x, y, x + FONT_PER_CHAR (hotkey), y);
1220     CLine (win, x - 1, y + 1, x + FONT_PER_CHAR (hotkey) / 2, y + 1);
1221     CLine (win, x - 1, y + 2, x + FONT_PER_CHAR (hotkey) / 4 - 1, y + 2);
1222 }
1223 
look_cool_render_text(CWidget * wdt)1224 static void look_cool_render_text (CWidget * wdt)
1225 {
1226     Window win = wdt->winid;
1227     char text[1024], *p, *q;
1228     int hot, y, w = wdt->width, center = 0;
1229 
1230     CPushFont ("widget", 0);
1231 
1232     CSetColor (COLOR_FLAT);
1233     CRectangle (win, 1, 1, w - 2, wdt->height - 2);
1234     CSetColor (COLOR_BLACK);
1235 
1236     hot = wdt->hotkey;		/* a letter that needs underlining */
1237     y = 1;			/* bevel */
1238     q = wdt->text;
1239 
1240     CSetBackgroundColor (COLOR_FLAT);
1241     for (;;) {
1242 	p = strchr (q, '\n');
1243 	if (!p) {	/* last line */
1244 	    if (wdt->options & TEXT_CENTRED)
1245 		center = (wdt->width - (TEXT_RELIEF + 1) * 2 - CImageTextWidth (q, strlen (q))) / 2;
1246 	    drawstring_xy_hotkey (win, TEXT_RELIEF + 1 + center,
1247 		 TEXT_RELIEF + y, q, hot);
1248 	    break;
1249 	} else {
1250 	    int l;
1251 	    l = min (1023, (unsigned long) p - (unsigned long) q);
1252 	    memcpy (text, q, l);
1253 	    text[l] = 0;
1254 	    if (wdt->options & TEXT_CENTRED)
1255 		center = (wdt->width - (TEXT_RELIEF + 1) * 2 - CImageTextWidth (q, l)) / 2;
1256 	    drawstring_xy_hotkey (win, TEXT_RELIEF + 1 + center,
1257 		 TEXT_RELIEF + y, text, hot);
1258 	}
1259 	y += FONT_PIX_PER_LINE;
1260 	hot = 0;	/* only for first line */
1261 	q = p + 1;	/* next line */
1262     }
1263     render_bevel (win, 0, 0, w - 1, wdt->height - 1, 1, 1);
1264     CPopFont ();
1265 }
1266 
look_cool_render_window(CWidget * wdt)1267 static void look_cool_render_window (CWidget * wdt)
1268 {
1269     int w = wdt->width, h = wdt->height;
1270 
1271     Window win = wdt->winid;
1272 
1273     if (wdt->options & WINDOW_NO_BORDER)
1274 	return;
1275 
1276     if (wdt->position & WINDOW_RESIZABLE) {
1277 	CSetColor (color_widget (13));
1278 	CLine (win, w - 4, h - 31, w - 31, h - 4);
1279 	CLine (win, w - 4, h - 21, w - 21, h - 4);
1280 	CLine (win, w - 4, h - 11, w - 11, h - 4);
1281 
1282 	CLine (win, w - 4, h - 32, w - 32, h - 4);
1283 	CLine (win, w - 4, h - 22, w - 22, h - 4);
1284 	CLine (win, w - 4, h - 12, w - 12, h - 4);
1285 
1286 	CSetColor (color_widget (3));
1287 	CLine (win, w - 4, h - 27, w - 27, h - 4);
1288 	CLine (win, w - 4, h - 17, w - 17, h - 4);
1289 	CLine (win, w - 4, h -  7, w -  7, h - 4);
1290 
1291 	CLine (win, w - 4, h - 28, w - 28, h - 4);
1292 	CLine (win, w - 4, h - 18, w - 18, h - 4);
1293 	CLine (win, w - 4, h -  8, w -  8, h - 4);
1294     }
1295     render_bevel (win, 0, 0, w - 1, h - 1, 2, 0);
1296     if (CRoot != wdt->parentid)
1297 	if (win == CGetFocus ())
1298 	    render_bevel (win, 4, 4, w - 5, h - 5, 3, 1);
1299 }
1300 
look_cool_render_vert_scrollbar(Window win,int x,int y,int w,int h,int pos,int prop,int pos2,int prop2,int flags)1301 static void look_cool_render_vert_scrollbar (Window win, int x, int y, int w, int h, int pos, int prop, int pos2, int prop2, int flags)
1302 {
1303     int l = h - 10 * w / 3 - 5;
1304 
1305     render_bevel (win, 0, 0, w - 1, h - 1, 2, 1);
1306     CSetColor (COLOR_FLAT);
1307     CRectangle (win, 2, w + 2 * w / 3 + 2, w - 4, (l - 5) * pos / 65535);
1308     CRectangle (win, 2, w + 2 * w / 3 + 3 + l * (prop + pos) / 65535, w - 4, h - 1 - w - 2 * w / 3 - (w + 2 * w / 3 + 4 + l * (prop + pos) / 65535));
1309 
1310     if (flags & 32) {
1311 	render_bevel (win, 2, 2, w - 3, w + 1, 2 - ((flags & 15) == 1), 2);
1312 	render_bevel (win, 2, w + 2, w - 3, w + 2 * w / 3 + 1, 2 - ((flags & 15) == 2), 2);
1313 	render_bevel (win, 2, h - 2 - w, w - 3, h - 3, 2 - ((flags & 15) == 4), 2);
1314 	render_bevel (win, 2, h - 2 - w - 2 * w / 3, w - 3, h - 3 - w, 2 - ((flags & 15) == 5), 2);
1315 	render_bevel (win, 2, w + 2 * w / 3 + 2 + (l - 5) * pos / 65535, w - 3, w + 2 * w / 3 + 7 + (l - 5) * (prop + pos) / 65535, 2 - ((flags & 15) == 3), 2);
1316     } else {
1317 	render_bevel (win, 2, 2, w - 3, w + 1, 2, 2 | ((flags & 15) == 1));
1318 	render_bevel (win, 2, w + 2, w - 3, w + 2 * w / 3 + 1, 2, 2 | ((flags & 15) == 2));
1319 	render_bevel (win, 2, h - 2 - w, w - 3, h - 3, 2, 2 | ((flags & 15) == 4));
1320 	render_bevel (win, 2, h - 2 - w - 2 * w / 3, w - 3, h - 3 - w, 2, 2 | ((flags & 15) == 5));
1321 	if ((flags & 15) == 3) {
1322 	    CSetColor (color_widget (5));
1323 	    XDrawRectangle (CDisplay, win, CGC, 4, w + 2 * w / 3 + 4 + (l - 5) * pos2 / 65535, w - 10, 2 + (l - 5) * prop2 / 65535);
1324 	}
1325 	render_bevel (win, 2, w + 2 * w / 3 + 2 + (l - 5) * pos / 65535, w - 3, w + 2 * w / 3 + 7 + (l - 5) * (prop + pos) / 65535, 2, 2 | ((flags & 15) == 3));
1326     }
1327 }
1328 
look_cool_render_hori_scrollbar(Window win,int x,int y,int h,int w,int pos,int prop,int flags)1329 static void look_cool_render_hori_scrollbar (Window win, int x, int y, int h, int w, int pos, int prop, int flags)
1330 {
1331     int l = h - 10 * w / 3 - 5, k;
1332     k = (l - 5) * pos / 65535;
1333 
1334     render_bevel (win, 0, 0, h - 1, w - 1, 2, 1);
1335     CSetColor (COLOR_FLAT);
1336 
1337     CRectangle (win, w + 2 * w / 3 + 2, 2, (l - 5) * pos / 65535, w - 4);
1338     CRectangle (win, w + 2 * w / 3 + 3 + l * (prop + pos) / 65535, 2, h - 1 - w - 2 * w / 3 - (w + 2 * w / 3 + 4 + l * (prop + pos) / 65535), w - 4);
1339 
1340     if (flags & 32) {
1341 	render_bevel (win, 2, 2, w + 1, w - 3, 2 - ((flags & 15) == 1), 2);
1342 	render_bevel (win, w + 2, 2, w + 2 * w / 3 + 1, w - 3, 2 - ((flags & 15) == 2), 2);
1343 	render_bevel (win, h - 2 - w, 2, h - 3, w - 3, 2 - ((flags & 15) == 4), 2);
1344 	render_bevel (win, h - 2 - w - 2 * w / 3, 2, h - 3 - w, w - 3, 2 - ((flags & 15) == 5), 2);
1345 	render_bevel (win, w + 2 * w / 3 + 2 + k, 2, w + 2 * w / 3 + 7 + (l - 5) * (prop + pos) / 65535, w - 3, 2 - ((flags & 15) == 3), 2);
1346     } else {
1347 	render_bevel (win, 2, 2, w + 1, w - 3, 2, 2 | ((flags & 15) == 1));
1348 	render_bevel (win, w + 2, 2, w + 2 * w / 3 + 1, w - 3, 2, 2 | ((flags & 15) == 2));
1349 	render_bevel (win, h - 2 - w, 2, h - 3, w - 3, 2, 2 | ((flags & 15) == 4));
1350 	render_bevel (win, h - 2 - w - 2 * w / 3, 2, h - 3 - w, w - 3, 2, 2 | ((flags & 15) == 5));
1351 	render_bevel (win, w + 2 * w / 3 + 2 + k, 2, w + 2 * w / 3 + 7 + (l - 5) * (prop + pos) / 65535, w - 3, 2, 2 | ((flags & 15) == 3));
1352     }
1353 }
1354 
look_cool_render_scrollbar(CWidget * wdt)1355 static void look_cool_render_scrollbar (CWidget * wdt)
1356 {
1357     int flags = wdt->options;
1358     if (!wdt)
1359 	return;
1360     if (wdt->numlines < 0)
1361 	wdt->numlines = 0;
1362     if (wdt->firstline < 0)
1363 	wdt->firstline = 0;
1364     if (wdt->firstline > 65535)
1365 	wdt->firstline = 65535;
1366     if (wdt->firstline + wdt->numlines >= 65535)
1367 	wdt->numlines = 65535 - wdt->firstline;
1368     if (wdt->kind == C_VERTSCROLL_WIDGET) {
1369 	look_cool_render_vert_scrollbar (wdt->winid,
1370 			      wdt->x, wdt->y,
1371 			      wdt->width, wdt->height,
1372 			      wdt->firstline, wdt->numlines, wdt->search_start, wdt->search_len, flags);
1373     } else
1374 	look_cool_render_hori_scrollbar (wdt->winid,
1375 			      wdt->x, wdt->y,
1376 			      wdt->width, wdt->height,
1377 			      wdt->firstline, wdt->numlines, flags);
1378     if (wdt->scroll_bar_extra_render)
1379 	(*wdt->scroll_bar_extra_render) (wdt);
1380 }
1381 
1382 /*
1383    Which scrollbar button was pressed: 3 is the middle button ?
1384  */
look_cool_which_scrollbar_button(int bx,int by,CWidget * wdt)1385 static int look_cool_which_scrollbar_button (int bx, int by, CWidget * wdt)
1386 {
1387     int w, h;
1388     int pos = wdt->firstline;
1389     int prop = wdt->numlines;
1390     int l;
1391 
1392     if (wdt->kind == C_VERTSCROLL_WIDGET) {
1393 	w = wdt->width;
1394 	h = wdt->height;
1395     } else {
1396 	int t = bx;
1397 	bx = by;
1398 	by = t;
1399 	w = wdt->height;
1400 	h = wdt->width;
1401     }
1402     l = h - 10 * w / 3 - 5;
1403 
1404     if (inbounds (bx, by, 2, 2, w - 3, w + 1))
1405 	return 1;
1406     if (inbounds (bx, by, 2, w + 2, w - 3, w + 2 * w / 3 + 1))
1407 	return 2;
1408     if (inbounds (bx, by, 2, h - 2 - w, w - 3, h - 3))
1409 	return 4;
1410     if (inbounds (bx, by, 2, h - 2 - w - 2 * w / 3, w - 3, h - 3 - w))
1411 	return 5;
1412     if (inbounds (bx, by, 2, w + 2 * w / 3 + 2 + (l - 5) * pos / 65535, w - 3, w + 2 * w / 3 + 7 + (l - 5) * (prop + pos) / 65535))
1413 	return 3;
1414     return 0;
1415 }
1416 
look_cool_scrollbar_handler(CWidget * w,XEvent * xevent,CEvent * cwevent)1417 int look_cool_scrollbar_handler (CWidget * w, XEvent * xevent, CEvent * cwevent)
1418 {
1419     static int buttonypos, y, whichscrbutton = 0;	/* which of the five scroll bar buttons was pressed */
1420     int xevent_xbutton_y, length, width;
1421 
1422     if (w->kind == C_VERTSCROLL_WIDGET) {
1423 	xevent_xbutton_y = xevent->xbutton.y;
1424 	length = w->height;
1425 	width = w->width;
1426     } else {
1427 	xevent_xbutton_y = xevent->xbutton.x;
1428 	length = w->width;
1429 	width = w->height;
1430     }
1431 
1432     switch (xevent->type) {
1433     case LeaveNotify:
1434     case Expose:
1435 	w->options = 0;
1436 	break;
1437     case ButtonRepeat:
1438 	resolve_button (xevent, cwevent);
1439 	if (cwevent->button == Button1 || cwevent->button == Button2) {
1440 	    int b;
1441 	    b = (*look->which_scrollbar_button) (cwevent->x, cwevent->y, w);
1442 	    if (b == 3 || !b)
1443 		return 0;
1444 	    y = w->firstline;
1445 	    buttonypos = xevent_xbutton_y;
1446 	    w->options = whichscrbutton = b;
1447 	    cwevent->ident = w->ident;
1448 	    xevent->type = cwevent->type = ButtonPress;
1449 	}
1450 	break;
1451     case ButtonPress:
1452 	resolve_button (xevent, cwevent);
1453 	if (cwevent->button == Button1 || cwevent->button == Button2) {
1454 	    buttonypos = xevent_xbutton_y;
1455 	    y = w->firstline;
1456 	    w->options = whichscrbutton =
1457 		(*look->which_scrollbar_button) (cwevent->x, cwevent->y, w);
1458 	    cwevent->ident = w->ident;
1459 	    w->search_start = w->firstline;
1460 	    w->search_len = w->numlines;
1461 	}
1462 	break;
1463     case ButtonRelease:
1464 	resolve_button (xevent, cwevent);
1465 	w->options = 32 + whichscrbutton;
1466 	if (whichscrbutton == 3) {
1467 	    y +=
1468 		(double) (xevent_xbutton_y - buttonypos) * (double) 65535.0 / (length -
1469 									       10 * width / 3 - 10);
1470 	    w->firstline = y;
1471 	    buttonypos = xevent_xbutton_y;
1472 	}
1473 	break;
1474     case MotionNotify:
1475 	resolve_button (xevent, cwevent);
1476 	if (cwevent->state & (Button1Mask | Button2Mask)) {
1477 	    w->options = whichscrbutton;
1478 	    if (whichscrbutton == 3) {
1479 		y +=
1480 		    (double) (xevent_xbutton_y - buttonypos) * (double) 65535.0 / (length -
1481 										   10 * width / 3 -
1482 										   10);
1483 		w->firstline = y;
1484 		buttonypos = xevent_xbutton_y;
1485 	    }
1486 	} else
1487 	    w->options =
1488 		32 + (*look->which_scrollbar_button) (xevent->xmotion.x, xevent->xmotion.y, w);
1489 	break;
1490     default:
1491 	return 0;
1492     }
1493 
1494     if (w->firstline > 65535)
1495 	w->firstline = 65535;
1496     if (cwevent->state & (Button1Mask | Button2Mask) || cwevent->type == ButtonPress
1497 	|| cwevent->type == ButtonRelease)
1498 	if (w->scroll_bar_link && w->vert_scrollbar)
1499 	    (*w->scroll_bar_link) (w, w->vert_scrollbar, xevent, cwevent, whichscrbutton);
1500 
1501     if (xevent->type != Expose || !xevent->xexpose.count)
1502 	(*look->render_scrollbar) (w);
1503 
1504     return 0;
1505 }
1506 
look_cool_init_scrollbar_icons(CWidget * w)1507 static void look_cool_init_scrollbar_icons (CWidget * w)
1508 {
1509     return;
1510 }
1511 
look_cool_get_scrollbar_size(int type)1512 static int look_cool_get_scrollbar_size (int type)
1513 {
1514     if (type == C_HORISCROLL_WIDGET)
1515 	return 13;
1516     return 20;
1517 }
1518 
1519 extern char *init_fg_color_red;
1520 extern char *init_fg_color_green;
1521 extern char *init_fg_color_blue;
1522 
look_cool_get_button_color(XColor * color,int i)1523 static void look_cool_get_button_color (XColor * color, int i)
1524 {
1525     double r, g, b, min_wc;
1526 
1527     r = 1 / atof (init_fg_color_red);
1528     g = 1 / atof (init_fg_color_green);
1529     b = 1 / atof (init_fg_color_blue);
1530 
1531     min_wc = min (r, min (g, b));
1532 
1533     color->red = (float) 65535 *my_pow ((float) i / 20, r) * my_pow (0.75, -min_wc);
1534     color->green = (float) 65535 *my_pow ((float) i / 20, g) * my_pow (0.75, -min_wc);
1535     color->blue = (float) 65535 *my_pow ((float) i / 20, b) * my_pow (0.75, -min_wc);
1536     color->flags = DoRed | DoBlue | DoGreen;
1537 }
1538 
look_cool_get_default_interwidget_spacing(void)1539 static int look_cool_get_default_interwidget_spacing (void)
1540 {
1541     return 4;
1542 }
1543 
look_cool_window_handler(CWidget * w,XEvent * xevent,CEvent * cwevent)1544 int look_cool_window_handler (CWidget * w, XEvent * xevent, CEvent * cwevent)
1545 {
1546     static Window window_is_resizing = 0;
1547     static int windowx, windowy;
1548     static int wx = 0, wy = 0;
1549     static int wwidth = 0, wheight = 0;
1550     static int allowwindowmove = 0;
1551     static int allowwindowresize = 0;
1552 
1553     switch (xevent->type) {
1554     case ClientMessage:
1555 	if (!w->disabled)
1556 	    cwevent->ident = w->ident;
1557 	break;
1558     case Expose:
1559 	if (!xevent->xexpose.count)
1560 	    render_window (w);
1561 	break;
1562     case ButtonRelease:
1563 	strcpy (cwevent->ident, w->ident);
1564 	window_is_resizing = 0;
1565 	resolve_button (xevent, cwevent);
1566 	allowwindowmove = 0;
1567 	allowwindowresize = 0;
1568 	break;
1569     case ButtonPress:
1570 	strcpy (cwevent->ident, w->ident);
1571 	resolve_button (xevent, cwevent);
1572 	if (cwevent->double_click == 1) {
1573 	    CWidget *c = CChildFocus (w);
1574 	    if (c)
1575 		CFocus (c);
1576 	}
1577 	if (cwevent->button == Button1 && !(w->position & WINDOW_ALWAYS_LOWERED)) {
1578 	    XRaiseWindow (CDisplay, w->winid);
1579 	    CRaiseWindows ();
1580 	} else if (cwevent->button == Button2 && !(w->position & WINDOW_ALWAYS_RAISED)) {
1581 	    XLowerWindow (CDisplay, w->winid);
1582 	    CLowerWindows ();
1583 	}
1584 	windowx = xevent->xbutton.x_root - w->x;
1585 	windowy = xevent->xbutton.y_root - w->y;
1586 	wx = xevent->xbutton.x;
1587 	wy = xevent->xbutton.y;
1588 	wwidth = w->width;
1589 	wheight = w->height;
1590 	if (wx + wy > w->width + w->height - 33 && w->position & WINDOW_RESIZABLE)
1591 	    allowwindowresize = 1;
1592 	else
1593 	    allowwindowmove = 1;
1594 	break;
1595     case MotionNotify:
1596 	resolve_button (xevent, cwevent);
1597 	if (!(w->position & WINDOW_UNMOVEABLE) && allowwindowmove
1598 	    && (cwevent->state & (Button1Mask | Button2Mask))) {
1599 	    w->x = xevent->xmotion.x_root - windowx;
1600 	    w->y = xevent->xmotion.y_root - windowy;
1601 	    if (w->x + xevent->xmotion.x < 2)
1602 		w->x = -wx + 2;
1603 	    if (w->y + xevent->xmotion.y < 2)
1604 		w->y = -wy + 2;
1605 	    XMoveWindow (CDisplay, w->winid, w->x, w->y);
1606 	}
1607 	if ((w->position & WINDOW_RESIZABLE) && allowwindowresize
1608 	    && (cwevent->state & (Button1Mask | Button2Mask))) {
1609 	    int wi, he;
1610 	    window_is_resizing = w->winid;
1611 	    wi = wwidth + xevent->xmotion.x_root - windowx - w->x;
1612 	    he = wheight + xevent->xmotion.y_root - windowy - w->y;
1613 
1614 /* this is actually for the edit windows, and needs to be generalized */
1615 	    if (wi < w->mark1)
1616 		wi = w->mark1;
1617 	    if (he < w->mark2)
1618 		he = w->mark2;
1619 
1620 	    wi -= w->firstcolumn;
1621 	    wi -= wi % w->textlength;
1622 	    wi += w->firstcolumn;
1623 	    he -= w->firstline;
1624 	    he -= he % w->numlines;
1625 	    he += w->firstline;
1626 	    w->position &= ~WINDOW_MAXIMISED;
1627 	    CSetSize (w, wi, he);
1628 	}
1629 	break;
1630     }
1631     return 0;
1632 }
1633 
1634 extern Pixmap Cswitchon;
1635 extern Pixmap Cswitchoff;
1636 
look_cool_render_switch(CWidget * wdt)1637 static void look_cool_render_switch (CWidget * wdt)
1638 {
1639     int w = wdt->width, h = wdt->height;
1640     Window win = wdt->winid;
1641     int x = 0, y = 0;
1642 
1643     CSetColor (COLOR_FLAT);
1644     CRectangle (win, x+5, y+5, w - 10, h - 10);
1645 
1646     CSetColor (wdt->fg);
1647     CSetBackgroundColor (wdt->bg);
1648     if (wdt->options & SWITCH_PICTURE_TYPE) {
1649 	if (wdt->keypressed)
1650 	    XCopyPlane (CDisplay, Cswitchon, win, CGC, 0, 0,
1651 			w, h, x, y, 1);
1652 	else
1653 	    XCopyPlane (CDisplay, Cswitchoff, win, CGC, 0, 0,
1654 			w, h, x, y, 1);
1655     } else {
1656 	if (wdt->keypressed)
1657 	{
1658 	    render_bevel (win, x + 3, y + 3, x + w - 4, y + h - 4, 2, 1);
1659 	}else
1660 	    render_bevel (win, x + 3, y + 3, x + w - 4, y + h - 4, 2, 0);
1661     }
1662     if (wdt->options & (BUTTON_HIGHLIGHT | BUTTON_PRESSED))
1663 	render_rounded_bevel (win, x, y, x + w - 1, y + h - 1, 7, 1, 1);
1664     else
1665 	render_rounded_bevel (win, x, y, x + w - 1, y + h - 1, 7, 1, 0);
1666 }
1667 
1668 extern unsigned long edit_normal_background_color;
1669 
look_cool_edit_render_tidbits(CWidget * wdt)1670 static void look_cool_edit_render_tidbits (CWidget * wdt)
1671 {
1672     int isfocussed;
1673     int w = wdt->width, h = wdt->height;
1674     Window win;
1675 
1676     win = wdt->winid;
1677     isfocussed = (win == CGetFocus ());
1678     CSetColor (COLOR_FLAT);
1679     if (isfocussed) {
1680 	render_bevel (win, 0, 0, w - 1, h - 1, 3, 1);	/*most outer border bevel */
1681     } else {
1682 	render_bevel (win, 2, 2, w - 3, h - 3, 1, 1);	/*border bevel */
1683 	render_bevel (win, 0, 0, w - 1, h - 1, 2, 0);	/*most outer border bevel */
1684     }
1685     CSetColor (edit_normal_background_color);
1686     CLine (CWindowOf (wdt), 3, 3, 3, CHeightOf (wdt) - 4);
1687 }
1688 
look_cool_draw_exclam_cancel_button(char * ident,Window win,int x,int y)1689 CWidget *look_cool_draw_exclam_cancel_button (char *ident, Window win, int x, int y)
1690 {
1691     CWidget *wdt;
1692     wdt = CDrawPixmapButton (ident, win, x, y, PIXMAP_BUTTON_EXCLAMATION);
1693     return wdt;
1694 }
1695 
look_cool_draw_tick_cancel_button(char * ident,Window win,int x,int y)1696 CWidget *look_cool_draw_tick_cancel_button (char *ident, Window win, int x, int y)
1697 {
1698     CWidget *wdt;
1699     wdt = CDrawPixmapButton (ident, win, x, y, PIXMAP_BUTTON_TICK);
1700     return wdt;
1701 }
1702 
look_cool_draw_cross_cancel_button(char * ident,Window win,int x,int y)1703 CWidget *look_cool_draw_cross_cancel_button (char *ident, Window win, int x, int y)
1704 {
1705     CWidget *wdt;
1706     wdt = CDrawPixmapButton (ident, win, x, y, PIXMAP_BUTTON_CROSS);
1707     return wdt;
1708 }
1709 
look_cool_render_fielded_textbox_tidbits(CWidget * w,int isfocussed)1710 static void look_cool_render_fielded_textbox_tidbits (CWidget * w, int isfocussed)
1711 {
1712     if (isfocussed) {
1713 	render_bevel (w->winid, 0, 0, w->width - 1, w->height - 1, 3, 1);	/*most outer border bevel */
1714     } else {
1715 	render_bevel (w->winid, 2, 2, w->width - 3, w->height - 3, 1, 1);	/*border bevel */
1716 	render_bevel (w->winid, 0, 0, w->width - 1, w->height - 1, 2, 0);	/*most outer border bevel */
1717     }
1718     CSetColor (edit_normal_background_color);
1719     CLine (w->winid, 3, 3, 3, w->height - 4);
1720 }
1721 
look_cool_render_textbox_tidbits(CWidget * w,int isfocussed)1722 static void look_cool_render_textbox_tidbits (CWidget * w, int isfocussed)
1723 {
1724     if (isfocussed) {
1725 	render_bevel (w->winid, 0, 0, w->width - 1, w->height - 1, 3, 1);	/*most outer border bevel */
1726     } else {
1727 	render_bevel (w->winid, 2, 2, w->width - 3, w->height - 3, 1, 1);	/*border bevel */
1728 	render_bevel (w->winid, 0, 0, w->width - 1, w->height - 1, 2, 0);	/*most outer border bevel */
1729     }
1730 }
1731 
look_cool_render_passwordinput_tidbits(CWidget * wdt,int isfocussed)1732 static void look_cool_render_passwordinput_tidbits (CWidget * wdt, int isfocussed)
1733 {
1734     int w = wdt->width, h = wdt->height;
1735     Window win = wdt->winid;
1736     if (isfocussed) {
1737 	render_bevel (win, 0, 0, w - 1, h - 1, 3, 1);
1738     } else {
1739 	render_bevel (win, 2, 2, w - 3, h - 3, 1, 1);
1740 	render_bevel (win, 0, 0, w - 1, h - 1, 2, 0);
1741     }
1742 }
1743 
look_cool_render_textinput_tidbits(CWidget * wdt,int isfocussed)1744 static void look_cool_render_textinput_tidbits (CWidget * wdt, int isfocussed)
1745 {
1746     int w = wdt->width, h = wdt->height;
1747     Window win = wdt->winid;
1748     if (isfocussed) {
1749 	render_bevel (win, 0, 0, w - h - 1, h - 1, 3, 1);	/*most outer border bevel */
1750     } else {
1751 	render_bevel (win, 2, 2, w - h - 3, h - 3, 1, 1);	/*border bevel */
1752 	render_bevel (win, 0, 0, w - h - 1, h - 1, 2, 0);	/*most outer border bevel */
1753     }
1754     if (wdt->options & BUTTON_PRESSED) {
1755 	CRectangle (win, w - h + 2, 2, h - 4, h - 4);
1756 	render_bevel (win, w - h, 0, w - 1, h - 1, 2, 3);
1757     } else if (wdt->options & BUTTON_HIGHLIGHT) {
1758 	CRectangle (win, w - h + 1, 1, h - 2, h - 2);
1759 	render_bevel (win, w - h, 0, w - 1, h - 1, 1, 2);
1760     } else {
1761 	CRectangle (win, w - h + 2, 2, h - 4, h - 4);
1762 	render_bevel (win, w - h, 0, w - 1, h - 1, 2, 2);
1763     }
1764 }
1765 
1766 extern struct focus_win focus_border;
1767 
render_focus_border_n(Window win,int i)1768 static void render_focus_border_n (Window win, int i)
1769 {
1770     int j;
1771     j = (i > 3) + 1;
1772     if (win == focus_border.top) {
1773 	render_bevel (win, 0, 0, focus_border.width + 2 * WIDGET_FOCUS_RING - 1, focus_border.height + 2 * WIDGET_FOCUS_RING - 1, j, 0);
1774 	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);
1775     } else if (win == focus_border.bottom) {
1776 	render_bevel (win, 0, 0 - focus_border.height, focus_border.width + 2 * WIDGET_FOCUS_RING - 1, WIDGET_FOCUS_RING - 1, j, 0);
1777 	render_bevel (win, i, i - focus_border.height, focus_border.width + 2 * WIDGET_FOCUS_RING - 1 - i, WIDGET_FOCUS_RING - 1 - i, 2, 1);
1778     } else if (win == focus_border.left) {
1779 	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);
1780 	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);
1781     } else if (win == focus_border.right) {
1782 	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);
1783 	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);
1784     }
1785 }
1786 
look_cool_render_focus_border(Window win)1787 static void look_cool_render_focus_border (Window win)
1788 {
1789     render_focus_border_n (win, focus_border.border);
1790 }
1791 
look_cool_get_extra_window_spacing(void)1792 static int look_cool_get_extra_window_spacing (void)
1793 {
1794     return 2;
1795 }
1796 
look_cool_get_focus_ring_size(void)1797 static int look_cool_get_focus_ring_size (void)
1798 {
1799     return 4;
1800 }
1801 
look_cool_get_button_flat_color(void)1802 static unsigned long look_cool_get_button_flat_color (void)
1803 {
1804     return color_widget(9);
1805 }
1806 
look_cool_get_window_resize_bar_thickness(void)1807 static int look_cool_get_window_resize_bar_thickness (void)
1808 {
1809     return 0;
1810 }
1811 
look_cool_get_switch_size(void)1812 static int look_cool_get_switch_size (void)
1813 {
1814     return FONT_PIX_PER_LINE + TEXT_RELIEF * 2 + 2 + 4;
1815 }
1816 
look_cool_get_fielded_textbox_hscrollbar_width(void)1817 static int look_cool_get_fielded_textbox_hscrollbar_width (void)
1818 {
1819     return 12;
1820 }
1821 
1822 struct look look_cool = {
1823     look_cool_get_default_interwidget_spacing,
1824     look_cool_menu_draw,
1825     look_cool_get_menu_item_extents,
1826     look_cool_render_menu_button,
1827     look_cool_render_button,
1828     look_cool_render_bar,
1829     look_cool_render_raised_bevel,
1830     look_cool_render_sunken_bevel,
1831     look_cool_draw_hotkey_understroke,
1832     look_cool_get_default_widget_font,
1833     look_cool_render_text,
1834     look_cool_render_window,
1835     look_cool_render_scrollbar,
1836     look_cool_get_scrollbar_size,
1837     look_cool_init_scrollbar_icons,
1838     look_cool_which_scrollbar_button,
1839     look_cool_scrollbar_handler,
1840     look_cool_get_button_color,
1841     look_cool_get_extra_window_spacing,
1842     look_cool_window_handler,
1843     look_cool_get_focus_ring_size,
1844     look_cool_get_button_flat_color,
1845     look_cool_get_window_resize_bar_thickness,
1846     look_cool_render_switch,
1847     look_cool_get_switch_size,
1848     look_cool_draw_browser,
1849     look_cool_get_file_or_dir,
1850     look_cool_draw_file_list,
1851     look_cool_redraw_file_list,
1852     look_cool_get_file_list_line,
1853     look_cool_search_replace_dialog,
1854     look_cool_edit_render_tidbits,
1855     look_cool_draw_exclam_cancel_button,
1856     look_cool_draw_tick_cancel_button,
1857     look_cool_draw_cross_cancel_button,
1858     look_cool_draw_tick_cancel_button,
1859     look_cool_render_fielded_textbox_tidbits,
1860     look_cool_render_textbox_tidbits,
1861     look_cool_get_fielded_textbox_hscrollbar_width,
1862     look_cool_render_textinput_tidbits,
1863     look_cool_render_passwordinput_tidbits,
1864     look_cool_render_focus_border,
1865 };
1866 
1867