1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 
5 #ifndef __MSW__
6 #include <unistd.h>
7 
8 #include <X11/X.h>
9 #include <X11/Xlib.h>
10 #include <X11/Xutil.h>
11 #include <X11/keysym.h>
12 #include <X11/Xproto.h>
13 #include <X11/Xatom.h>
14 #include <X11/cursorfont.h>
15 #include <X11/extensions/shape.h>
16 
17 /* XPM Library */
18 #ifdef HAVE_LIBXPM
19 # include <X11/xpm.h>
20 # ifndef XPM_H
21 #  define XPM_H
22 # endif
23 # ifndef XpmDefaultColorCloseness
24 #  define XpmDefaultColorCloseness	40000
25 # endif
26 # include "gwdata/icon_info.xpm"
27 # include "gwdata/icon_warning.xpm"
28 # include "gwdata/icon_error.xpm"
29 # include "gwdata/icon_question.xpm"
30 #endif
31 
32 /* Motif WM Hints Definations */
33 #ifdef HAVE_MWMUTIL_H
34 # include "gwdata/MwmUtil.h"
35 # ifndef MWMUTIL_H
36 #  define MWMUTIL_H
37 # endif
38 #endif
39 
40 #include "gw.h"
41 
42 
43 /* Utility functions */
44 static Pixel GWXPixelNew(
45 	gw_display_struct *display,
46 	u_int8_t r, u_int8_t g, u_int8_t b
47 );
48 static void GWXPixelDelete(gw_display_struct *display, Pixel pixel);
49 
50 static XFontStruct *GWXFontNew(
51 	gw_display_struct *display, const char *name
52 );
53 static void GWXFontDelete(gw_display_struct *display, XFontStruct *font);
54 static int GWXGetFontStringLength(XFontStruct *font, const char *s);
55 
56 /* Widgets */
57 void GWXWidgetSetFlags(
58 	gw_display_struct *display, gwx_widget_struct *widget,
59 	gwx_widget_flags flags
60 );
61 void GWXWidgetUnsetFlags(
62 	gw_display_struct *display, gwx_widget_struct *widget,
63 	gwx_widget_flags flags
64 );
65 void GWXWidgetMapRaise(
66 	gw_display_struct *display, gwx_widget_struct *widget
67 );
68 void GWXWidgetMap(
69 	gw_display_struct *display, gwx_widget_struct *widget
70 );
71 void GWXWidgetUnmap(
72 	gw_display_struct *display, gwx_widget_struct *widget
73 );
74 void GWXWidgetFocus(
75 	gw_display_struct *display, gwx_widget_struct *widget
76 );
77 void GWXWidgetUnfocus(
78 	gw_display_struct *display, gwx_widget_struct *widget
79 );
80 void GWXWidgetGrabDefault(
81 	gw_display_struct *display, gwx_widget_struct *widget
82 );
83 void GWXWidgetUngrabDefault(
84 	gw_display_struct *display, gwx_widget_struct *widget
85 );
86 void GWXWidgetSetSensitive(
87 	gw_display_struct *display, gwx_widget_struct *widget,
88 	Boolean sensitive
89 );
90 
91 /* Push button */
92 int GWXButtonCreate(
93 	gw_display_struct *display, gwx_button_struct *btn,
94 	void *dialog,           /* Parent gwx_dialog_struct */
95 	Window parent,
96 	int x, int y,
97 	unsigned int width, unsigned int height,
98 	const char *label,
99 	void *client_data,
100 	void (*func_cb)(void *, void *)
101 );
102 void GWXButtonUpdateSize(
103 	gw_display_struct *display, gwx_button_struct *btn
104 );
105 void GWXButtonResize(
106 	gw_display_struct *display, gwx_button_struct *btn
107 );
108 void GWXButtonDraw(
109 	gw_display_struct *display, gwx_button_struct *btn
110 );
111 int GWXButtonManage(
112 	gw_display_struct *display, gwx_button_struct *btn,
113 	XEvent *event
114 );
115 void GWXButtonDestroy(
116 	gw_display_struct *display, gwx_button_struct *btn
117 );
118 
119 /* Message dialog */
120 int GWXDialogCreate(
121 	gw_display_struct *display, gwx_dialog_struct *md,
122 	gwx_dialog_type type
123 );
124 void GWXDialogLoadIcon(
125 	gw_display_struct *display, gwx_dialog_struct *md,
126 	gwx_icon icon_code	/* One of GWX_ICON_* */
127 );
128 void GWXDialogUpdateSize(
129 	gw_display_struct *display, gwx_dialog_struct *md
130 );
131 void GWXDialogResize(
132 	gw_display_struct *display, gwx_dialog_struct *md
133 );
134 void GWXDialogDraw(
135 	gw_display_struct *display, gwx_dialog_struct *md
136 );
137 int GWXDialogManage(
138 	gw_display_struct *display, gwx_dialog_struct *md,
139 	XEvent *event
140 );
141 void GWXDialogDestroy(
142 	gw_display_struct *display, gwx_dialog_struct *md
143 );
144 
145 /* Message dialog callbacks */
146 void GWXDialogNoBtnCB(void *object, void *client_data);
147 void GWXDialogYesBtnCB(void *object, void *client_data);
148 void GWXDialogCancelBtnCB(void *object, void *client_data);
149 void GWXDialogOKBtnCB(void *object, void *client_data);
150 
151 /* Message dialog operations */
152 void GWXDialogSetMesg(
153 	gw_display_struct *display, gwx_dialog_struct *md,
154 	const char *title,
155 	const char *mesg,
156 	const char *details
157 );
158 void GWXDialogMap(
159 	gw_display_struct *display, gwx_dialog_struct *md
160 );
161 int GWXDoBlockUntilConf(gw_display_struct *display);
162 
163 int GWX_Widget_Has_Default(gwx_button_struct *my_button);
164 
165 #define ATOI(s)         (((s) != NULL) ? atoi(s) : 0)
166 #define ATOL(s)         (((s) != NULL) ? atol(s) : 0)
167 #define ATOF(s)         (((s) != NULL) ? atof(s) : 0.0f)
168 #define STRDUP(s)       (((s) != NULL) ? strdup(s) : NULL)
169 
170 #define MAX(a,b)        (((a) > (b)) ? (a) : (b))
171 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
172 #define CLIP(a,l,h)     (MIN(MAX((a),(l)),(h)))
173 #define STRLEN(s)	(((s) != NULL) ? ((int)strlen(s)) : 0)
174 
175 #define ISSTREMPTY(s)	(((s) != NULL) ? ((s) == '\0') : True)
176 
177 #define RADTODEG(r)     ((r) * 180 / PI)
178 #define DEGTORAD(d)     ((d) * PI / 180)
179 
180 #define FREE_PIXMAP(p)		\
181 { if(*(p) != None) { XFreePixmap(dpy, *(p)); *(p) = None; } }
182 #define FREE_BITMAP(p)		FREE_PIXMAP(p)
183 #define DESTROY_WINDOW(p)	\
184 { if(*(p) != None) { XDestroyWindow(dpy, *(p)); *(p) = None; } }
185 #define DELETE_FONT(p)		\
186 { GWXFontDelete(display, *(p)); *(p) = NULL; }
187 
188 #define DESTROY_TOPLEVEL_WINDOW(p)			\
189 { if(*(p) != None) {					\
190  /* Get WM hints and destroy icon Window, Pixmap, and	\
191   * mask.						\
192   */							\
193  XWMHints *wm_hints = XGetWMHints(dpy, *(p));		\
194  if(wm_hints != NULL) {					\
195   if(wm_hints->flags & IconWindowHint)                  \
196    DESTROY_WINDOW(&wm_hints->icon_window);		\
197   if(wm_hints->flags & IconPixmapHint)			\
198    FREE_PIXMAP(&wm_hints->icon_pixmap);			\
199   if(wm_hints->flags & IconMaskHint)			\
200    FREE_BITMAP(&wm_hints->icon_mask);			\
201   XFree(wm_hints);					\
202  }							\
203  /* Destroy toplevel Window */				\
204  DESTROY_WINDOW(p);					\
205 } }
206 
207 #define XCOLOR_SET_RGB_COEFF(p,r,g,b)                   \
208 { if((p) != NULL) {                                     \
209  (p)->flags     = DoRed | DoGreen | DoBlue;             \
210  (p)->red       = (float)(r) * (unsigned short)-1;      \
211  (p)->green     = (float)(g) * (unsigned short)-1;      \
212  (p)->blue      = (float)(b) * (unsigned short)-1;      \
213  (p)->pad       = 0;                                    \
214 } }
215 #define XCOLOR_SET_GREY_COEFF(p,g)                      \
216 { if((p) != NULL) {                                     \
217  (p)->flags     = DoRed | DoGreen | DoBlue;             \
218  (p)->red       = (float)(g) * (unsigned short)-1;      \
219  (p)->green     = (p)->red;                             \
220  (p)->blue      = (p)->red;                             \
221  (p)->pad       = 0;                                    \
222 } }
223 
224 
225 /* Default button sizes and margins */
226 #define GWX_BTN_DEF_WIDTH	80
227 #define GWX_BTN_DEF_HEIGHT	25
228 #define GWX_BTN_XMARGIN		5
229 #define GWX_BTN_YMARGIN		5
230 
231 /* Widget style colors {a, r, g, b} in values from 0x00 to 0xff */
232 static u_int8_t style_fg_color[]	= {0xff, 0x00, 0x00, 0x00};
233 static u_int8_t style_bg_color[]	= {0xff, 0xd7, 0xd7, 0xd7};
234 static u_int8_t style_fg_insensitive[]	= {0xff, 0x80, 0x80, 0x80};
235 static u_int8_t style_bg_highlight_color[]	= {0xff, 0xe8, 0xe8, 0xe8};
236 static u_int8_t style_highlight_color[]	= {0xff, 0xf0, 0xf0, 0xf0};
237 static u_int8_t style_shade_color[]	= {0xff, 0x80, 0x80, 0x80};
238 
239 
240 
241 /* Records the last confirmation dialog return code, one of
242  * GWConfirmation*.
243  */
244 static int last_conf_dialog_code;
245 
246 
247 
248 /* A replacement for the macro of the name name that
249    is giving us optimization warnings.
250 */
GWX_Widget_Has_Default(gwx_button_struct * my_button)251 int GWX_Widget_Has_Default(gwx_button_struct *my_button)
252 {
253    if (! my_button)
254       return False;
255 
256    return (my_button->flags & GWX_HAS_DEFAULT);
257 }
258 
259 
260 
261 /*
262  *	Allocates a new pixel color with the given rgb values.
263  *
264  *	The returned Pixel value needs to be deallocated by calling
265  *	GWXPixelDelete().
266  */
GWXPixelNew(gw_display_struct * display,u_int8_t r,u_int8_t g,u_int8_t b)267 static Pixel GWXPixelNew(
268 	gw_display_struct *display,
269 	u_int8_t r, u_int8_t g, u_int8_t b
270 )
271 {
272 	Display *dpy = (display != NULL) ? display->display : NULL;
273 	Colormap cmap;
274 	XColor c;
275 	if(dpy == NULL)
276 	    return(0);
277 
278 	cmap = display->colormap;
279 	if(cmap == None)
280 	    return(0);
281 
282 	XCOLOR_SET_RGB_COEFF(
283 	    &c,
284 	    (float)r / (float)0xff,
285 	    (float)g / (float)0xff,
286 	    (float)b / (float)0xff
287 	);
288 
289 	if(XAllocColor(dpy, cmap, &c))
290 	    return(c.pixel);
291 	else
292 	    return(0);
293 }
294 /*
295  *	Deletess a pixel returned by GWXPixelNew().
296  */
GWXPixelDelete(gw_display_struct * display,Pixel pixel)297 static void GWXPixelDelete(gw_display_struct *display, Pixel pixel)
298 {
299 	Display *dpy = (display != NULL) ? display->display : NULL;
300 	Colormap cmap;
301 	if(dpy == NULL)
302 	    return;
303 
304 	cmap = display->colormap;
305 	if(cmap == None)
306 	    return;
307 
308 	XFreeColors(dpy, cmap, &pixel, 1, 0);
309 }
310 
311 /*
312  *	Creates (loads) a font from the given font name.
313  *
314  *	Can return NULL on error.
315  */
GWXFontNew(gw_display_struct * display,const char * name)316 static XFontStruct *GWXFontNew(
317 	gw_display_struct *display, const char *name
318 )
319 {
320 	Display *dpy = (display != NULL) ? display->display : NULL;
321 	if((dpy == NULL) || (name == NULL))
322 	    return(NULL);
323 
324 	return(XLoadQueryFont(dpy, name));
325 }
326 /*
327  *	Deletes a font returned by GWXFontNew().
328  */
GWXFontDelete(gw_display_struct * display,XFontStruct * font)329 static void GWXFontDelete(gw_display_struct *display, XFontStruct *font)
330 {
331 	Display *dpy = (display != NULL) ? display->display : NULL;
332 	if((dpy == NULL) || (font == NULL))
333 	    return;
334 
335 	XFreeFont(dpy, font);
336 }
337 
338 /*
339  *	Returns the length of the string is in pixels with respect to
340  *	the size of the font.
341  *
342  *	The string is terminated by either a '\0' or '\n' character
343  *	(exclusive), so it will never be counted beyond its end or
344  *	end of line.
345  *
346  *	Can return 0 on error.
347  */
GWXGetFontStringLength(XFontStruct * font,const char * s)348 static int GWXGetFontStringLength(XFontStruct *font, const char *s)
349 {
350 	int len = 0;		/* In pixels */
351 	XCharStruct *csp;
352 
353 
354 	if((font == NULL) || (s == NULL))
355 	    return(len);
356 
357 	/* Do we have per character geometry information? */
358 	if(font->per_char != NULL)
359 	{
360 	    /* 8 bits per character type? */
361 	    if(!font->min_byte1 && !font->max_byte1)
362 	    {
363 		int c;
364 		int i = 0;
365 		int m = (int)font->max_char_or_byte2 -
366 			(int)font->min_char_or_byte2;
367 
368 		/* Iterate through given string */
369 		while((*s != '\0') && (*s != '\n') && (*s != '\r'))
370 		{
371 		    c = *s++;	/* Get current string char and increment */
372 		    c -= (int)font->min_char_or_byte2;	/* Offset for per_char index */
373 
374 		    /* Clip, check if string char in bounds? */
375 		    if((c >= i) && (c <= m))
376 		    {
377 			csp = &font->per_char[c];	/* Ptr to geometry */
378 			len += csp->width;		/* Inc str len */
379 		    }
380 		}
381 	    }
382 	    else
383 	    {
384 		/* 16 bits per character, ouch, code this in later */
385 
386 
387 	    }
388 	}
389 	else
390 	{
391 	    /* No per character info, use max bounds */
392 	    csp = &font->max_bounds;
393 
394 	    /* Iterate through given string */
395 	    while((*s != '\0') && (*s != '\n') && (*s != '\r'))
396 		len += csp->width;
397 	}
398 
399 	return(len);
400 }
401 
402 
403 /*
404  *	Sets the specified flags on the widget.
405  */
GWXWidgetSetFlags(gw_display_struct * display,gwx_widget_struct * widget,gwx_widget_flags flags)406 void GWXWidgetSetFlags(
407 	gw_display_struct *display, gwx_widget_struct *widget,
408 	gwx_widget_flags flags
409 )
410 {
411 	if(widget == NULL)
412 	    return;
413 
414 	widget->flags |= flags;
415 }
416 
417 /*
418  *	Unsets the specified flags on the widget.
419  */
GWXWidgetUnsetFlags(gw_display_struct * display,gwx_widget_struct * widget,gwx_widget_flags flags)420 void GWXWidgetUnsetFlags(
421 	gw_display_struct *display, gwx_widget_struct *widget,
422 	gwx_widget_flags flags
423 )
424 {
425 	if(widget == NULL)
426 	    return;
427 
428 	widget->flags &= ~flags;
429 }
430 
431 /*
432  *	Maps and raises the widget's toplevel Window.
433  */
GWXWidgetMapRaise(gw_display_struct * display,gwx_widget_struct * widget)434 void GWXWidgetMapRaise(
435 	gw_display_struct *display, gwx_widget_struct *widget
436 )
437 {
438 	Display *dpy = (display != NULL) ? display->display : NULL;
439 	if((dpy == NULL) || (widget == NULL))
440 	    return;
441 
442 	if(widget->toplevel != None)
443 	    XMapRaised(dpy, widget->toplevel);
444 	GWXWidgetSetFlags(display, widget, GWX_MAPPED);
445 }
446 
447 /*
448  *	Maps the widget's toplevel Window.
449  */
GWXWidgetMap(gw_display_struct * display,gwx_widget_struct * widget)450 void GWXWidgetMap(
451 	gw_display_struct *display, gwx_widget_struct *widget
452 )
453 {
454 	Display *dpy = (display != NULL) ? display->display : NULL;
455 	if((dpy == NULL) || (widget == NULL))
456 	    return;
457 
458 	if(widget->toplevel != None)
459 	    XMapWindow(dpy, widget->toplevel);
460 	GWXWidgetSetFlags(display, widget, GWX_MAPPED);
461 }
462 
463 /*
464  *	Unmaps the widget's toplevel Window.
465  */
GWXWidgetUnmap(gw_display_struct * display,gwx_widget_struct * widget)466 void GWXWidgetUnmap(
467 	gw_display_struct *display, gwx_widget_struct *widget
468 )
469 {
470 	Display *dpy = (display != NULL) ? display->display : NULL;
471 	if((dpy == NULL) || (widget == NULL))
472 	    return;
473 
474 	if(widget->toplevel != None)
475 	    XUnmapWindow(dpy, widget->toplevel);
476 	GWXWidgetUnsetFlags(display, widget, GWX_MAPPED);
477 }
478 
479 /*
480  *	Sets the GWX_HAS_FOCUS flag on the widget (if the widget has
481  *	the GWX_CAN_FOCUS flag).
482  */
GWXWidgetFocus(gw_display_struct * display,gwx_widget_struct * widget)483 void GWXWidgetFocus(
484 	gw_display_struct *display, gwx_widget_struct *widget
485 )
486 {
487 	if(GWX_WIDGET_CAN_FOCUS(widget))
488 	    GWXWidgetSetFlags(display, widget, GWX_HAS_FOCUS);
489 }
490 
491 /*
492  *	Unsets the GWX_HAS_FOCUS flag on the widget.
493  */
GWXWidgetUnfocus(gw_display_struct * display,gwx_widget_struct * widget)494 void GWXWidgetUnfocus(
495 	gw_display_struct *display, gwx_widget_struct *widget
496 )
497 {
498 	GWXWidgetUnsetFlags(display, widget, GWX_HAS_FOCUS);
499 }
500 
501 /*
502  *	Sets the GWX_HAS_DEFAULT flag on the widget (if the widget has
503  *	the GWX_CAN_DEFAULT flag).
504  */
GWXWidgetGrabDefault(gw_display_struct * display,gwx_widget_struct * widget)505 void GWXWidgetGrabDefault(
506 	gw_display_struct *display, gwx_widget_struct *widget
507 )
508 {
509 	if(GWX_WIDGET_CAN_DEFAULT(widget))
510 	    GWXWidgetSetFlags(display, widget, GWX_HAS_DEFAULT);
511 }
512 
513 /*
514  *	Unsets the GWX_HAS_DEFAULT flag on the widget.
515  */
GWXWidgetUngrabDefault(gw_display_struct * display,gwx_widget_struct * widget)516 void GWXWidgetUngrabDefault(
517 	gw_display_struct *display, gwx_widget_struct *widget
518 )
519 {
520 	GWXWidgetUnsetFlags(display, widget, GWX_HAS_DEFAULT);
521 }
522 
523 /*
524  *	Sets the widget as sensitive or insensitive.
525  */
GWXWidgetSetSensitive(gw_display_struct * display,gwx_widget_struct * widget,Boolean sensitive)526 void GWXWidgetSetSensitive(
527 	gw_display_struct *display, gwx_widget_struct *widget,
528 	Boolean sensitive
529 )
530 {
531 	if(sensitive)
532 	    GWXWidgetSetFlags(display, widget, GWX_SENSITIVE);
533 	else
534 	    GWXWidgetUnsetFlags(display, widget, GWX_SENSITIVE);
535 }
536 
537 
538 /*
539  *	Creates a button by setting up the given button structure's
540  *	values. Returns non-zero on error.
541  */
GWXButtonCreate(gw_display_struct * display,gwx_button_struct * btn,void * dialog,Window parent,int x,int y,unsigned int width,unsigned int height,const char * label,void * client_data,void (* func_cb)(void *,void *))542 int GWXButtonCreate(
543 	gw_display_struct *display, gwx_button_struct *btn,
544 	void *dialog,           /* Parent gwx_dialog_struct */
545 	Window parent,
546 	int x, int y,
547 	unsigned int width, unsigned int height,
548 	const char *label,
549 	void *client_data,
550 	void (*func_cb)(void *, void *)
551 )
552 {
553 	Display *dpy = (display != NULL) ? display->display : NULL;
554 	Window w;
555 	XFontStruct *font;
556 	u_int8_t *sc;		/* Style color */
557 	if((dpy == NULL) || (btn == NULL) || (parent == None))
558 	    return(-1);
559 
560 	memset(btn, 0x00, sizeof(gwx_button_struct));
561 
562 	btn->flags =	GWX_CAN_FOCUS | GWX_CAN_DEFAULT |
563 			GWX_SENSITIVE;
564 	btn->parent = parent;
565 	btn->x = x;
566 	btn->y = y;
567 	btn->width = width;
568 	btn->height = height;
569 	btn->dialog = dialog;
570 
571 	/* Create button's toplevel window */
572 	w = GWCreateWindow(
573 	    display, parent,
574 	    x, y,
575 	    width, height,
576 	    label
577 	);
578 	if(w == None)
579 	    return(-1);
580 	else
581 	    btn->toplevel = w;
582 	XSelectInput(
583 	    dpy, w,
584 	    ButtonPressMask | ButtonReleaseMask |
585 	    ExposureMask |
586 	    EnterWindowMask | LeaveWindowMask
587 	);
588 
589 	btn->accelerator = NULL;
590 	btn->total_accelerators = 0;
591 
592 	sc = style_fg_color;
593 	btn->color_fg = GWXPixelNew(display, sc[1], sc[2], sc[3]);
594 	sc = style_bg_color;
595 	btn->color_bg = GWXPixelNew(display, sc[1], sc[2], sc[3]);
596 	sc = style_fg_insensitive;
597 	btn->color_fg_insensitive = GWXPixelNew(display, sc[1], sc[2], sc[3]);
598 	sc = style_bg_highlight_color;
599 	btn->color_bg_highlighted = GWXPixelNew(display, sc[1], sc[2], sc[3]);
600 	sc = style_highlight_color;
601 	btn->color_highlight = GWXPixelNew(display, sc[1], sc[2], sc[3]);
602 	sc = style_shade_color;
603 	btn->color_shade = GWXPixelNew(display, sc[1], sc[2], sc[3]);
604 
605 	btn->colors_initialized = True;
606 
607 	btn->font = font = GWXFontNew(
608 	    display, display->def_xfont_name
609 	);
610 
611 	btn->label = STRDUP(label);
612 	btn->label_len_pixels = GWXGetFontStringLength(
613 	    font, label
614 	);
615 	if(font == NULL)
616 	    btn->label_height_pixels = 0;
617 	else
618 	    btn->label_height_pixels = font->max_bounds.ascent +
619 		font->max_bounds.descent;
620 
621 	btn->client_data = client_data;
622 	btn->func_cb = func_cb;
623 
624 	GWXButtonResize(display, btn);
625 
626 	return(0);
627 }
628 
629 /*
630  *	Recalculates the size of the button's toplevel window and
631  *      sets the new size, then calls GWXButtonResize() to realize the
632  *      changes.
633  */
GWXButtonUpdateSize(gw_display_struct * display,gwx_button_struct * btn)634 void GWXButtonUpdateSize(
635 	gw_display_struct *display, gwx_button_struct *btn
636 )
637 {
638 	Display *dpy = (display != NULL) ? display->display : NULL;
639 	Window w;
640 	if((dpy == NULL) || (btn == NULL))
641 	    return;
642 
643 	w = btn->toplevel;
644 	if(w == None)
645 	    return;
646 
647 
648 
649 
650 	GWXButtonResize(display, btn);
651 }
652 
653 /*
654  *	Resizes all button resources to its newly resized toplevel
655  *	window size.
656  */
GWXButtonResize(gw_display_struct * display,gwx_button_struct * btn)657 void GWXButtonResize(gw_display_struct *display, gwx_button_struct *btn)
658 {
659 	Display *dpy = (display != NULL) ? display->display : NULL;
660 	GC gc;
661 	Window w;
662 	XWindowAttributes wattr;
663 	Boolean size_changed = False;
664 	if((dpy == NULL) || (btn == NULL))
665 	    return;
666 
667 	gc = display->gc;
668 	w = btn->toplevel;
669 	if((gc == None) || (w == None))
670 	    return;
671 
672 /*	XSync(dpy, False); */
673 	XGetWindowAttributes(dpy, w, &wattr);
674 	if((wattr.width != btn->width) ||
675 	   (wattr.height != btn->height)
676 	)
677 	    size_changed = True;
678 
679 	btn->x = wattr.x;
680 	btn->y = wattr.y;
681 	btn->width = wattr.width;
682 	btn->height = wattr.height;
683 
684 	if(size_changed || (btn->toplevel_buf == None))
685 	{
686 	    FREE_PIXMAP(&btn->toplevel_buf);
687 	    btn->toplevel_buf = XCreatePixmap(
688 	        dpy, btn->toplevel, btn->width, btn->height, display->depth
689 	    );
690 	}
691 }
692 
693 /*
694  *	Redraws the button.
695  */
GWXButtonDraw(gw_display_struct * display,gwx_button_struct * btn)696 void GWXButtonDraw(gw_display_struct *display, gwx_button_struct *btn)
697 {
698 	Display *dpy = (display != NULL) ? display->display : NULL;
699 	GC gc;
700 	Window w;
701 	Pixmap pm;
702 	Pixel c_fg = 0l, c_bg = 0l, c_highlight = 0l, c_shade = 0l;
703 	unsigned int width, height;
704 	XPoint p[3];
705 	char *label;
706 	XFontStruct *font;
707 	int label_len_pixels, label_height_pixels;
708 	XGCValues gcv;
709 	if((dpy == NULL) || (btn == NULL))
710 	    return;
711 
712 	gc = display->gc;
713 	w = btn->toplevel;
714 	pm = btn->toplevel_buf;
715 	if((gc == None) || (w == None) || (pm == None))
716 	    return;
717 
718 	width = btn->width;
719 	height = btn->height;
720 
721 	GWXWidgetMapRaise(display, GWX_WIDGET(btn));
722 
723 	switch(btn->state)
724 	{
725 	  case GWX_BUTTON_STATE_UNARMED:
726 	    c_fg = btn->color_fg;
727 	    c_bg = btn->color_bg;
728 	    c_highlight = btn->color_highlight;
729 	    c_shade = btn->color_shade;
730 	    break;
731 	  case GWX_BUTTON_STATE_ARMED:
732 	    c_fg = btn->color_fg;
733 	    c_bg = btn->color_bg_highlighted;
734 	    c_highlight = btn->color_shade;
735 	    c_shade = btn->color_highlight;
736 	    break;
737 	  case GWX_BUTTON_STATE_HIGHLIGHTED:
738 	    c_fg = btn->color_fg;
739 	    c_bg = btn->color_bg_highlighted;
740 	    c_highlight = btn->color_highlight;
741 	    c_shade = btn->color_shade;
742 	    break;
743 	}
744 	font = btn->font;
745 
746 
747 	/* Draw (clear) background */
748 	XSetForeground(dpy, gc, c_bg);
749 	XFillRectangle(dpy, pm, gc, 0, 0, width, height);
750 
751 	/* Draw highlight */
752 	XSetForeground(dpy, gc, c_highlight);
753 	XSetLineAttributes(
754 	    dpy, gc,
755 	    2, LineSolid, CapRound, JoinMiter
756 	);
757 	p[0].x = 1;
758 	p[0].y = (int)((int)height - 1);
759 	p[1].x = 1;
760 	p[1].y = 1;
761 	p[2].x = (int)((int)width - 1);
762 	p[2].y = 1;
763 	XDrawLines(
764 	    dpy, pm, gc,
765 	    &(p[0]), 3,		/* Point array and number of points */
766 	    CoordModeOrigin
767 	);
768 
769 	/* Draw shadow */
770 	XSetForeground(dpy, gc, c_shade);
771 	p[0].x = (int)((int)width - 1);
772 	p[0].y = 0;
773 	p[1].x = (int)((int)width - 1);
774 	p[1].y = (int)((int)height - 1);
775 	p[2].x = 0;
776 	p[2].y = (int)((int)height - 1);
777 	XDrawLines(
778 	    dpy, pm, gc,
779 	    &(p[0]), 3,         /* Point array and number of points */
780 	    CoordModeOrigin
781 	);
782 
783 
784 	/* Get pointer to button label */
785 	label = btn->label;
786 	label_len_pixels = btn->label_len_pixels;
787 	label_height_pixels = btn->label_height_pixels;
788 	/* Got enough info to draw button's label? */
789 	if((font != NULL) && (label != NULL) &&
790 	   (label_len_pixels > 0) && (label_height_pixels > 0)
791 	)
792 	{
793 	    /* Calculate length and position to draw label */
794 	    int len = STRLEN(label);
795 	    int x = (int)(((int)width / 2) - (label_len_pixels / 2));
796 	    int y = (int)(((int)height / 2) - (label_height_pixels / 2));
797 
798 	    /* Set up GC for button label drawing */
799 	    if(font->fid != None)
800 		XSetFont(dpy, gc, font->fid);
801 	    XSetForeground(
802 		dpy, gc,
803 		GWX_WIDGET_SENSITIVE(btn) ? c_fg : btn->color_fg
804 	    );
805 
806 	    /* Draw the button's label */
807 	    XDrawString(
808 		dpy, pm, gc,
809 		x, y + font->max_bounds.ascent,
810 		label, len
811 	    );
812 
813 	    /* Button has default? */
814 	    if(GWX_WIDGET_CAN_DEFAULT(btn) &&
815 	       GWX_WIDGET_HAS_DEFAULT(btn)
816 	    )
817 	    {
818 		int focus_margin = 3;
819 		unsigned long gcv_mask =	GCFunction | GCCapStyle |
820 						GCJoinStyle | GCLineWidth |
821 						GCLineStyle | GCDashOffset |
822 						GCDashList;
823 
824 		/* Set up GC to draw `focus rectangle' */
825 		gcv.function = GXinvert;
826 		gcv.cap_style = CapNotLast;
827 		gcv.join_style = JoinBevel;
828 		gcv.line_width = 1;
829 		gcv.line_style = LineOnOffDash;
830 		gcv.dash_offset = 0;
831 		gcv.dashes = 1;
832 		XChangeGC(dpy, gc, gcv_mask, &gcv);
833 
834 		/* Draw `focus rectangle' */
835 		XDrawRectangle(
836 		    dpy, pm, gc,
837 		    0 + focus_margin, 0 + focus_margin,
838 		    width - (focus_margin * 2) - 1,
839 		    height - (focus_margin * 2) - 1
840 		);
841 
842 		/* Restore GC */
843 		gcv.function = GXcopy;
844 		gcv.cap_style = CapNotLast;
845 		gcv.join_style = JoinMiter;
846 		gcv.line_width = 1;
847 		gcv.line_style = LineSolid;
848 		gcv.dash_offset = 0;
849 		gcv.dashes = 2;
850 		XChangeGC(dpy, gc, gcv_mask, &gcv);
851 	    }
852 	}
853 
854 	/* Put Pixmap buffer to Window */
855 	XCopyArea(dpy, pm, w, gc, 0, 0, width, height, 0, 0);
856 }
857 
858 /*
859  *	Manages the given event if it is for the button.
860  */
GWXButtonManage(gw_display_struct * display,gwx_button_struct * btn,XEvent * event)861 int GWXButtonManage(
862 	gw_display_struct *display, gwx_button_struct *btn,
863 	XEvent *event
864 )
865 {
866 	Display *dpy = (display != NULL) ? display->display : NULL;
867 	Window w, ew;
868 	int events_handled = 0;
869 	if((dpy == NULL) || (btn == NULL) || (event == NULL))
870 	    return(events_handled);
871 
872 	w = btn->toplevel;
873 	if(w == None)
874 	    return(events_handled);
875 
876 	ew = event->xany.window;
877 
878 	switch(event->type)
879 	{
880 	  case ButtonPress:
881 	    if(w == ew)
882 	    {
883 		btn->state = GWX_BUTTON_STATE_ARMED;
884 		GWXButtonDraw(display, btn);
885 		events_handled++;
886 	    }
887 	    break;
888 
889 	  case ButtonRelease:
890 	    if(w == ew)
891 	    {
892 		if(btn->state == GWX_BUTTON_STATE_ARMED)
893 		{
894 		    btn->state = GWX_BUTTON_STATE_HIGHLIGHTED;
895 		    GWXButtonDraw(display, btn);
896 		    events_handled++;
897 
898 		    if(btn->func_cb != NULL)
899 		    {
900 			btn->func_cb(
901 			    (void *)btn,	/* This object */
902 			    btn->client_data	/* Client data */
903 			);
904 		    }
905 		}
906 	    }
907 	    break;
908 
909 	  case Expose:
910 	    if(w == ew)
911 	    {
912 		GWXButtonDraw(display, btn);
913 		events_handled++;
914 	    }
915 	    break;
916 
917 	  case EnterNotify:
918 	    if(w == ew)
919 	    {
920 		btn->state = GWX_BUTTON_STATE_HIGHLIGHTED;
921 		GWXButtonDraw(display, btn);
922 		events_handled++;
923 	    }
924 	    break;
925 
926 	  case LeaveNotify:
927 	    if(w == ew)
928 	    {
929 		btn->state = GWX_BUTTON_STATE_UNARMED;
930 		GWXButtonDraw(display, btn);
931 		events_handled++;
932 	    }
933 	    break;
934 	}
935 
936 	return(events_handled);
937 }
938 
939 /*
940  *	Deallocates all resources on the button structure but does not
941  *	deallocate the structure itself.
942  */
GWXButtonDestroy(gw_display_struct * display,gwx_button_struct * btn)943 void GWXButtonDestroy(gw_display_struct *display, gwx_button_struct *btn)
944 {
945 	Display *dpy = (display != NULL) ? display->display : NULL;
946 	if((dpy == NULL) || (btn == NULL))
947 	    return;
948 
949 	DESTROY_WINDOW(&btn->toplevel);
950 	FREE_PIXMAP(&btn->toplevel_buf);
951 
952 	if(btn->colors_initialized)
953 	{
954 	    GWXPixelDelete(display, btn->color_fg);
955 	    GWXPixelDelete(display, btn->color_bg);
956 	    GWXPixelDelete(display, btn->color_fg_insensitive);
957 	    GWXPixelDelete(display, btn->color_bg_highlighted);
958 	    GWXPixelDelete(display, btn->color_highlight);
959 	    GWXPixelDelete(display, btn->color_shade);
960 	    btn->colors_initialized = False;
961 	}
962 
963 	DELETE_FONT(&btn->font);
964 
965 	free(btn->label);
966 	btn->label = NULL;
967 
968 	GWAcceleratorListDelete(
969 	    &btn->accelerator, &btn->total_accelerators
970 	);
971 
972 	memset(btn, 0x00, sizeof(gwx_button_struct));
973 }
974 
975 
976 /*
977  *	Create new message dialog by setting up the values in the given
978  *	message dialog structure.
979  */
GWXDialogCreate(gw_display_struct * display,gwx_dialog_struct * md,gwx_dialog_type type)980 int GWXDialogCreate(
981 	gw_display_struct *display, gwx_dialog_struct *md,
982 	gwx_dialog_type type
983 )
984 {
985 	Display *dpy = (display != NULL) ? display->display : NULL;
986 	Window w, parent;
987 	const char *cstrptr;
988 	int len;
989 	u_int8_t *sc;
990 #ifdef MWMUTIL_H
991 	PropMwmHints mwm_prop;
992 #endif	/* MWMUTIL_H */
993 	gwx_button_struct *btn;
994 	if((dpy == NULL) || (md == NULL))
995 	    return(-1);
996 
997 	parent = display->root;
998 	if(parent == None)
999 	    return(-1);
1000 
1001 	memset(md, 0x00, sizeof(gwx_dialog_struct));
1002 
1003 	md->flags =	GWX_CAN_FOCUS | GWX_CAN_DEFAULT |
1004 			GWX_SENSITIVE;
1005 	md->parent = parent;
1006 	md->x = 0;
1007 	md->y = 0;
1008 	md->width = 200;
1009 	md->height = 100;
1010 
1011 	md->type = type;
1012 	md->margin = 10;
1013 
1014 	w = GWCreateWindow(
1015 	    display, parent,
1016 	    md->x, md->y,
1017 	    md->width, md->height,
1018 	    "Message Dialog"
1019 	);
1020 	if(w == None)
1021 	    return(-1);
1022 	else
1023 	    md->toplevel = w;
1024 
1025 	XSelectInput(
1026 	    dpy, w,
1027 	    KeyPressMask | KeyReleaseMask |
1028 	    ExposureMask | FocusChangeMask |
1029 	    VisibilityChangeMask | StructureNotifyMask
1030 	);
1031 
1032 #ifdef MWMUTIL_H
1033 	/* Set up decorations */
1034 	mwm_prop.flags =	MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS
1035 /*
1036 				| MWM_HINTS_INPUT_MODE | MWM_HINTS_STATUS
1037  */
1038 	;
1039 	mwm_prop.functions =	/* MWM_FUNC_RESIZE | */
1040 				MWM_FUNC_MOVE     |
1041 				/* MWM_FUNC_MINIMIZE | */
1042 				/* MWM_FUNC_MAXIMIZE | */
1043 				MWM_FUNC_CLOSE
1044 	;
1045 	mwm_prop.decorations =	MWM_DECOR_BORDER   |
1046 				/* MWM_DECOR_RESIZEH  | */
1047 				MWM_DECOR_TITLE |
1048 				MWM_DECOR_MENU
1049 				/* MWM_DECOR_MINIMIZE | */
1050 				/* MWM_DECOR_MAXIMIZE */
1051 	;
1052 	mwm_prop.inputMode = 0;
1053 	mwm_prop.status = 0;
1054 	XChangeProperty(
1055 	    dpy, w,
1056 	    display->atom_wm_motif_hints,	/* Property atom */
1057 	    display->atom_wm_motif_hints,	/* Type atom */
1058 	    32,					/* Bits */
1059 	    PropModeReplace,			/* Format */
1060 	    (unsigned char *)&mwm_prop,		/* Data */
1061 	    PROP_MWM_HINTS_ELEMENTS		/* Number of elements */
1062 	);
1063 #endif	/* MWMUTIL_H */
1064 
1065 	/* Set transient for the first toplevel Window */
1066 	if((display->total_gl_contexts > 0) ?
1067 	    (display->toplevel[0] != None) : False
1068 	)
1069 	    XSetTransientForHint(dpy, w, display->toplevel[0]);
1070 
1071 	sc = style_fg_color;
1072 	md->color_fg = GWXPixelNew(display, sc[1], sc[2], sc[3]);
1073 	sc = style_bg_color;
1074 	md->color_bg = GWXPixelNew(display, sc[1], sc[2], sc[3]);
1075 	sc = style_highlight_color;
1076 	md->color_highlight = GWXPixelNew(display, sc[1], sc[2], sc[3]);
1077 	sc = style_shade_color;
1078 	md->color_shade = GWXPixelNew(display, sc[1], sc[2], sc[3]);
1079 
1080 	md->colors_initialized = True;
1081 
1082 	md->font = GWXFontNew(
1083 	    display, display->def_xfont_name
1084 	);
1085 
1086 
1087 	switch(type)
1088 	{
1089 	  case GWX_DIALOG_TYPE_CONF_CANCEL:
1090 	    cstrptr = "Cancel";
1091 	    len = STRLEN(cstrptr);
1092 	    btn = &md->cancel_btn;
1093 	    GWXButtonCreate(
1094 		display, btn, md, w,
1095 		0, 0,
1096 		GWX_BTN_DEF_WIDTH,
1097 		GWX_BTN_DEF_HEIGHT,
1098 		cstrptr,
1099 		display, GWXDialogCancelBtnCB
1100 	    );
1101 	    GWAcceleratorListAdd(
1102 		&btn->accelerator, &btn->total_accelerators,
1103 		'c', 0
1104 	    );
1105 	    GWAcceleratorListAdd(
1106 		&btn->accelerator, &btn->total_accelerators,
1107 		0x1b, 0
1108 	    );
1109 	    /* Fall through */
1110 
1111 	  case GWX_DIALOG_TYPE_CONF:
1112 	    cstrptr = "No";
1113 	    len = STRLEN(cstrptr);
1114 	    btn = &md->no_btn;
1115 	    GWXButtonCreate(
1116 		display, btn, md, w,
1117 		0, 0,
1118 		GWX_BTN_DEF_WIDTH,
1119 		GWX_BTN_DEF_HEIGHT,
1120 		cstrptr,
1121 		display, GWXDialogNoBtnCB
1122 	    );
1123 	    GWAcceleratorListAdd(
1124 		&btn->accelerator, &btn->total_accelerators,
1125 		'n', 0
1126 	    );
1127 	    if(type == GWX_DIALOG_TYPE_CONF)
1128 		GWAcceleratorListAdd(
1129 		    &btn->accelerator, &btn->total_accelerators,
1130 		    0x1b, 0
1131 		);
1132 
1133 	    cstrptr = "Yes";
1134 	    len = STRLEN(cstrptr);
1135 	    btn = &md->yes_btn;
1136 	    GWXButtonCreate(
1137 		display, btn, md, w,
1138 		0, 0,
1139 		GWX_BTN_DEF_WIDTH,
1140 		GWX_BTN_DEF_HEIGHT,
1141 		cstrptr,
1142 		display, GWXDialogYesBtnCB
1143 	    );
1144 	    GWAcceleratorListAdd(
1145 		&btn->accelerator, &btn->total_accelerators,
1146 		'y', 0
1147 	    );
1148 	    break;
1149 
1150 	  case GWX_DIALOG_TYPE_MESG:
1151 	    cstrptr = "OK";
1152 	    len = STRLEN(cstrptr);
1153 	    btn = &md->ok_btn;
1154 	    GWXButtonCreate(
1155 	        display, btn, md, w,
1156 	        0, 0,
1157 		GWX_BTN_DEF_WIDTH,
1158 		GWX_BTN_DEF_HEIGHT,
1159 	        cstrptr,
1160 	        display, GWXDialogOKBtnCB
1161 	    );
1162 	    GWAcceleratorListAdd(
1163 		&btn->accelerator, &btn->total_accelerators,
1164 		'o', 0
1165 	    );
1166 	    GWAcceleratorListAdd(
1167 		&btn->accelerator, &btn->total_accelerators,
1168 		0x1b, 0
1169 	    );
1170 	    break;
1171 	}
1172 
1173 
1174 	GWXDialogResize(display, md);
1175 
1176 	return(0);
1177 }
1178 
1179 /*
1180  *	Loads the message dialog icon (the icon displayed next to
1181  *	dialog's text, not the WM icon).
1182  */
GWXDialogLoadIcon(gw_display_struct * display,gwx_dialog_struct * md,gwx_icon icon_code)1183 void GWXDialogLoadIcon(
1184 	gw_display_struct *display, gwx_dialog_struct *md,
1185 	gwx_icon icon_code		/* One of GWX_ICON_* */
1186 )
1187 {
1188 	Display *dpy = (display != NULL) ? display->display : NULL;
1189 	GC gc;
1190 	Window w, *icon_w;
1191 	Pixmap *icon, *icon_mask;
1192 	unsigned int btn_height = 0;
1193 #ifdef XPM_H
1194 	int xpm_status;
1195 	XpmAttributes xpm_attr;
1196 	char **xpm_data;
1197 #endif
1198 	if((dpy == NULL) || (md == NULL))
1199 	    return;
1200 
1201 	gc = display->gc;
1202 	w = md->toplevel;
1203 	if((gc == None) || (w == None))
1204 	    return;
1205 
1206 	/* Calculate height based on type of dialog */
1207 	switch(md->type)
1208 	{
1209 	  case GWX_DIALOG_TYPE_CONF_CANCEL:
1210 	  case GWX_DIALOG_TYPE_CONF:
1211 	    btn_height = md->yes_btn.height;
1212 	    break;
1213 	  case GWX_DIALOG_TYPE_MESG:
1214 	    btn_height = md->ok_btn.height;
1215 	    break;
1216 	}
1217 
1218 	/* Get pointers to icon window, pixmap, and pixmap mask on dialog
1219 	 * structure.
1220 	 */
1221 	icon_w = &md->icon_w;
1222 	icon = &md->icon;
1223 	icon_mask = &md->icon_mask;
1224 
1225 	/* Destroy old icons and window if any */
1226 	DESTROY_WINDOW(icon_w);
1227 	FREE_PIXMAP(icon);
1228 	FREE_BITMAP(icon_mask);
1229 
1230 #ifdef XPM_H
1231 	/* Get icon data based on the icon code */
1232 	switch(icon_code)
1233 	{
1234 	  case GWX_ICON_WARNING:
1235 	    xpm_data = icon_warning_xpm;
1236 	    break;
1237 
1238 	  case GWX_ICON_ERROR:
1239 	    xpm_data = icon_error_xpm;
1240 	    break;
1241 
1242 	  case GWX_ICON_QUESTION:
1243 	    xpm_data = icon_question_xpm;
1244 	    break;
1245 
1246 	  default:
1247 	    xpm_data = icon_info_xpm;
1248 	    break;
1249 	}
1250 
1251 	/* Set up XPM attributes for the loading of the XPM data */
1252 	xpm_attr.valuemask =	XpmCloseness | XpmVisual | XpmColormap |
1253 				XpmSize | XpmDepth;
1254 	xpm_attr.closeness = XpmDefaultColorCloseness;
1255 	xpm_attr.depth = display->depth;
1256 	xpm_attr.visual = display->visual;
1257 	xpm_attr.colormap = display->colormap;
1258 
1259 	/* Load XPM data */
1260 	xpm_status = XpmCreatePixmapFromData(
1261 	    dpy, w, xpm_data,
1262 	    icon, icon_mask,
1263 	    &xpm_attr
1264 	);
1265 	if(xpm_status == XpmSuccess)
1266 	{
1267 	    /* Get loaded XPM size */
1268 	    md->icon_width = xpm_attr.width,
1269 	    md->icon_height = xpm_attr.height;
1270 
1271 	    /* Create icon Window */
1272 	    *icon_w = GWCreateWindow(
1273 		display, w,
1274 		0, 0,
1275 		md->icon_width, md->icon_height,
1276 		NULL
1277 	    );
1278 	    if(*icon_w != None)
1279 	    {
1280 		/* Begin setting up icon Window */
1281 		XSelectInput(dpy, *icon_w, ExposureMask);
1282 		XShapeCombineMask(
1283 		    dpy, *icon_w,
1284 		    ShapeBounding,
1285 		    0, 0,
1286 		    *icon_mask,
1287 		    ShapeSet
1288 		);
1289 		XMapRaised(dpy, *icon_w);
1290 	    }
1291 	}
1292 #endif	/* XPM_H */
1293 
1294 	/* Update size of dialog due to change in icon size */
1295 	GWXDialogUpdateSize(display, md);
1296 }
1297 
1298 /*
1299  *	Recalculates the size of the dialog's toplevel window and
1300  *	sets the new size, then calls GWXDialogResize() to realize the
1301  *	changes.
1302  */
GWXDialogUpdateSize(gw_display_struct * display,gwx_dialog_struct * md)1303 void GWXDialogUpdateSize(gw_display_struct *display, gwx_dialog_struct *md)
1304 {
1305 	Display *dpy = (display != NULL) ? display->display : NULL;
1306 	Window w;
1307 	unsigned int width, height;
1308 	unsigned int btn_width_total = 0, btn_height = 0;
1309 	gwx_button_struct *btn;
1310 	if((dpy == NULL) || (md == NULL))
1311 	    return;
1312 
1313 	w = md->toplevel;
1314 	if(w == None)
1315 	    return;
1316 
1317 	/* Get button height depending on dialog type */
1318 	switch(md->type)
1319 	{
1320 	  case GWX_DIALOG_TYPE_CONF_CANCEL:
1321 	    btn = &md->cancel_btn;
1322 	    btn_width_total += btn->width + md->margin;
1323 	    btn_height = MAX(btn->height, btn_height);
1324 	  case GWX_DIALOG_TYPE_CONF:
1325 	    btn = &md->yes_btn;
1326 	    btn_width_total += btn->width + md->margin;
1327 	    btn_height = MAX(btn->height, btn_height);
1328 	    btn = &md->no_btn;
1329 	    btn_width_total += btn->width;
1330 	    btn_height = MAX(btn->height, btn_height);
1331 	    break;
1332 	  case GWX_DIALOG_TYPE_MESG:
1333 	    btn = &md->ok_btn;
1334 	    btn_width_total += btn->width;
1335 	    btn_height = MAX(btn->height, btn_height);
1336 	    break;
1337 	}
1338 
1339 	/* Calculate new size of dialog */
1340 	width = (unsigned int)(
1341 	    ((md->icon_w == None) ? (md->margin * 2) : (md->margin * 3)) +
1342 	    md->icon_width +
1343 	    MAX(md->longest_line_pixels, btn_width_total)
1344 	);
1345 	height = (unsigned int)MAX(
1346 	    (md->margin * 4) + btn_height + md->icon_height,
1347 	    (md->margin * 4) + btn_height + md->lines_height_pixels
1348 	);
1349 
1350 	/* Set new toplevel Window size */
1351 	XResizeWindow(dpy, w, width, height);
1352 
1353 	GWXDialogResize(display, md);
1354 }
1355 
1356 /*
1357  *	Resizes message dialog resources with respect to the dialog's
1358  *	toplevel window.
1359  */
GWXDialogResize(gw_display_struct * display,gwx_dialog_struct * md)1360 void GWXDialogResize(gw_display_struct *display, gwx_dialog_struct *md)
1361 {
1362 	Display *dpy = (display != NULL) ? display->display : NULL;
1363 	GC gc;
1364 	Window w;
1365 	Boolean size_changed = False;
1366 	XWindowAttributes wattr;
1367 	gwx_button_struct *btn;
1368 	int btn_x, btn_width_total;
1369 	if((dpy == NULL) || (md == NULL))
1370 	    return;
1371 
1372 	gc = display->gc;
1373 	w = md->toplevel;
1374 	if((gc == None) || (w == None))
1375 	    return;
1376 
1377 /*	XSync(dpy, False); */
1378 	XGetWindowAttributes(dpy, w, &wattr);
1379 	if((wattr.width != md->width) ||
1380 	   (wattr.height != md->height)
1381 	)
1382 	    size_changed = True;
1383 
1384 	md->x = wattr.x;
1385 	md->y = wattr.y;
1386 	md->width = wattr.width;
1387 	md->height = wattr.height;
1388 
1389 	if(size_changed || (md->toplevel_buf == None))
1390 	{
1391 	    FREE_PIXMAP(&md->toplevel_buf);
1392 	    md->toplevel_buf = XCreatePixmap(
1393 		dpy, md->toplevel, md->width, md->height, display->depth
1394 	    );
1395 	}
1396 
1397 	/* Move icon window? */
1398 	if(md->icon_w != None)
1399 	    XMoveWindow(
1400 		dpy, md->icon_w,
1401 		(int)md->margin,
1402 		(int)md->margin + (int)MAX(
1403 		    (md->lines_height_pixels / 2) - ((int)md->icon_height / 2),
1404 		    0
1405 		)
1406 	    );
1407 
1408 	/* Reposition buttons */
1409 	switch(md->type)
1410 	{
1411 	  case GWX_DIALOG_TYPE_CONF_CANCEL:
1412 	    btn_width_total = 0;
1413 	    btn = &md->yes_btn;
1414 	    btn_width_total += btn->width + md->margin;
1415 	    btn = &md->no_btn;
1416 	    btn_width_total += btn->width + md->margin;
1417 	    btn = &md->cancel_btn;
1418 	    btn_width_total += btn->width;
1419 
1420 	    btn_x = ((int)md->width / 2) - (btn_width_total / 2);
1421 
1422 	    btn = &md->yes_btn;
1423 	    XMoveWindow(
1424 		dpy, btn->toplevel,
1425 		btn_x,
1426 		(int)((int)md->height - (int)md->margin - (int)btn->height)
1427 	    );
1428 	    GWXButtonResize(display, btn);
1429 	    btn_x += btn->width + md->margin;
1430 
1431 	    btn = &md->no_btn;
1432 	    XMoveWindow(
1433 		dpy, btn->toplevel,
1434 		btn_x,
1435 		(int)((int)md->height - (int)md->margin - (int)btn->height)
1436 	    );
1437 	    GWXButtonResize(display, btn);
1438 	    btn_x += btn->width + md->margin;
1439 
1440 	    btn = &md->cancel_btn;
1441 	    XMoveWindow(
1442 		dpy, btn->toplevel,
1443 		btn_x,
1444 		(int)((int)md->height - (int)md->margin - (int)btn->height)
1445 	    );
1446 	    GWXButtonResize(display, btn);
1447 
1448 	    break;
1449 
1450 	  case GWX_DIALOG_TYPE_CONF:
1451 	    btn_width_total = 0;
1452 	    btn = &md->yes_btn;
1453 	    btn_width_total += btn->width + md->margin;
1454 	    btn = &md->no_btn;
1455 	    btn_width_total += btn->width;
1456 
1457 	    btn_x = ((int)md->width / 2) - (btn_width_total / 2);
1458 
1459 	    btn = &md->yes_btn;
1460 	    XMoveWindow(
1461 		dpy, btn->toplevel,
1462 		btn_x,
1463 		(int)((int)md->height - (int)md->margin - (int)btn->height)
1464 	    );
1465 	    GWXButtonResize(display, btn);
1466 	    btn_x += btn->width + md->margin;
1467 
1468 	    btn = &md->no_btn;
1469 	    XMoveWindow(
1470 		dpy, btn->toplevel,
1471 		btn_x,
1472 		(int)((int)md->height - (int)md->margin - (int)btn->height)
1473 	    );
1474 	    GWXButtonResize(display, btn);
1475 
1476 	    break;
1477 
1478 	  case GWX_DIALOG_TYPE_MESG:
1479 	    btn_width_total = 0;
1480 	    btn = &md->ok_btn;
1481 	    btn_width_total += btn->width;
1482 
1483 	    btn_x = ((int)md->width / 2) - (btn_width_total / 2);
1484 
1485 	    btn = &md->ok_btn;
1486 	    XMoveWindow(
1487 		dpy, btn->toplevel,
1488 		btn_x,
1489 		(int)((int)md->height - (int)md->margin - (int)btn->height)
1490 	    );
1491 	    GWXButtonResize(display, btn);
1492 	    break;
1493 	}
1494 }
1495 
1496 /*
1497  *	Redraws message dialog.
1498  */
GWXDialogDraw(gw_display_struct * display,gwx_dialog_struct * md)1499 void GWXDialogDraw(gw_display_struct *display, gwx_dialog_struct *md)
1500 {
1501 	Display *dpy = (display != NULL) ? display->display : NULL;
1502 	GC gc;
1503 	Window w;
1504 	Pixmap pm;
1505 	Pixel c_fg, c_bg, c_highlight, c_shade;
1506 	unsigned int width, height, margin;
1507 	unsigned int btn_height = 0;
1508 	XFontStruct *font;
1509 	char **strv;
1510 	int strc;
1511 	int line_height_pixels;
1512 	XPoint p[2];
1513 	if((dpy == NULL) || (md == NULL))
1514 	    return;
1515 
1516 	gc = display->gc;
1517 	w = md->toplevel;
1518 	pm = md->toplevel_buf;
1519 	if((gc == None) || (w == None) || (pm == None))
1520 	    return;
1521 
1522 	width = md->width;
1523 	height = md->height;
1524 	margin = md->margin;
1525 
1526 	GWXWidgetMapRaise(display, GWX_WIDGET(md));
1527 
1528 	switch(md->type)
1529 	{
1530 	  case GWX_DIALOG_TYPE_CONF_CANCEL:
1531 	  case GWX_DIALOG_TYPE_CONF:
1532 	    btn_height = md->yes_btn.height;
1533 	    break;
1534 
1535 	  case GWX_DIALOG_TYPE_MESG:
1536 	    btn_height = md->ok_btn.height;
1537 	    break;
1538 	}
1539 
1540 	c_fg = md->color_fg;
1541 	c_bg = md->color_bg;
1542 	c_highlight = md->color_highlight;
1543 	c_shade = md->color_shade;
1544 
1545 	font = md->font;
1546 
1547 
1548 	/* Draw background */
1549 	XSetForeground(dpy, gc, c_bg);
1550 	XFillRectangle(dpy, pm, gc, 0, 0, width, height);
1551 
1552 
1553 	/* Draw HR */
1554 	XSetForeground(dpy, gc, c_shade);
1555 	XSetLineAttributes(
1556 	    dpy, gc,
1557 	    2, LineSolid, CapRound, JoinMiter
1558 	);
1559 	p[0].x = 0;
1560 	p[0].y = (int)((int)height - ((int)md->margin * 2) - (int)btn_height);
1561 	p[1].x = (int)width;
1562 	p[1].y = p[0].y;
1563 	XDrawLines(
1564 	    dpy, pm, gc,
1565 	    &(p[0]), 2,         /* Point array and number of points */
1566 	    CoordModeOrigin
1567 	);
1568 
1569 	XSetForeground(dpy, gc, c_highlight);
1570 	p[0].y += 1;
1571 	p[1].y = p[0].y;
1572 	XDrawLines(
1573 	    dpy, pm, gc,
1574 	    &(p[0]), 2,         /* Point array and number of points */
1575 	    CoordModeOrigin
1576 	);
1577 
1578 
1579 	/* Get values for drawing message lines */
1580 	strv = md->strv;
1581 	strc = md->strc;
1582 	line_height_pixels = md->line_height_pixels;
1583 
1584 	/* Got enough information to draw message lines? */
1585 	if((font != NULL) && (strv != NULL) &&
1586 	   (line_height_pixels > 0)
1587 	)
1588 	{
1589 	    int	x = (int)((md->margin * 2) + md->icon_width),
1590 		y = (int)md->margin,
1591 		i, len;
1592 	    const char *s;
1593 
1594 	    /* Set up GC for message lines drawing */
1595 	    if(font->fid != None)
1596 		XSetFont(dpy, gc, font->fid);
1597 	    XSetForeground(dpy, gc, c_fg);
1598 
1599 	    /* Draw each message line */
1600 	    for(i = 0; i < strc; i++)
1601 	    {
1602 		s = (const char *)strv[i];
1603 		if(s == NULL)
1604 		    continue;
1605 
1606 		len = STRLEN(s);
1607 		if(len > 0)
1608 		    XDrawString(
1609 			dpy, pm, gc,
1610 			x, y + font->max_bounds.ascent,
1611 			s, len
1612 		    );
1613 
1614 		y += line_height_pixels;
1615 	    }
1616 	}
1617 
1618 	/* Copy Pixmap buffer to Window */
1619 	XCopyArea(dpy, pm, w, gc, 0, 0, width, height, 0, 0);
1620 
1621 
1622 	/* Draw icon */
1623 	w = md->icon_w;
1624 	pm = md->icon;
1625 	width = md->icon_width;
1626 	height = md->icon_height;
1627 	if((w != None) && (pm != None) &&
1628 	   (width > 0) && (height > 0)
1629 	)
1630 	    XCopyArea(dpy, pm, w, gc, 0, 0, width, height, 0, 0);
1631 }
1632 
1633 /*
1634  *	Manages the event if it is for the given message dialog.
1635  */
GWXDialogManage(gw_display_struct * display,gwx_dialog_struct * md,XEvent * event)1636 int GWXDialogManage(
1637 	gw_display_struct *display, gwx_dialog_struct *md,
1638 	XEvent *event
1639 )
1640 {
1641 	Display *dpy = (display != NULL) ? display->display : NULL;
1642 	Window w, ew;
1643 	int events_handled = 0;
1644 	if((dpy == NULL) || (md == NULL) || (event == NULL))
1645 	    return(events_handled);
1646 
1647 	w = md->toplevel;
1648 	if(w == None)
1649 	    return(events_handled);
1650 
1651 	ew = event->xany.window;
1652 
1653 	switch(event->type)
1654 	{
1655 	  case Expose:
1656 	    if(w == ew)
1657 	    {
1658 		GWXDialogDraw(display, md);
1659 		events_handled++;
1660 	    }
1661 	    break;
1662 
1663 	  case ConfigureNotify:
1664 	    if(w == ew)
1665 	    {
1666 		GWXDialogResize(display, md);
1667 		events_handled++;
1668 	    }
1669 	    break;
1670 
1671 	  case VisibilityNotify:
1672 	    if(w == ew)
1673 	    {
1674 
1675 
1676 		events_handled++;
1677 	    }
1678 	    break;
1679 
1680 	  case KeyPress:
1681 	    if(GWX_WIDGET_MAPPED(md) && GWX_WIDGET_HAS_FOCUS(md))
1682 	    {
1683 		gwx_button_struct *btn, *btn_next;
1684 		Boolean shift = display->shift_key_state;
1685 		int modifier = GWGetCharacterFromKeyCode(
1686 		    display, event->xkey.state
1687 		);
1688 		int k = GWGetCharacterFromKeyCode(
1689 		    display, event->xkey.keycode
1690 		);
1691 #define DO_FOCUS_NEXT_BUTTON				\
1692 { if(GWX_WIDGET_CAN_DEFAULT(btn_next)) {		\
1693  GWXWidgetUngrabDefault(display, GWX_WIDGET(btn));	\
1694  GWXWidgetUnfocus(display, GWX_WIDGET(btn));		\
1695  GWXWidgetGrabDefault(display, GWX_WIDGET(btn_next));	\
1696  GWXWidgetFocus(display, GWX_WIDGET(btn_next));		\
1697  GWXButtonDraw(display, btn);				\
1698  GWXButtonDraw(display, btn_next);			\
1699 } }
1700 #define DO_BTN_HANDLE_ACCEL_KEY(b,k)			\
1701 { if( GWAcceleratorListCheck(				\
1702  (b)->accelerator, (b)->total_accelerators,		\
1703  (k), modifier)) {					\
1704   (b)->state = GWX_BUTTON_STATE_ARMED;			\
1705   GWXButtonDraw(display, (b));				\
1706 } }
1707 #define DO_BTN_SET_ARMED(b)				\
1708 { if((b) != NULL) {					\
1709   (b)->state = GWX_BUTTON_STATE_ARMED;			\
1710   GWXButtonDraw(display, (b));				\
1711 } }
1712 		switch(k)
1713 		{
1714 		  case '\t':
1715 		    switch(md->type)
1716 		    {
1717 		      case GWX_DIALOG_TYPE_CONF_CANCEL:
1718 			if(GWX_Widget_Has_Default(&md->yes_btn))
1719 			{
1720 			    btn = &md->yes_btn;
1721 			    btn_next = shift ?
1722 				&md->cancel_btn : &md->no_btn;
1723 			    DO_FOCUS_NEXT_BUTTON
1724 			}
1725 			else if(GWX_Widget_Has_Default(&md->no_btn))
1726 			{
1727 			    btn = &md->no_btn;
1728 			    btn_next = shift ?
1729 				&md->yes_btn : &md->cancel_btn;
1730 			    DO_FOCUS_NEXT_BUTTON
1731 			}
1732 			else if(GWX_Widget_Has_Default(&md->cancel_btn))
1733 			{
1734 			    btn = &md->cancel_btn;
1735 			    btn_next = shift ?
1736 				&md->no_btn : &md->yes_btn;
1737 			    DO_FOCUS_NEXT_BUTTON
1738 			}
1739 			break;
1740 		      case GWX_DIALOG_TYPE_CONF:
1741 			if(GWX_Widget_Has_Default(&md->yes_btn))
1742 			{
1743 			    btn = &md->yes_btn;
1744 			    btn_next = shift ?
1745 				&md->no_btn : &md->no_btn;
1746 			    DO_FOCUS_NEXT_BUTTON
1747 			}
1748 			else if(GWX_Widget_Has_Default(&md->no_btn))
1749 			{
1750 			    btn = &md->no_btn;
1751 			    btn_next = shift ?
1752 				&md->yes_btn : &md->yes_btn;
1753 			    DO_FOCUS_NEXT_BUTTON
1754 			}
1755 			break;
1756 		      case GWX_DIALOG_TYPE_MESG:
1757 			break;
1758 		    }
1759 		    break;
1760 
1761 		  case '\n': case ' ':
1762 		    switch(md->type)
1763 		    {
1764 		      case GWX_DIALOG_TYPE_CONF_CANCEL:
1765 			if(GWX_Widget_Has_Default(&md->yes_btn))
1766 			{
1767 			     DO_BTN_SET_ARMED(&md->yes_btn);
1768 			}
1769 			else if(GWX_Widget_Has_Default(&md->no_btn))
1770 			{
1771 			     DO_BTN_SET_ARMED(&md->no_btn);
1772 			}
1773 			else if(GWX_Widget_Has_Default(&md->cancel_btn))
1774 			{
1775 			     DO_BTN_SET_ARMED(&md->cancel_btn);
1776 			}
1777 			break;
1778 		      case GWX_DIALOG_TYPE_CONF:
1779 			if(GWX_Widget_Has_Default(&md->yes_btn))
1780 			{
1781 			    DO_BTN_SET_ARMED(&md->yes_btn);
1782 			}
1783 			else if(GWX_Widget_Has_Default(&md->no_btn))
1784 			{
1785 			    DO_BTN_SET_ARMED(&md->no_btn);
1786 			}
1787 			break;
1788 		      case GWX_DIALOG_TYPE_MESG:
1789 			if(GWX_Widget_Has_Default(&md->ok_btn))
1790 			{
1791 			    DO_BTN_SET_ARMED(&md->ok_btn);
1792 			}
1793 			break;
1794 		    }
1795 		    break;
1796 
1797 		  default:
1798 		    switch(md->type)
1799 		    {
1800 		      case GWX_DIALOG_TYPE_CONF_CANCEL:
1801 			DO_BTN_HANDLE_ACCEL_KEY(
1802 			    &md->cancel_btn, k
1803 			);
1804 		      case GWX_DIALOG_TYPE_CONF:
1805 			DO_BTN_HANDLE_ACCEL_KEY(
1806 			    &md->yes_btn, k
1807 			);
1808 			DO_BTN_HANDLE_ACCEL_KEY(
1809 			    &md->no_btn, k
1810 			);
1811 			break;
1812 		      case GWX_DIALOG_TYPE_MESG:
1813 			DO_BTN_HANDLE_ACCEL_KEY(
1814 			    &md->ok_btn, k
1815 			);
1816 			break;
1817 		    }
1818 		    break;
1819 		}
1820 #undef DO_BTN_SET_ARMED
1821 #undef DO_BTN_HANDLE_ACCEL_KEY
1822 #undef DO_FOCUS_NEXT_BUTTON
1823 		events_handled++;
1824 	    }
1825 	    break;
1826 
1827 	  case KeyRelease:
1828 	    if(GWX_WIDGET_MAPPED(md) && GWX_WIDGET_HAS_FOCUS(md))
1829 	    {
1830 		int modifier = GWGetCharacterFromKeyCode(
1831 		    display, event->xkey.state
1832 		);
1833 		int k = GWGetCharacterFromKeyCode(
1834 		    display, event->xkey.keycode
1835 		);
1836 #define DO_BTN_HANDLE_ACCEL_KEY(b,k)                    \
1837 { if(GWAcceleratorListCheck(                            \
1838  (b)->accelerator, (b)->total_accelerators,             \
1839  (k), modifier)) {					\
1840   (b)->state = GWX_BUTTON_STATE_UNARMED;                \
1841   GWXButtonDraw(display, (b));				\
1842   if((b)->func_cb != NULL)				\
1843    (b)->func_cb((b), (b)->client_data);			\
1844 } }
1845 #define DO_BTN_SET_UNARMED_CALL(b)			\
1846 { if((b) != NULL) {                                     \
1847   (b)->state = GWX_BUTTON_STATE_UNARMED;		\
1848   GWXButtonDraw(display, (b));                          \
1849   if((b)->func_cb != NULL)                              \
1850    (b)->func_cb((b), (b)->client_data);                 \
1851 } }
1852 		switch(k)
1853 		{
1854 		  case '\n': case ' ':
1855 		    switch(md->type)
1856 		    {
1857 		      case GWX_DIALOG_TYPE_CONF_CANCEL:
1858 			if(GWX_Widget_Has_Default(&md->yes_btn))
1859 			{
1860 			     DO_BTN_SET_UNARMED_CALL(&md->yes_btn);
1861 			}
1862 			else if(GWX_Widget_Has_Default(&md->no_btn))
1863 			{
1864 			     DO_BTN_SET_UNARMED_CALL(&md->no_btn);
1865 			}
1866 			else if(GWX_Widget_Has_Default(&md->cancel_btn))
1867 			{
1868 			     DO_BTN_SET_UNARMED_CALL(&md->cancel_btn);
1869 			}
1870 			break;
1871 		      case GWX_DIALOG_TYPE_CONF:
1872 			if(GWX_Widget_Has_Default(&md->yes_btn))
1873 			{
1874 			    DO_BTN_SET_UNARMED_CALL(&md->yes_btn);
1875 			}
1876 			else if(GWX_Widget_Has_Default(&md->no_btn))
1877 			{
1878 			    DO_BTN_SET_UNARMED_CALL(&md->no_btn);
1879 			}
1880 			break;
1881 		      case GWX_DIALOG_TYPE_MESG:
1882 			if(GWX_Widget_Has_Default(&md->ok_btn))
1883 			{
1884 			    DO_BTN_SET_UNARMED_CALL(&md->ok_btn);
1885 			}
1886 			break;
1887 		    }
1888 		    break;
1889 
1890 		  default:
1891 		    switch(md->type)
1892 		    {
1893 		      case GWX_DIALOG_TYPE_CONF_CANCEL:
1894 			DO_BTN_HANDLE_ACCEL_KEY(
1895 			    &md->cancel_btn, k
1896 			);
1897 		      case GWX_DIALOG_TYPE_CONF:
1898 			DO_BTN_HANDLE_ACCEL_KEY(
1899 			    &md->yes_btn, k
1900 			);
1901 			DO_BTN_HANDLE_ACCEL_KEY(
1902 			    &md->no_btn, k
1903 			);
1904 			break;
1905 		      case GWX_DIALOG_TYPE_MESG:
1906 			DO_BTN_HANDLE_ACCEL_KEY(
1907 			    &md->ok_btn, k
1908 			);
1909 			break;
1910 		    }
1911 		    break;
1912 		}
1913 #undef DO_BTN_SET_UNARMED_CALL
1914 #undef DO_BTN_HANDLE_ACCEL_KEY
1915 		events_handled++;
1916 	    }
1917 	    break;
1918 
1919 	  case FocusOut:
1920 	    if(w == ew)
1921 	    {
1922 		GWXWidgetUnfocus(display, GWX_WIDGET(md));
1923 		events_handled++;
1924 	    }
1925 	    break;
1926 
1927 	  case FocusIn:
1928 	    if(w == ew)
1929 	    {
1930 		GWXWidgetFocus(display, GWX_WIDGET(md));
1931 		events_handled++;
1932 	    }
1933 	    break;
1934 
1935 	  case ClientMessage:
1936 	    if((event->xclient.format == 32) &&
1937 	       (event->xclient.data.l[0] == display->atom_wm_delete_window) &&
1938 	       (w == ew)
1939 	    )
1940 	    {
1941 		switch(md->type)
1942 		{
1943 		  case GWX_DIALOG_TYPE_CONF_CANCEL:
1944 		    GWXDialogCancelBtnCB(
1945 			&md->cancel_btn,
1946 			md->cancel_btn.client_data
1947 		    );
1948 		    break;
1949 
1950 		  case GWX_DIALOG_TYPE_CONF:
1951 		    GWXDialogNoBtnCB(
1952 			&md->no_btn,
1953 			md->no_btn.client_data
1954 		    );
1955 		    break;
1956 
1957 		  default:
1958 		    GWXDialogOKBtnCB(
1959 		        &md->ok_btn,
1960 		        md->ok_btn.client_data
1961 		    );
1962 		    break;
1963 		}
1964 		events_handled++;
1965 	    }
1966 	    break;
1967 	}
1968 
1969 	switch(md->type)
1970 	{
1971 	  case GWX_DIALOG_TYPE_CONF_CANCEL:
1972 	    if(!events_handled)
1973 		events_handled += GWXButtonManage(display, &md->cancel_btn, event);
1974 	  case GWX_DIALOG_TYPE_CONF:
1975 	    if(!events_handled)
1976 		events_handled += GWXButtonManage(display, &md->no_btn, event);
1977 	    if(!events_handled)
1978 		events_handled += GWXButtonManage(display, &md->yes_btn, event);
1979 	    break;
1980 
1981 	  case GWX_DIALOG_TYPE_MESG:
1982 	    if(!events_handled)
1983 		events_handled += GWXButtonManage(display, &md->ok_btn, event);
1984 	    break;
1985 	}
1986 
1987 	return(events_handled);
1988 }
1989 
1990 /*
1991  *	Destroys and deallocates all resources on the given dialog.
1992  */
GWXDialogDestroy(gw_display_struct * display,gwx_dialog_struct * md)1993 void GWXDialogDestroy(
1994 	gw_display_struct *display, gwx_dialog_struct *md
1995 )
1996 {
1997 	int i;
1998 	Display *dpy = (display != NULL) ? display->display : NULL;
1999 	if((dpy == NULL) || (md == NULL))
2000 	    return;
2001 
2002 	switch(md->type)
2003 	{
2004 	  case GWX_DIALOG_TYPE_CONF_CANCEL:
2005 	    GWXButtonDestroy(display, &md->cancel_btn);
2006 	  case GWX_DIALOG_TYPE_CONF:
2007 	    GWXButtonDestroy(display, &md->yes_btn);
2008 	    GWXButtonDestroy(display, &md->no_btn);
2009 	    break;
2010 	  case GWX_DIALOG_TYPE_MESG:
2011 	    GWXButtonDestroy(display, &md->ok_btn);
2012 	    break;
2013 	}
2014 
2015 	DESTROY_WINDOW(&md->icon_w);
2016 	FREE_PIXMAP(&md->icon);
2017 	FREE_BITMAP(&md->icon_mask);
2018 
2019 	DESTROY_TOPLEVEL_WINDOW(&md->toplevel);
2020 	FREE_PIXMAP(&md->toplevel_buf);
2021 
2022 	if(md->colors_initialized)
2023 	{
2024 	    GWXPixelDelete(display, md->color_fg);
2025 	    GWXPixelDelete(display, md->color_bg);
2026 	    GWXPixelDelete(display, md->color_highlight);
2027 	    GWXPixelDelete(display, md->color_shade);
2028 	    md->colors_initialized = False;
2029 	}
2030 
2031 	DELETE_FONT(&md->font);
2032 
2033 	for(i = 0; i < md->strc; i++)
2034 	    free(md->strv[i]);
2035 	free(md->strv);
2036 	md->strv = NULL;
2037 	md->strc = 0;
2038 
2039 	memset(md, 0x00, sizeof(gwx_dialog_struct));
2040 }
2041 
2042 
2043 /*
2044  *      Confirmation dialog No button callback.
2045  */
GWXDialogNoBtnCB(void * object,void * client_data)2046 void GWXDialogNoBtnCB(void *object, void *client_data)
2047 {
2048 	gw_display_struct *display = GW_DISPLAY(client_data);
2049 	gwx_button_struct *btn = GWX_BUTTON(object);
2050 	gwx_dialog_struct *md;
2051 	if((display == NULL) || (btn == NULL))
2052 	    return;
2053 
2054 	md = &display->conf_dialog;
2055 	if(&md->no_btn == btn)
2056 	    last_conf_dialog_code = GWConfirmationNo;
2057 }
2058 
2059 /*
2060  *	Confirmation dialog Yes button callback.
2061  */
GWXDialogYesBtnCB(void * object,void * client_data)2062 void GWXDialogYesBtnCB(void *object, void *client_data)
2063 {
2064 	gw_display_struct *display = GW_DISPLAY(client_data);
2065 	gwx_button_struct *btn = GWX_BUTTON(object);
2066 	gwx_dialog_struct *md;
2067 	if((display == NULL) || (btn == NULL))
2068 	    return;
2069 
2070 	md = &display->conf_dialog;
2071 	if(&md->yes_btn == btn)
2072 	    last_conf_dialog_code = GWConfirmationYes;
2073 }
2074 
2075 /*
2076  *      Confirmation dialog Cancel button callback.
2077  */
GWXDialogCancelBtnCB(void * object,void * client_data)2078 void GWXDialogCancelBtnCB(void *object, void *client_data)
2079 {
2080 	gw_display_struct *display = GW_DISPLAY(client_data);
2081 	gwx_button_struct *btn = GWX_BUTTON(object);
2082 	gwx_dialog_struct *md;
2083 	if((display == NULL) || (btn == NULL))
2084 	    return;
2085 
2086 	md = &display->conf_dialog;
2087 	if(&md->cancel_btn == btn)
2088 	    last_conf_dialog_code = GWConfirmationCancel;
2089 }
2090 
2091 /*
2092  *	Dialog OK button callback.
2093  */
GWXDialogOKBtnCB(void * object,void * client_data)2094 void GWXDialogOKBtnCB(void *object, void *client_data)
2095 {
2096 	gw_display_struct *display = GW_DISPLAY(client_data);
2097 	gwx_button_struct *btn = GWX_BUTTON(object);
2098 	gwx_dialog_struct *md;
2099 	if((display == NULL) || (btn == NULL))
2100 	    return;
2101 
2102 	/* Is this our message dialog's ok button? */
2103 	md = &display->mesg_dialog;
2104 	if(&md->ok_btn == btn)
2105 	    GWXWidgetUnmap(display, GWX_WIDGET(md));
2106 }
2107 
2108 /*
2109  *	Sets the dialog messages, parsinging it into seperate lines
2110  *	and updates the longest line value and resizes the dialog.
2111  */
GWXDialogSetMesg(gw_display_struct * display,gwx_dialog_struct * md,const char * title,const char * mesg,const char * details)2112 void GWXDialogSetMesg(
2113 	gw_display_struct *display, gwx_dialog_struct *md,
2114 	const char *title,
2115 	const char *mesg,
2116 	const char *details
2117 )
2118 {
2119 	int i;
2120 	Display *dpy = (display != NULL) ? display->display : NULL;
2121 	Window w;
2122 	XFontStruct *font;
2123 	if((dpy == NULL) || (md == NULL))
2124 	    return;
2125 
2126 	/* Delete old message and reset message values */
2127 	for(i = 0; i < md->strc; i++)
2128 	    free(md->strv[i]);
2129 	free(md->strv);
2130 	md->strv = NULL;
2131 	md->strc = 0;
2132 	md->longest_line = 0;
2133 	md->longest_line_pixels = 0;
2134 	md->line_height_pixels = 0;
2135 	md->lines_height_pixels = 0;
2136 
2137 	w = md->toplevel;
2138 	if(w == None)
2139 	    return;
2140 
2141 	/* Set new title? */
2142 	if(title != NULL)
2143 	    XStoreName(dpy, w, title);
2144 
2145 	/* Get pointer to message dialog's font structure */
2146 	font = md->font;
2147 
2148 	/* Parse message and store each line, also updating the longest
2149 	 * line.
2150 	 */
2151 	if(mesg != NULL)
2152 	{
2153 	    int i, len;
2154 	    int len_pixels;
2155 	    const char *s = mesg, *sdelim;
2156 
2157 	    while(s != NULL)
2158 	    {
2159 		/* Seek to next newlinedeliminator (if any) */
2160 		sdelim = strchr(s, '\n');
2161 		if(sdelim == NULL)
2162 		    sdelim = strchr(s, '\r');
2163 
2164 		/* Allocate a new line */
2165 		i = MAX(md->strc, 0);
2166 		md->strc = i + 1;
2167 		md->strv = (char **)realloc(
2168 		    md->strv, md->strc * sizeof(char *)
2169 		);
2170 		if(md->strv == NULL)
2171 		{
2172 		    md->strc = 0;
2173 		    break;
2174 		}
2175 
2176 		/* No deliminter in this line? */
2177 		if(sdelim == NULL)
2178 		{
2179 		    /* This is the last line */
2180 		    len = STRLEN(s);
2181 		    md->strv[i] = STRDUP(s);
2182 
2183 		    len_pixels = GWXGetFontStringLength(font, s);
2184 		}
2185 		else
2186 		{
2187 		    /* Got new line deliminator, so copy this line segment */
2188 		    char *s2;
2189 
2190 		    len = sdelim - s;
2191 		    md->strv[i] = s2 = (char *)malloc(
2192 			(len + 1) * sizeof(char)
2193 		    );
2194 		    if(len > 0)
2195 			strncpy(s2, s, len);
2196 		    s2[len] = '\0';
2197 
2198 		    len_pixels = GWXGetFontStringLength(font, s2);
2199 		}
2200 		/* Now len and len_pixels should be set properly */
2201 
2202 		/* If this line is longer than the longest */
2203 		if(len > md->longest_line)
2204 		    md->longest_line = len;
2205 		if(len_pixels > md->longest_line_pixels)
2206 		    md->longest_line_pixels = len_pixels;
2207 
2208 		/* Seek to next line if sdelim is not NULL */
2209 		s = (sdelim != NULL) ? (sdelim + 1) : NULL;
2210 	    }
2211 	}
2212 
2213 	/* Update message line heights */
2214 	if(font != NULL)
2215 	{
2216 	    md->line_height_pixels = font->max_bounds.ascent +
2217 		font->max_bounds.descent;
2218 	    md->lines_height_pixels = md->line_height_pixels * md->strc;
2219 	}
2220 
2221 	/* Update dialog's size due to change in message */
2222 	GWXDialogUpdateSize(display, md);
2223 }
2224 
2225 /*
2226  *	Maps the dialog, the dialog will be resized and drawn.
2227  */
GWXDialogMap(gw_display_struct * display,gwx_dialog_struct * md)2228 void GWXDialogMap(gw_display_struct *display, gwx_dialog_struct *md)
2229 {
2230 	Display *dpy = (display != NULL) ? display->display : NULL;
2231 	Window w;
2232 	int x, y, width, height;
2233 	if((dpy == NULL) || (md == NULL))
2234 	    return;
2235 
2236 	w = md->toplevel;
2237 
2238 	GWContextGet(
2239 	    display, GWContextCurrent(display),
2240 	    NULL, NULL,
2241 	    &x, &y,
2242 	    &width, &height
2243 	);
2244 
2245 	/* Move dialog to center over toplevel window */
2246 	if(w != None)
2247 	{
2248 	    int cx = (int)(
2249 		x + (width / 2) - ((int)md->width / 2)
2250 	    );
2251 	    int cy = (int)(
2252 		y + (height / 2) - ((int)md->height / 2)
2253 	    );
2254 
2255 	    if((cx + (int)md->width) > (int)display->root_width)
2256 		cx = (int)display->root_width - (int)md->width;
2257 	    if((cy + (int)md->height) > (int)display->root_height)
2258 		cy = (int)display->root_height - (int)md->height;
2259 
2260 	    if(cx < 0)
2261 		cx = 0;
2262 	    if(cy < 0)
2263 		cy = 0;
2264 
2265 	    XMoveWindow(dpy, w, cx, cy);
2266 	}
2267 
2268 	/* Map dialog by calling the drawing function, it will map
2269 	 * it and redraw it.
2270 	 */
2271 	GWXDialogDraw(display, md);
2272 
2273 	/* Map buttons and subwindows */
2274 	switch(md->type)
2275 	{
2276 	  case GWX_DIALOG_TYPE_CONF_CANCEL:
2277 	    GWXButtonDraw(display, &md->cancel_btn);
2278 	  case GWX_DIALOG_TYPE_CONF:
2279 	    GWXButtonDraw(display, &md->no_btn);
2280 	    GWXButtonDraw(display, &md->yes_btn);
2281 	    break;
2282 
2283 	  case GWX_DIALOG_TYPE_MESG:
2284 	    GWXButtonDraw(display, &md->ok_btn);
2285 	    break;
2286 	}
2287 }
2288 
2289 /*
2290  *	Blocks client program execution until confirmation is
2291  *	recieved.
2292  *
2293  *	Calling function is responsible for checking reentry to this
2294  *	function.
2295  *
2296  *	Confirmation dialog is already assumed to have been set
2297  *	up and mapped prior to this call.
2298  *
2299  *	The confermation dialog will not be unmapped by this call,
2300  *	it is up the calling function to do that.
2301  */
GWXDoBlockUntilConf(gw_display_struct * display)2302 int GWXDoBlockUntilConf(gw_display_struct *display)
2303 {
2304 	if(display == NULL)
2305 	    return(GWConfirmationNo);
2306 
2307 
2308 	/* Reset local global confirmation code */
2309 	last_conf_dialog_code = GWConfirmationNotAvailable;
2310 
2311 	/* Keep managing here until confirmation dialog code
2312 	 * has been set or display has been closed.
2313 	 */
2314 	while((last_conf_dialog_code == GWConfirmationNotAvailable) &&
2315 	      (display->display != NULL)
2316 	)
2317 	{
2318 	    GWManage(display);
2319 	    usleep(1000);
2320 	}
2321 
2322 	return(last_conf_dialog_code);
2323 }
2324 
2325 
2326 
2327 
2328 
2329 
2330 
2331 #endif	/* Not __MSW__ */
2332