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