Convert uses of XKeycodeToKeysym (deprecated) to XkbKeycodeToKeysym
[oweals/cde.git] / cde / programs / dtinfo / clients / dtinfo_start / dtinfo_start.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 libraries 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: dtinfo_start.c /main/9 1999/09/20 13:26:59 mgreess $
24  *
25  * (c) Copyright 1996 Digital Equipment Corporation.
26  * (c) Copyright 1996 Hewlett-Packard Company.
27  * (c) Copyright 1996 International Business Machines Corp.
28  * (c) Copyright 1996 Sun Microsystems, Inc.
29  * (c) Copyright 1996 Novell, Inc. 
30  * (c) Copyright 1996 FUJITSU LIMITED.
31  * (c) Copyright 1996 Hitachi.
32  *
33  * This file contains the main program for: dtinfo_start
34  */
35
36 #include <stdio.h>
37 #include <stdlib.h>
38
39 #include <X11/Intrinsic.h>
40
41 #include <Xm/XmP.h>
42 #include <Xm/XmAll.h>
43
44 #include <Dt/EnvControlP.h>
45 #include <Dt/Action.h>
46 #include <Dt/DtGetMessageP.h>
47 #include <Dt/MsgLog.h>
48 #include <Dt/Dt.h>
49
50 #include <Tt/tt_c.h>
51
52 #include "dtinfo_start.h"
53 #include "dtinfo_start.opnums"
54
55 /*
56  * Operation names, number of arguments and default action names
57  */
58 static const char       * LOAD_INFO_LIB_STRING = "DtInfo_LoadInfoLib";
59 static const int        LOAD_INFO_LIB_ARGS = 3;
60 static const char       * LOAD_INFO_LIB_ACTION = "DtInfoStart";
61
62 static const char       * SHOW_INFO_AT_LOC_STRING = "DtInfo_ShowInfoAtLoc";
63 static const int        SHOW_INFO_AT_LOC_ARGS = 4;
64 static const char       * SHOW_INFO_LIB_SECTION_ACTION = "DtInfoStartAtLoc";
65
66 /*
67  * Static global vars
68  */
69 static Widget           top_level;
70
71 static XtAppContext     app_context;
72
73 static const int        time_out = 1000;        /* milliseconds */
74
75 static const int        SET_NUM = 1;            /* message cat set number */
76
77 static const char       * name = "DtInfo"; /* ptype name and Xt name */
78
79 /*
80  * Forward declarations for static functions
81  */
82 static int InvokeAction (
83         char                    * prog_name, 
84         int                     op_num,
85         const char              * action_name, 
86         char                    * exec_host, 
87         char                    * info_lib, 
88         char                    * topic);
89
90 static void ActionDoneCallback (
91         DtActionInvocationID    id,
92         XtPointer               client_data,
93         DtActionArg             * args,
94         int                     num_args,
95         DtActionStatus          status);
96
97 static void Exit (
98         XtPointer               client_data,
99         XtIntervalId            id);
100
101 static Tt_status ConnectToMessageServer (
102         char                    * prog_name);
103
104 static void ReceiveMessage (
105         XtPointer               client_data,
106         int                     * fd,
107         XtInputId               * id);
108
109 static void LogToolTalkError (
110         DtMsgLogType            msg_type,
111         char                    * prog_name,
112         char                    * function_name,
113         Tt_status               error_num);
114 static void DieFromToolTalkError (
115         Widget                  parent,
116         char                    * errfmt,
117         Tt_status               status);
118
119
120 int
121 main ( 
122         int                     argc,
123         char                    ** argv) 
124 {
125         Display                 * display;
126         Arg                     args[10];
127         int                     i = 0;
128         Tt_status               status;
129   
130         XtSetLanguageProc (NULL, NULL, NULL);
131
132         _DtEnvControl (DT_ENV_SET);
133
134         XtToolkitInitialize ();
135
136         app_context = XtCreateApplicationContext ();
137
138         if (!(display = XtOpenDisplay (app_context, NULL, NULL, name,
139                                        NULL, 0, &argc, argv))) {
140                 DtMsgLogMessage (argv[0], DtMsgLogError, 
141                         (char *) GETMESSAGE (SET_NUM, 7, "XtOpenDisplay() failed.  Perhaps the DISPLAY environment\nvariable is not set or is invalid."));
142                 exit (1);
143         }
144   
145         /*
146          * Create a minimalist application shell - needed by
147          * DtActionInvoke.
148          */
149         XtSetArg (args[i], XtNallowShellResize,         True);  i++;
150         XtSetArg (args[i], XtNmappedWhenManaged,        False); i++;
151         XtSetArg (args[i], XtNheight,                   1);     i++;
152         XtSetArg (args[i], XtNwidth,                    1);     i++;
153
154         top_level = XtAppCreateShell (argv[0], 
155                                       name, 
156                                       topLevelShellWidgetClass, 
157                                       display, 
158                                       args, 
159                                       i);
160
161         XtRealizeWidget (top_level);
162
163         /*  
164          * Initialize the desktop
165          */
166         if (DtAppInitialize (app_context, display, top_level,
167                              argv[0], (char *)name) == False) {
168                 DtMsgLogMessage (argv[0], DtMsgLogError, 
169                         (char *) GETMESSAGE (SET_NUM, 8, "DtAppInitialize() failed.  Perhaps the desktop environment\nis not properly installed."));
170                 exit (1);
171         }
172
173         /*
174          * Connect to the message server
175          */
176         status = ConnectToMessageServer (argv[0]);
177         if (TT_OK != status) {
178                 char *errfmt;
179
180                 /*
181                  * An error Message has already been logged.
182                  */
183                 errfmt = GETMESSAGE (2, 2,
184                           "Could not connect to ToolTalk:\n%s\nExiting ...");
185                 DieFromToolTalkError (top_level, errfmt, status);
186         }
187
188         /* 
189          * Load the datatypes and actions 
190          */
191         DtDbLoad();
192
193         XtAppMainLoop (app_context);
194
195         return (0);
196 }
197
198
199 static int
200 InvokeAction (
201         char                    * prog_name, 
202         int                     op_num,
203         const char              * action_name, 
204         char                    * exec_host, 
205         char                    * info_lib, 
206         char                    * topic)
207 {
208         DtActionArg             * args;
209         int                     num_args = 1;
210         DtActionInvocationID    action_id;
211
212         if (op_num == SHOW_INFO_AT_LOC)
213                 num_args = 2;
214
215         args = (DtActionArg *) XtCalloc (num_args, sizeof (DtActionArg));
216         if (!args) {
217                 DtMsgLogMessage (prog_name, DtMsgLogError, 
218                         (char *) GETMESSAGE (SET_NUM, 6,
219                         "Cannot invoke an action because malloc(1) failed."));
220                 return (0);
221         }
222
223         args[0].argClass = DtACTION_FILE;
224         args[0].u.file.name = info_lib;
225
226         if (op_num == SHOW_INFO_AT_LOC) {
227                 args[1].argClass = DtACTION_BUFFER;
228                 args[1].u.buffer.name = topic;
229                 args[1].u.buffer.size = strlen (topic) + 1;
230                 args[1].u.buffer.writable = False;
231         }
232
233         action_id = DtActionInvoke (top_level,
234                                     (char *) action_name,
235                                     args,
236                                     num_args,
237                                     NULL,
238                                     exec_host,
239                                     NULL,
240                                     True,
241                                     (DtActionCallbackProc) ActionDoneCallback,
242                                     prog_name);
243
244 #if defined(DEBUG)
245         DtMsgLogMessage (prog_name, DtMsgLogError, "Invoked %s\n", action_name);
246 #endif
247
248         /*
249          * The following test, comment and code are from:
250          *   $TOP/dtaction/Main.c
251          *
252          * "Set up a timer if we didn't get a valid procId --
253          *  since there will be no invocation update in that case."
254          */
255         if (!action_id) {
256                 XtAppAddTimeOut (app_context,
257                                  10, 
258                                  (XtTimerCallbackProc) Exit,
259                                  NULL);
260         }
261
262         return (1);
263 }
264
265
266 /* ARGSUSED */
267 static void 
268 ActionDoneCallback (
269         DtActionInvocationID    id,
270         XtPointer               client_data,
271         DtActionArg             * args,
272         int                     num_args,
273         DtActionStatus          status)
274 {
275 #if defined(DEBUG)
276         char *status_name;
277
278         switch (status) {
279                 case DtACTION_DONE:
280                     status_name = "DtACTION_DONE";
281                     break;
282                 case DtACTION_OK:
283                     status_name = "DtACTION_DONE";
284                     break;
285                 case DtACTION_INVOKED:
286                     status_name = "DtACTION_DONE";
287                     break;
288                 case DtACTION_FAILED:
289                     status_name = "DtACTION_DONE";
290                     break;
291                 case DtACTION_CANCELED:
292                     status_name = "DtACTION_DONE";
293                     break;
294                 case DtACTION_INVALID_ID:
295                     status_name = "DtACTION_DONE";
296                     break;
297                 case DtACTION_STATUS_UPDATE:
298                     status_name = "DtACTION_DONE";
299                     break;
300                 default:
301                     status_name = "UNKNOWN";
302                     break;
303         }
304 #endif
305         switch (status) {
306                 case DtACTION_DONE:
307                 case DtACTION_OK:
308 #if defined(DEBUG)
309                         DtMsgLogMessage ("dtinfo_start", DtMsgLogError,
310                                          "Action returned %s\n", status_name);
311 #endif
312                         XtAppAddTimeOut(app_context, 10 * time_out, 
313                                         (XtTimerCallbackProc) Exit,
314                                         NULL);
315
316                 case DtACTION_INVOKED:
317                 case DtACTION_FAILED:
318                 case DtACTION_CANCELED:
319                 case DtACTION_INVALID_ID:
320                 case DtACTION_STATUS_UPDATE:
321                 default:
322 #if defined(DEBUG)
323                         DtMsgLogMessage ("dtinfo_start", DtMsgLogError,
324                                          "Action returned %s\n", status_name);
325 #endif
326                         XtAppAddTimeOut(app_context, 10 * time_out, 
327                                         (XtTimerCallbackProc) Exit,
328                                         NULL);
329         }
330 }
331
332
333 static Tt_status
334 ConnectToMessageServer (
335         char                    * prog_name)
336 {
337         int                     mark;
338         char                    * procid;
339         int                     ttfd;
340         Tt_status               status;
341   
342         mark = tt_mark();
343
344         procid = tt_open();
345         status = tt_pointer_error (procid);
346         if (status != TT_OK) {
347                 LogToolTalkError (DtMsgLogError, prog_name,
348                                     "tt_open", status);
349                 tt_release (mark);
350                 return (status);
351         }
352   
353         status = tt_ptype_declare (name);
354         if (status != TT_OK) {
355                 LogToolTalkError (DtMsgLogError, prog_name, 
356                                     "tt_ptype_declare", status);
357                 tt_release (mark);
358                 return (status);
359         }
360
361         ttfd = tt_fd ();
362         if ((tt_int_error (ttfd)) != TT_OK) {
363                 LogToolTalkError (DtMsgLogError, prog_name, 
364                                     "tt_fd", status);
365                 tt_release (mark);
366                 return (status);
367         }
368
369         XtAppAddInput (app_context, ttfd, (XtPointer) XtInputReadMask,
370                        ReceiveMessage, (char *) prog_name);
371
372         status = tt_session_join (tt_default_session());
373         if ((tt_int_error (ttfd)) != TT_OK) {
374                 LogToolTalkError (DtMsgLogError, prog_name, 
375                                     "tt_session_join", status);
376                 tt_release (mark);
377                 return (status);
378         }
379   
380         tt_release(mark);
381
382         return (TT_OK);
383 }
384
385
386 /* ARGSUSED */
387 static void
388 ReceiveMessage (
389         XtPointer               client_data,
390         int                     * fd,
391         XtInputId               * id)
392 {
393         static int              last_op_num = 0;
394         int                     op_num;
395         int                     opstatus;
396         int                     num_args;
397         Tt_message              message;
398         const char              * action_name;
399         char                    * exec_host;
400         char                    * locale;
401         char                    * topic = NULL;
402         char                    * prog_name = (char *) client_data;
403         static                  char lang[200];
404         const char              * op_name;
405         char                    * info_lib = NULL;
406
407         message = tt_message_receive();
408
409         /* from tt_message_receive(3), and after examining other TT clients */
410         if (message == 0) return;
411
412         if (tt_pointer_error (message) != TT_OK) {
413                 LogToolTalkError (DtMsgLogError, prog_name, 
414                                     "tt_message_receive", 
415                                     tt_pointer_error (message));
416                 exit (1);
417         }
418
419         op_num = tt_message_opnum (message);
420         switch (op_num) {
421
422                 case LOAD_INFO_LIB:
423                         op_name = LOAD_INFO_LIB_STRING;
424                         break;
425
426                 case SHOW_INFO_AT_LOC:
427                         op_name = SHOW_INFO_AT_LOC_STRING;
428                         break;
429
430                 default: {
431                         /*
432                          * Don't know how I got this message
433                          */
434                         DtMsgLogMessage (prog_name, DtMsgLogError, 
435                                 (char *) GETMESSAGE (SET_NUM, 11, "The message operation '%d' is not supported."),
436                                 op_num);
437
438                         tt_message_reject (message);
439                         tt_message_destroy(message);
440                         exit (1);
441                 }
442         }
443
444         /*
445          * Check the number of arguments
446          */
447         num_args =  tt_message_args_count (message);
448         if ((op_num == LOAD_INFO_LIB &&    num_args != LOAD_INFO_LIB_ARGS) ||
449             (op_num == SHOW_INFO_AT_LOC && num_args != SHOW_INFO_AT_LOC_ARGS)) {
450
451                 DtMsgLogMessage (prog_name, DtMsgLogError, 
452                         (char *) GETMESSAGE (SET_NUM, 12, "Message '%s' does not have the required\nnumber of arguments '%d'."),
453                         op_name, 
454                         (op_num == LOAD_INFO_LIB) ?
455                                 LOAD_INFO_LIB_ARGS : SHOW_INFO_AT_LOC_ARGS);
456                 tt_message_reject (message);
457                 tt_message_destroy(message);
458                 exit (1);
459         }
460
461         /*
462          * Check for an info lib
463          */
464         info_lib = tt_message_file (message);
465         if ((tt_ptr_error (info_lib) != TT_OK) || info_lib == NULL) {
466                 /*
467                  * Use DTINFOLIBDEFAULT if it is defined
468                  */
469                 if ((info_lib = getenv ("DTINFOLIBDEFAULT")) == NULL) {
470                         DtMsgLogMessage (prog_name, DtMsgLogError, 
471                                 (char *) GETMESSAGE (SET_NUM, 10, "An InfoLib was not provided in the '%s' message\nand the environment variable DTINFOLIBDEFAULT was not defined."),
472                                 op_name);
473                         exit (1);
474                 }
475         }
476
477         if ((action_name = tt_message_arg_val (message, 0)) == NULL) {
478
479                 action_name = (op_num == LOAD_INFO_LIB) ? 
480                         LOAD_INFO_LIB_ACTION : SHOW_INFO_LIB_SECTION_ACTION;
481
482                 DtMsgLogMessage (prog_name, DtMsgLogWarning,
483                         (char *) GETMESSAGE (SET_NUM, 13, "Message '%s' specified a NULL action name.\nAction '%s' will be invoked."),
484                         op_name,
485                         action_name);
486         }
487
488         if ((exec_host = tt_message_arg_val (message, 1)) == NULL) {
489
490                 DtMsgLogMessage (prog_name, DtMsgLogWarning, 
491                         (char *) GETMESSAGE (SET_NUM, 14, "Message '%s' specified a NULL execution host."),
492                         op_name);
493         }
494
495         if ((locale = tt_message_arg_val (message, 2)) == NULL) {
496
497                 DtMsgLogMessage (prog_name, DtMsgLogWarning,
498                         (char *) GETMESSAGE (SET_NUM, 15, "Message '%s' specified a NULL locale."),
499                         op_name);
500         }
501         else {
502                 /*
503                  * Put locale into the environment so that DtActionInvoke
504                  * will propagate it to the dtinfo process.
505                  */
506                 (void) snprintf (lang, sizeof(lang), "LANG=%s", locale);
507                 (void) putenv (lang);
508         }
509
510         if (op_num == SHOW_INFO_AT_LOC) {
511                 if ((topic = tt_message_arg_val (message, 3)) == NULL) {
512
513                         DtMsgLogMessage (prog_name, DtMsgLogError, 
514                                 (char *) GETMESSAGE (SET_NUM, 16, "Message '%s' specified a NULL topic."),
515                                 op_name);
516                         exit (1);
517                 }
518         }
519
520         if (op_num == last_op_num)
521         {
522 #if defined(DEBUG)
523             DtMsgLogMessage("dtinfo_start", DtMsgLogError,
524                             "Received a duplicate tooltalk message:  %s",
525                             (op_num == LOAD_INFO_LIB) ? 
526                               "LOAD_INFO_LIB" : "SHOW_INFO_AT_LOC" );
527 #endif
528         }
529         else
530         {
531 #if defined(DEBUG)
532             DtMsgLogMessage(
533                 "dtinfo_start", DtMsgLogError,
534                 "Received a tooltalk message:  %s\nInvoking action %s",
535                 (op_num==LOAD_INFO_LIB) ? "LOAD_INFO_LIB" : "SHOW_INFO_AT_LOC",
536                 action_name);
537 #endif
538             last_op_num = op_num;
539             opstatus = InvokeAction (prog_name, 
540                                      op_num, 
541                                      action_name, 
542                                      exec_host, 
543                                      info_lib,
544                                      topic);
545             if (!opstatus) {
546                     tt_message_fail (message);
547                     exit (1);
548             }
549         }
550
551         tt_message_reply (message);
552
553         tt_message_destroy(message);
554 }
555
556
557 static void
558 LogToolTalkError (
559         DtMsgLogType            msg_type,
560         char                    * prog_name,
561         char                    * function_name,
562         Tt_status               error_num)
563 {
564         char                    *message;
565         message = tt_status_message(error_num);
566         DtMsgLogMessage (prog_name, msg_type, "%s: %s", function_name, message);
567 }
568
569 #define GETXMSTRING(s, m, d)    XmStringCreateLocalized(GETMESSAGE(s,m,d))
570
571 static void
572 ExitCB (Widget dialog, XtPointer client_data, XtPointer call_data)
573 {
574     exit((size_t) client_data);
575 }
576
577 static void
578 DieFromToolTalkError(Widget parent, char *errfmt, Tt_status status)
579 {
580     Arg          args[10];
581     Widget       dialog, dialogShell;
582     char        *errmsg, *statmsg;
583     XmString     xms_errmsg, xms_ok, xms_title;
584     int          n, errmsglen;
585
586     if (! tt_is_err(status)) return;
587
588     statmsg = tt_status_message(status);
589     errmsglen = strlen(errfmt) + strlen(statmsg) + 2;
590     errmsg = XtMalloc(errmsglen);
591     snprintf(errmsg, errmsglen, errfmt, statmsg);
592
593     xms_ok = GETXMSTRING(2, 3, "OK");
594     xms_errmsg = XmStringCreateLocalized(errmsg);
595     xms_title = GETXMSTRING(2, 1, "Dtinfo: Error");
596
597     n = 0;
598     XtSetArg(args[n], XmNautoUnmanage, False); n++;
599     XtSetArg(args[n], XmNokLabelString, xms_ok); n++;
600     XtSetArg(args[n], XmNdialogTitle, xms_title); n++;
601     XtSetArg(args[n], XmNmessageString, xms_errmsg); n++;
602     XtSetArg(args[n], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); n++;
603
604     dialog = XmCreateErrorDialog(parent, "DtinfoStartError", args, n);
605     XtAddCallback(dialog, XmNokCallback, ExitCB, (XtPointer) status);
606     XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON));
607     XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));
608
609     /*
610      * Disable the frame menu from dialog since we don't want the user
611      * to be able to close dialogs with the frame menu
612      */
613     dialogShell = XtParent(dialog);
614     n = 0;
615     XtSetArg(args[n], XmNmwmDecorations, MWM_DECOR_ALL | MWM_DECOR_MENU); n++;
616     XtSetValues(dialogShell, args, n);
617     XtManageChild(dialog);
618     XtRealizeWidget(dialogShell);
619
620     XtFree(errmsg);
621     XmStringFree(xms_ok);
622     XmStringFree(xms_errmsg);
623     XmStringFree(xms_title);
624
625     while (TRUE)
626       XtAppProcessEvent(XtWidgetToApplicationContext(dialog), XtIMAll);
627 }
628
629 /* ARGSUSED */
630 static void
631 Exit (
632         XtPointer               client_data,
633         XtIntervalId            id)
634 {
635         /*
636          * The following code to determine if DtActionInvoke
637          * resulted in the posting a dialog is from:
638          *   $TOP/dtaction/Main.c
639          */
640         if (top_level->core.num_popups ==  0)
641                 exit(0);
642
643         XtAppAddTimeOut (app_context, 
644                          time_out, 
645                          (XtTimerCallbackProc) Exit, 
646                          NULL);
647
648 }