Link with C++ linker
[oweals/cde.git] / cde / programs / dtimsstart / win.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* @(#)$TOG: win.c /main/9 1997/06/18 17:33:01 samborn $ */
24
25 #include        <X11/X.h>
26 #include        <X11/Xlib.h>
27 #include        <X11/Xatom.h>
28 #include        <X11/Intrinsic.h>
29 #include        <X11/cursorfont.h>
30 #include        <Xm/Xm.h>
31 #include        <Xm/Protocols.h>
32 #include        <Xm/MwmUtil.h>
33
34 #include        <Xm/Form.h>
35 #include        <Xm/RowColumn.h>
36 #include        <Xm/LabelG.h>
37 #include        <Xm/SeparatoG.h>
38 #include        <Xm/DialogS.h>
39 #include        <Xm/MessageB.h>
40 #include        <Xm/TextF.h>
41 #include        <Xm/Text.h>
42
43 #include        "xims.h"
44 #include        <limits.h>
45
46
47 Display                 *Dpy = (Display *) 0;
48 Widget                  TopW = (Widget) 0;
49 XtAppContext            appC = (XtAppContext) 0;
50
51 static Widget           SelW = (Widget) 0;
52 static Widget           ModeW = (Widget) 0;
53 static Widget           MsgW = (Widget) 0;
54 static Widget           HelpW = (Widget) 0;
55 static Widget           HostW = (Widget) 0;
56 static Widget           HostText = (Widget) 0;
57
58 static Widget           SelRC = (Widget) 0;
59 static Widget           HostRC = (Widget) 0;
60
61 static Widget           FocusW = (Widget) 0;
62
63 static int              (*defaultErrorHandler)() = 0;
64
65
66 /* application resource */
67 typedef struct {
68     String      selectionHelpMsg;
69     String      modeHelpMsg;
70     String      windowLocation;
71 } AppResRec, *AppResP;
72
73 static AppResRec        appres;
74
75 static XtResource app_resources[] = {
76     { "selectionHelpMsg", "SelectionHelpMsg", XtRString, sizeof(String),
77       XtOffset(AppResP, selectionHelpMsg), XtRString, (XtPointer)NULL },
78     { "modeHelpMsg", "ModeHelpMsg", XtRString, sizeof(String),
79       XtOffset(AppResP, modeHelpMsg), XtRString, (XtPointer)NULL },
80     { "windowLocation", "WindowLocation", XtRString, sizeof(String),
81       XtOffset(AppResP, windowLocation), XtRString, (XtPointer)NULL },
82 };
83
84 static XrmOptionDescRec options[] = {
85     { "-geometry", "*XmDialogShell.geometry", XrmoptionSepArg, (XPointer) NULL },
86     { "-fn", "*fontList", XrmoptionSepArg, (XPointer) NULL },
87     { "-font", "*fontList", XrmoptionSepArg, (XPointer) NULL },
88
89 };
90
91 static char     *fallbacks[] = {
92     NULL
93 };
94
95
96 #define OK_BTN                  0
97 #define CANCEL_BTN              1
98 #define CLEAR_BTN               2
99 #define HOST_BTN                3
100 #define HELP_BTN                4
101
102 #ifdef  DEBUG2
103 #define WIN_FUNC        (MWM_FUNC_RESIZE | MWM_FUNC_MOVE)
104 #define WIN_DECR        (MWM_DECOR_BORDER | MWM_DECOR_TITLE | MWM_DECOR_RESIZEH)
105 #else
106 #define WIN_FUNC        (MWM_FUNC_MOVE)
107 #define WIN_DECR        (MWM_DECOR_BORDER)
108 #endif
109
110 #define MSGWIN_FUNC     0
111 #define MSGWIN_DECR     (MWM_DECOR_BORDER)
112 /* #define      DIALOG_STYLE            XmDIALOG_MODELESS */
113 #define DIALOG_STYLE            XmDIALOG_PRIMARY_APPLICATION_MODAL
114
115 #define MAX_HOSTNAME_LEN        63      /* limitation of ARPA host name */
116 #define TEXT_COLUMNS            (MAX_HOSTNAME_LEN / 4)
117
118     /* beep */
119 #ifdef  DEBUG
120 #define Beep()          XBell(Dpy, 0); DPR(("Beep!\n"))
121 #else
122 #define Beep()          XBell(Dpy, 0)
123 #endif  /* DEBUG */
124
125
126         /* local functions */
127     /* window env */
128 static int      ignoreBadWindow(/* dpy, error */);
129 static void     finish_window(/* w, end_window */);
130 static int      own_main_atom(/* win */);
131 static int      disown_main_atom(/* win */);
132     /* selection window */
133 static void     free_ims_list(/* list */);
134 static void     clear_selection_var(/*  */);
135 static void     finish_selection_window(/* end_window */);
136 static void     done_cb(/* w, client_data, call_data */);
137 static void     select_cb(/* w, client_data, call_data */);
138 static void     host_btn_cb(/* w, client_data, call_data */);
139 static void     help_cb(/* w, client_data, call_data */);
140 static int      create_selection_window(/*  */);
141 static int      change_host(/* new_host, host_type */);
142 static void     add_btn_trans(/* btn */);
143 static void     change_ims_list(/* last_ims_name, init_idx */);
144 static void     set_host_label(/* host_type, hostname */);
145 static void     add_cmd_btn(/* parent_rc, cb_ok, cb_clear, cb_cancel, cb_host, cb_help */);
146     /* host window */
147 static void     start_host_window(/* cur_host */);
148 static void     finish_host_window(/*  */);
149 static void     host_done_cb(/* w, client_data, call_data */);
150 static void     host_clear_cb(/* w, client_data, call_data */);
151 static void     host_done_action(/* w, ev, args, num_args */);
152 static void     create_host_window(/* cur_host */);
153     /* mode window */
154 static void     finish_mode_window(/* end_window */);
155 static void     mode_done_cb(/* w, client_data, call_data */);
156 static void     mode_cb(/* w, client_data, call_data */);
157 static void     mode_help_cb(/* w, client_data, call_data */);
158 static int      create_mode_window(/* cur_mode */);
159     /* help window */
160 static void     help_ok(/* w, client_data, call_data */);
161 static void     create_help(/*  */);
162     /* msg window */
163 static void     dialog_resp_cb(/* w, client_data, call_data */);
164 static int      wait_confirmation(/* w */);
165     /* locate window */
166 static int      window_location(/* loc_str */);
167 static void     locate_window(/* w */);
168     /* cursor */
169 static void     set_cursor(/* w, is_wait */);
170     /* timer */
171 static void     xt_timer_cb(/* client_data, timer_id */);
172
173
174         /* ********  window env  ******** */
175
176 int     open_display()
177 {
178     if (Dpy)    return NoError;         /* already done */
179
180     Dpy = XOpenDisplay(Opt.DisplayName);
181     if (!Dpy) {
182         DPR(("%s: cannot open display \"%s\"\n",
183                                 ProgramName, XDisplayName(Opt.DisplayName)));
184         return ErrOpenDpy;
185     }
186     return NoError;
187 }
188
189 void    close_display()
190 {
191     if (TopW)   return;         /* Xt not finished */
192
193     if (Dpy) {
194         XCloseDisplay(Dpy);
195         Dpy = (Display *) 0;
196     }
197     return;
198 }
199
200 int     window_env_ok()
201 {
202     return winEnv.status != WIN_ST_NONE ? True : False;
203 }
204
205 int     init_window_env()
206 {
207     enum { XA_DTIMS_ATOM_MAIN, XA_DTIMS_ATOM_STATUS, XA_DTIMS_ATOM_DATA, 
208            NUM_ATOMS }; 
209     static char *atom_names[] = { 
210       DTIMS_ATOM_MAIN, DTIMS_ATOM_STATUS, DTIMS_ATOM_DATA };
211
212     Display             *dpy = (Display *) 0;
213     Widget              topW = (Widget) 0;
214     XtAppContext        app = (XtAppContext) 0;
215     int                 ret = NoError;
216     Atom                atoms[XtNumber(atom_names)];
217
218     if (winEnv.status != WIN_ST_NONE)   return NoError;
219
220         /* disable XIM on my own XmText* */
221     putenv("XMODIFIERS=@im=_XIMP_None");        /* putenv("XMODIFIERS=@im=none"); */
222     XtSetLanguageProc(NULL, NULL, NULL);
223
224     if (!Dpy) {
225         ret = open_display();
226         if (ret != NoError)
227             return ret;
228     }
229
230     if (!(OpFlag & FLAG_NORESOURCE) && isXsession()) {
231         if (open_display() == NoError) {        /* set RESOURCE_MANAGER */
232             load_resources();
233         }
234     }
235     if (Dpy)    close_display();
236
237     topW = XtAppInitialize(&app, DTIMS_CLASS,
238                 options, XtNumber(options),
239                 &Wargc, Wargv, fallbacks, (ArgList) NULL, (Cardinal) 0);
240
241     dpy = XtDisplay(topW);
242     XtSetMappedWhenManaged(topW, False);
243     XtRealizeWidget(topW);
244
245     /* set my error handler */
246     defaultErrorHandler = XSetErrorHandler(ignoreBadWindow);
247
248     XtGetApplicationResources(topW, &appres,
249                               app_resources, XtNumber(app_resources),
250                               NULL, 0);
251
252 #if     0
253     /* handle system Menu's "close" */
254     XmAddWMProtocolCallback(topW,
255                         XmInternAtom(dpy, "WM_DELETE_WINDOW", True),
256                         (XtCallbackProc)end_window_env, (XtPointer)0);
257 #endif
258
259     Dpy = dpy; TopW = topW; appC = app; /* @@@ */
260
261     XInternAtoms(dpy, atom_names, XtNumber(atom_names), False, atoms);
262
263     winEnv.Dpy = dpy;
264     winEnv.TopW = topW;
265     winEnv.appC = app;
266     winEnv.atom_main = atoms[XA_DTIMS_ATOM_MAIN];
267     winEnv.atom_status = atoms[XA_DTIMS_ATOM_STATUS];
268     winEnv.atom_data = atoms[XA_DTIMS_ATOM_DATA];
269     winEnv.atom_owner = XGetSelectionOwner(dpy, winEnv.atom_main);
270     winEnv.status = WIN_ST_INIT;
271
272     clear_cmd_property(XtWindow(topW));
273
274     if (winEnv.atom_main == None)
275         return ErrOpenDpy;
276
277     if ((OpMode == MODE_START || OpMode == MODE_LISTNAME) 
278         && !(OpFlag & FLAG_REMOTERUN)) {
279         if (own_main_atom(XtWindow(TopW)) != True) {
280             DPR(("another program is running on the display '%s'\n",
281                                                         XDisplayString(Dpy)));
282             return ErrAnotherProg;
283         }
284     }
285
286     return NoError;
287 }
288
289 void    end_window_env()
290 {
291     if (TopW) {
292         disown_main_atom(XtWindow(TopW));
293         XSetErrorHandler(defaultErrorHandler);
294
295         /* XtUnmapWidget(TopW); */
296         XtDestroyWidget(TopW);
297         XtDestroyApplicationContext(appC);
298     } else if (Dpy)
299         close_display();
300
301     TopW = (Widget) 0;
302     appC = (XtAppContext) 0;
303     Dpy = (Display *) 0;
304
305     ximsMain();
306
307     /* return; */
308 }
309
310
311 int     clear_cmd_property(win)                 /* clear WM_COMMAND property */
312     Window      win;
313 {
314     int         ret, ac = 0;
315     int         clear_ok = False;
316     char        **av = NULL;
317
318     /* if (!Dpy || !win)        return False; */
319
320     ret = XGetCommand(Dpy, win, &av, &ac);
321     if (ret && ac > 0) {
322         XFreeStringList(av);
323         XSetCommand(Dpy, win, 0, NULL);
324         XSync(Dpy, False);
325         clear_ok = True;
326         DPR2(("\tWM_COMMAND cleared on %#x\n", win));
327     }
328
329     return clear_ok;
330 }
331
332 static int      ignoreBadWindow(dpy, error)
333     Display *dpy;
334     XErrorEvent *error;
335 {
336     if (error->error_code == BadWindow || error->error_code == BadDrawable) {
337         return 0;
338     } else {            /* invoke default error handler */
339         return (*defaultErrorHandler)(dpy, error);
340     }
341 }
342
343 #ifdef  unused
344 static void     finish_window(w, end_window)
345     Widget      *w;
346     int         end_window;
347 {
348     if (*w) {
349         XtUnmapWidget(*w);
350         XtDestroyWidget(*w);
351         *w = (Widget) 0;
352     }
353
354     if (end_window)
355         end_window_env();
356
357     return;
358 }
359 #endif  /* unused */
360
361
362 static int      own_main_atom(win)      /* own DTIMS_ATOM_MAIN */
363     Window      win;
364 {
365     Window      owner = None;
366
367     if (winEnv.atom_main == None)       return False;
368     /* if (winEnv.atom_owner != None)   return False; */
369
370     owner = XGetSelectionOwner(winEnv.Dpy, winEnv.atom_main);
371     if (owner != None && owner != win) {
372         winEnv.atom_owner = owner;
373         return False;
374     }
375
376     XSetSelectionOwner(winEnv.Dpy, winEnv.atom_main, win, CurrentTime);
377     DPR2(("own_main_atom(%#x): atom=%s[%d]\n",
378                                 win, DTIMS_ATOM_MAIN, winEnv.atom_main));
379     winEnv.atom_owner = XGetSelectionOwner(winEnv.Dpy, winEnv.atom_main);
380
381     return winEnv.atom_owner == win ? True : False;
382 }
383
384 static int      disown_main_atom(win)   /* disown DTIMS_ATOM_MAIN */
385     Window      win;
386 {
387     if (winEnv.atom_main == None)       return False;
388     /* if (winEnv.atom_owner == None)   return False; */
389
390     /* give up ownership of DTIMS_ATOM_MAIN */
391     if (XGetSelectionOwner(winEnv.Dpy, winEnv.atom_main) == winEnv.atom_owner)
392         XSetSelectionOwner(winEnv.Dpy, winEnv.atom_main, None, CurrentTime);
393     winEnv.atom_owner = XGetSelectionOwner(winEnv.Dpy, winEnv.atom_main);
394
395     return True;
396 }
397
398
399         /* ********  resource_manager  ******** */
400
401 static char     *saved_xdefs = NULL;    /* should not be freed */
402
403 int     save_RM()
404 {
405     if (!Dpy)   return False;
406     saved_xdefs = XResourceManagerString(Dpy);
407     return saved_xdefs ? True : False;
408 }
409
410 int     merge_RM(res1, res2)
411     char        *res1, *res2;
412 {
413     char        cmdbuf[BUFSIZ*2];
414     int         ret;
415
416     if (!Dpy)   return False;
417
418     cmdbuf[0] = 0;
419     if (isDT()) {
420         char    *dtres_cmd = DTSESSION_RES_PATH;
421         if (is_executable(dtres_cmd)) {
422             sprintf(cmdbuf, "%s -merge -system -xdefaults ", dtres_cmd);
423             if (res1) { strcat(cmdbuf, " -file "); strcat(cmdbuf, res1); }
424             if (res2) { strcat(cmdbuf, " -file "); strcat(cmdbuf, res2); }
425             strcat(cmdbuf, " >/dev/null 2>&1");
426         }
427     }
428     if (!cmdbuf[0]) {
429         sprintf(cmdbuf, "%s %s %s 2>/dev/null | %s -merge -quiet - 2>/dev/null",
430                                         CAT_PATH, res1, res2, XRDB_PATH);
431     }
432
433     ret = system(cmdbuf);
434
435     DPR2(("merge_RM(): '%s' & '%s' merged to RESOURCE_MANAGER\n", res1, res2));
436     return ret == 0 ? True : False;
437 }
438
439 int     restore_RM()
440 {
441     int         len = saved_xdefs ? strlen(saved_xdefs) : 0;
442     int         max = (XMaxRequestSize(Dpy) << 2) - 28;
443     int         mode = PropModeReplace;
444     unsigned char       *bp = (unsigned char *) saved_xdefs;
445     Window      root = RootWindow(Dpy, 0);
446
447     if (!Dpy /* || len < 0 */)          return False;
448
449     DPR2(("restore_RM(): saved RESOURCE_MANAGER = %d (bytes)\n", len));
450
451     if (saved_xdefs == NULL) {          /* len == 0 */
452         XDeleteProperty(Dpy, root, XA_RESOURCE_MANAGER);
453 #if     0
454         XSync(Dpy, False);
455         {   char        buf[BUFSIZ];
456             sprintf(buf, "%s -quiet -remove 2>/dev/null", XRDB_PATH);
457             DPR(("restore_RM(): '%s'\n", buf));
458             system(buf);
459         }
460 #endif
461         return True;
462     }
463
464     if (len > max) {
465         XGrabServer(Dpy);
466         do {
467             XChangeProperty(Dpy, root,
468                         XA_RESOURCE_MANAGER, XA_STRING, 8, mode, bp, len);
469             bp += max; len -= max;
470             mode = PropModeAppend;
471         } while (len > max);
472     }
473     XChangeProperty(Dpy, root,
474                         XA_RESOURCE_MANAGER, XA_STRING, 8, mode, bp, len);
475     if (mode != PropModeReplace)
476         XUngrabServer(Dpy);
477
478     return True;
479 }
480
481
482         /* ********  selection window  ******** */
483
484 static int              CurIdx = -1;
485 static char             *CurHost = NULL;
486 static int              CurHostType = HOST_UNKNOWN;
487 static ImsList          *curList = 0;
488 static bool             selection_changed = False;
489
490
491 static void     free_ims_list(list)
492     ImsList     *list;
493 {
494     /* DPR(("free_ims_list(list=%p)\n", list)); */
495     if (list && list != localList && list != userSel.list) {
496         clear_ImsList(list);
497         FREE(list);
498     }
499 }
500
501 static void     clear_selection_var()
502 {
503     free_ims_list(curList);
504     curList = (ImsList *) 0;
505
506     if (CurHost)        FREE(CurHost);
507     CurHost = NULL;
508     CurHostType = HOST_UNKNOWN;
509     CurIdx = -1;
510     selection_changed = False;
511 }
512
513 int     start_selection_window()
514 {
515     int         ret = NoError;
516
517     if ((ret = init_window_env()) != NoError)
518         return ret;
519
520     clear_selection_var();
521     curList = userSel.list;
522     /* curHost = NEWSTR(userSel.hostname); */
523
524     if ((ret = create_selection_window()) != NoError)
525         return ret;
526
527     /* handle system Menu's "close" */
528     XmAddWMProtocolCallback(XtParent(SelW),
529                         XmInternAtom(Dpy, "WM_DELETE_WINDOW", True),
530                         (XtCallbackProc)done_cb, (XtPointer)CANCEL_BTN);
531
532     if (isXsession()) {
533         clear_cmd_property(XtWindow(TopW));
534     }
535
536     locate_window(SelW);
537     XtManageChild(SelW);
538     XtPopup(XtParent(SelW), XtGrabNone);
539
540     if (FocusW)
541         XmProcessTraversal(FocusW, XmTRAVERSE_CURRENT);
542
543     XtRealizeWidget(TopW);
544     XtAppMainLoop(appC);
545     /* not reached */
546 }
547
548 static void     finish_selection_window(end_window)
549     int         end_window;
550 {
551     DPR(("finish_selection_window(end=%s)\n", end_window ? "True" : "False"));
552
553     clear_selection_var();
554
555     stop_help();
556
557     if (SelW) {
558 #if     0
559         if (TopW)
560             disown_main_atom(XtWindow(TopW));
561 #endif
562
563         XtUnmanageChild(SelW);
564         XtPopdown(XtParent(SelW));
565         XtDestroyWidget(XtParent(SelW));
566         SelW = (Widget) 0;
567
568         if (HostW) {
569             XtUnmanageChild(HostW);
570             XtPopdown(XtParent(HostW));
571             XtDestroyWidget(XtParent(HostW));
572             HostW = (Widget) 0;
573         }
574     }
575
576     if (end_window)
577         end_window_env();
578
579     return;
580 }
581
582 static void     done_cb(w, client_data, call_data)
583     Widget      w;
584     XtPointer   client_data, call_data;
585 {
586     int         canceled = (int)client_data == CANCEL_BTN;
587     int         idx;
588     UserSelection       *sel = &userSel;
589
590     if (!canceled) {            /* update userSel */
591         idx = CurIdx;
592         DPR2(("done_cb(): selected IMS: [%d]%s\n",
593                                         idx, curList->elist[idx]->name));
594
595         if (curList->elist[idx]->status != NoError) {
596             Beep();
597             return;
598         }
599
600         if ((CurHost != sel->hostname) 
601             || (CurHost && sel->hostname && strcmp(sel->hostname, CurHost))
602             || sel->list != curList || sel->ims_idx != idx)
603             selection_changed = True;
604
605         if (selection_changed == True) {
606             update_user_selection(sel, curList, idx, CurHost, CurHostType);
607             curList = (ImsList *) 0;
608         }
609     }
610
611     finish_selection_window(False);
612
613     OpErrCode = NoError;
614     OpState = canceled ? State_Select_Canceled : State_Select_Done;
615     ximsMain();
616 }
617
618 static void     select_cb(w, client_data, call_data)
619     Widget      w;
620     XtPointer   client_data, call_data;
621 {
622     int         new_idx = (int) client_data;
623
624     if (new_idx < 0 || new_idx >= curList->num_ent) {
625         DPR(("select_cb():\tinvalid index (%d)\n", new_idx));
626         return;
627     }
628
629     DPR3(("select_cb(): '%s' selected (%d <- %d)\n",
630             curList->elist[new_idx]->name, new_idx, CurIdx));
631
632     CurIdx = new_idx;
633 }
634
635 static void     host_btn_cb(w, client_data, call_data)
636     Widget      w;
637     XtPointer   client_data, call_data;
638 {
639     start_host_window(CurHost);
640 }
641
642 static void     help_cb(w, client_data, call_data)
643     Widget      w;
644     XtPointer   client_data, call_data;
645 {
646     ximsHelp(HELP_SELECTION);
647 }
648
649
650 static int      create_selection_window()
651 {
652     Widget      form, sel_rc, host_rc, cmd_rc, lb, sep;
653     Widget      w_tbl[8];
654     Arg         args[16];
655     int         i, j, n;
656     int         ret;
657     bool        use_local = False;
658
659         /* selection top window */
660
661         i = 0;
662         XtSetArg(args[i], XmNmwmFunctions, WIN_FUNC); i++;
663         XtSetArg(args[i], XmNmwmDecorations, WIN_DECR); i++;
664         XtSetArg(args[i], XmNdefaultPosition, False); i++;
665         XtSetArg(args[i], XmNnoResize, True); i++;
666         XtSetArg(args[i], XmNallowShellResize, True); i++;
667         /* XtSetArg(args[i], XmNresizable, True); i++; */
668         XtSetArg(args[i], XmNmappedWhenManaged, False); i++;
669     SelW =
670     form = XmCreateFormDialog(TopW, "Selection", args, i);
671
672         /* for child of form */
673         i = 0;
674         XtSetArg(args[i], XmNtopAttachment, XmATTACH_WIDGET); i++;
675         XtSetArg(args[i], XmNleftAttachment, XmATTACH_FORM); i++;
676         XtSetArg(args[i], XmNrightAttachment, XmATTACH_FORM); i++;
677     n = 0;
678     w_tbl[n] = 0;
679         XtSetArg(args[i], XmNtopWidget, w_tbl[n]);
680     w_tbl[n] = lb = XmCreateLabelGadget(form, "title", args, i + 1);
681
682     if (RemoteOn()) {
683         XtSetArg(args[i], XmNtopWidget, w_tbl[n]);
684         j = i + 1;
685         XtSetArg(args[j], XmNorientation, XmHORIZONTAL); j++;
686         XtSetArg(args[j], XmNpacking, XmPACK_TIGHT); j++;
687         XtSetArg(args[j], XmNisAligned, TRUE); j++;
688         XtSetArg(args[j], XmNentryAlignment, XmALIGNMENT_BEGINNING); j++;
689         XtSetArg(args[j], XmNentryBorder, 0); j++;
690         XtSetArg(args[j], XmNmarginHeight, 1); j++;
691         XtSetArg(args[j], XmNmarginWidth, 20); j++;
692     HostRC =
693     w_tbl[++n] = host_rc = XmCreateRowColumn(form, "host_rc", args, j);
694     }
695
696         XtSetArg(args[i], XmNtopWidget, w_tbl[n]);
697         j = i + 1;
698         XtSetArg(args[j], XmNorientation, XmHORIZONTAL); j++;
699         XtSetArg(args[j], XmNpacking, XmPACK_COLUMN); j++;
700         XtSetArg(args[j], XmNnumColumns, curList->num_ent); j++;
701         XtSetArg(args[j], XmNisAligned, TRUE); j++;
702         XtSetArg(args[j], XmNentryAlignment, XmALIGNMENT_BEGINNING); j++;
703         XtSetArg(args[j], XmNentryBorder, 0); j++;
704         XtSetArg(args[j], XmNmarginHeight, 10); j++;
705         /* XtSetArg(args[j], XmNmarginWidth, 40); j++; */
706     SelRC =
707     w_tbl[++n] = sel_rc = XmCreateRadioBox(form, "select_rc", args, j);
708
709         XtSetArg(args[i], XmNtopWidget, w_tbl[n]);
710     w_tbl[++n] = sep = XmCreateSeparatorGadget(form, "sep", args, i + 1);
711
712         XtSetArg(args[i], XmNtopWidget, w_tbl[n]);
713         XtSetArg(args[i+1], XmNbottomAttachment, XmATTACH_FORM);
714     w_tbl[++n] = cmd_rc = XmCreateRowColumn(form,"cmd_rc", args, i + 2);
715
716     use_local = True;
717     if (RemoteOn()) {
718         switch (userSel.host_type) {
719             case HOST_UNKNOWN:
720                 put_xims_errmsg(ErrUnknownHost, userSel.hostname, 0, 0);
721                 ret = change_host(NULL, HOST_LOCAL);
722                 break;
723             case HOST_REMOTE:
724                 ret = change_host(userSel.hostname, userSel.host_type);
725                 if (ret == NoError) {
726                     change_ims_list(userSel.name, -1);
727                     use_local = False;
728                 } else {
729                     if (ret != ErrRemoteAction) {
730                         put_xims_errmsg(ret, 0 /* userSel.hostname */, 0, 0);
731                     }
732                 }
733         }
734     }
735     if (use_local)
736         change_ims_list(NULL, userSel.ims_idx);
737
738     add_cmd_btn(cmd_rc, done_cb, 0, done_cb,
739                                         RemoteOn() ? host_btn_cb : 0, help_cb);
740
741     XtManageChildren(w_tbl, ++n);
742
743     XtManageChild(SelW); locate_window(SelW); XtUnmanageChild(SelW);
744     XtVaSetValues(SelW, XmNmappedWhenManaged, True, NULL);
745     XtVaSetValues(XtParent(SelW), XmNmappedWhenManaged, True, NULL);
746     set_cursor(SelW, False);
747
748     return NoError;
749 }
750
751
752 static int      change_host(new_host, host_type)
753     char        *new_host;
754     int         host_type;
755 {
756     int         ret = NoError;
757     ImsList     *new_list = (ImsList *) 0;
758
759     if (new_host && host_type == HOST_REMOTE) {
760         set_cursor(HostW, True);
761         ret = get_remote_conf(&new_list, new_host, NULL, NULL);
762         set_cursor(HostW, False);
763     } else {
764         if (!localList)
765             ret = get_ims_list(&localList, NULL, True);
766         new_host = NULL;
767         new_list = localList;
768     }
769
770     if (ret == NoError) {
771         if (CurHost)    FREE(CurHost);
772         CurHost = new_host ? NEWSTR(new_host) : NULL;
773         CurHostType = host_type;
774
775         DPR(("change_host(%s): curList=(%p) <- (%p)\n",
776                                         new_host, new_list, curList));
777         free_ims_list(curList);
778         curList = new_list;
779     } else if (new_list) {
780         free_ims_list(new_list);
781     }
782
783     return ret;
784 }
785
786 # define        SelectByReturn  1
787
788 #ifdef  SelectByReturn
789 #include        <Xm/ToggleB.h>
790 #include        <Xm/PushB.h>
791 #define createPB        XmCreatePushButton
792 #define createTB        XmCreateToggleButton
793
794 static void     add_btn_trans(btn)
795     Widget      btn;
796 {
797     char        btn_trans_str[] = "<Key>Return: ArmAndActivate()";
798     static XtTranslations       btn_trans = 0;
799
800     if (!btn_trans)
801         btn_trans = XtParseTranslationTable(btn_trans_str);
802    XtOverrideTranslations(btn, btn_trans);
803 }
804
805 #else
806 #include        <Xm/ToggleBG.h>
807 #include        <Xm/PushBG.h>
808 #define createPB        XmCreatePushButtonGadget
809 #define createTB        XmCreateToggleButtonGadget
810 #define add_btn_trans(btn)
811 # endif /* SelectByReturn */
812
813
814 static void     change_ims_list(last_ims_name, init_idx)
815     char        *last_ims_name;
816     int         init_idx;
817 {
818     int idx;
819     int i, j;
820     Arg args[8];
821     XmString    str;
822     static int          num_chld = 0;
823     static Widget       tb[MAXIMSENT];
824
825 #define IMS_OK(i)       (curList->elist[i]->status == NoError)
826
827         /* deternime initial selection */
828     idx = -1;
829     if (last_ims_name) {
830         i = get_ims_idx(curList, last_ims_name);
831         if (i >= 0 && IMS_OK(i))
832             idx = i;
833     }
834     if (idx < 0) {
835         if (init_idx >= 0 && init_idx < curList->num_ent && IMS_OK(init_idx)) {
836             idx = init_idx;
837         } else {
838             idx = curList->default_idx;
839             if (!(idx >= 0 && idx < curList->num_ent && IMS_OK(idx))) {
840                 for (idx = 0; idx < curList->num_ent; idx++)
841                     if (IMS_OK(idx))    break;
842                 if (idx >= curList->num_ent)
843                     idx = 0;
844             }
845         }
846     }
847
848     for (j = 0; j < curList->num_ent; j++) {
849         str = XmStringCreateLocalized(curList->elist[j]->label);
850         i = 0;
851         XtSetArg(args[i], XmNset, j == idx ? True : False); i++;
852         XtSetArg(args[i], XmNsensitive, IMS_OK(j)); i++;
853         XtSetArg(args[i], XmNlabelString, str); i++;
854         XtSetArg(args[i], XmNspacing, 10); i++;
855         if (j < num_chld) {
856             XtSetValues(tb[j], args, i);
857         } else {
858             tb[j] = createTB(SelRC, "ims", args, i);
859             XtAddCallback(tb[j], XmNvalueChangedCallback, select_cb, (XtPointer)j);
860             add_btn_trans(tb[j]);
861         }
862         XmStringFree(str);
863     }
864     if (j > num_chld)
865         num_chld = j;
866     else if (j < num_chld)
867         XtUnmanageChildren(tb + j, num_chld - j);
868     XtManageChildren(tb, j);
869
870     CurIdx = idx;
871     if (RemoteOn()) {
872         if (CurHostType == HOST_UNKNOWN)
873             CurHostType = check_hostname(CurHost);
874         set_host_label(CurHostType, CurHost);
875     }
876
877 #undef  IMS_OK
878 }
879
880 static void     set_host_label(host_type, hostname)
881     int         host_type;
882     char        *hostname;
883 {
884     static Widget       lb_host = 0;
885
886     /* if (!HostRC)     return; */
887
888     if (host_type == HOST_REMOTE) {     /* change HostLabel & manage HostRC */
889         XmString        str;
890
891         if (!lb_host) {
892             Widget      lb;
893             Arg args[4];
894             int n = 0;
895
896             XtSetArg(args[n], XmNmarginLeft, 100); n++;
897             lb = XmCreateLabelGadget(HostRC, "host_label", args, n);
898             lb_host = XmCreateLabelGadget(HostRC, "hostname", NULL, 0);
899             XtManageChild(lb);
900             XtManageChild(lb_host);
901         }
902         str = XmStringCreateLocalized(hostname);
903         XtVaSetValues(lb_host, XmNlabelString, str, NULL);
904         XmStringFree(str);
905
906         XtManageChild(HostRC);
907     } else {
908             /* unmanage HostRC */
909         XtUnmanageChild(HostRC);
910     }
911 }
912
913
914 static void     add_cmd_btn(parent_rc, cb_ok, cb_clear, cb_cancel, cb_host, cb_help)
915     Widget      parent_rc;
916     void        (*cb_ok)(), (*cb_cancel)(), (*cb_clear)(),
917                         (*cb_host)(), (*cb_help)();
918 {
919     Widget      pb[4];
920     Arg         args[12];
921     int         n, nbtn;
922
923     nbtn = 0;
924     if (cb_ok)          nbtn++;
925     if (cb_clear)       nbtn++;
926     if (cb_cancel)      nbtn++;
927     if (cb_host)        nbtn++;
928     if (cb_help)        nbtn++;
929     if (nbtn == 0)      return;
930
931         /* command buttons on "cmd_rc" */
932         n = 0;
933       if (nbtn > 3) {
934         XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
935         XtSetArg(args[n], XmNpacking, XmPACK_TIGHT); n++;
936       } else {
937         XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
938         XtSetArg(args[n], XmNpacking, XmPACK_COLUMN); n++;
939       }
940         XtSetArg(args[n], XmNnumColumns, nbtn); n++;
941         XtSetArg(args[n], XmNisAligned, TRUE); n++;
942         XtSetArg(args[n], XmNentryAlignment, XmALIGNMENT_CENTER); n++;
943         XtSetArg(args[n], XmNentryBorder, 0); n++;
944         XtSetArg(args[n], XmNmarginHeight, 1); n++;
945         XtSetArg(args[n], XmNnavigationType, XmTAB_GROUP); n++;
946         /* XtSetArg(args[n], XmNmarginWidth, 20); n++; */
947         /* XtSetArg(args[n], XmNspacing, 20); n++; */
948     XtSetValues(parent_rc, args, n);
949
950         /* for child of parent_rc */
951
952     nbtn = 0;
953         n = 0;
954     if (cb_ok) {
955         pb[nbtn] = createPB(parent_rc, "OK", args, n);
956         XtAddCallback(pb[nbtn], XmNactivateCallback,
957                                         cb_ok, (XtPointer)OK_BTN);
958         FocusW = pb[nbtn];
959         /* XtVaSetValues(parent_rc, XmNinitialFocus, pb, NULL); */
960         nbtn++;
961     }
962     if (cb_clear) {
963         pb[nbtn] = createPB(parent_rc, "Clear", args, n);
964         XtAddCallback(pb[nbtn], XmNactivateCallback,
965                                         cb_clear, (XtPointer)CLEAR_BTN);
966         nbtn++;
967     }
968     if (cb_cancel) {
969         pb[nbtn] = createPB(parent_rc, "Cancel", args, n);
970         XtAddCallback(pb[nbtn], XmNactivateCallback,
971                                         cb_cancel, (XtPointer)CANCEL_BTN);
972         nbtn++;
973     }
974     if (cb_host) {
975         pb[nbtn] = createPB(parent_rc, "ChangeHost", args, n);
976         XtAddCallback(pb[nbtn], XmNactivateCallback,
977                                         cb_host, (XtPointer)HOST_BTN);
978         nbtn++;
979     }
980     if (cb_help) {
981         pb[nbtn] = createPB(parent_rc, "Help", args, n);
982         XtAddCallback(pb[nbtn], XmNactivateCallback,
983                                         cb_help, (XtPointer)HELP_BTN);
984         nbtn++;
985     }
986 #ifdef  SelectByReturn
987     for (n = 0; n < nbtn; n++)
988         add_btn_trans(pb[n]);
989 #endif  /* SelectByReturn */
990
991     XtManageChildren(pb, nbtn);
992 }
993
994         /* ***** host window ***** */
995
996 static void     start_host_window(cur_host)
997     char        *cur_host;
998 {
999     int ret;
1000
1001     if (!HostW) {
1002         create_host_window(cur_host);
1003
1004         /* handle system Menu's "close" */
1005         XmAddWMProtocolCallback(XtParent(HostW),
1006                         XmInternAtom(Dpy, "WM_DELETE_WINDOW", True),
1007                         (XtCallbackProc)host_done_cb, (XtPointer)CANCEL_BTN);
1008     }
1009
1010     XtVaSetValues(HostText, XmNvalue, CurHost, NULL);
1011
1012     if (HostText)
1013         XmProcessTraversal(HostText, XmTRAVERSE_CURRENT);
1014
1015     locate_window(HostW);
1016     XtManageChild(HostW);
1017     XtPopup(XtParent(HostW), XtGrabNone);
1018
1019 #ifdef  DEBUG
1020     pr_brk("start_host_window");
1021 #endif
1022
1023     return;
1024 }
1025
1026 static void     finish_host_window()
1027 {
1028     DPR(("finish_host_window()\n"));
1029
1030     if (HostW) {
1031         XtUnmanageChild(HostW);
1032         XtPopdown(XtParent(HostW));
1033             /* not destroy */
1034     }
1035 }
1036
1037 static void     host_done_cb(w, client_data, call_data)
1038     Widget      w;
1039     XtPointer   client_data, call_data;
1040 {
1041     int         cancel = (int)client_data == CANCEL_BTN;
1042     int         ret = NoError;
1043     char        *new_host, *txt, *p;
1044     bool        host_changed = False;
1045     int         host_type;
1046
1047     if (cancel) {
1048         finish_host_window();
1049         return;
1050     }
1051
1052     /* if (!HostText)   return; */
1053     new_host = NULL;
1054     txt = XmTextFieldGetString(HostText);
1055     if (txt) {
1056         p = trim_line(txt);
1057         new_host = (*p) ? p : NULL;
1058     }
1059     if (new_host) {
1060         if (!(CurHost) || strcmp(CurHost, new_host)) {
1061             host_type = check_hostname(new_host);
1062
1063             switch (host_type) {
1064                 case HOST_LOCAL:
1065                     new_host = NULL;
1066                     if (CurHost)
1067                         host_changed = True;
1068                     break;
1069                 case HOST_REMOTE:
1070                     host_changed = True;
1071                     break;
1072                 case HOST_UNKNOWN:
1073                     host_changed = False;
1074                     put_xims_errmsg(ErrUnknownHost, new_host, 0, 0);
1075
1076                         /* don't finish window */
1077                     XtFree(txt);
1078                     return;
1079             }
1080         }
1081     } else if (CurHost) {               /* 'new_host == NULL' ==> local host */
1082         host_type = HOST_LOCAL;
1083         host_changed = True;
1084     }
1085
1086     DPR(("host_cb(): hostname %s changed '%s' (<- %s)\n",
1087                             host_changed ? NULL : "NOT", new_host, CurHost));
1088
1089     if (host_changed) {
1090         char    *last_ims = NULL;
1091
1092             /* save the name of selected ims */
1093         if (CurIdx >= 0 && CurIdx < curList->num_ent)
1094             last_ims = NEWSTR(curList->elist[CurIdx]->name);
1095
1096         ret = change_host(new_host, host_type);
1097         if (ret == NoError) {
1098             finish_host_window();
1099             change_ims_list(last_ims, -1);
1100             selection_changed = True;
1101         } else {
1102             if (ret != ErrRemoteAction) {
1103                 put_xims_errmsg(ret, new_host, 0, 0);
1104             }
1105                 /* don't finish window */
1106         }
1107
1108         FREE(last_ims);
1109     } else {
1110         finish_host_window();
1111     }
1112
1113     XtFree(txt);
1114
1115 #ifdef  DEBUG
1116     pr_brk("host_done_window");
1117 #endif
1118 }
1119
1120 static void     host_clear_cb(w, client_data, call_data)
1121     Widget      w;
1122     XtPointer   client_data, call_data;
1123 {
1124     /* if (!HostText)   return; */
1125     XtVaSetValues(HostText, XmNvalue, "", NULL);
1126 }
1127
1128 static void     host_done_action(w, ev, args, num_args)
1129     Widget      w;
1130     XEvent      *ev;
1131     String      *args;
1132     Cardinal    *num_args;
1133 {
1134     host_done_cb(w, (XtPointer) OK_BTN, 0);
1135 }
1136
1137 static void     create_host_window(cur_host)
1138     char        *cur_host;
1139 {
1140     Widget      form, cmd_rc, lb1, sep, w_tbl[5];
1141     Widget      host_desc, host_rc, host_lb, host_txt;
1142     Arg         args[16], hargs[8];
1143     int         i, j, n;
1144     Widget      hw[4];
1145     int         nhw = 0;
1146     XtTranslations      trans;
1147     static char         host_trans[] = "<Key>Return: host-done()";
1148     static XtActionsRec host_actions[] = {
1149         { "host-done", (XtActionProc) host_done_action }
1150     };
1151
1152         i = 0;
1153         XtSetArg(args[i], XmNmwmFunctions, WIN_FUNC); i++;
1154         XtSetArg(args[i], XmNmwmDecorations, WIN_DECR); i++;
1155         XtSetArg(args[i], XmNdefaultPosition, False); i++;
1156         XtSetArg(args[i], XmNnoResize, True); i++;
1157         XtSetArg(args[i], XmNallowShellResize, True); i++;
1158         XtSetArg(args[i], XmNmappedWhenManaged, False); i++;
1159         XtSetArg(args[i], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); i++;
1160     HostW =
1161     form = XmCreateFormDialog(TopW, "Host", args, i);
1162
1163         /* for child of form */
1164         i = 0;
1165         XtSetArg(args[i], XmNtopAttachment, XmATTACH_WIDGET); i++;
1166         XtSetArg(args[i], XmNleftAttachment, XmATTACH_FORM); i++;
1167         XtSetArg(args[i], XmNrightAttachment, XmATTACH_FORM); i++;
1168     n = 0;
1169     w_tbl[n] = 0;
1170         XtSetArg(args[i], XmNtopWidget, w_tbl[n]);
1171     w_tbl[n] = lb1 = XmCreateLabelGadget(form, "title", args, i + 1);
1172
1173         XtSetArg(args[i], XmNtopWidget, w_tbl[n]);
1174         j = i + 1;
1175         XtSetArg(args[j], XmNmarginHeight, 8); j++;
1176         XtSetArg(args[j], XmNmarginWidth, 8); j++;
1177     w_tbl[++n] = host_desc = XmCreateLabelGadget(form, "host_desc", args, j);
1178
1179         XtSetArg(args[i], XmNtopWidget, w_tbl[n]);
1180         j = i + 1;
1181         XtSetArg(args[j], XmNorientation, XmHORIZONTAL); j++;
1182         XtSetArg(args[j], XmNpacking, XmPACK_TIGHT); j++;
1183         XtSetArg(args[j], XmNisAligned, TRUE); j++;
1184         XtSetArg(args[j], XmNentryAlignment, XmALIGNMENT_BEGINNING); j++;
1185         XtSetArg(args[j], XmNentryBorder, 0); j++;
1186         XtSetArg(args[j], XmNmarginHeight, 1); j++;
1187         /* XtSetArg(args[j], XmNmarginWidth, 20); j++; */
1188     w_tbl[++n] = host_rc = XmCreateRowColumn(form, "host_rc", args, j);
1189
1190     nhw = 0;
1191         j = 0;
1192         XtSetArg(hargs[j], XmNalignment, XmALIGNMENT_BEGINNING); j++;
1193     hw[nhw++] = host_lb = XmCreateLabelGadget(host_rc, "host_label", hargs, j);
1194         j = 0;
1195         /* XtSetArg(hargs[j], XmNcolumns, TEXT_COLUMNS); j++; */
1196         /* XtSetArg(hargs[j], XmNmaxLength, MAX_HOSTNAME_LEN); j++; */
1197         XtSetArg(hargs[j], XmNeditable, True); j++;
1198         XtSetArg(hargs[j], XmNvalue, cur_host); j++;
1199         XtSetArg(hargs[j], XmNmarginHeight, 1); j++;
1200         XtSetArg(hargs[j], XmNmarginWidth, 1); j++;
1201     HostText =
1202     hw[nhw++] = host_txt = XmCreateTextField(host_rc, "host_text", hargs, j);
1203     XtManageChildren(hw, nhw);
1204
1205         XtSetArg(args[i], XmNtopWidget, w_tbl[n]);
1206     w_tbl[++n] = sep = XmCreateSeparatorGadget(form, "sep", args, i + 1);
1207         XtSetArg(args[i], XmNtopWidget, w_tbl[n]);
1208         XtSetArg(args[i+1], XmNbottomAttachment, XmATTACH_FORM);
1209     w_tbl[++n] = cmd_rc = XmCreateRowColumn(form, "cmd_rc", args, i + 2);
1210     XtManageChildren(w_tbl, ++n);
1211
1212     add_cmd_btn(cmd_rc, host_done_cb, host_clear_cb, host_done_cb, 0, 0);
1213
1214     /* set 'host-done' action for 'Return' key */
1215     XtAppAddActions(appC, host_actions, XtNumber(host_actions));
1216     trans = XtParseTranslationTable(host_trans);
1217     XtOverrideTranslations(HostText, trans);
1218
1219     XtManageChild(HostW); locate_window(HostW); XtUnmanageChild(HostW);
1220     XtVaSetValues(XtParent(HostW), XmNmappedWhenManaged, True, NULL);
1221     XtVaSetValues(HostW, XmNmappedWhenManaged, True, NULL);
1222     set_cursor(HostW, False);
1223
1224     return;
1225 }
1226
1227
1228         /* ********  mode window ******** */
1229
1230 static int      OrgMode = SEL_MODE_NONE;
1231 static int      CurMode = SEL_MODE_NONE;
1232
1233 int     start_mode_window(cur_mode)
1234     int         cur_mode;
1235 {
1236     int ret;
1237
1238     OrgMode = CurMode = cur_mode;
1239
1240     if ((ret = init_window_env()) != NoError)
1241         return ret;
1242
1243     if ((ret = create_mode_window(cur_mode)) != NoError)
1244         return ret;
1245
1246     /* handle system Menu's "close" */
1247     XmAddWMProtocolCallback(XtParent(ModeW),
1248                         XmInternAtom(Dpy, "WM_DELETE_WINDOW", True),
1249                         (XtCallbackProc)mode_done_cb, (XtPointer)CANCEL_BTN);
1250
1251     locate_window(ModeW);
1252     XtManageChild(ModeW);
1253     XtPopup(XtParent(ModeW), XtGrabNone);
1254
1255     if (FocusW)
1256         XmProcessTraversal(FocusW, XmTRAVERSE_CURRENT);
1257
1258     XtAppMainLoop(appC);
1259     /* not rearched */
1260 }
1261
1262 static void     finish_mode_window(end_window)
1263     int         end_window;
1264 {
1265     if (ModeW) {
1266         XtUnmanageChild(ModeW);
1267         XtPopdown(XtParent(ModeW));
1268         XtDestroyWidget(XtParent(ModeW));
1269         ModeW = (Widget) 0;
1270     }
1271     stop_help();
1272
1273     if (end_window)
1274         end_window_env();
1275
1276     return;
1277 }
1278
1279 static void     mode_done_cb(w, client_data, call_data)
1280     Widget      w;
1281     XtPointer   client_data, call_data;
1282 {
1283     int         ret = NoError;
1284     int         canceled = (int)client_data == CANCEL_BTN;
1285
1286     DPR(("mode_done(%s):\torg=%d  cur=%d\n",
1287                                 canceled ? "Cancel" : "OK", OrgMode, CurMode));
1288     if (canceled) {
1289         OpErrCode = NoError;
1290         OpState = State_Mode_Canceled;
1291     } else {
1292         ret = set_select_mode(OrgMode, CurMode);
1293
1294         OpErrCode = ret;
1295         OpState = State_Mode_Done;
1296
1297         if (OpErrCode != NoError) {
1298             finish_mode_window(False);
1299             LastErrMsg = OpErrCode;
1300             put_xims_errmsg(OpErrCode, 0, 0, 0);
1301             if (WaitingDialogReply) {
1302                 DPR(("mode_done_cb(): enter xevent_loop()\n"));
1303                 xevent_loop();  /* never returns */
1304             }
1305         }
1306     }
1307     finish_mode_window(True);
1308         /* never returns */
1309 }
1310
1311 static void     mode_cb(w, client_data, call_data)
1312     Widget      w;
1313     XtPointer   client_data, call_data;
1314 {
1315     int         is_set = (int)((XmToggleButtonCallbackStruct *)call_data)->set;
1316     int         is_auto = (int)client_data;
1317
1318     CurMode = (is_auto && is_set) ? SEL_MODE_AUTO : SEL_MODE_NOAUTO;
1319 }
1320
1321 static void     mode_help_cb(w, client_data, call_data)
1322     Widget      w;
1323     XtPointer   client_data, call_data;
1324 {
1325     ximsHelp(HELP_MODE);
1326 }
1327
1328 static int      create_mode_window(cur_mode)
1329     int         cur_mode;
1330 {
1331     Widget      form, mode_rc, cmd_rc, lb1, sep, w_tbl[8];
1332     Arg         args[16];
1333     int         i, j, n;
1334
1335         i = 0;
1336         XtSetArg(args[i], XmNmwmFunctions, WIN_FUNC); i++;
1337         XtSetArg(args[i], XmNmwmDecorations, WIN_DECR); i++;
1338         XtSetArg(args[i], XmNdefaultPosition, False); i++;
1339         XtSetArg(args[i], XmNnoResize, True); i++;
1340         XtSetArg(args[i], XmNallowShellResize, True); i++;
1341         XtSetArg(args[i], XmNmappedWhenManaged, False); i++;
1342     ModeW =
1343     form = XmCreateFormDialog(TopW, "Mode", args, i);
1344
1345         /* for child of form */
1346         i = 0;
1347         XtSetArg(args[i], XmNtopAttachment, XmATTACH_WIDGET); i++;
1348         XtSetArg(args[i], XmNleftAttachment, XmATTACH_FORM); i++;
1349         XtSetArg(args[i], XmNrightAttachment, XmATTACH_FORM); i++;
1350     n = 0;
1351     w_tbl[n] = 0;
1352         XtSetArg(args[i], XmNtopWidget, w_tbl[n]);
1353     w_tbl[n] = lb1 = XmCreateLabelGadget(form, "title", args, i + 1);
1354
1355         XtSetArg(args[i], XmNtopWidget, w_tbl[n]);
1356         j = i + 1;
1357         XtSetArg(args[j], XmNisAligned, TRUE); j++;
1358         XtSetArg(args[j], XmNentryAlignment, XmALIGNMENT_BEGINNING); j++;
1359         XtSetArg(args[j], XmNentryBorder, 0); j++;
1360         XtSetArg(args[j], XmNmarginHeight, 10); j++;
1361         XtSetArg(args[j], XmNmarginWidth, 30); j++;
1362
1363 #ifdef  SelectByReturn
1364                 /* use TB */
1365         XtSetArg(args[j], XmNorientation, XmHORIZONTAL); j++;
1366         XtSetArg(args[j], XmNpacking, XmPACK_COLUMN); j++;
1367         XtSetArg(args[j], XmNnumColumns, NUM_SEL_MODE); j++;
1368     w_tbl[++n] = mode_rc = XmCreateRadioBox(form, "mode_rc", args, j);
1369     {
1370         Arg     bargs[8];
1371         Widget  tb[NUM_SEL_MODE];
1372         int     k = 0;
1373         int     set_idx = cur_mode == SEL_MODE_AUTO ? 1 : 0;
1374
1375         k = 0;
1376         XtSetArg(bargs[k], XmNspacing, 10); k++;
1377         tb[0] = createTB(mode_rc, "button_0", bargs, k);
1378         tb[1] = createTB(mode_rc, "button_1", bargs, k);
1379         for (k = 0; k < NUM_SEL_MODE; k++) {
1380             XtVaSetValues(tb[k], XmNset, k == set_idx ? True : False, NULL);
1381             XtAddCallback(tb[k], XmNvalueChangedCallback, mode_cb, (XtPointer)k);
1382             add_btn_trans(tb[k]);
1383         }
1384         XtManageChildren(tb, NUM_SEL_MODE);
1385     }
1386 #else
1387                 /* use TBGadget */
1388         XtSetArg(args[j], XmNbuttonCount, NUM_SEL_MODE); j++;
1389         XtSetArg(args[j], XmNbuttonSet, cur_mode == SEL_MODE_AUTO ? 1 : 0); j++;
1390         XtSetArg(args[j], XmNsimpleCallback, mode_cb); j++;
1391     w_tbl[++n] = mode_rc = XmCreateSimpleRadioBox(form, "mode_rc", args, j);
1392 #endif  /* SelectByReturn */
1393
1394         XtSetArg(args[i], XmNtopWidget, w_tbl[n]);
1395     w_tbl[++n] = sep = XmCreateSeparatorGadget(form, "sep", args, i + 1);
1396         XtSetArg(args[i], XmNtopWidget, w_tbl[n]);
1397         XtSetArg(args[i+1], XmNbottomAttachment, XmATTACH_FORM);
1398     w_tbl[++n] = cmd_rc = XmCreateRowColumn(form, "cmd_rc", args, i + 2);
1399     XtManageChildren(w_tbl, ++n);
1400
1401     add_cmd_btn(cmd_rc, mode_done_cb, 0, mode_done_cb, 0, mode_help_cb);
1402
1403     XtManageChild(ModeW); locate_window(ModeW); XtUnmanageChild(ModeW);
1404     XtVaSetValues(XtParent(ModeW), XmNmappedWhenManaged, True, NULL);
1405     XtVaSetValues(ModeW, XmNmappedWhenManaged, True, NULL);
1406     set_cursor(ModeW, False);
1407
1408     return NoError;
1409 }
1410
1411
1412         /* ********  ximsHelp  ******** */
1413
1414 static void     help_ok(w, client_data, call_data)
1415     Widget      w;
1416     XtPointer   client_data, call_data;
1417 {
1418     stop_help();
1419 }
1420
1421 void    stop_help()
1422 {
1423     if (HelpW) {
1424         XtUnmanageChild(HelpW);
1425         XtPopdown(XtParent(HelpW));
1426     }
1427 }
1428
1429 static void     create_help()
1430 {
1431     int         i;
1432     Arg         args[10];
1433
1434         i = 0;
1435         XtSetArg(args[i], XmNmwmFunctions, WIN_FUNC); i++;
1436         XtSetArg(args[i], XmNmwmDecorations, WIN_DECR); i++;
1437         XtSetArg(args[i], XmNautoUnmanage, True); i++;
1438         XtSetArg(args[i], XmNdefaultPosition, False); i++;
1439         XtSetArg(args[i], XmNnoResize, True); i++;
1440         XtSetArg(args[i], XmNallowShellResize, True); i++;
1441         XtSetArg(args[i], XmNmappedWhenManaged, False); i++;
1442     HelpW = XmCreateInformationDialog(TopW, "Help", args, i);
1443
1444     XtUnmanageChild(XmMessageBoxGetChild(HelpW, XmDIALOG_CANCEL_BUTTON));
1445     XtUnmanageChild(XmMessageBoxGetChild(HelpW, XmDIALOG_HELP_BUTTON));
1446     XtAddCallback(HelpW, XmNokCallback, help_ok, (XtPointer)0);
1447
1448         /* help_dialog is not located correctly unless once managed */
1449     /* XtSetMappedWhenManaged(XtParent(HelpW), False); */
1450     XtManageChild(HelpW);
1451     XtUnmanageChild(HelpW);
1452     XtSetMappedWhenManaged(XtParent(HelpW), True);
1453     XtSetMappedWhenManaged(HelpW, True);
1454     set_cursor(HelpW, False);
1455
1456     return;
1457 }
1458
1459 void    ximsHelp(help_type)
1460     int         help_type;
1461 {
1462     char        *msg = NULL;
1463     XmString    str;
1464     static int  last_help_type = -1;
1465
1466     if (!HelpW)
1467         create_help();
1468
1469     if (help_type != last_help_type) {
1470
1471         switch (help_type) {
1472             case HELP_MODE:             msg = appres.modeHelpMsg; break;
1473             default:
1474             case HELP_SELECTION:        msg = appres.selectionHelpMsg; break;
1475         }
1476
1477         if (!msg || !*msg) {
1478             Beep();
1479 #ifdef  DEBUG
1480             if (DebugLvl > 0)
1481                 msg = "help message not defined in resource file\n";
1482             else
1483 #endif
1484                 return;
1485         }
1486
1487         if (XtIsManaged(HelpW))
1488             XtUnmanageChild(HelpW);
1489
1490         str = XmStringCreateLocalized(msg);
1491         XtVaSetValues(HelpW, XmNmessageString, str, NULL);
1492         XmStringFree(str);
1493
1494         last_help_type = help_type;
1495     }
1496
1497     locate_window(HelpW);
1498     XtManageChild(HelpW);
1499     XtPopup(XtParent(HelpW), XtGrabNone);
1500 }
1501
1502
1503         /* ********  message dialog  ******** */
1504
1505 static int      dialog_resp = XmCR_NONE;
1506 static bool     in_confirmation = False;
1507
1508 static void     dialog_resp_cb(w, client_data, call_data)
1509     Widget      w;
1510     XtPointer   client_data, call_data;
1511 {
1512     Widget      msg_box = (Widget) client_data;
1513     XmAnyCallbackStruct *cbs = (XmAnyCallbackStruct *) call_data;
1514
1515     dialog_resp = cbs->reason;
1516     XtUnmanageChild(msg_box);
1517
1518     if (!in_confirmation) {
1519         WaitingDialogReply = False;
1520         DPR3(("dialog_resp_cb(): WaitingDialogReply ==> False\n"));
1521
1522         if (InWaitingState())
1523             ximsMain();
1524     }
1525 }
1526
1527 #ifdef  unused
1528 static int      wait_confirmation(w)
1529     Widget      w;
1530 {
1531     XtAppContext        context;
1532
1533     dialog_resp = XmCR_NONE;
1534
1535     /* XtManageChild(w); */
1536     /* context = XtWidgetToApplicationContext(w); */
1537     context = appC;
1538     in_confirmation = True;
1539     while (dialog_resp == XmCR_NONE || XtAppPending(context)) {
1540         XtAppProcessEvent(context, XtIMAll);
1541     }
1542     XtUnmanageChild(w);
1543     in_confirmation = False;
1544
1545     return dialog_resp;
1546 }
1547 #endif  /* unused */
1548
1549 int     put_msg_win(type, msg)
1550     int         type;
1551     char        *msg;
1552 {
1553     int         reply;
1554     Widget      btn;
1555     int         wait_resp = FALSE;
1556     XmString    str;
1557     int         ret;
1558
1559     DPR3(("put_msg_win(type=%d):\tmsg=%s", type, msg));
1560
1561     if (!msg || !*msg) {
1562         DPR(("put_msg_win(): msg is empty\n"));
1563         return -1;
1564     } else if (msg[strlen(msg) - 1] != '\n') {
1565         DPR(("put_msg_win(): msg isn't terminated by '\\n'\n"));
1566         return -1;
1567     }
1568
1569     switch (type) {
1570         case MSGTYP_FATAL:              type = XmDIALOG_ERROR; break;
1571         case MSGTYP_WARN:               type = XmDIALOG_WARNING; break;
1572         case MSGTYP_CONFIRM:            type = XmDIALOG_QUESTION;
1573                                         wait_resp = TRUE; break;
1574         default:
1575         case MSGTYP_INFO:               type = XmDIALOG_INFORMATION; break;
1576     }
1577
1578     if ((ret = init_window_env()) != NoError)
1579         return -1;
1580
1581     if (!MsgW) {                /* create message dialog */
1582         Arg     args[10];
1583         int     i = 0;
1584
1585         XtSetArg(args[i], XmNautoUnmanage, True); i++;
1586         XtSetArg(args[i], XmNmwmFunctions, WIN_FUNC); i++;
1587         XtSetArg(args[i], XmNmwmDecorations, WIN_DECR); i++;
1588         XtSetArg(args[i], XmNdefaultButtonType, XmDIALOG_OK_BUTTON); i++;
1589         XtSetArg(args[i], XmNdefaultPosition, False); i++;
1590         XtSetArg(args[i], XmNnoResize, True); i++;
1591         XtSetArg(args[i], XmNallowShellResize, True); i++;
1592         XtSetArg(args[i], XmNmappedWhenManaged, False); i++;
1593         MsgW = XmCreateMessageDialog(TopW, "Message", args, i);
1594             XtUnmanageChild(XmMessageBoxGetChild(MsgW, XmDIALOG_HELP_BUTTON));
1595         XtAddCallback(MsgW, XmNokCallback, dialog_resp_cb, (XtPointer)MsgW);
1596         XtAddCallback(MsgW, XmNcancelCallback, dialog_resp_cb, (XtPointer)MsgW);
1597
1598         /* dialog is not located correctly unless once managed */
1599         XtManageChild(MsgW); XtUnmanageChild(MsgW);
1600         XtSetMappedWhenManaged(XtParent(MsgW), True);
1601         XtSetMappedWhenManaged(MsgW, True);
1602         set_cursor(MsgW, False);
1603     }
1604     btn = XmMessageBoxGetChild(MsgW, XmDIALOG_CANCEL_BUTTON);
1605
1606     if (wait_resp)      XtManageChild(btn);
1607     else                XtUnmanageChild(btn);
1608
1609     str = XmStringCreateLocalized(msg);
1610     XtVaSetValues(MsgW, XmNdialogType, type,
1611                         XmNmessageString, str,
1612                         XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL,
1613                         /*
1614                         XmNdialogStyle, wait_resp ? XmDIALOG_FULL_APPLICATION_MODAL
1615                                                         : XmDIALOG_MODELESS,
1616                         */
1617                         NULL);
1618     XmStringFree(str);
1619
1620     locate_window(MsgW);
1621     XtManageChild(MsgW);
1622     if (type == MSGTYP_FATAL || type == MSGTYP_WARN) {
1623         Beep();
1624     }
1625
1626     reply = XmCR_OK;
1627     if (wait_resp) {
1628 #ifdef  unused
1629         DPR3(("wait_dialog_resp(START): WaitingDialogReply ==> True\n"));
1630         WaitingDialogReply = True;
1631
1632         reply = wait_confirmation(MsgW);
1633
1634         WaitingDialogReply = False;
1635         DPR3(("wait_dialog_resp(DONE): WaitingDialogReply ==> False\n"));
1636 #endif  /* unused */
1637     } else {
1638         DPR3(("put_msg_win(): WaitingDialogReply ==> True\n"));
1639         WaitingDialogReply = True;
1640     }
1641
1642     return reply == XmCR_OK ? True : False;
1643 }
1644
1645
1646         /* ********  locate_window  ******** */
1647
1648 #define LOC_NONE                -1
1649 #define LOC_CENTER              0
1650 #define LOC_TOP                 (1<<0)
1651 #define LOC_BOTTOM              (1<<1)
1652 #define LOC_LEFT                (1<<2)
1653 #define LOC_RIGHT               (1<<3)
1654 #define LOC_MARGIN              5
1655
1656 static int      window_location(loc_str)
1657     char        *loc_str;
1658 {
1659     int         locate_type = LOC_CENTER;
1660     char        *lower_str, *p;
1661
1662     lower_str = NEWSTR(loc_str);
1663     if (p = lower_str) {
1664         to_lower_str(p);
1665         if (strstr(lower_str, "center"))        locate_type |= LOC_CENTER;
1666         if (strstr(lower_str, "top"))           locate_type |= LOC_TOP;
1667         if (strstr(lower_str, "bottom"))        locate_type |= LOC_BOTTOM;
1668         if (strstr(lower_str, "left"))          locate_type |= LOC_LEFT;
1669         if (strstr(lower_str, "right"))         locate_type |= LOC_RIGHT;
1670         FREE(lower_str);
1671     }
1672     return locate_type;
1673 }
1674
1675 static void     locate_window(w)
1676     Widget      w;
1677 {
1678     int         scr;
1679     int         x, y;
1680     int         dpy_w, dpy_h;
1681     Dimension   width, height;
1682     static int  locate_type = LOC_NONE;
1683
1684     /* if (!isXsession())       return; */
1685
1686     if (locate_type == LOC_NONE) {
1687         locate_type = window_location(appres.windowLocation);
1688         DPR3(("locate_window(): locate_type=%d (%s)\n",
1689                                 locate_type, appres.windowLocation));
1690     }
1691
1692     width = height = (Dimension) 0;
1693     scr = XDefaultScreen(Dpy);
1694     dpy_w = DisplayWidth(Dpy, scr);
1695     dpy_h = DisplayHeight(Dpy, scr);
1696
1697     XtVaGetValues(w, XmNwidth, &width, XmNheight, &height, NULL);
1698
1699     x = y = 0;
1700     if (locate_type) {
1701         if (locate_type & LOC_TOP)      y = LOC_MARGIN;
1702         if (locate_type & LOC_BOTTOM)   y = dpy_h - height - LOC_MARGIN * 2;
1703         if (locate_type & LOC_LEFT)     x = LOC_MARGIN;
1704         if (locate_type & LOC_RIGHT)    x = dpy_w - width - LOC_MARGIN * 2;
1705     }
1706     if (!x)     x = (int) (dpy_w - width - LOC_MARGIN * 2) / 2;
1707     if (!y)     y = (int) (dpy_h - height - LOC_MARGIN * 2) / 2;
1708
1709     DPR3(("locate_window(): w=%d h=%d ==> x=%d y=%d\n", width, height, x, y));
1710
1711     XtVaSetValues(w, XmNx, x, XmNy, y, NULL);
1712 }
1713
1714
1715         /* ********  cursor (normal / wait)  ******** */
1716
1717 static void     set_cursor(w, is_wait)
1718     Widget      w;
1719     int         is_wait;
1720 {
1721     static Cursor       cursors[2] = { None, None };
1722     int         idx;
1723
1724     idx = is_wait ? 1 : 0;
1725
1726     /* if (!Dpy || !TopW || !w) return; */
1727     if (cursors[idx] == None) {
1728         cursors[idx] = XCreateFontCursor(Dpy, idx ? XC_watch : XC_left_ptr);
1729     }
1730
1731     XDefineCursor(Dpy, XtWindow(w), cursors[idx]);
1732     XFlush(Dpy);
1733 }
1734
1735
1736         /* *****  waiting functions  ***** */
1737 void    xevent_loop()
1738 {
1739     if (appC)
1740         XtAppMainLoop(appC);
1741 }
1742
1743 static time_t           xt_start_tm = 0L;       /* in sec */
1744 static XtIntervalId     xt_last_timer = (XtIntervalId)0;
1745 static bool             xt_waiting = False;
1746
1747 void    xt_start_waiting()
1748 {
1749     if (!appC)  return;
1750
1751     xt_start_tm = time((time_t) 0);
1752     xt_last_timer = XtAppAddTimeOut(appC, (unsigned long) Opt.Interval,
1753                                                 xt_timer_cb, (XtPointer)0);
1754     /* if (!xt_last_timer)      return; */
1755
1756     DPR(("xt_start_waiting(): EventLoop (interval=%d)\n", Opt.Interval));
1757
1758     xt_waiting = True;
1759     XtAppMainLoop(appC);
1760 }
1761
1762 void    xt_stop_waiting()
1763 {
1764     if (xt_last_timer) {
1765         XtRemoveTimeOut(xt_last_timer);
1766         xt_last_timer = (XtIntervalId) 0;
1767     }
1768
1769     xt_waiting = False;
1770     ximsWaitDone();
1771 }
1772
1773 static void     xt_timer_cb(client_data, timer_id)
1774     XtPointer           client_data;
1775     XtIntervalId        *timer_id;
1776 {
1777     int         lapse;
1778
1779     /* DPR3(("xt_timer_cb(timer_id=%d): last_timer=%d\n",
1780                                                 *timer_id, xt_last_timer)); */
1781
1782     if (*timer_id != xt_last_timer)     return;
1783     xt_last_timer = (XtIntervalId) 0;
1784     lapse = (int) time((time_t) 0) - xt_start_tm;
1785
1786 #ifdef  DEBUG
1787     if (DebugLvl >= 1)  putc('.', LogFp), fflush(LogFp);
1788 #endif
1789
1790     if (im_mod_available((RunEnv *) 0) != 0 || lapse >= Opt.Timeout) {
1791         DPR(("xt_timer_cb(tmout=%d): wait done (%d sec.)\n",
1792                                                         Opt.Timeout, lapse));
1793         xt_stop_waiting();      /* never returns */
1794     }
1795
1796     xt_last_timer = XtAppAddTimeOut(appC, (unsigned long) Opt.Interval,
1797                                                 xt_timer_cb, (XtPointer)0);
1798     return;
1799 }
1800