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