1 /*
2  * Author:      William Chia-Wei Cheng (bill.cheng@acm.org)
3  *
4  * Copyright (C) 2001-2009, William Chia-Wei Cheng.
5  *
6  * This file may be distributed under the terms of the Q Public License
7  * as defined by Trolltech AS of Norway and appearing in the file
8  * LICENSE.QPL included in the packaging of this file.
9  *
10  * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING
11  * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
12  * PURPOSE.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
13  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
14  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
16  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  *
18  * @(#)$Header: /mm2/home/cvs/bc-src/tgif/dialog.c,v 1.10 2011/05/16 16:21:57 william Exp $
19  */
20 
21 #define _INCLUDE_FROM_DIALOG_C_
22 
23 #include "tgifdefs.h"
24 
25 #include "auxtext.e"
26 #include "box.e"
27 #include "button.e"
28 #include "cutpaste.e"
29 #include "cursor.e"
30 #include "dialog.e"
31 #include "drawing.e"
32 #include "file.e"
33 #include "font.e"
34 #include "grid.e"
35 #include "mainloop.e"
36 #include "mainmenu.e"
37 #include "menu.e"
38 #include "msg.e"
39 #include "raster.e"
40 #include "rect.e"
41 #include "ruler.e"
42 #include "setup.e"
43 #include "strtbl.e"
44 #include "text.e"
45 #include "util.e"
46 
47 int	doPassword=FALSE;
48 char	gszMsgBox[2048];
49 
50 int	dialogboxUse3DBorder=TRUE;
51 
CornerLoop(OrigX,OrigY)52 unsigned int CornerLoop(OrigX, OrigY)
53    int *OrigX, *OrigY;
54 {
55    XEvent input;
56 
57    XGrabPointer(mainDisplay, rootWindow, False, ButtonPressMask,
58          GrabModeAsync, GrabModeAsync, None, cornerCursor, CurrentTime);
59 
60    for (;;) {
61       XNextEvent(mainDisplay, &input);
62 
63       if (input.type == Expose || input.type == VisibilityNotify) {
64          ExposeEventHandler(&input, TRUE);
65       } else if (input.type == ButtonPress) {
66          XUngrabPointer(mainDisplay, CurrentTime);
67          XSync(mainDisplay, False);
68          *OrigX = input.xbutton.x;
69          *OrigY = input.xbutton.y;
70          return input.xbutton.button;
71       }
72    }
73 }
74 
75 static XComposeStatus c_stat;
76 
DrawWindowLoop(OrigX,OrigY,cursor,snap_to_grid)77 unsigned int DrawWindowLoop(OrigX, OrigY, cursor, snap_to_grid)
78    int *OrigX, *OrigY, snap_to_grid;
79    Cursor cursor;
80 {
81    Window focus_win=None;
82    int revert_to=0;
83 
84    XGetInputFocus(mainDisplay, &focus_win, &revert_to);
85    XGrabPointer(mainDisplay, drawWindow, False,
86          PointerMotionMask | ButtonPressMask,
87          GrabModeAsync, GrabModeAsync, None, cursor, CurrentTime);
88 
89    for (;;) {
90       XEvent input;
91 
92       XNextEvent(mainDisplay, &input);
93 
94       if (input.type == Expose || input.type == VisibilityNotify) {
95          ExposeEventHandler(&input, TRUE);
96       } else if (input.type == ButtonPress) {
97          XUngrabPointer(mainDisplay, CurrentTime);
98          if (focus_win != mainWindow) {
99             XSetInputFocus(mainDisplay, mainWindow, RevertToPointerRoot,
100                   CurrentTime);
101          }
102          XSync(mainDisplay, False);
103          *OrigX = input.xbutton.x;
104          *OrigY = input.xbutton.y;
105          return input.xbutton.button;
106       } else if (input.type == KeyPress) {
107          if (KeyPressEventIsEscape(&input.xkey)) {
108             XUngrabPointer(mainDisplay, CurrentTime);
109             if (focus_win != mainWindow) {
110                XSetInputFocus(mainDisplay, mainWindow, RevertToPointerRoot,
111                      CurrentTime);
112             }
113             XSync(mainDisplay, False);
114             return (unsigned int)(-1);
115          }
116       } else if (input.type == MotionNotify) {
117          if (snap_to_grid) {
118             int grid_x, grid_y;
119 
120             GridXY(input.xmotion.x, input.xmotion.y, &grid_x, &grid_y);
121             MarkRulers(grid_x, grid_y);
122          } else {
123             MarkRulers(input.xmotion.x, input.xmotion.y);
124          }
125       }
126    }
127 }
128 
PickAPoint(OrigX,OrigY,cursor)129 unsigned int PickAPoint(OrigX, OrigY, cursor)
130    int *OrigX, *OrigY;
131    Cursor cursor;
132 {
133    XEvent input;
134 
135 #ifdef _TGIF_DBG
136    if (!debugNoPointerGrab) {
137 #endif /* _TGIF_DBG */
138       XGrabPointer(mainDisplay, drawWindow, False, ButtonPressMask,
139             GrabModeAsync, GrabModeAsync, None, cursor, CurrentTime);
140 #ifdef _TGIF_DBG
141    }
142 #endif /* _TGIF_DBG */
143    for (;;) {
144       XNextEvent(mainDisplay, &input);
145 
146       if (input.type == Expose || input.type == VisibilityNotify) {
147          ExposeEventHandler(&input, TRUE);
148       } else if (input.type == ButtonPress) {
149          XUngrabPointer(mainDisplay, CurrentTime);
150          XSync(mainDisplay, False);
151          *OrigX = input.xbutton.x;
152          *OrigY = input.xbutton.y;
153          return input.xbutton.button;
154       } else if (input.type == KeyPress) {
155          if (KeyPressEventIsEscape(&input.xkey)) {
156             XUngrabPointer(mainDisplay, CurrentTime);
157             XSync(mainDisplay, False);
158             return (unsigned int)(-1);
159          }
160       }
161    }
162 }
163 
164 #include "xbm/info.xbm"
165 
166 #define ICON_W (info_width)
167 #define ICON_H (info_height)
168 
169 #define X_MARGIN 20
170 #define Y_MARGIN 16
171 #define X_GAP 20
172 #define Y_GAP 20
173 
174 #define SPACING 0
175 
176 #define BTN_X_MARGIN 8
177 #define BTN_Y_MARGIN 2
178 #define BTN_XY_EXTRA 2
179 #define BTN_MIN_X_GAP 8
180 
181 #define MAX_KEYSYMS 10
182 
183 #define LF_BUTTON  0x01
184 #define MD_BUTTON  0x02
185 #define RT_BUTTON  0x03
186 #define XT_BUTTON  0x04
187 
188 #define DEF_BUTTON 0x10
189 
190 #define MAX_BUTTONS 3
191 #define MAX_BTN_STR_LEN 10
192 
193 typedef struct BtnInfoRec {
194    char		* str;
195    struct BBRec	bbox;
196    int		id, highlight;
197    KeySym	key_sym[MAX_KEYSYMS];
198 } * BtnInfoRecPtr;
199 
200 typedef struct MBRec {
201    Window main_win, root_win, icon_win, msg_win, btn_win;
202 
203    int main_win_x, main_win_y, main_win_w, main_win_h;
204    int icon_win_w, icon_win_h, msg_win_w, msg_win_h;
205    int btn_win_w, btn_win_h, max_msg_win_w;
206    int max_msg_str_len, max_msg_str_total;
207    int exposed;
208 
209    char * msg_copy;
210 
211    Pixmap cur_bitmap;
212 
213    struct BtnInfoRec btn_info[MAX_BUTTONS+1];
214 
215    /* dialog specific */
216    int is_dialog;
217    int cur_x, cur_y, cursor_x, cursor_y, index, str_w;
218    char *return_str;
219 } * MBRecPtr;
220 
221 static struct MBRec	mbInfo;
222 
223 static int	numButtons=MAX_BUTTONS;
224 static char	extraBtnChar='q';
225 
226 static
SetupMBButton(MBInfoPtr,BtnDesc,BtnCh,BtnID)227 void SetupMBButton(MBInfoPtr, BtnDesc, BtnCh, BtnID)
228    struct MBRec *MBInfoPtr;
229    int BtnDesc, BtnID;
230    char BtnCh;
231 {
232    char *psz=NULL;
233    int btn_index=(BtnDesc & 0x0f)-1, i=0;
234 
235    switch (BtnID) {
236    case MB_ID_FAILED: psz = NULL; break;
237    case MB_ID_OK: psz = TgLoadCachedString(CSTID_OK); break;
238    case MB_ID_CANCEL: psz = TgLoadCachedString(CSTID_CANCEL); break;
239    case MB_ID_YES: psz = TgLoadCachedString(CSTID_YES); break;
240    case MB_ID_NO: psz = TgLoadCachedString(CSTID_NO); break;
241    case MB_ID_EXTRA: psz = TgLoadCachedString(CSTID_EXTRA); break;
242    }
243    MBInfoPtr->btn_info[btn_index].str = psz;
244 
245    MBInfoPtr->btn_info[btn_index].id = BtnID;
246    switch (BtnCh) {
247    case 'o':
248       MBInfoPtr->btn_info[btn_index].key_sym[i++] = XK_o;
249       MBInfoPtr->btn_info[btn_index].key_sym[i++] = XK_O;
250       break;
251    case 'y':
252       MBInfoPtr->btn_info[btn_index].key_sym[i++] = XK_y;
253       MBInfoPtr->btn_info[btn_index].key_sym[i++] = XK_Y;
254       break;
255    case 'n':
256       MBInfoPtr->btn_info[btn_index].key_sym[i++] = XK_n;
257       MBInfoPtr->btn_info[btn_index].key_sym[i++] = XK_N;
258       break;
259    case 'c':
260       MBInfoPtr->btn_info[btn_index].key_sym[i++] = XK_c;
261       MBInfoPtr->btn_info[btn_index].key_sym[i++] = XK_C;
262       break;
263    }
264    if (BtnDesc & DEF_BUTTON) {
265       MBInfoPtr->btn_info[btn_index].key_sym[i++] = XK_Return;
266       MBInfoPtr->btn_info[btn_index].key_sym[i++] = XK_Linefeed;
267       MBInfoPtr->btn_info[btn_index].highlight = TRUE;
268    } else {
269       MBInfoPtr->btn_info[btn_index].highlight = FALSE;
270    }
271    MBInfoPtr->btn_info[btn_index].key_sym[i] = (KeySym)0;
272 }
273 
CalcFormatStringInBox(buf,xfs,font_height,format_box_w,pn_num_lines,pn_max_w,pn_max_h,ppsz_formated_buf)274 void CalcFormatStringInBox(buf, xfs, font_height, format_box_w, pn_num_lines,
275       pn_max_w, pn_max_h, ppsz_formated_buf)
276    char *buf, **ppsz_formated_buf;
277    XFontStruct *xfs;
278    int font_height, format_box_w, *pn_num_lines, *pn_max_w, *pn_max_h;
279 {
280    char *dest_ptr=NULL, *c_ptr=NULL, *msg_copy=NULL;
281    int len=strlen(buf), max_len=0, max_w=0, max_h=0, total=0;
282    int num_lines=1, spacing=SPACING, sz=((((len+10)<<1)+1)*sizeof(char));
283 
284    total = BoldMsgTextWidth(xfs, buf, len);
285 
286    msg_copy = (char*)malloc(sz);
287    if (msg_copy == NULL) FailAllocMessage();
288    memset(msg_copy, 0, sz);
289 
290    dest_ptr = msg_copy;
291    *dest_ptr = '\0';
292    c_ptr = buf;
293    while (c_ptr != NULL) {
294       /* a line at a time */
295       char *lf_ptr=BoldMsgStrChr(c_ptr, '\n');
296       int full_str_len, full_str_total;
297 
298       if (lf_ptr != NULL) *lf_ptr = '\0';
299       full_str_len = strlen(c_ptr);
300       full_str_total = BoldMsgTextWidth(xfs, c_ptr, full_str_len);
301       if (full_str_total > max_w) {
302          if (full_str_total > format_box_w) {
303             /* line too long for the message box */
304             char *line=c_ptr;
305 
306             max_w = format_box_w;
307             while (line != NULL && *line != '\0') {
308                int line_len, line_total;
309 
310                while (*line == ' ') line++;
311                line_len = strlen(line);
312                line_total = BoldMsgTextWidth(xfs, line, line_len);
313                if (line_total > format_box_w) {
314                   char *lead_ptr=line, *last_ptr=NULL, saved_last_ch='\0';
315                   int lead_index=0, last_index=0, still_going=TRUE;
316 
317                   while (still_going && *lead_ptr != '\0') {
318                      char saved_ch='\0';
319                      int w=0;
320 
321                      while (*lead_ptr != ' ' && *lead_ptr != '\0') {
322                         if (BoldMsgCharBytes(lead_ptr) == 2) {
323                            /* for double-byte chars, one can break anywhere */
324                            break;
325                         }
326                         lead_ptr++;
327                         lead_index++;
328                      }
329                      saved_ch = (*lead_ptr);
330                      *lead_ptr = '\0';
331                      w = BoldMsgTextWidth(xfs, line, lead_index);
332                      if (w > format_box_w) {
333                         if (last_ptr == NULL) {
334                            /* very long word */
335                            sprintf(dest_ptr, "%s\n", line);
336                            dest_ptr = &dest_ptr[strlen(dest_ptr)];
337                            max_h += font_height+spacing;
338                            num_lines++;
339                            line = &line[lead_index];
340                         } else {
341                            /* find a good space */
342                            saved_last_ch = (*last_ptr);
343                            *last_ptr = '\0';
344                            sprintf(dest_ptr, "%s\n", line);
345                            *last_ptr = saved_last_ch;
346                            dest_ptr = &dest_ptr[strlen(dest_ptr)];
347                            max_h += font_height+spacing;
348                            num_lines++;
349                            line = BoldMsgNextChar(&line[last_index]);
350                         }
351                         still_going = FALSE;
352                      } else {
353                         last_ptr = lead_ptr;
354                         last_index = lead_index;
355                      }
356                      *lead_ptr++ = saved_ch;
357                      lead_index++;
358                   }
359                   if (still_going && *lead_ptr == '\0') {
360                      if (last_ptr == NULL) {
361                         /* very long word */
362                         sprintf(dest_ptr, "%s\n", line);
363                         dest_ptr = &dest_ptr[strlen(dest_ptr)];
364                         max_h += font_height+spacing;
365                         num_lines++;
366                         line = &line[lead_index];
367                      } else {
368                         /* find a good space */
369                         saved_last_ch = (*last_ptr);
370                         *last_ptr = '\0';
371                         sprintf(dest_ptr, "%s\n", line);
372                         *last_ptr = saved_last_ch;
373                         dest_ptr = &dest_ptr[strlen(dest_ptr)];
374                         max_h += font_height+spacing;
375                         num_lines++;
376                         line = BoldMsgNextChar(&line[last_index]);
377                      }
378                   }
379                } else if (line_len > 0) {
380                   sprintf(dest_ptr, "%s\n", line);
381                   dest_ptr = &dest_ptr[strlen(dest_ptr)];
382                   max_h += font_height+spacing;
383                   break;
384                }
385             }
386          } else {
387             max_len = full_str_len;
388             max_w = full_str_total;
389             sprintf(dest_ptr, "%s\n", c_ptr);
390             dest_ptr = &dest_ptr[strlen(dest_ptr)];
391             max_h += font_height+spacing;
392             if (lf_ptr != NULL) num_lines++;
393          }
394       } else {
395          sprintf(dest_ptr, "%s\n", c_ptr);
396          dest_ptr = &dest_ptr[strlen(dest_ptr)];
397          max_h += font_height+spacing;
398          if (lf_ptr != NULL) num_lines++;
399       }
400       max_h -= spacing;
401       if (lf_ptr != NULL) {
402          *lf_ptr = '\n';
403          c_ptr = &lf_ptr[1];
404       } else {
405          break;
406       }
407    }
408    if (pn_num_lines != NULL) *pn_num_lines = num_lines;
409    if (pn_max_w != NULL) *pn_max_w = max_w;
410    if (pn_max_h != NULL) *pn_max_h = max_h;
411    if (ppsz_formated_buf == NULL) {
412       free(msg_copy);
413    } else {
414       *ppsz_formated_buf = msg_copy;
415    }
416 }
417 
418 static
CalcSimpleGeometry(MBInfoPtr,Message)419 void CalcSimpleGeometry(MBInfoPtr, Message)
420    struct MBRec *MBInfoPtr;
421    char *Message;
422 {
423    int i=0, max_h=0, left=0, inc=0, a_btn_w=0, a_btn_h=0, y=0, max_w=0;;
424 
425    CalcFormatStringInBox(Message, defaultFontPtr, defaultFontHeight,
426          MBInfoPtr->max_msg_str_total, NULL, &max_w, &max_h,
427          &MBInfoPtr->msg_copy);
428 
429    if (MBInfoPtr->is_dialog) {
430       MBInfoPtr->msg_win_w = MBInfoPtr->max_msg_str_total;
431    } else {
432       MBInfoPtr->msg_win_w = max_w;
433    }
434    MBInfoPtr->msg_win_h = max_h;
435    MBInfoPtr->icon_win_w = ICON_W;
436    MBInfoPtr->icon_win_h = ICON_H;
437    if (info_bits == NULL) { }
438    if (MBInfoPtr->msg_win_h > MBInfoPtr->icon_win_h) {
439       MBInfoPtr->icon_win_h = MBInfoPtr->msg_win_h;
440    } else {
441       MBInfoPtr->msg_win_h = MBInfoPtr->icon_win_h;
442    }
443    a_btn_w = MAX_BTN_STR_LEN*defaultFontWidth + (BTN_XY_EXTRA<<1);
444    if (MBInfoPtr->is_dialog) {
445       if (msgFontSet == NULL && msgFontPtr == NULL) {
446          a_btn_h = defaultFontHeight + (BTN_Y_MARGIN<<1) + (BTN_XY_EXTRA<<1);
447       } else {
448          a_btn_h = msgFontHeight + (BTN_Y_MARGIN<<1) + (BTN_XY_EXTRA<<1);
449       }
450    } else {
451       if (boldMsgFontSet == NULL && boldMsgFontPtr == NULL) {
452          a_btn_h = defaultFontHeight + (BTN_Y_MARGIN<<1) + (BTN_XY_EXTRA<<1);
453       } else {
454          a_btn_h = boldMsgFontHeight + (BTN_Y_MARGIN<<1) + (BTN_XY_EXTRA<<1);
455       }
456    }
457 
458    MBInfoPtr->btn_win_w = numButtons*a_btn_w+BTN_MIN_X_GAP*(numButtons-1)+2;
459    MBInfoPtr->btn_win_h = a_btn_h+2+(windowPadding<<2);
460 
461    if (MBInfoPtr->btn_win_w >
462          MBInfoPtr->msg_win_w+MBInfoPtr->icon_win_w+X_GAP) {
463       MBInfoPtr->msg_win_w =
464             MBInfoPtr->btn_win_w-MBInfoPtr->icon_win_w-X_GAP;
465    } else {
466       MBInfoPtr->btn_win_w =
467             MBInfoPtr->msg_win_w+MBInfoPtr->icon_win_w+X_GAP;
468    }
469    MBInfoPtr->main_win_w = MBInfoPtr->btn_win_w + (X_MARGIN<<1) +
470          (brdrW<<1);
471    MBInfoPtr->main_win_h = MBInfoPtr->icon_win_h + MBInfoPtr->btn_win_h +
472          (Y_MARGIN<<1) + Y_GAP + (brdrW<<1);
473    left = ((MBInfoPtr->btn_win_w - numButtons*a_btn_w -
474          BTN_MIN_X_GAP*(numButtons-1))>>1);
475    inc = a_btn_w + ((MBInfoPtr->btn_win_w-(left<<1)-numButtons*a_btn_w) /
476          (numButtons-1));
477    y = ((MBInfoPtr->btn_win_h - ((BTN_Y_MARGIN<<1) +
478          ((boldMsgFontSet==NULL && boldMsgFontPtr==NULL) ? defaultFontHeight :
479          boldMsgFontHeight))) >> 1);
480    for (i=0; i < numButtons; i++) {
481       MBInfoPtr->btn_info[i].bbox.ltx = left+BTN_XY_EXTRA;
482       MBInfoPtr->btn_info[i].bbox.lty = y;
483       MBInfoPtr->btn_info[i].bbox.rbx = left +
484             MAX_BTN_STR_LEN*defaultFontWidth + BTN_XY_EXTRA;
485       MBInfoPtr->btn_info[i].bbox.rby = y + (BTN_Y_MARGIN<<1) +
486             ((boldMsgFontSet==NULL && boldMsgFontPtr==NULL) ?
487             defaultFontHeight : boldMsgFontHeight);
488       left += inc;
489    }
490    MBInfoPtr->main_win_x = ((DisplayWidth(mainDisplay, mainScreen) -
491          MBInfoPtr->main_win_w)>>1);
492    MBInfoPtr->main_win_y = ((DisplayHeight(mainDisplay, mainScreen) -
493          MBInfoPtr->main_win_h)/3);
494    if (MBInfoPtr->main_win_x < 0) MBInfoPtr->main_win_x = 0;
495    if (MBInfoPtr->main_win_y < 0) MBInfoPtr->main_win_y = 0;
496 }
497 
498 static
CalcGeometry(MBInfoPtr,Message)499 void CalcGeometry(MBInfoPtr, Message)
500    struct MBRec *MBInfoPtr;
501    char *Message;
502 {
503    int i=0, max_h=0, left=0, inc=0, a_btn_w=0, a_btn_h=0;
504    int font_height=boldMsgFontHeight, y=0, max_w=0;
505 
506    CalcFormatStringInBox(Message, boldMsgFontPtr, boldMsgFontHeight,
507          MBInfoPtr->max_msg_str_total, NULL, &max_w, &max_h,
508          &MBInfoPtr->msg_copy);
509 
510    if (MBInfoPtr->is_dialog) {
511       MBInfoPtr->msg_win_w = MBInfoPtr->max_msg_str_total;
512    } else {
513       MBInfoPtr->msg_win_w = max_w;
514    }
515    MBInfoPtr->msg_win_h = max_h;
516    MBInfoPtr->icon_win_w = ICON_W;
517    MBInfoPtr->icon_win_h = ICON_H;
518    if (MBInfoPtr->msg_win_h > MBInfoPtr->icon_win_h) {
519       MBInfoPtr->icon_win_h = MBInfoPtr->msg_win_h;
520    } else {
521       MBInfoPtr->msg_win_h = MBInfoPtr->icon_win_h;
522    }
523    /* do not translate -- the string is used to measure things */
524    a_btn_w = BoldMsgTextWidth(boldMsgFontPtr, "  CANCEL  ", 10) +
525          (BTN_XY_EXTRA<<1);
526    if (MBInfoPtr->is_dialog) {
527       a_btn_h = (BTN_Y_MARGIN<<1) + (BTN_XY_EXTRA<<1) +
528             ((msgFontSet==NULL && msgFontPtr==NULL) ? defaultFontHeight :
529             msgFontHeight);
530    } else {
531       a_btn_h = (BTN_Y_MARGIN<<1) + (BTN_XY_EXTRA<<1) +
532             ((boldMsgFontSet==NULL && boldMsgFontPtr==NULL) ?
533             defaultFontHeight : boldMsgFontHeight);
534    }
535    MBInfoPtr->btn_win_w = numButtons*a_btn_w+BTN_MIN_X_GAP*(numButtons-1)+2;
536    MBInfoPtr->btn_win_h = a_btn_h+2+(windowPadding<<1);
537 
538    if (MBInfoPtr->btn_win_w >
539          MBInfoPtr->msg_win_w+MBInfoPtr->icon_win_w+X_GAP) {
540       MBInfoPtr->msg_win_w =
541             MBInfoPtr->btn_win_w-MBInfoPtr->icon_win_w-X_GAP;
542    } else {
543       MBInfoPtr->btn_win_w =
544             MBInfoPtr->msg_win_w+MBInfoPtr->icon_win_w+X_GAP;
545    }
546    MBInfoPtr->main_win_w = MBInfoPtr->btn_win_w + (X_MARGIN<<1) +
547          (brdrW<<1);
548    MBInfoPtr->main_win_h = MBInfoPtr->icon_win_h + MBInfoPtr->btn_win_h +
549          (Y_MARGIN<<1) + Y_GAP + (brdrW<<1);
550    left = ((MBInfoPtr->btn_win_w - numButtons*a_btn_w -
551          BTN_MIN_X_GAP*(numButtons-1))>>1);
552    inc = a_btn_w + ((MBInfoPtr->btn_win_w-(left<<1)-numButtons*a_btn_w) /
553          (numButtons-1));
554    y = ((MBInfoPtr->btn_win_h - ((BTN_Y_MARGIN<<1) + font_height)) >> 1);
555    for (i=0; i < numButtons; i++) {
556       MBInfoPtr->btn_info[i].bbox.ltx = left+BTN_XY_EXTRA;
557       MBInfoPtr->btn_info[i].bbox.lty = y;
558       MBInfoPtr->btn_info[i].bbox.rbx = left +
559             (a_btn_w-(BTN_XY_EXTRA<<1)) + BTN_XY_EXTRA;
560       MBInfoPtr->btn_info[i].bbox.rby = y + font_height + (BTN_Y_MARGIN<<1);
561       left += inc;
562    }
563    MBInfoPtr->main_win_x = ((DisplayWidth(mainDisplay, mainScreen) -
564          MBInfoPtr->main_win_w)>>1);
565    MBInfoPtr->main_win_y = ((DisplayHeight(mainDisplay, mainScreen) -
566          MBInfoPtr->main_win_h)/3);
567    if (MBInfoPtr->main_win_x < 0) MBInfoPtr->main_win_x = 0;
568    if (MBInfoPtr->main_win_y < 0) MBInfoPtr->main_win_y = 0;
569 }
570 
571 static
SetupMBWindow(MBInfoPtr,Message,Title,IconAndBtns,IsDialog)572 int SetupMBWindow(MBInfoPtr, Message, Title, IconAndBtns, IsDialog)
573    struct MBRec *MBInfoPtr;
574    char *Message, *Title;
575    int IconAndBtns, IsDialog;
576 {
577    int bg_pixel=(threeDLook ? myLtGryPixel : myBgPixel);
578    XWMHints wmhints;
579    XSizeHints sizehints;
580    XSetWindowAttributes win_attrs;
581 
582    memset(MBInfoPtr, 0, sizeof(struct MBRec));
583    MBInfoPtr->is_dialog = IsDialog;
584    MBInfoPtr->msg_copy = NULL;
585    MBInfoPtr->max_msg_win_w = (DisplayWidth(mainDisplay,mainScreen)>>1);
586    MBInfoPtr->max_msg_str_len = MBInfoPtr->max_msg_win_w / defaultFontWidth;
587    MBInfoPtr->max_msg_str_total = MBInfoPtr->max_msg_win_w;
588 
589    numButtons = MAX_BUTTONS;
590    if (IconAndBtns & MB_BTN_EXTRA) numButtons++;
591    if (boldMsgFontSet == NULL && boldMsgFontPtr == NULL) {
592       CalcSimpleGeometry(MBInfoPtr, Message);
593    } else {
594       CalcGeometry(MBInfoPtr, Message);
595    }
596    switch (IconAndBtns & MB_BTNMASK) {
597    case MB_BTN_NONE:
598       break;
599    case MB_BTN_OK:
600       SetupMBButton(MBInfoPtr, LF_BUTTON, '\0', MB_ID_FAILED);
601       SetupMBButton(MBInfoPtr, MD_BUTTON | DEF_BUTTON, 'o', MB_ID_OK);
602       SetupMBButton(MBInfoPtr, RT_BUTTON, '\0', MB_ID_FAILED);
603       break;
604    case MB_BTN_YESNOCANCEL:
605       SetupMBButton(MBInfoPtr, LF_BUTTON | DEF_BUTTON, 'y', MB_ID_YES);
606       SetupMBButton(MBInfoPtr, MD_BUTTON, 'n', MB_ID_NO);
607       SetupMBButton(MBInfoPtr, RT_BUTTON, 'c', MB_ID_CANCEL);
608       break;
609    case MB_BTN_OKCANCEL:
610       SetupMBButton(MBInfoPtr, LF_BUTTON | DEF_BUTTON, 'o', MB_ID_OK);
611       SetupMBButton(MBInfoPtr, MD_BUTTON, '\0', MB_ID_FAILED);
612       SetupMBButton(MBInfoPtr, RT_BUTTON, 'c', MB_ID_CANCEL);
613       break;
614    case MB_BTN_YESNO:
615       SetupMBButton(MBInfoPtr, LF_BUTTON | DEF_BUTTON, 'y', MB_ID_YES);
616       SetupMBButton(MBInfoPtr, MD_BUTTON, '\0', MB_ID_FAILED);
617       SetupMBButton(MBInfoPtr, RT_BUTTON, 'n', MB_ID_NO);
618       break;
619    default:
620       SetupMBButton(MBInfoPtr, LF_BUTTON, '\0', MB_ID_FAILED);
621       SetupMBButton(MBInfoPtr, MD_BUTTON, '\0', MB_ID_FAILED);
622       SetupMBButton(MBInfoPtr, RT_BUTTON, '\0', MB_ID_FAILED);
623       break;
624    }
625    if (IconAndBtns & MB_BTN_EXTRA) {
626       if ((IconAndBtns & MB_BTNMASK) != 0) {
627          SetupMBButton(MBInfoPtr, XT_BUTTON, extraBtnChar, MB_ID_EXTRA);
628       } else {
629          SetupMBButton(MBInfoPtr, XT_BUTTON | DEF_BUTTON, extraBtnChar,
630                MB_ID_EXTRA);
631       }
632    } else {
633       SetupMBButton(MBInfoPtr, XT_BUTTON, '\0', MB_ID_FAILED);
634    }
635 
636    switch (IconAndBtns & MB_ICONMASK) {
637    case MB_ICON_STOP:
638       MBInfoPtr->cur_bitmap = msgBoxPixmap[MB_PIXMAP_STOP];
639       break;
640    case MB_ICON_QUESTION:
641       MBInfoPtr->cur_bitmap = msgBoxPixmap[MB_PIXMAP_QUESTION];
642       break;
643    case MB_ICON_INFORMATION:
644       MBInfoPtr->cur_bitmap = msgBoxPixmap[MB_PIXMAP_INFORMATION];
645       break;
646    case MB_ICON_DIALOG:
647       MBInfoPtr->cur_bitmap = msgBoxPixmap[MB_PIXMAP_DIALOG];
648       break;
649    default: MBInfoPtr->cur_bitmap = None; break;
650    }
651 
652    if ((MBInfoPtr->main_win=XCreateSimpleWindow(mainDisplay, rootWindow,
653          MBInfoPtr->main_win_x, MBInfoPtr->main_win_y,
654          MBInfoPtr->main_win_w, MBInfoPtr->main_win_h, brdrW,
655          myBorderPixel, bg_pixel)) == 0) {
656       fprintf(stderr, "%s\n", TgLoadString(STID_FAIL_TO_CREATE_WINDOW));
657       return FALSE;
658    }
659    if ((MBInfoPtr->icon_win=XCreateSimpleWindow(mainDisplay,
660          MBInfoPtr->main_win, X_MARGIN, Y_MARGIN,
661          MBInfoPtr->icon_win_w, MBInfoPtr->icon_win_h, 0,
662          myBorderPixel, bg_pixel)) == 0) {
663       fprintf(stderr, "%s\n", TgLoadString(STID_FAIL_TO_CREATE_WINDOW));
664       return FALSE;
665    }
666    if ((MBInfoPtr->msg_win=XCreateSimpleWindow(mainDisplay,
667          MBInfoPtr->main_win, X_MARGIN+MBInfoPtr->icon_win_w+X_GAP, Y_MARGIN,
668          MBInfoPtr->msg_win_w, MBInfoPtr->msg_win_h, 0,
669          myBorderPixel, bg_pixel)) == 0) {
670       fprintf(stderr, "%s\n", TgLoadString(STID_FAIL_TO_CREATE_WINDOW));
671       return FALSE;
672    }
673    if ((MBInfoPtr->btn_win=XCreateSimpleWindow(mainDisplay,
674          MBInfoPtr->main_win, X_MARGIN, Y_MARGIN+Y_GAP+MBInfoPtr->icon_win_h,
675          MBInfoPtr->btn_win_w, MBInfoPtr->btn_win_h, 0,
676          myBorderPixel, bg_pixel)) == 0) {
677       fprintf(stderr, "%s\n", TgLoadString(STID_FAIL_TO_CREATE_WINDOW));
678       return FALSE;
679    }
680    win_attrs.save_under = True;
681    win_attrs.colormap = mainColormap;
682    XChangeWindowAttributes(mainDisplay, MBInfoPtr->main_win,
683          CWSaveUnder | CWColormap, &win_attrs);
684 
685    wmhints.flags = InputHint | StateHint;
686    wmhints.input = True;
687    wmhints.initial_state = NormalState;
688    XSetWMHints(mainDisplay, MBInfoPtr->main_win, &wmhints);
689    wmhints.flags = InputHint;
690    XSetWMHints(mainDisplay, MBInfoPtr->icon_win, &wmhints);
691    XSetWMHints(mainDisplay, MBInfoPtr->msg_win, &wmhints);
692    XSetWMHints(mainDisplay, MBInfoPtr->btn_win, &wmhints);
693 
694    sizehints.flags = PPosition | PSize | USPosition | PMinSize | PMaxSize;
695    sizehints.x = MBInfoPtr->main_win_x;
696    sizehints.y = MBInfoPtr->main_win_y;
697    sizehints.width = sizehints.max_width = sizehints.min_width =
698          MBInfoPtr->main_win_w;
699    sizehints.height = sizehints.max_height = sizehints.min_height =
700          MBInfoPtr->main_win_h;
701 #ifdef NOTR4MODE
702    XSetNormalHints(mainDisplay, MBInfoPtr->main_win, &sizehints);
703 #else
704    XSetWMNormalHints(mainDisplay, MBInfoPtr->main_win, &sizehints);
705 #endif /* NOTR4MODE */
706    RegisterWM_DELETE_WINDOW(MBInfoPtr->main_win);
707    XStoreName(mainDisplay, MBInfoPtr->main_win, Title);
708    /* so that MessageBox() and Dialog() window stays on top of tgif's window */
709    XSetTransientForHint(mainDisplay, MBInfoPtr->main_win, mainWindow);
710 
711 #ifdef MAPBEFORESELECT
712    XMapWindow(mainDisplay, MBInfoPtr->main_win);
713    XMapWindow(mainDisplay, MBInfoPtr->icon_win);
714    XMapWindow(mainDisplay, MBInfoPtr->msg_win);
715    XMapWindow(mainDisplay, MBInfoPtr->btn_win);
716    XSelectInput(mainDisplay, MBInfoPtr->main_win, ButtonPressMask |
717          KeyPressMask | StructureNotifyMask | VisibilityChangeMask);
718    XSelectInput(mainDisplay, MBInfoPtr->icon_win,
719          ButtonPressMask | KeyPressMask | ExposureMask);
720    XSelectInput(mainDisplay, MBInfoPtr->msg_win,
721          ButtonPressMask | KeyPressMask | ExposureMask);
722    XSelectInput(mainDisplay, MBInfoPtr->btn_win, ButtonReleaseMask |
723          ButtonPressMask | PointerMotionMask | KeyPressMask | ExposureMask);
724 #else /* !MAPBEFORESELECT */
725    XSelectInput(mainDisplay, MBInfoPtr->main_win, ButtonPressMask |
726          KeyPressMask | StructureNotifyMask | VisibilityChangeMask);
727    XSelectInput(mainDisplay, MBInfoPtr->icon_win,
728          ButtonPressMask | KeyPressMask | ExposureMask);
729    XSelectInput(mainDisplay, MBInfoPtr->msg_win,
730          ButtonPressMask | KeyPressMask | ExposureMask);
731    XSelectInput(mainDisplay, MBInfoPtr->btn_win, ButtonReleaseMask |
732          ButtonPressMask | PointerMotionMask | KeyPressMask | ExposureMask);
733    XMapWindow(mainDisplay, MBInfoPtr->main_win);
734    XMapWindow(mainDisplay, MBInfoPtr->icon_win);
735    XMapWindow(mainDisplay, MBInfoPtr->msg_win);
736    XMapWindow(mainDisplay, MBInfoPtr->btn_win);
737 #endif /* !MAPBEFORESELECT */
738    if (warpToWinCenter) {
739       XWarpPointer(mainDisplay, None, MBInfoPtr->main_win, 0, 0, 0, 0,
740             (MBInfoPtr->main_win_w>>1), (MBInfoPtr->main_win_h>>1));
741    }
742    XSync(mainDisplay, False);
743    return TRUE;
744 }
745 
746 static
DisplayInput(MBInfoPtr)747 void DisplayInput(MBInfoPtr)
748    struct MBRec *MBInfoPtr;
749 {
750    Window win=MBInfoPtr->btn_win;
751    char *buf=MBInfoPtr->return_str, *dup_buf=NULL, *msg=NULL;
752    int buf_len;
753 
754    MBInfoPtr->str_w = 0;
755    MBInfoPtr->cur_x = (MBInfoPtr->btn_win_w>>1);
756    if (buf == NULL) return;
757 
758    buf_len = strlen(buf);
759    if (msgFontSet == NULL && msgFontPtr == NULL) {
760       MBInfoPtr->str_w = defaultFontWidth*strlen(buf);
761    } else {
762       MBInfoPtr->str_w = MsgTextWidth(msgFontPtr, buf, buf_len);
763    }
764    MBInfoPtr->cur_x = ((MBInfoPtr->btn_win_w-MBInfoPtr->str_w)>>1);
765    MBInfoPtr->cursor_x = MBInfoPtr->cur_x+MBInfoPtr->str_w+1;
766    if (doPassword) {
767       int i;
768 
769       dup_buf = (char*)malloc((buf_len+1)*sizeof(char));
770       if (dup_buf == NULL) FailAllocMessage();
771       for (i=0; i < buf_len; i++) dup_buf[i] = '*';
772       msg = dup_buf;
773    } else {
774       msg = buf;
775    }
776    if (msgFontPtr != NULL) {
777       XSetFont(mainDisplay, defaultGC, msgFontPtr->fid);
778    }
779    DrawMsgString(mainDisplay, win, defaultGC, MBInfoPtr->cur_x,
780          MBInfoPtr->cur_y, msg, buf_len);
781    if (msgFontSet != NULL || msgFontPtr != NULL) {
782       XSetFont(mainDisplay, defaultGC, defaultFontPtr->fid);
783    }
784    if (dup_buf != NULL) free(dup_buf);
785 }
786 
787 static
HandleMsgBoxKeyEvent(MBInfoPtr,input)788 int HandleMsgBoxKeyEvent(MBInfoPtr, input)
789    struct MBRec *MBInfoPtr;
790    XEvent *input;
791 {
792    XKeyEvent *key_ev=(&(input->xkey));
793    KeySym key_sym;
794    char buf[80];
795    int i, j, has_ch;
796    int bg_pixel=(threeDLook ? myLtGryPixel : myBgPixel);
797 
798    has_ch = XLookupString(key_ev, buf, sizeof(buf), &key_sym, &c_stat);
799    TranslateKeys(buf, &key_sym);
800    if (MBInfoPtr->is_dialog) {
801       /* for Dialog(), return INVALID for <ESC> */
802       /*    return FALSE for a normal character, including <BS> */
803       /*    return TRUE for <CR> or <LF> */
804       if (MBInfoPtr->exposed) {
805          /* erase the old cursor */
806          PutCursor(MBInfoPtr->btn_win, MBInfoPtr->cursor_x, MBInfoPtr->cursor_y,
807                bg_pixel);
808       }
809       if (CharIsESC(key_ev, buf, key_sym, &has_ch)) {
810          if (MBInfoPtr->return_str != NULL) *MBInfoPtr->return_str = '\0';
811          return INVALID;
812       } else if (CharIsCRorLF(key_ev, buf, key_sym, &has_ch)) {
813          if (MBInfoPtr->return_str == NULL) {
814             return INVALID;
815          }
816          return TRUE;
817       } else if (CharIsBSorDEL(key_ev, buf, key_sym, &has_ch, FALSE)) {
818          if (MBInfoPtr->return_str == NULL) {
819             return INVALID;
820          }
821          if (MBInfoPtr->index > 0) {
822             if (MBInfoPtr->exposed) {
823                XClearWindow(mainDisplay, MBInfoPtr->btn_win);
824             }
825             MBInfoPtr->return_str[--MBInfoPtr->index] = '\0';
826             DisplayInput(MBInfoPtr);
827          }
828       } else if ((key_ev->state & ControlMask)==0 &&
829             key_sym>='\040' && key_sym<='\177') {
830          if (MBInfoPtr->return_str == NULL) {
831             return INVALID;
832          }
833          if (buf[0] >= '\040' && MBInfoPtr->index < 80) {
834             if (MBInfoPtr->exposed) {
835                XClearWindow(mainDisplay, MBInfoPtr->btn_win);
836             }
837             MBInfoPtr->return_str[MBInfoPtr->index++] = buf[0];
838             MBInfoPtr->return_str[MBInfoPtr->index] = '\0';
839             DisplayInput(MBInfoPtr);
840          }
841       }
842       if (MBInfoPtr->exposed) {
843          PutCursor(MBInfoPtr->btn_win, MBInfoPtr->cursor_x, MBInfoPtr->cursor_y,
844                myFgPixel);
845       }
846       return FALSE;
847    } else {
848       /* for MsgBox(), return a button id */
849       if (CharIsESC(key_ev, buf, key_sym, &has_ch)) {
850          return (MB_ID_CANCEL);
851       }
852       for (i=0; i < numButtons; i++) {
853          if (MBInfoPtr->btn_info[i].str != NULL) {
854             for (j=0; MBInfoPtr->btn_info[i].key_sym[j] != (KeySym)0; j++) {
855                if (MBInfoPtr->btn_info[i].key_sym[j] == key_sym) {
856                   DisplayButtonInBBox(MBInfoPtr->btn_win,
857                         MBInfoPtr->btn_info[i].str,
858                         strlen(MBInfoPtr->btn_info[i].str),
859                         &MBInfoPtr->btn_info[i].bbox, BUTTON_INVERT,
860                         MBInfoPtr->btn_info[i].highlight, BTN_XY_EXTRA, NULL);
861                   XSync(mainDisplay, False);
862                   return MBInfoPtr->btn_info[i].id;
863                }
864             }
865          }
866       }
867    }
868    return INVALID;
869 }
870 
871 static
HandleDeleteMsgBox(MBInfoPtr)872 int HandleDeleteMsgBox(MBInfoPtr)
873    struct MBRec *MBInfoPtr;
874 {
875    int bg_pixel=(threeDLook ? myLtGryPixel : myBgPixel);
876 
877    if (MBInfoPtr->is_dialog) {
878       /* for Dialog(), same as <ESC> is pressed */
879       if (MBInfoPtr->exposed) {
880          /* erase the old cursor */
881          PutCursor(MBInfoPtr->btn_win, MBInfoPtr->cursor_x, MBInfoPtr->cursor_y,
882                bg_pixel);
883       }
884       if (MBInfoPtr->return_str != NULL) *MBInfoPtr->return_str = '\0';
885       return INVALID;
886    }
887    /* for MsgBox(), return a button id */
888    return MB_ID_CANCEL;
889 }
890 
891 static
HandlePasteInDialog(MBInfoPtr,input)892 void HandlePasteInDialog(MBInfoPtr, input)
893    struct MBRec *MBInfoPtr;
894    XEvent *input;
895 {
896    XButtonEvent *button_ev=(&(input->xbutton));
897    int buf_len=0, from_selection=FALSE;
898    char *cut_buffer=NULL;
899 
900    if (button_ev->button != Button2) return;
901 
902    cut_buffer = FetchSelectionOrCutBuffer(&buf_len, &from_selection);
903    if (cut_buffer == NULL) return;
904    if ((unsigned char)(*cut_buffer) != TGIF_HEADER &&
905          MBInfoPtr->return_str != NULL) {
906       unsigned char *c_ptr=(unsigned char *)cut_buffer;
907 
908       if (MBInfoPtr->exposed) {
909          XClearWindow(mainDisplay, MBInfoPtr->btn_win);
910       }
911       for ( ; buf_len > 0 && MBInfoPtr->index < 80 && *c_ptr != '\0';
912             c_ptr++, buf_len--) {
913          if (*c_ptr >= (unsigned char)('\040') &&
914                *c_ptr < (unsigned char)('\377')) {
915             MBInfoPtr->return_str[MBInfoPtr->index++] = (char)(*c_ptr);
916          } else {
917             break;
918          }
919       }
920       MBInfoPtr->return_str[MBInfoPtr->index] = '\0';
921       if (MBInfoPtr->exposed) {
922          DisplayInput(MBInfoPtr);
923          PutCursor(MBInfoPtr->btn_win, MBInfoPtr->cursor_x, MBInfoPtr->cursor_y,
924                myFgPixel);
925       }
926    }
927    FreeSelectionOrCutBuffer(cut_buffer, from_selection);
928 }
929 
930 static
HandleMsgBoxBtnEvent(MBInfoPtr,input)931 int HandleMsgBoxBtnEvent(MBInfoPtr, input)
932    struct MBRec *MBInfoPtr;
933    XEvent *input;
934 {
935    XButtonEvent *button_ev=(&(input->xbutton));
936    int i, x=button_ev->x, y=button_ev->y;
937 
938    for (i=0; i < numButtons; i++) {
939       if (MBInfoPtr->btn_info[i].str != NULL) {
940          if (x >= MBInfoPtr->btn_info[i].bbox.ltx &&
941                x < MBInfoPtr->btn_info[i].bbox.rbx &&
942                y >= MBInfoPtr->btn_info[i].bbox.lty &&
943                y < MBInfoPtr->btn_info[i].bbox.rby) {
944             int inside=TRUE;
945 
946             DisplayButtonInBBox(MBInfoPtr->btn_win, MBInfoPtr->btn_info[i].str,
947                   strlen(MBInfoPtr->btn_info[i].str),
948                   &MBInfoPtr->btn_info[i].bbox, BUTTON_INVERT,
949                   MBInfoPtr->btn_info[i].highlight, BTN_XY_EXTRA, NULL);
950             if (!debugNoPointerGrab) {
951                XGrabPointer(mainDisplay, MBInfoPtr->btn_win, FALSE,
952                      PointerMotionMask | ButtonReleaseMask, GrabModeAsync,
953                      GrabModeAsync, None, defaultCursor, CurrentTime);
954             }
955             while (TRUE) {
956                XEvent ev;
957 
958                XNextEvent(mainDisplay, &ev);
959                if (ev.type == ButtonRelease) {
960                   XUngrabPointer(mainDisplay, CurrentTime);
961                   XSync(mainDisplay, False);
962                   button_ev = &(ev.xbutton);
963                   x = button_ev->x;
964                   y = button_ev->y;
965                   if (x >= MBInfoPtr->btn_info[i].bbox.ltx &&
966                         x < MBInfoPtr->btn_info[i].bbox.rbx &&
967                         y >= MBInfoPtr->btn_info[i].bbox.lty &&
968                         y < MBInfoPtr->btn_info[i].bbox.rby) {
969                      DisplayButtonInBBox(MBInfoPtr->btn_win,
970                            MBInfoPtr->btn_info[i].str,
971                            strlen(MBInfoPtr->btn_info[i].str),
972                            &MBInfoPtr->btn_info[i].bbox,
973                            BUTTON_NORMAL,
974                            MBInfoPtr->btn_info[i].highlight, BTN_XY_EXTRA,
975                            NULL);
976                      return MBInfoPtr->btn_info[i].id;
977                   }
978                   break;
979                } else if (ev.type == MotionNotify) {
980                   XEvent tmp_ev;
981                   XMotionEvent *motion_ev=(&(ev.xmotion));
982 
983                   while (XCheckMaskEvent(mainDisplay, PointerMotionMask,
984                         &tmp_ev)) ;
985                   x = motion_ev->x;
986                   y = motion_ev->y;
987                   if (inside) {
988                      if (!(x >= MBInfoPtr->btn_info[i].bbox.ltx &&
989                            x < MBInfoPtr->btn_info[i].bbox.rbx &&
990                            y >= MBInfoPtr->btn_info[i].bbox.lty &&
991                            y < MBInfoPtr->btn_info[i].bbox.rby)) {
992                         DisplayButtonInBBox(MBInfoPtr->btn_win,
993                               MBInfoPtr->btn_info[i].str,
994                               strlen(MBInfoPtr->btn_info[i].str),
995                               &MBInfoPtr->btn_info[i].bbox, BUTTON_NORMAL,
996                               MBInfoPtr->btn_info[i].highlight, BTN_XY_EXTRA,
997                               NULL);
998                         inside = FALSE;
999                      }
1000                   } else {
1001                      if (x >= MBInfoPtr->btn_info[i].bbox.ltx &&
1002                            x < MBInfoPtr->btn_info[i].bbox.rbx &&
1003                            y >= MBInfoPtr->btn_info[i].bbox.lty &&
1004                            y < MBInfoPtr->btn_info[i].bbox.rby) {
1005                         DisplayButtonInBBox(MBInfoPtr->btn_win,
1006                               MBInfoPtr->btn_info[i].str,
1007                               strlen(MBInfoPtr->btn_info[i].str),
1008                               &MBInfoPtr->btn_info[i].bbox, BUTTON_INVERT,
1009                               MBInfoPtr->btn_info[i].highlight, BTN_XY_EXTRA,
1010                               NULL);
1011                         inside = TRUE;
1012                      }
1013                   }
1014                }
1015             }
1016             return INVALID;
1017          }
1018       }
1019    }
1020    return INVALID;
1021 }
1022 
1023 static
RefreshMsgBox(MBInfoPtr)1024 void RefreshMsgBox(MBInfoPtr)
1025    struct MBRec *MBInfoPtr;
1026 {
1027    int i;
1028    XEvent ev;
1029 
1030    if (MBInfoPtr->msg_copy != NULL && *MBInfoPtr->msg_copy != '\0') {
1031       int y=0;
1032       char *c_ptr=MBInfoPtr->msg_copy;
1033 
1034       if (boldMsgFontPtr != NULL) {
1035          XSetFont(mainDisplay, defaultGC, boldMsgFontPtr->fid);
1036       }
1037       while (c_ptr != NULL) {
1038          char *c_ptr1=BoldMsgStrChr(c_ptr, '\n');
1039          int len, w;
1040 
1041          if (c_ptr1 != NULL) *c_ptr1 = '\0';
1042          len = strlen(c_ptr);
1043          if (boldMsgFontSet == NULL && boldMsgFontPtr == NULL) {
1044             if (MBInfoPtr->is_dialog) {
1045                w = len * defaultFontWidth;
1046                DrawBoldMsgString(mainDisplay, MBInfoPtr->msg_win, defaultGC,
1047                      (MBInfoPtr->msg_win_w-w)>>1, y+defaultFontAsc, c_ptr, len);
1048             } else {
1049                DrawBoldMsgString(mainDisplay, MBInfoPtr->msg_win, defaultGC,
1050                      0, y+defaultFontAsc, c_ptr, len);
1051             }
1052             y += defaultFontHeight+SPACING;
1053          } else {
1054             if (MBInfoPtr->is_dialog) {
1055                w = BoldMsgTextWidth(boldMsgFontPtr, c_ptr, len);
1056                DrawBoldMsgString(mainDisplay, MBInfoPtr->msg_win, defaultGC,
1057                      (MBInfoPtr->msg_win_w-w)>>1, y+boldMsgFontAsc, c_ptr, len);
1058             } else {
1059                DrawBoldMsgString(mainDisplay, MBInfoPtr->msg_win, defaultGC,
1060                      0, y+boldMsgFontAsc, c_ptr, len);
1061             }
1062             y += boldMsgFontHeight+SPACING;
1063          }
1064          if (c_ptr1 != NULL) {
1065             *c_ptr1 = '\n';
1066             c_ptr = &c_ptr1[1];
1067          } else {
1068             break;
1069          }
1070       }
1071       if (boldMsgFontSet != NULL || boldMsgFontPtr != NULL) {
1072          XSetFont(mainDisplay, defaultGC, defaultFontPtr->fid);
1073       }
1074    }
1075    if (MBInfoPtr->is_dialog) {
1076       DisplayInput(MBInfoPtr);
1077       PutCursor(MBInfoPtr->btn_win, MBInfoPtr->cursor_x, MBInfoPtr->cursor_y,
1078             myFgPixel);
1079    } else {
1080       for (i=0; i < numButtons; i++) {
1081          if (MBInfoPtr->btn_info[i].str != NULL) {
1082             DisplayButtonInBBox(MBInfoPtr->btn_win, MBInfoPtr->btn_info[i].str,
1083                   strlen(MBInfoPtr->btn_info[i].str),
1084                   &MBInfoPtr->btn_info[i].bbox, BUTTON_NORMAL,
1085                   MBInfoPtr->btn_info[i].highlight, BTN_XY_EXTRA,
1086                   NULL);
1087          }
1088       }
1089    }
1090    if (MBInfoPtr->cur_bitmap != None) {
1091       int y=((MBInfoPtr->icon_win_h-ICON_H)>>1);
1092 
1093       XSetTSOrigin(mainDisplay, defaultGC, 0, y);
1094       XSetFillStyle(mainDisplay, defaultGC, FillOpaqueStippled);
1095       XSetStipple(mainDisplay, defaultGC, MBInfoPtr->cur_bitmap);
1096       XFillRectangle(mainDisplay, MBInfoPtr->icon_win, defaultGC, 0, y,
1097             ICON_W, ICON_H);
1098       XSetFillStyle(mainDisplay, defaultGC, FillSolid);
1099       XSetTSOrigin(mainDisplay, defaultGC, 0, 0);
1100    }
1101    while (XCheckWindowEvent(mainDisplay,MBInfoPtr->main_win,ExposureMask,&ev)) ;
1102    while (XCheckWindowEvent(mainDisplay,MBInfoPtr->icon_win,ExposureMask,&ev)) ;
1103    while (XCheckWindowEvent(mainDisplay,MBInfoPtr->msg_win,ExposureMask,&ev)) ;
1104    while (XCheckWindowEvent(mainDisplay,MBInfoPtr->btn_win,ExposureMask,&ev)) ;
1105 
1106    if (threeDLook && dialogboxUse3DBorder) {
1107       struct BBRec bbox;
1108 
1109       SetBBRec(&bbox, 0, 0, MBInfoPtr->main_win_w, MBInfoPtr->main_win_h);
1110       TgDrawThreeDButton(mainDisplay, MBInfoPtr->main_win, textMenuGC, &bbox,
1111             TGBS_RAISED, 2, FALSE);
1112    }
1113 }
1114 
MsgBox(Message,Title,IconAndBtns)1115 int MsgBox(Message, Title, IconAndBtns)
1116    char *Message, *Title;
1117    int IconAndBtns;
1118 {
1119    static int stShowing=FALSE;
1120    char *dup_msg=NULL;
1121    int rc=MB_ID_FAILED, looping=TRUE;
1122 
1123    if (PRTGIF) {
1124       fprintf(stderr, "%s\n", Message);
1125       return rc;
1126    }
1127    dup_msg = UtilStrDup(Message);
1128    if (dup_msg == NULL) {
1129       FailAllocMessage();
1130       return rc;
1131    }
1132    if (stShowing) return rc;
1133 
1134    stShowing = TRUE;
1135    if (!SetupMBWindow(&mbInfo, dup_msg, Title, IconAndBtns, FALSE)) {
1136       char msg[MAXSTRING];
1137 
1138       sprintf(msg, TgLoadString(STID_INVALID_PARAM_PASSED_TO_FUNC), "MsgBox()");
1139       fprintf(stderr, "%s\n", msg);
1140       Msg(msg);
1141       if (mbInfo.msg_copy != NULL) {
1142          free(mbInfo.msg_copy);
1143          mbInfo.msg_copy = NULL;
1144       }
1145       free(dup_msg);
1146       stShowing = FALSE;
1147       return rc;
1148    }
1149    EndMeasureTooltip(FALSE);
1150    while (looping) {
1151       XEvent input, ev;
1152 
1153       XNextEvent(mainDisplay, &input);
1154       if ((input.type==MapNotify && input.xany.window==mbInfo.main_win) ||
1155             (input.type==Expose && (input.xany.window==mbInfo.main_win ||
1156             input.xany.window==mbInfo.icon_win ||
1157             input.xany.window==mbInfo.msg_win ||
1158             input.xany.window==mbInfo.btn_win)) ||
1159             (!mbInfo.exposed &&
1160             (XCheckWindowEvent(mainDisplay,mbInfo.main_win,ExposureMask,&ev) ||
1161             XCheckWindowEvent(mainDisplay,mbInfo.main_win,StructureNotifyMask,
1162             &ev)))) {
1163          RefreshMsgBox(&mbInfo);
1164          mbInfo.exposed = TRUE;
1165          XSync(mainDisplay, False);
1166          if (input.xany.window==mbInfo.main_win ||
1167                input.xany.window==mbInfo.icon_win ||
1168                input.xany.window==mbInfo.msg_win ||
1169                input.xany.window==mbInfo.btn_win) {
1170             continue;
1171          }
1172       }
1173       if (input.type == Expose) {
1174          ExposeEventHandler(&input, FALSE);
1175       } else if (input.type == ConfigureNotify &&
1176             input.xany.window == mainWindow) {
1177          Reconfigure(FALSE);
1178       } else if (input.type == VisibilityNotify &&
1179             input.xany.window==mainWindow &&
1180             input.xvisibility.state==VisibilityUnobscured) {
1181          int i;
1182 
1183          while (XCheckWindowEvent(mainDisplay, mainWindow,
1184                VisibilityChangeMask, &ev)) ;
1185          if (pinnedMainMenu) XMapRaised(mainDisplay, mainMenuWindow);
1186          for (i = 0; i < numExtraWins; i++) {
1187             if (extraWinInfo[i].mapped && extraWinInfo[i].raise &&
1188                   extraWinInfo[i].window != None) {
1189                XMapRaised(mainDisplay, extraWinInfo[i].window);
1190             }
1191          }
1192          XMapRaised(mainDisplay, mbInfo.main_win);
1193       } else if (input.type == KeyPress) {
1194          if ((rc=HandleMsgBoxKeyEvent(&mbInfo, &input)) != INVALID) {
1195             break;
1196          }
1197       } else if (input.type==ButtonPress && input.xany.window==mbInfo.btn_win) {
1198          if ((rc=HandleMsgBoxBtnEvent(&mbInfo, &input)) != INVALID) {
1199             break;
1200          }
1201       } else if (IsWM_DELETE_WINDOW(&input)) {
1202          rc = HandleDeleteMsgBox(&mbInfo);
1203          break;
1204       }
1205    }
1206    if (mbInfo.msg_copy != NULL) {
1207       free(mbInfo.msg_copy);
1208       mbInfo.msg_copy = NULL;
1209    }
1210    free(dup_msg);
1211 
1212    XDestroyWindow(mainDisplay, mbInfo.main_win);
1213    if (warpToWinCenter) {
1214       XWarpPointer(mainDisplay, None, drawWindow, 0, 0, 0, 0,
1215             (int)(ZOOMED_SIZE(drawWinW)>>1), (int)(ZOOMED_SIZE(drawWinH)>>1));
1216    }
1217    stShowing = FALSE;
1218    return rc;
1219 }
1220 
1221 static
DoDialog(Message,ReturnStr)1222 int DoDialog(Message, ReturnStr)
1223    char *Message, *ReturnStr;
1224 {
1225    char *dup_msg=UtilStrDup(Message), szTitle[80];
1226    int rc=FALSE, looping=TRUE;
1227 
1228    if (dup_msg == NULL) {
1229       FailAllocMessage();
1230       return INVALID;
1231    }
1232    sprintf(szTitle, TgLoadString(STID_TOOL_INPUT), TOOL_NAME);
1233    if (!SetupMBWindow(&mbInfo, dup_msg, szTitle, MB_ICON_DIALOG, TRUE)) {
1234       char msg[MAXSTRING];
1235 
1236       sprintf(msg, TgLoadString(STID_INVALID_PARAM_PASSED_TO_FUNC), "MsgBox()");
1237       fprintf(stderr, "%s\n", msg);
1238       Msg(msg);
1239       if (mbInfo.msg_copy != NULL) {
1240          free(mbInfo.msg_copy);
1241          mbInfo.msg_copy = NULL;
1242       }
1243       free(dup_msg);
1244       return INVALID;
1245    }
1246    if (ReturnStr != NULL) {
1247       /* Use as is. */
1248       /* *ReturnStr = '\0'; */
1249    }
1250    mbInfo.cur_x = ((mbInfo.btn_win_w)>>1);
1251    mbInfo.cursor_x = mbInfo.cur_x + 1;
1252    if (msgFontSet == NULL && msgFontPtr == NULL) {
1253       mbInfo.cur_y = ((mbInfo.btn_win_h-defaultFontHeight)>>1)+defaultFontAsc;
1254       mbInfo.cursor_y = mbInfo.cur_y - defaultFontAsc +
1255             ((defaultFontAsc-16)>>1);
1256    } else {
1257       mbInfo.cur_y = ((mbInfo.btn_win_h-msgFontHeight)>>1)+msgFontAsc;
1258       mbInfo.cursor_y = mbInfo.cur_y - msgFontAsc +
1259             ((msgFontAsc-16)>>1);
1260    }
1261    mbInfo.index = 0;
1262    if (ReturnStr != NULL) {
1263       mbInfo.index = strlen(ReturnStr);
1264    }
1265    mbInfo.return_str = ReturnStr;
1266 
1267    while (looping) {
1268       XEvent input, ev;
1269 
1270       XNextEvent(mainDisplay, &input);
1271       if ((input.type==MapNotify && input.xany.window==mbInfo.main_win) ||
1272             (input.type==Expose && (input.xany.window==mbInfo.main_win ||
1273             input.xany.window==mbInfo.icon_win ||
1274             input.xany.window==mbInfo.msg_win ||
1275             input.xany.window==mbInfo.btn_win)) ||
1276             (!mbInfo.exposed &&
1277             (XCheckWindowEvent(mainDisplay,mbInfo.main_win,ExposureMask,&ev) ||
1278             XCheckWindowEvent(mainDisplay,mbInfo.main_win,StructureNotifyMask,
1279             &ev)))) {
1280          RefreshMsgBox(&mbInfo);
1281          mbInfo.exposed = TRUE;
1282          XSync(mainDisplay, False);
1283          if (input.xany.window==mbInfo.main_win ||
1284                input.xany.window==mbInfo.icon_win ||
1285                input.xany.window==mbInfo.msg_win ||
1286                input.xany.window==mbInfo.btn_win) {
1287             continue;
1288          }
1289       }
1290       if (input.type == Expose) {
1291          ExposeEventHandler(&input, FALSE);
1292       } else if (input.type == ConfigureNotify &&
1293             input.xany.window == mainWindow) {
1294          Reconfigure(FALSE);
1295       } else if (input.type == VisibilityNotify &&
1296             input.xany.window==mainWindow &&
1297             input.xvisibility.state==VisibilityUnobscured) {
1298          int i;
1299 
1300          while (XCheckWindowEvent(mainDisplay, mainWindow,
1301                VisibilityChangeMask, &ev)) ;
1302          if (pinnedMainMenu) XMapRaised(mainDisplay, mainMenuWindow);
1303          for (i = 0; i < numExtraWins; i++) {
1304             if (extraWinInfo[i].mapped && extraWinInfo[i].raise &&
1305                   extraWinInfo[i].window != None) {
1306                XMapRaised(mainDisplay, extraWinInfo[i].window);
1307             }
1308          }
1309          XMapRaised(mainDisplay, mbInfo.main_win);
1310       } else if (input.type == KeyPress) {
1311          switch (HandleMsgBoxKeyEvent(&mbInfo, &input)) {
1312          case INVALID: looping = FALSE; rc = INVALID; break;
1313          case TRUE: looping = FALSE; rc = TRUE; break;
1314          case FALSE: break;
1315          }
1316       } else if (input.type==ButtonPress && input.xany.window==mbInfo.btn_win) {
1317          HandlePasteInDialog(&mbInfo, &input);
1318       } else if (IsWM_DELETE_WINDOW(&input)) {
1319          looping = FALSE;
1320          rc = INVALID;
1321          break;
1322       }
1323    }
1324    if (mbInfo.msg_copy != NULL) {
1325       free(mbInfo.msg_copy);
1326       mbInfo.msg_copy = NULL;
1327    }
1328    free(dup_msg);
1329 
1330    XDestroyWindow(mainDisplay, mbInfo.main_win);
1331    if (warpToWinCenter) {
1332       XWarpPointer(mainDisplay, None, drawWindow, 0, 0, 0, 0,
1333             (int)(ZOOMED_SIZE(drawWinW)>>1), (int)(ZOOMED_SIZE(drawWinH)>>1));
1334    }
1335    return rc;
1336 }
1337 
Dialog(Message,Comment,ReturnStr)1338 int Dialog(Message, Comment, ReturnStr)
1339    char *Message, *Comment, *ReturnStr;
1340    /* returns INVALID if <ESC> is types */
1341    /* returns FALSE otherwise */
1342    /* if Comment is NULL, "( <CR> or <ESC> to continue )" is assumed */
1343    /* if ReturnStr is NULL, hitting any key will return INVALID */
1344 {
1345    static int stDialoging=FALSE;
1346    char *real_msg=NULL, def_comment[MAXSTRING+1];
1347    int real_len=strlen(Message), rc;
1348 
1349    if (Comment == NULL) {
1350       strcpy(def_comment, TgLoadCachedString(CSTID_DLG_DEF_CONTINUE));
1351       real_len += strlen(def_comment)+2;
1352    } else {
1353       real_len += strlen(Comment)+2;
1354    }
1355    real_msg = (char*)malloc((real_len+1)*sizeof(char));
1356    if (real_msg == NULL) {
1357       FailAllocMessage();
1358       return INVALID;
1359    }
1360    if (stDialoging) return INVALID;
1361 
1362    stDialoging = TRUE;
1363    if (Comment == NULL) {
1364       sprintf(real_msg, "%s\n\n%s", Message, def_comment);
1365    } else {
1366       sprintf(real_msg, "%s\n\n%s", Message, Comment);
1367    }
1368    EndMeasureTooltip(FALSE);
1369    rc = DoDialog(real_msg, ReturnStr);
1370    free(real_msg);
1371    stDialoging = FALSE;
1372    return rc;
1373 }
1374