1 /* coolwidget.c - routines for simple widgets. Widget setup and destruction
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 #define COOL_WIDGET_C
21 
22 #include <X11/Xatom.h>
23 #include "coolwidget.h"
24 #include "coollocal.h"
25 
26 #include "mad.h"
27 
28 extern struct look *look;
29 
30 
31 /* call this for fatal errors */
CError(const char * fmt,...)32 void CError (const char *fmt,...)
33 {
34     va_list s;
35     char *str;
36     va_start (s, fmt);
37     str = vsprintf_alloc (catstrs (" ", fmt, " ", NULL), s);
38     CFatalErrorDialog (20, 20, str);
39     va_end (s);
40     free (str);
41 }
42 
43 
44 
45 /* an malloc with an error check */
46 
47 #ifndef HAVE_MAD
48 
49 #ifndef CMalloc
CMalloc(size_t size)50 void *CMalloc (size_t size)
51 {
52     void *p;
53     if ((p = malloc (size + 8)) == NULL)
54 /* Not essential to translate */
55 	CError (_("Unable to allocate memory.\n"));
56     return p;
57 }
58 #endif
59 
60 #ifdef DEBUG
61 #ifndef HAVE_MAD
CDebugMalloc(size_t x,int line,const char * file)62 void *CDebugMalloc (size_t x, int line, const char *file)
63 {
64     void *p;
65     if ((p = malloc (x)) == NULL)
66 /* Not essential to translate */
67 	CError (_("Unable to allocate memory: line %d, file %s.\n"), line, file);
68     return p;
69 }
70 #endif
71 #endif
72 
73 #endif
74 
75 
allocate_color(char * color)76 int allocate_color (char *color)
77 {
78     if (!color)
79 	return NO_COLOR;
80     if (*color >= '0' && *color <= '9') {
81 	return atoi (color);
82     } else {
83 	int i;
84 	XColor c;
85 	if (!color)
86 	    return NO_COLOR;
87 	if (!XParseColor (CDisplay, CColormap, color, &c))
88 	    return NO_COLOR;
89 	if (!XAllocColor (CDisplay, CColormap, &c))
90 	    return NO_COLOR;
91 	for (i = 0; i < color_last_pixel; i++)
92 	    if (color_palette (i) == c.pixel)
93 		return i;
94 	color_palette (color_last_pixel) = c.pixel;
95 	return color_last_pixel++;
96     }
97 }
98 
99 
100 struct cursor_state {
101     int x, y, h, w;
102     Window window;
103     GC gc;
104     XFontSet font_set;
105     XFontStruct *font_struct;
106     int state;
107     int type;
108     wchar_t chr;
109     unsigned long bg, fg;
110     int style;
111     int font_x, font_y;
112 };
113 
114 struct cursor_state CursorState =
115 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
116 
117 void render_cursor (struct cursor_state c);
118 
set_cursor_position(Window win,int x,int y,int w,int h,int type,wchar_t chr,unsigned long bg,unsigned long fg,int style)119 void set_cursor_position (Window win, int x, int y, int w, int h, int type, wchar_t chr, unsigned long bg, unsigned long fg, int style)
120 {
121     if (win == CGetFocus ()) {
122 	CursorState.x = x;
123 	CursorState.y = y;
124 	CursorState.h = h;
125 	CursorState.w = w;
126 	CursorState.window = win;
127 	CursorState.gc = CGC;
128 	CursorState.font_set = current_font->font_set;
129 	CursorState.font_struct = current_font->font_struct;
130 	CursorState.type = type;
131 	CursorState.chr = chr;
132 	CursorState.style = style;
133 	CursorState.bg = bg;
134 	CursorState.fg = fg;
135 	CursorState.font_x = FONT_OFFSET_X;
136 	CursorState.font_y = FONT_OFFSET_Y;
137 	render_cursor (CursorState);
138     } else {
139 	if (!(win | h | w))
140 	    CursorState.window = 0;
141     }
142 }
143 
144 int option_never_raise_wm_windows = 0;
145 int option_xor_cursor = 0;
146 int option_flashing_cursor = 1;
147 unsigned long option_cursor_color;
148 
render_cursor(struct cursor_state c)149 void render_cursor (struct cursor_state c)
150 {
151     if (!CursorState.window)
152 	return;
153     if (c.type == CURSOR_TYPE_EDITOR) {
154 	if (CursorState.window != CGetFocus ())
155 	    return;
156 	CPushFont ("editor", 0);
157 	if (!option_xor_cursor) {
158 	    if (c.state || !option_flashing_cursor)
159 		CSetColor (option_cursor_color);
160 	    else
161 		CSetColor (c.bg);
162 	    if (c.style & MOD_REVERSE) {
163 		CLine (c.window, c.x + c.w - 1, c.y + FONT_OVERHEAD, c.x + c.w - 1, c.y + c.h - 1);
164 		CLine (c.window, c.x + c.w - 2, c.y + FONT_OVERHEAD, c.x + c.w - 2, c.y + c.h - 1);
165 	    } else {
166 		CLine (c.window, c.x, c.y + FONT_OVERHEAD, c.x, c.y + c.h - 1);
167 		CLine (c.window, c.x + 1, c.y + FONT_OVERHEAD, c.x + 1, c.y + c.h - 1);
168 	    }
169 	    CLine (c.window, c.x, c.y + FONT_OVERHEAD, c.x + c.w - 1, c.y + FONT_OVERHEAD);
170 	    CLine (c.window, c.x, c.y + FONT_OVERHEAD + 1, c.x + c.w - 1, c.y + FONT_OVERHEAD + 1);
171 	}
172 	if (!c.state && option_flashing_cursor) {
173 	    XSetBackground (CDisplay, c.gc, c.bg);
174 	    XSetForeground (CDisplay, c.gc, c.fg);
175 	    CImageTextWC (c.window, c.x + c.font_x, c.y + c.font_y, 0, &(c.chr), 1);
176 	} else {
177 	    if (option_xor_cursor) {
178 		XSetBackground (CDisplay, c.gc, c.fg);
179 		XSetForeground (CDisplay, c.gc, c.bg);
180 		CImageTextWC (c.window, c.x + c.font_x, c.y + c.font_y, 0, &(c.chr), 1);
181 	    }
182 	}
183 	CPopFont ();
184     } else {
185 	if (CursorState.window != CGetFocus ()) {
186 	    CSetColor (COLOR_FLAT);
187 	    CLine (c.window, c.x, c.y, c.x, c.y + c.h - 6);
188 	} else {
189 	    render_bevel (c.window, c.x - 1, c.y - 1, c.x, c.y + c.h - 5, 1, CursorState.state ? 0 : 1);
190 	}
191     }
192 }
193 
194 
CSetCursorColor(unsigned long c)195 void CSetCursorColor (unsigned long c)
196 {
197     option_cursor_color = c;
198 }
199 
200 /* this is called from CNextEvent if an alarm event comes */
toggle_cursor(void)201 void toggle_cursor (void)
202 {
203     CursorState.state = 1 - CursorState.state;
204     render_cursor (CursorState);
205 }
206 
set_cursor_visible(void)207 void set_cursor_visible (void)
208 {
209     CursorState.state = 1;
210     render_cursor (CursorState);
211 }
212 
set_cursor_invisible(void)213 void set_cursor_invisible (void)
214 {
215     CursorState.state = 0;
216     render_cursor (CursorState);
217 }
218 
219 
220 
221 /*
222    These three routines are not much slower than doing the same
223    thing with integers as identifiers instead of strings.
224    It returns the index in the global array of widgets of
225    the widget named ident. Returns 0 if not found.
226  */
find_ident(const char * ident)227 static int find_ident (const char *ident)
228 {
229     int i = last_widget + 1;
230     u_32bit_t p;
231 
232     if (!ident)
233 	return 0;
234     if (!ident[0])
235 	return 0;
236     memcpy (&p, ident, sizeof (u_32bit_t));	/* we need four byte alignment for some machines */
237 
238     if (!ident[1])
239 	goto word_search;
240     if (ident[2]) {		/* can compare first four bytes at once */
241 	while (--i)
242 	    if (CIndex (i))
243 		if (*((u_32bit_t *) CIndex (i)->ident) == p)
244 		    if (!strcmp (CIndex (i)->ident, ident))
245 			return i;
246 	return 0;
247     } else {
248 	word s;
249       word_search:
250 	s = *((word *) (&p));
251 	while (--i)
252 	    if (CIndex (i))
253 		if (*((word *) CIndex (i)->ident) == s)
254 		    if (!strcmp (CIndex (i)->ident, ident))
255 			return i;
256 
257     }
258     return 0;
259 }
260 
CIdent(const char * ident)261 CWidget *CIdent (const char *ident)
262 {
263     return CIndex (find_ident (ident));
264 }
265 
CWidgetOfWindow(Window win)266 CWidget *CWidgetOfWindow (Window win)
267 {
268     return CIndex (widget_of_window (win));
269 }
270 
CSystem(const char * string)271 int CSystem (const char *string)
272 {
273     int r;
274     CDisableAlarm ();
275     r = system (string);
276     CEnableAlarm ();
277     return r;
278 }
279 
280 extern int (*global_alarm_callback[33]) (CWidget *, XEvent *, CEvent *);
281 
CAddCallback(const char * ident,int (* callback)(CWidget *,XEvent *,CEvent *))282 void CAddCallback (const char *ident, int (*callback) (CWidget *, XEvent *, CEvent *))
283 {
284     CWidget *w = CIdent (ident);
285     if (w)
286 	w->callback = callback;
287     else {
288 	if (!strcmp (ident, "AlarmCallback"))
289 	    global_alarm_callback[0] = callback;
290 	if (!strncmp (ident, "AlarmCallback", 13))
291 	    global_alarm_callback[atoi (ident + 13) + 1] = callback;
292     }
293 }
294 
CAddBeforeCallback(const char * ident,int (* callback)(CWidget *,XEvent *,CEvent *))295 void CAddBeforeCallback (const char *ident, int (*callback) (CWidget *, XEvent *, CEvent *))
296 {
297     CWidget *w = CIdent (ident);
298     if (w)
299 	w->callback_before = callback;
300 }
301 
302 #ifdef DEBUG_DOUBLE
303 /* checks the magic numbers */
widget_check_magic()304 int widget_check_magic ()
305 {
306     int i = 0;
307 
308     while (last_widget > i++)
309 	if (CIndex (i) != NULL)
310 	    if (CIndex (i)->magic_begin != WIDGET_MAGIC_BEGIN || CIndex (i)->magic_end != WIDGET_MAGIC_END)
311 /* NLS ? */
312 		CError ("Cool widget internal error - magic number overwritten overwritten.\n");
313     return 0;
314 }
315 #endif
316 
317 /* sends a full expose event to the widget */
CExpose(const char * ident)318 void CExpose (const char *ident)
319 {
320     CWidget *w = CIdent (ident);
321     if (w)
322 	CSendExpose (w->winid, 0, 0, w->width, w->height);
323 }
324 
325 /* Returns the widgets window or 0 if not found */
CWindowOfWidget(const char * ident)326 Window CWindowOfWidget (const char *ident)
327 {
328     CWidget *w = CIdent (ident);
329     if (w)
330 	return w->winid;
331     else
332 	return 0;
333 }
334 
335 /* send an expose event to the internel queue */
CExposeWindowArea(Window win,int count,int x,int y,int w,int h)336 void CExposeWindowArea (Window win, int count, int x, int y, int w, int h)
337 {
338     if (x < 0) {
339 	w = x + w;
340 	x = 0;
341     }
342     if (y < 0) {
343 	h = y + h;
344 	y = 0;
345     }
346     if (w <= 0 || h <= 0)
347 	return;
348 
349     CSendExpose (win, x, y, w, h);
350 }
351 
352 
353 /* Returns the first NULL list entry. Exits if list full. */
find_empty_widget_entry()354 CWidget **find_empty_widget_entry ()
355 {
356     int i = 0;
357 
358 /* widget can be added to an empty point in the list (created from an
359    undraw command, or to the end of the list. */
360     while (last_widget > i++) {
361 	if (CIndex (i) == NULL)
362 	    break;
363     }
364 
365     if (i == MAX_NUMBER_OF_WIDGETS - 2)
366 /* NLS ? */
367 	CError ("No more space in widget list\nIncrease MAX_NUMBER_OF_WIDGETS in coolwidget.h\n");
368 
369     if (i == last_widget)
370 	last_widget++;		/* increase list length if an entry was added to the end */
371 
372     return &(CIndex (i));
373 }
374 
375 
376 /* Fills in the widget structure. */
allocate_widget(Window newwin,const char * ident,Window parent,int x,int y,int width,int height,int kindofwidget)377 CWidget *allocate_widget (Window newwin, const char *ident, Window parent, int x, int y,
378 			  int width, int height, int kindofwidget)
379 {
380     CWidget *w = CMalloc (sizeof (CWidget));
381     memset (w, 0, sizeof (CWidget));	/*: important, 'cos free's check if NULL before freeing many parems */
382 
383     w->magic_begin = WIDGET_MAGIC_BEGIN;
384     w->winid = newwin;
385     w->parentid = parent;
386     w->width = width;
387     w->height = height;
388     w->x = x;
389     w->y = y;
390     strncpy (w->ident, ident, 32);
391 
392     w->kind = kindofwidget;
393     w->magic_end = WIDGET_MAGIC_END;
394     return w;
395 }
396 
397 static int override_redirect = 0;
398 
CSetOverrideRedirect(void)399 void CSetOverrideRedirect (void)
400 {
401     override_redirect = 1;
402 }
403 
CClearOverrideRedirect(void)404 void CClearOverrideRedirect (void)
405 {
406     override_redirect = 0;
407 }
408 
409 
410 /*
411    Sets up the widget's window and calls allocate_widget()
412    to allocate space and set up the data structures.
413    What is set up here is common to all widgets, so
414    it will always be the first routine called by a CDraw...()
415    function.
416  */
CSetupWidget(const char * identifier,Window parent,int x,int y,int width,int height,int kindofwidget,unsigned long input,unsigned long bgcolor,int takes_focus)417 CWidget *CSetupWidget (const char *identifier, Window parent, int x, int y,
418 	    int width, int height, int kindofwidget, unsigned long input,
419 		       unsigned long bgcolor, int takes_focus)
420 {
421     XSetWindowAttributes xswa;
422     Window newwin;
423     CWidget **w;
424 
425 /* NLS ? */
426     if (CIdent (identifier) && kindofwidget == C_BUTTON_WIDGET)
427 /* Not essential to translate */
428 	CError (_ ("Trying to create a button with the same identifier as an existing widget.\n"));
429 
430     xswa.colormap = CColormap;
431     xswa.bit_gravity = NorthWestGravity;
432     xswa.background_pixel = bgcolor;
433     switch (kindofwidget) {
434     case C_MENU_WIDGET:
435     case C_TOOLHINT_WIDGET:
436     case C_ICON_WIDGET:
437 	xswa.override_redirect = 1;
438 	break;
439     default:
440 	xswa.override_redirect = override_redirect;
441 	break;
442     }
443 
444     newwin = XCreateWindow (CDisplay, parent, x, y, width, height, 0,
445 			    CDepth, InputOutput, CVisual,
446 	    CWOverrideRedirect | CWColormap | CWBackPixel | CWBitGravity,
447 			    &xswa);
448 
449     w = find_empty_widget_entry ();	/* find first unused list entry in list of widgets */
450     *w = allocate_widget (newwin, identifier, parent, x, y,
451 			  width, height, kindofwidget);
452 
453     (*w)->mainid = CFindParentMainWindow (parent);
454     (*w)->eh = default_event_handler (kindofwidget);
455     (*w)->takes_focus = takes_focus;
456 
457     XSelectInput (CDisplay, newwin, input);
458     switch ((*w)->kind) {
459     case C_WINDOW_WIDGET:	/* window widgets must only be mapped
460 				   once all there children are drawn */
461 #ifdef USE_XIM
462 	if (CIM) {
463 	    create_input_context (*w, get_input_style ());
464 	    set_status_position (*w);
465 	}
466 #endif
467 	break;
468     default:
469 	XMapWindow (CDisplay, newwin);	/* shows the window */
470 	XFlush (CDisplay);
471 	break;
472     }
473     return (*w);
474 }
475 
476 extern Atom ATOM_WM_PROTOCOLS, ATOM_WM_DELETE_WINDOW, ATOM_WM_TAKE_FOCUS, ATOM_WM_NAME, ATOM_WM_NORMAL_HINTS;
477 
CSetWindowSizeHints(CWidget * wdt,int min_w,int min_h,int max_w,int max_h)478 void CSetWindowSizeHints (CWidget * wdt, int min_w, int min_h, int max_w, int max_h)
479 {
480     XSizeHints size_hints;
481     long d;
482     size_hints.min_width = min_w;
483     size_hints.min_height = min_h;
484     size_hints.max_width = max_w;
485     size_hints.max_height = max_h;
486     size_hints.width_inc = FONT_MEAN_WIDTH;
487     size_hints.height_inc = FONT_PIX_PER_LINE;
488     size_hints.base_width = min_w;
489     size_hints.base_height = min_h;
490     size_hints.flags = PBaseSize | PResizeInc | PMaxSize | PMinSize;
491 
492     if (wdt->options & WINDOW_USER_POSITION) {
493 	size_hints.x = wdt->x;
494 	size_hints.y = wdt->y;
495 	size_hints.flags |= USPosition | PPosition;
496     }
497     if (wdt->options & WINDOW_USER_SIZE) {
498 	size_hints.width = wdt->width;
499 	size_hints.height = wdt->height;
500 	size_hints.flags |= USSize | PSize;
501     }
502 /* used as check if hints are not set when CMap is called */
503     wdt->options |= WINDOW_SIZE_HINTS_SET;
504 
505     XSetWMNormalHints (CDisplay, wdt->winid, &size_hints);
506     XSync (CDisplay, 0);
507     XGetWMNormalHints (CDisplay, wdt->winid, &size_hints, &d);
508     XSync (CDisplay, 0);
509 }
510 
CSetWindowResizable(const char * ident,int min_width,int min_height,int max_width,int max_height)511 void CSetWindowResizable (const char *ident, int min_width, int min_height, int max_width, int max_height)
512 {
513     Window w;
514     int width, height;
515     CWidget *wdt;
516 
517     wdt = CIdent (ident);
518     w = wdt->winid;
519     width = wdt->width;
520     height = wdt->height;
521 
522     min_width = width - ((width - min_width) / FONT_MEAN_WIDTH) * FONT_MEAN_WIDTH;
523     min_height = height - ((height - min_height) / FONT_PIX_PER_LINE) * FONT_PIX_PER_LINE;
524     max_width = width - ((width - max_width) / FONT_MEAN_WIDTH) * FONT_MEAN_WIDTH;
525     max_height = height - ((height - max_height) / FONT_PIX_PER_LINE) * FONT_PIX_PER_LINE;
526 
527     if (wdt->parentid == CRoot) {
528 	/* set the window manager to manage resizing */
529 	XWMHints wm_hints;
530 	XClassHint class_hints;
531 
532 	class_hints.res_name = CAppName;
533 	class_hints.res_class = CAppName;
534 	wm_hints.flags = (InputHint | StateHint);
535 	wm_hints.input = True;
536 	wm_hints.initial_state = NormalState;
537 
538 	XSetWMProperties (CDisplay, w, 0, 0, 0, 0, 0, &wm_hints, &class_hints);
539 	CSetWindowSizeHints (wdt, min_width, min_height, max_width, max_height);
540     } else {
541 /* else, we must manage our own resizing. */
542 /* the member names do not mean what they are named here */
543 	XSelectInput (CDisplay, w, INPUT_MOTION | StructureNotifyMask);
544 	wdt->position |= WINDOW_RESIZABLE;
545 	wdt->mark1 = min_width;
546 	wdt->mark2 = min_height;
547 	wdt->firstcolumn = width;
548 	wdt->firstline = height;
549 /* we are not going to specify a maximum */
550 	wdt->numlines = FONT_PIX_PER_LINE;	/* resizing granularity x */
551 	wdt->textlength = FONT_MEAN_WIDTH;	/* resizing granularity y */
552     }
553 }
554 
555 extern char *init_geometry;
556 
CDrawHeadedDialog(const char * identifier,Window parent,int x,int y,const char * label)557 Window CDrawHeadedDialog (const char *identifier, Window parent, int x, int y, const char *label)
558 {
559     Window win;
560     CWidget *wdt;
561 
562     if ((parent == CRoot || !parent) && !override_redirect) {
563 	int width, height, bitmask;
564 	bitmask = 0;
565 	x = 0;
566 	y = 0;
567 	width = 10;
568 	height = 10;
569 	parent = CRoot;
570 	if (!CFirstWindow) {
571 	    if (init_geometry)
572 		bitmask = XParseGeometry (init_geometry, &x, &y, (unsigned int *) &width, (unsigned int *) &height);
573 	}
574 	win = (wdt = CSetupWidget (identifier, CRoot, x, y,
575 	width, height, C_WINDOW_WIDGET, INPUT_MOTION | StructureNotifyMask
576 			       | FocusChangeMask, COLOR_FLAT, 0))->winid;
577 	if (!CFirstWindow) {	/* create the GC the first time round and
578 				   CFirstWindow. when the window is closed,
579 				   the app gets a QuitApplication event */
580 	    CFirstWindow = win;
581 
582 /* these options tell CSetWindowSizeHints() to give those hints to the WM: */
583 	    if (bitmask & (XValue | YValue))
584 		wdt->options |= WINDOW_USER_POSITION;
585 	    if (bitmask & (WidthValue | HeightValue))
586 		wdt->options |= WINDOW_USER_SIZE;
587 	}
588 	wdt->label = (char *) strdup (label);
589 	XSetIconName (CDisplay, win, wdt->label);
590 	XStoreName (CDisplay, win, wdt->label);
591 	{
592 	    Atom a[2];
593 	    a[0] = ATOM_WM_DELETE_WINDOW;
594 #if 0
595 	    a[1] = ATOM_WM_TAKE_FOCUS;
596 	    XChangeProperty (CDisplay, win, ATOM_WM_PROTOCOLS, XA_ATOM, 32,
597 		PropModeReplace, (unsigned char *) a, 2);
598 #else
599 	    XChangeProperty (CDisplay, win, ATOM_WM_PROTOCOLS, XA_ATOM, 32,
600 		PropModeReplace, (unsigned char *) a, 1);
601 #endif
602 	}
603 	reset_hint_pos (WIDGET_SPACING + 2, WIDGET_SPACING + 2);
604 	wdt->position |= WINDOW_UNMOVEABLE;
605 	wdt->options |= WINDOW_NO_BORDER;
606     } else {
607 	int w, h;
608 	CTextSize (&w, &h, label);
609 	win = CDrawDialog (identifier, parent, x, y);
610 	(CDrawText (catstrs (identifier, ".header", NULL), win, WIDGET_SPACING, WIDGET_SPACING + 2, label))->position |= POSITION_CENTRE;
611 	CGetHintPos (&x, &y);
612 #ifndef NEXT_LOOK
613 	(CDrawBar (win, WIDGET_SPACING, y, 10))->position |= POSITION_FILL;
614 	CGetHintPos (&x, &y);
615 #endif
616 	reset_hint_pos (WIDGET_SPACING + 2, y);
617     }
618     return win;
619 }
620 
CDrawDialog(const char * identifier,Window parent,int x,int y)621 Window CDrawDialog (const char *identifier, Window parent, int x, int y)
622 {
623     Window w;
624     CWidget *wdt;
625     w = (wdt = CSetupWidget (identifier, parent, x, y,
626 	     2, 2, C_WINDOW_WIDGET, INPUT_MOTION, COLOR_FLAT, 0))->winid;
627     reset_hint_pos (WIDGET_SPACING + 2, WIDGET_SPACING + 2);
628     return w;
629 }
630 
631 /* returns the actual window that is a child  of the root window */
632 /* this is not the same as a main window, since the WM places each */
633 /* main window inside a cosmetic window */
CGetWMWindow(Window win)634 Window CGetWMWindow (Window win)
635 {
636     Window root, parent, *children;
637     unsigned int nchildren;
638 
639     for (;;) {
640 	if (!XQueryTree (CDisplay, win, &root, &parent, &children, &nchildren))
641 	    break;
642 	if (parent == CRoot)
643 	    return win;
644 	if (children)
645 	    XFree ((char *) children);
646 	win = parent;
647     }
648     return 0;
649 }
650 
651 /* I tested this procedure with kwm, fvwm95, fvwm, twm, olwm, without problems */
CRaiseWMWindow(char * ident)652 void CRaiseWMWindow (char *ident)
653 {
654     Window wm_win;
655     CWidget *w;
656     XWindowChanges c;
657     XEvent ev;
658 
659     w = CIdent (ident);
660     if (!w)
661 	return;
662     wm_win = CGetWMWindow (w->mainid);
663     if (!wm_win)
664 	return;
665     c.stack_mode = Above;
666     XConfigureWindow (CDisplay, wm_win, CWStackMode, &c);
667     XFlush (CDisplay);
668 }
669 
CSetBackgroundPixmap(const char * ident,const char * data[],int w,int h,char start_char)670 void CSetBackgroundPixmap (const char *ident, const char *data[], int w, int h, char start_char)
671 {
672     XSetWindowAttributes xswa;
673     CWidget *wdt;
674     wdt = CIdent (ident);
675     if (wdt->pixmap)
676 	XFreePixmap (CDisplay, wdt->pixmap);
677     xswa.background_pixmap = wdt->pixmap = CCreatePixmap (data, w, h, start_char);
678     if (xswa.background_pixmap)
679 	XChangeWindowAttributes (CDisplay, wdt->winid, CWBackPixmap, &xswa);
680 }
681 
682 #define MAX_KEYS_IN_DIALOG 64
683 
find_letter_at_word_start(unsigned char * label,unsigned char * used_keys,int n)684 int find_letter_at_word_start (unsigned char *label, unsigned char *used_keys, int n)
685 {
686     int c, j;
687     for (j = 0; label[j]; j++) {	/* check for letters with an & in front of them */
688 	c = my_lower_case (label[j + 1]);
689 	if (!c)
690 	    break;
691 	if (label[j] == '&')
692 	    if (!memchr (used_keys, c, n))
693 		return label[j + 1];
694     }
695     c = my_lower_case (label[0]);
696     if (c >= 'a' && c <= 'z')
697 	if (!memchr (used_keys, c, n))	/* check if first letter has not already been used */
698 	    return label[0];
699     for (j = 1; label[j]; j++) {	/* check for letters at start of words that have not already been used */
700 	c = my_lower_case (label[j]);
701 	if (label[j - 1] == ' ' && c >= 'a' && c <= 'z')
702 	    if (!memchr (used_keys, c, n))
703 		return label[j];
704     }
705     for (j = 1; label[j]; j++) {	/* check for any letters that have not already been used */
706 	c = my_lower_case (label[j]);
707 	if (c >= 'a' && c <= 'z')
708 	    if (!memchr (used_keys, c, n))
709 		return label[j];
710     }
711     return 0;
712 }
713 
find_hotkey(CWidget * w)714 int find_hotkey (CWidget * w)
715 {
716     unsigned char used_keys[MAX_KEYS_IN_DIALOG + 3];
717     const char *label;
718     int n = 0;
719     CWidget *p = w;
720     label = w->label ? w->label : w->text;	/* text for text-widgets which don't have a label */
721     if (!label)
722 	return 0;
723     if (!*label)
724 	return 0;
725     do {
726 	w = CNextFocus (w);
727 	if (!w || n == MAX_KEYS_IN_DIALOG)
728 	    return 0;
729 	if (w->hotkey < 256)
730 	    used_keys[n++] = my_lower_case (w->hotkey);
731     } while ((unsigned long) w != (unsigned long) p);
732     if (!n)
733 	return 0;
734     return find_letter_at_word_start ((unsigned char *) label, used_keys, n);
735 }
736 
737 
CDrawButton(const char * identifier,Window parent,int x,int y,int width,int height,const char * label)738 CWidget *CDrawButton (const char *identifier, Window parent, int x, int y,
739 		      int width, int height, const char *label)
740 {
741     CWidget *wdt;
742     int w, h;
743     CPushFont ("widget", 0);
744     if (width == AUTO_WIDTH || height == AUTO_HEIGHT)
745 	CTextSize (&w, &h, label);
746     if (width == AUTO_WIDTH)
747 	width = w + 4 + BUTTON_RELIEF * 2;
748     if (height == AUTO_HEIGHT) {
749 	height = h + 4 + BUTTON_RELIEF * 2;
750 #ifdef NEXT_LOOK
751 	height++ ;
752 #endif
753     }
754     wdt = CSetupWidget (identifier, parent, x, y,
755 	    width, height, C_BUTTON_WIDGET, INPUT_BUTTON, COLOR_FLAT, 1);
756     if (label)
757 	wdt->label = (char *) strdup (label);
758     wdt->hotkey = find_hotkey (wdt);
759     wdt->render = render_button;
760     wdt->options |= WIDGET_TAKES_FOCUS_RING | WIDGET_HOTKEY_ACTIVATES;
761     set_hint_pos (x + width + WIDGET_SPACING, y + height + WIDGET_SPACING);
762     CPopFont ();
763     return wdt;
764 }
765 
CDrawProgress(const char * identifier,Window parent,int x,int y,int width,int height,int p)766 CWidget *CDrawProgress (const char *identifier, Window parent, int x, int y,
767 			int width, int height, int p)
768 {
769     CWidget *w;
770     if ((w = CIdent (identifier))) {
771 	w->cursor = p;
772 	CSetWidgetPosition (identifier, x, y);
773 	CSetWidgetSize (identifier, width, height);
774 	CExpose (identifier);
775     } else {
776 	w = CSetupWidget (identifier, parent, x, y,
777 	       width, height, C_PROGRESS_WIDGET, INPUT_EXPOSE, COLOR_FLAT, 0);
778 	w->cursor = p;
779 	set_hint_pos (x + width + WIDGET_SPACING, y + height + WIDGET_SPACING);
780     }
781     return w;
782 }
783 
CDrawBar(Window parent,int x,int y,int w)784 CWidget *CDrawBar (Window parent, int x, int y, int w)
785 {
786     CWidget *wdt;
787     wdt = CSetupWidget ("hbar", parent, x, y,
788 			 w, 3, C_BAR_WIDGET, INPUT_EXPOSE, COLOR_FLAT, 0);
789     set_hint_pos (x + w + WIDGET_SPACING, y + 3 + WIDGET_SPACING);
790     return wdt;
791 }
792 
793 /* returns the text size. The result is one descent greater than the actual size */
CTextSize(int * w,int * h,const char * str)794 void CTextSize (int *w, int *h, const char *str)
795 {
796     char *p, *q = (char *) str;
797     int w1, h1;
798     if (!w)
799 	w = &w1;
800     if (!h)
801 	h = &h1;
802     *w = *h = 0;
803     for (;;) {
804 	if (!(p = strchr (q, '\n')))
805 	    p = q + strlen (q);
806 	*h += FONT_PIX_PER_LINE;
807 	*w = max (CImageTextWidth (q, (unsigned long) p - (unsigned long) q), *w);
808 	if (!*p)
809 	    break;
810 	q = p + 1;
811     }
812 }
813 
814 
CDrawText(const char * identifier,Window parent,int x,int y,const char * fmt,...)815 CWidget *CDrawText (const char *identifier, Window parent, int x, int y, const char *fmt,...)
816 {
817     va_list pa;
818     char *str;
819     int w, h;
820     CWidget *wdt;
821 
822     va_start (pa, fmt);
823     str = vsprintf_alloc (fmt, pa);
824     va_end (pa);
825 
826     CPushFont ("widget", 0);
827     CTextSize (&w, &h, str);
828     w += TEXT_RELIEF * 2 + 2;
829     h += TEXT_RELIEF * 2 + 2;
830     wdt = CSetupWidget (identifier, parent, x, y,
831 			w, h, C_TEXT_WIDGET, INPUT_EXPOSE, COLOR_FLAT, 0);
832     wdt->text = (char *) strdup (str);
833     free (str);
834     set_hint_pos (x + w + WIDGET_SPACING, y + h + WIDGET_SPACING);
835     CPopFont ();
836     return wdt;
837 }
838 
CDrawStatus(const char * identifier,Window parent,int x,int y,int w,char * str)839 CWidget *CDrawStatus (const char *identifier, Window parent, int x, int y, int w, char *str)
840 {
841     CWidget *wdt;
842     int h;
843     h = FONT_PIX_PER_LINE + TEXT_RELIEF * 2 + 2;
844     wdt = CSetupWidget (identifier, parent, x, y,
845 		     w, h, C_STATUS_WIDGET, INPUT_EXPOSE, COLOR_FLAT, 0);
846     wdt->text = (char *) strdup (str);
847     set_hint_pos (x + w + WIDGET_SPACING, y + h + WIDGET_SPACING);
848     return wdt;
849 }
850 
851 void render_text (CWidget * w);
852 
CRedrawText(const char * identifier,const char * fmt,...)853 CWidget *CRedrawText (const char *identifier, const char *fmt,...)
854 {
855     va_list pa;
856     char *str;
857     CWidget *wdt;
858     int w, h;
859 
860     wdt = CIdent (identifier);
861     if (!wdt)
862 	return 0;
863 
864     va_start (pa, fmt);
865     str = vsprintf_alloc (fmt, pa);
866     va_end (pa);
867 
868     free (wdt->text);
869     wdt->text = (char *) strdup (str);
870 
871     CTextSize (&w, &h, str);
872     w += TEXT_RELIEF * 2 + 2;
873     h += TEXT_RELIEF * 2 + 2;
874 
875     CSetWidgetSize (identifier, w, h);
876     render_text (wdt);
877     free (str);
878     return wdt;
879 }
880 
881 void focus_stack_remove_window (Window w);
882 void selection_clear (void);
883 
884 /*
885    Unmaps and destroys widget and frees memory.
886    Only for a widget that has no children.
887  */
free_single_widget(int i)888 int free_single_widget (int i)
889 {
890     if (i && CIndex (i)) {
891 	if (CIndex (i)->winid) {
892 	    if (CIndex (i)->options & WIDGET_TAKES_SELECTION) {
893 		if (CIndex (i)->winid == XGetSelectionOwner (CDisplay, XA_PRIMARY))
894 		    XSetSelectionOwner (CDisplay, XA_PRIMARY, CFirstWindow, CurrentTime);
895 		if (CIndex (i)->winid == XGetSelectionOwner (CDisplay, ATOM_ICCCM_P2P_CLIPBOARD))
896 		    XSetSelectionOwner (CDisplay, ATOM_ICCCM_P2P_CLIPBOARD, CFirstWindow, CurrentTime);
897             }
898 	    if (CursorState.window == CIndex (i)->winid)
899 		set_cursor_position (0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
900 	    XUnmapWindow (CDisplay, CIndex (i)->winid);
901 	    XDestroyWindow (CDisplay, CIndex (i)->winid);
902 	    if (CFirstWindow == CIndex (i)->winid)
903 		CFirstWindow = 0;
904 	    focus_stack_remove_window (CIndex (i)->winid);	/* removes the window from the focus history stack */
905 	}
906 	if (CIndex (i)->label)
907 	    free (CIndex (i)->label);
908 	if (CIndex (i)->toolhint)
909 	    free (CIndex (i)->toolhint);
910 	if (CIndex (i)->headings)
911 	    free (CIndex (i)->headings);
912 	if (CIndex (i)->gl_graphicscontext) {
913 	    free (CIndex (i)->gl_graphicscontext);
914 	    CIndex (i)->gl_graphicscontext = 0;
915 	}
916 	if (CIndex (i)->ximage) {
917 	    if ((long) CIndex (i)->ximage->data == (long) CIndex (i)->graphic)
918 		CIndex (i)->graphic = NULL;
919 	    if (CIndex (i)->ximage->data) {
920 		free (CIndex (i)->ximage->data);
921 		CIndex (i)->ximage->data = 0;
922 	    }
923 	    XDestroyImage (CIndex (i)->ximage);
924 	}
925 	if (CIndex (i)->pixmap) {
926 	    XFreePixmap (CDisplay, CIndex (i)->pixmap);
927 	    CIndex (i)->pixmap = 0;
928 	}
929 	if (CIndex (i)->pixmap_mask) {
930 	    XFreePixmap (CDisplay, CIndex (i)->pixmap_mask);
931 	    CIndex (i)->pixmap_mask = 0;
932 	}
933 	if (CIndex (i)->graphic)
934 	    free (CIndex (i)->graphic);
935 	if (CIndex (i)->tab)
936 	    free (CIndex (i)->tab);
937 	if (CIndex (i)->destroy)
938 	    (*(CIndex (i)->destroy)) (CIndex (i));
939 	if (CIndex (i)->text)
940 	    free (CIndex (i)->text);	/* for input history, this must come
941 					   after the destroy, so that the text can be added to the input
942 					   history by the destroy function before the text is free'd */
943 	if (CIndex (i)->funcs)
944 	    free (CIndex (i)->funcs);
945 	if (CIndex (i)->free_user)
946 	    (*(CIndex (i)->free_user)) (CIndex (i)->user);
947 	else if (CIndex (i)->user && (CIndex (i)->options & WIDGET_FREE_USER_ON_DESTROY))
948 	    free (CIndex (i)->user);
949 	free (CIndex (i));
950 	CIndex (i) = NULL;
951 	while (!CIndex (last_widget - 1) && last_widget > 1)
952 	    last_widget--;
953 	return 1;
954     } else
955 	return 0;
956 }
957 
958 /*searches for the first widget in the list that has win as its parent
959    and returns index */
find_first_child_of(Window win)960 int find_first_child_of (Window win)
961 {
962     int i = 0;
963     while (last_widget > i++)
964 	if (CIndex (i) != NULL)
965 	    if (CIndex (i)->parentid == win)
966 		return i;
967     return 0;
968 }
969 
find_last_child_of(Window win)970 int find_last_child_of (Window win)
971 {
972     int i = last_widget;
973     while (--i > 0)
974 	if (CIndex (i) != NULL)
975 	    if (CIndex (i)->parentid == win)
976 		return i;
977     return 0;
978 }
979 
980 /* int for_all_widgets (int (callback *) (CWidget *, void *, void *), void *data1, void *data2) */
for_all_widgets(for_all_widgets_cb_t call_back,void * data1,void * data2)981 long for_all_widgets (for_all_widgets_cb_t call_back, void *data1, void *data2)
982 {
983     long (*callback) (CWidget *, void *, void *) = (for_all_widgets_cb_t) call_back;
984     int i = last_widget;
985     while (--i > 0)
986 	if (CIndex (i) != NULL)
987 	    if ((*callback) (CIndex (i), data1, data2))
988 		return 1;
989     return 0;
990 }
991 
widget_of_window(Window win)992 int widget_of_window (Window win)
993 {
994     int i = 0;
995     while (last_widget > i++)
996 	if (CIndex (i) != NULL)
997 	    if (CIndex (i)->winid == win)
998 		return i;
999     return 0;
1000 }
1001 
find_next_child_of(Window win,Window child)1002 int find_next_child_of (Window win, Window child)
1003 {
1004     int i = widget_of_window (child);
1005     if (i)
1006 	while (last_widget > i++)
1007 	    if (CIndex (i) != NULL)
1008 		if (CIndex (i)->parentid == win)
1009 		    return i;
1010     return 0;
1011 }
1012 
find_previous_child_of(Window win,Window child)1013 int find_previous_child_of (Window win, Window child)
1014 {
1015     int i = widget_of_window (child);
1016     if (i)
1017 	while (--i > 0)
1018 	    if (CIndex (i) != NULL)
1019 		if (CIndex (i)->parentid == win)
1020 		    return i;
1021     return 0;
1022 }
1023 
CDialogOfWindow(Window window)1024 CWidget *CDialogOfWindow (Window window)
1025 {
1026     for (;;) {
1027 	CWidget *w;
1028 	w = CWidgetOfWindow (window);
1029 	if (!w)
1030 	    break;
1031 	if (w->kind == C_WINDOW_WIDGET)
1032 	    return w;
1033 	window = w->parentid;
1034     }
1035     return 0;
1036 }
1037 
CFindParentMainWindow(Window parent)1038 Window CFindParentMainWindow (Window parent)
1039 {
1040     int i;
1041     if (parent == CRoot)
1042 	return 0;
1043     if (!(i = widget_of_window (parent)))
1044 	return 0;
1045     if (!CIndex (i)->mainid)
1046 	return CIndex (i)->winid;
1047     return CIndex (i)->mainid;
1048 }
1049 
1050 /*recursively destroys a widget and all its descendants */
recursive_destroy_widgets(int i)1051 static void recursive_destroy_widgets (int i)
1052 {
1053     int j;
1054     while ((j = find_first_child_of (CIndex (i)->winid)))
1055 	recursive_destroy_widgets (j);
1056     free_single_widget (i);
1057 }
1058 
1059 void CFocusLast (void);
1060 
1061 /*returns 1 on error --- not found. Destroys a widget by name and all its
1062    descendents */
CDestroyWidget(const char * identifier)1063 int CDestroyWidget (const char *identifier)
1064 {
1065     int i = find_ident (identifier);
1066 
1067     if (i) {
1068 	recursive_destroy_widgets (i);
1069 	CFocusLast ();
1070 	return 0;
1071     } else
1072 	return 1;
1073 }
1074 
1075 
CDestroyAll()1076 void CDestroyAll ()
1077 {
1078     int j;
1079     while ((j = find_first_child_of (CRoot)))
1080 	recursive_destroy_widgets (j);
1081 }
1082 
1083 void free_last_query_buttons (void);
1084 void edit_replace_cmd (WEdit * edit, int again);
1085 void free_selections (void);
1086 void remove_all_watch (void);
1087 
CShutdown(void)1088 void CShutdown (void)
1089 {
1090     remove_all_watch ();
1091     CDestroyAll ();
1092     free (home_dir);
1093     free (temp_dir);
1094     home_dir = 0;
1095     temp_dir = 0;
1096     free_last_query_buttons ();
1097     edit_replace_cmd (0, 0);
1098     edit_search_cmd (0, 0);
1099     free_selections ();
1100     mouse_shut ();
1101     CFreeAllFonts ();
1102     XCloseDisplay (CDisplay);
1103 }
1104 
drawstring_xy(Window win,int x,int y,const char * text)1105 void drawstring_xy (Window win, int x, int y, const char *text)
1106 {
1107     if (!text)
1108 	return;
1109     if (!*text)
1110 	return;
1111     CImageString (win, FONT_OFFSET_X + x, FONT_OFFSET_Y + y, text);
1112 }
1113 
1114 
whereis_hotchar(const char * labl,int hotkey)1115 char *whereis_hotchar (const char *labl, int hotkey)
1116 {
1117     unsigned char *label = (unsigned char *) labl;
1118     int i;
1119     if (hotkey <= ' ' || hotkey > 255)
1120 	return 0;
1121     if (*label == hotkey)
1122 	return (char *) label;
1123     for (i = 1; label[i]; i++)
1124 	if (label[i - 1] == ' ' && label[i] == hotkey)
1125 	    return (char *) label + i;
1126     return (char *) strchr ((char *) label, hotkey);
1127 }
1128 
underline_hotkey(Window win,int x,int y,const char * text,int hotkey)1129 void underline_hotkey (Window win, int x, int y, const char *text, int hotkey)
1130 {
1131     char *p;
1132     if (hotkey <= ' ' || hotkey > 255)
1133 	return;
1134     if (!(p = whereis_hotchar (text, hotkey)))
1135 	return;
1136     x += CImageTextWidth (text, (unsigned long) p - (unsigned long) text);
1137     y += FONT_BASE_LINE + FONT_PER_CHAR_DESCENT(hotkey) + 1;
1138     (*look->draw_hotkey_understroke) (win, x, y, hotkey);
1139 }
1140 
drawstring_xy_hotkey(Window win,int x,int y,const char * text,int hotkey)1141 void drawstring_xy_hotkey (Window win, int x, int y, const char *text, int hotkey)
1142 {
1143     drawstring_xy (win, x, y, text);
1144     underline_hotkey (win, x, y, text, hotkey);
1145 }
1146 
render_button(CWidget * wdt)1147 void render_button (CWidget * wdt)
1148 {
1149     (*look->render_button) (wdt);
1150 }
1151 
render_bar(CWidget * wdt)1152 void render_bar (CWidget * wdt)
1153 {
1154     (*look->render_bar) (wdt);
1155 }
1156 
1157 #define FB (TEXT_RELIEF + 1)
1158 #define FS (TEXT_RELIEF + 1)
1159 
1160 /* this is a zero flicker routine */
render_status(CWidget * wdt,int expose)1161 void render_status (CWidget * wdt, int expose)
1162 {
1163     static Window lastwin = 0;
1164     static char lasttext[1024] = "";
1165     Window win = CWindowOf (wdt);
1166     char *q, *r;
1167     int last_width = 0;
1168     int h = CHeightOf (wdt);
1169     int w = CWidthOf (wdt);
1170     int l, x, x1 = 0, color = 0;
1171     char *p;
1172     CPushFont ("widget", 0);
1173     q = wdt->text;
1174     p = lasttext;
1175     x = TEXT_RELIEF + 1;	/* bevel is 1 */
1176     if (lastwin == win && !expose) {
1177 	for (; *p && *q && *p == *q; p++, q++) {
1178 	    if (*q >= ' ') {
1179 		x += CImageTextWidth (q, 1);
1180 	    } else {
1181 		if (*q == '\034') {
1182 		    x1 = x;
1183 		} else if (*q == '\035') {
1184 		    x1 = x;
1185 		    x += FS;
1186 		} else
1187 		    color = *q;
1188 	    }
1189 	}
1190     }
1191     for (l = x, r = q; *r; r++)
1192 	if (*r >= ' ')
1193 	    l += CImageTextWidth (r, 1);
1194 	else if (*r == '\035')
1195 	    l += FS;
1196     if (lastwin == win && !expose) {
1197 	for (last_width = x, r = p; *r; r++)
1198 	    if (*r >= ' ')
1199 		last_width += CImageTextWidth (r, 1);
1200 	    else if (*r == '\035')
1201 		last_width += FS;
1202     }
1203     if (l < last_width && l < w) {
1204 	CSetColor (COLOR_FLAT);
1205 	CRectangle (win, l, 0, min (w - l, last_width - l), h);
1206     }
1207     CSetColor (color_palette (color % 27));
1208     CSetBackgroundColor (COLOR_FLAT);
1209     for (p = q;; p++) {
1210 	if (*p < ' ') {
1211 	    CImageText (win, FONT_OFFSET_X + x, FONT_OFFSET_Y + TEXT_RELIEF + 1, q, (unsigned long) p - (unsigned long) q);
1212 	    x += CImageTextWidth (q, (unsigned long) p - (unsigned long) q);
1213 	    if (*p == '\035') {
1214 		XClearArea (CDisplay, win, x, TEXT_RELIEF + 1, x + FS, FONT_PIX_PER_LINE, 0);
1215 		if (x - x1 + FB + FB - 2 > 0) {
1216 		    render_bevel (win, x1 - FB, 0, x + FB - 1, h - 1, 1, 1);
1217 		    XClearArea (CDisplay, win, x1 - FB + 1, 1, x - x1 + FB + FB - 2, TEXT_RELIEF + 1, 0);
1218 		    XClearArea (CDisplay, win, x1 - FB + 1, h - TEXT_RELIEF - 1, x - x1 + FB + FB - 2, TEXT_RELIEF, 0);
1219 		}
1220 		x1 = x;
1221 		x += FS;
1222 	    } else if (*p == '\034') {
1223 		if (x - x1 - FB - FB > 0) {
1224 		    XClearArea (CDisplay, win, x1 + FB, 0, x - x1 - FB - FB, TEXT_RELIEF + 1, 0);
1225 		    XClearArea (CDisplay, win, x1 + FB, h - TEXT_RELIEF - 1, x - x1 - FB - FB, TEXT_RELIEF + 1, 0);
1226 		}
1227 		x1 = x;
1228 	    } else
1229 		CSetColor (color_palette (*p % 27));
1230 	    if (!*p)
1231 		break;
1232 	    q = p + 1;
1233 	}
1234     }
1235     lastwin = win;
1236     strncpy (lasttext, wdt->text, 1023);
1237     CPopFont ();
1238     return;
1239 }
1240 
render_text(CWidget * wdt)1241 void render_text (CWidget * wdt)
1242 {
1243     (*look->render_text) (wdt);
1244 }
1245 
render_window(CWidget * wdt)1246 void render_window (CWidget * wdt)
1247 {
1248     (*look->render_window) (wdt);
1249 }
1250 
render_progress(CWidget * wdt)1251 void render_progress (CWidget * wdt)
1252 {
1253     int w = wdt->width, h = wdt->height;
1254     int p = wdt->cursor;
1255 
1256     Window win = wdt->winid;
1257 
1258     if (p > 65535)
1259 	p = 65535;
1260     if (p < 0)
1261 	p = 0;
1262     CSetColor (COLOR_FLAT);
1263     CRectangle (win, 4 + p * (w - 5) / 65535, 2, (65535 - p) * (w - 5) / 65535, h - 4);
1264     CSetColor (color_palette (3));
1265     CRectangle (win, 4, 4, p * (w - 9) / 65535, h - 8);
1266     render_bevel (win, 2, 2, 4 + p * (w - 9) / 65535, h - 3, 2, 0);
1267     render_bevel (win, 0, 0, w - 1, h - 1, 2, 1);
1268 }
1269 
render_sunken(CWidget * wdt)1270 void render_sunken (CWidget * wdt)
1271 {
1272     int w = wdt->width, h = wdt->height;
1273     Window win = wdt->winid;
1274     render_bevel (win, 0, 0, w - 1, h - 1, 2, 1);
1275 }
1276 
render_bevel(Window win,int x1,int y1,int x2,int y2,int thick,int sunken)1277 void render_bevel (Window win, int x1, int y1, int x2, int y2, int thick, int sunken)
1278 {
1279     if (option_low_bandwidth)
1280 	return;
1281     if (sunken & 1)
1282 	(*look->render_sunken_bevel) (win, x1, y1, x2, y2, thick, sunken);
1283     else
1284 	(*look->render_raised_bevel) (win, x1, y1, x2, y2, thick, sunken);
1285     CSetColor (COLOR_BLACK);
1286 }
1287 
1288 void expose_picture (CWidget * w);
1289 
set_widget_position(CWidget * w,int x,int y)1290 void set_widget_position (CWidget * w, int x, int y)
1291 {
1292     if (w->winid) {		/*some widgets have no window of there own */
1293 	w->x = x;
1294 	w->y = y;
1295 	XMoveWindow (CDisplay, w->winid, x, y);
1296     } else {
1297 #ifdef HAVE_PICTURE
1298 	expose_picture (w);
1299 	w->x = x;
1300 	w->y = y;
1301 	expose_picture (w);
1302 #endif
1303     }
1304 }
1305 
CSetWidgetPosition(const char * ident,int x,int y)1306 void CSetWidgetPosition (const char *ident, int x, int y)
1307 {
1308     CWidget *w = CIdent (ident);
1309     if (!w)
1310 	return;
1311     set_widget_position (w, x, y);
1312 }
1313 
configure_children(CWidget * wt,int w,int h)1314 void configure_children (CWidget * wt, int w, int h)
1315 {
1316     CWidget *wdt;
1317     int new_w, new_h, new_x, new_y, i;
1318     i = find_first_child_of (wt->winid);
1319     while (i) {
1320 	wdt = CIndex (i);
1321 	if (CGetFocus () == wdt->winid)		/* focus border must follow the widget */
1322 	    destroy_focus_border ();
1323 	if (wdt->resize) {
1324 	    (*(wdt->resize)) (w, h, wt->width, wt->height, &new_w, &new_h, &new_x, &new_y);
1325 	    if (wdt->height != new_h || wdt->width != new_w)
1326 		CSetSize (wdt, new_w, new_h);
1327 	    if (wdt->x != new_x || wdt->y != new_y)
1328 		set_widget_position (wdt, new_x, new_y);
1329 	} else {
1330 	    if (wdt->position & POSITION_CENTRE)
1331 		set_widget_position (wdt, (w - wdt->width) / 2, wdt->y);
1332 	    if (wdt->position & POSITION_FILL)
1333 		CSetSize (wdt, w - (WIDGET_SPACING + WINDOW_EXTRA_SPACING) - wdt->x, wdt->height);
1334 	    if (wdt->position & POSITION_RIGHT)
1335 		set_widget_position (wdt, wdt->x + w - wt->width, wdt->y);
1336 	    if (wdt->position & POSITION_WIDTH)
1337 		CSetSize (wdt, wdt->width + w - wt->width, wdt->height);
1338 	    if (wdt->position & POSITION_BOTTOM)
1339 		set_widget_position (wdt, wdt->x, wdt->y + h - wt->height);
1340 	    if (wdt->position & POSITION_HEIGHT)
1341 		CSetSize (wdt, wdt->width, wdt->height + h - wt->height);
1342 	}
1343 	if (CGetFocus () == wdt->winid)		/* focus border must follow the widget */
1344 	    if ((wdt->options & WIDGET_TAKES_FOCUS_RING))
1345 		create_focus_border (wdt, 2);
1346 	i = find_next_child_of (wdt->parentid, wdt->winid);
1347     }
1348 }
1349 
CSetSize(CWidget * wt,int w,int h)1350 void CSetSize (CWidget * wt, int w, int h)
1351 {
1352     int w_min, h_min;
1353     if (!wt)
1354 	return;
1355     if (w == wt->width && h == wt->height)
1356 	return;
1357 
1358     wt->resized = 1;
1359 
1360     if (w < 1)
1361 	w = 1;
1362     if (h < 1)
1363 	h = 1;
1364 
1365     if (wt->kind == C_WINDOW_WIDGET)
1366 	configure_children (wt, w, h);
1367 #if 0
1368     else if (wt->kind == C_RXVT_WIDGET)
1369 	rxvt_resize_window (wt->rxvt, w, h);
1370 #endif
1371 
1372 /* redraw right and bottom borders */
1373     w_min = min (wt->width, w);
1374     h_min = min (wt->height, h);
1375     if (wt->kind == C_WINDOW_WIDGET)
1376 	XClearArea (CDisplay, wt->winid, wt->width - 39, wt->height - 39, 39, 39, 1);
1377     XClearArea (CDisplay, wt->winid, w_min - 3, 0, 3, h_min, 1);
1378     XClearArea (CDisplay, wt->winid, 0, h_min - 3, w_min, 3, 1);
1379     wt->width = w;
1380     wt->height = h;
1381     if (wt->parentid == CRoot && wt->mapped)	/* afterstep doesn't like us to change the size of a mapped main window */
1382 	return;
1383     XResizeWindow (CDisplay, wt->winid, w, h);
1384 #ifdef USE_XIM
1385     set_status_position (wt);
1386 #endif
1387 }
1388 
CSetWidgetSize(const char * ident,int w,int h)1389 void CSetWidgetSize (const char *ident, int w, int h)
1390 {
1391     CWidget *wt = CIdent (ident);
1392     if (!wt)
1393 	return;
1394     CSetSize (wt, w, h);
1395 }
1396 
CSetMovement(const char * ident,unsigned long position)1397 void CSetMovement (const char *ident, unsigned long position)
1398 {
1399     CWidget *w;
1400     w = CIdent (ident);
1401     if (!w)
1402 	return;
1403     w->position |= position;
1404 }
1405 
CCentre(char * ident)1406 void CCentre (char *ident)
1407 {
1408     CSetMovement (ident, POSITION_CENTRE);
1409 }
1410 
1411 /* does a map as well */
CSetSizeHintPos(const char * ident)1412 void CSetSizeHintPos (const char *ident)
1413 {
1414     int x, y;
1415     CWidget *w;
1416     get_hint_limits (&x, &y);
1417     w = CIdent (ident);
1418     x += WINDOW_EXTRA_SPACING;
1419     y += WINDOW_EXTRA_SPACING;
1420     if (!(w->options & WINDOW_NO_BORDER))
1421 	y += (*look->get_window_resize_bar_thickness) ();
1422     XResizeWindow (CDisplay, w->winid, x, y);
1423     w->width = x;
1424     w->height = y;
1425     configure_children (w, x, y);
1426 }
1427 
1428 /* for mapping a main window. other widgets are mapped when created */
CMapDialog(const char * ident)1429 void CMapDialog (const char *ident)
1430 {
1431     CWidget *w;
1432     w = CIdent (ident);
1433     if (!w)
1434 	return;
1435     if (w->kind != C_WINDOW_WIDGET)
1436 	return;
1437     if (w->parentid == CRoot
1438 	&& !(w->options & WINDOW_SIZE_HINTS_SET)) {
1439 /* A main window with WM size hints not configured. */
1440 	CSetWindowSizeHints (w, w->width, w->height, w->width, w->height);
1441     }
1442     XMapWindow (CDisplay, w->winid);	/* shows the window */
1443     XFlush (CDisplay);
1444 }
1445