Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / programs / dtwm / WmIPC.c
1 /* $TOG: WmIPC.c /main/11 1999/09/20 15:17:25 mgreess $ */
2 /* 
3  * (c) Copyright 1997, The Open Group 
4  */
5 /* 
6  * (c) Copyright 1987, 1988, 1989, 1990, 1992, 1993 HEWLETT-PACKARD COMPANY 
7  * ALL RIGHTS RESERVED 
8 */ 
9 #ifdef REV_INFO
10 #ifndef lint
11 static char rcsid[] = ""
12 #endif
13 #endif
14
15 /*
16  * Included Files:
17  */
18 #include "WmGlobal.h"
19 #include <Xm/XmAll.h>
20 #include <Dt/DtP.h>
21 #include <Dt/Action.h>
22 #include <Dt/WsmM.h>
23 #include <Dt/IndicatorM.h>
24 #include <Dt/UserMsg.h>
25 #include <Dt/Icon.h>
26
27 #include "WmBackdrop.h"
28 #include "WmError.h"
29 #include "WmFunction.h"
30 #include "WmWrkspace.h"
31 #include "WmIPC.h"
32 #include "DataBaseLoad.h"
33
34
35 /*
36  * include extern functions and definitions
37  */
38
39 extern void UpdateFileTypeControlFields ( void );
40 extern WmScreenData * GetScreenForWindow (Window);
41
42 static void ToolTalkError(Widget, char*, Tt_status);
43
44
45 /*
46  *   data for the "DT screen"
47  */
48
49
50 /*
51  * globals
52  */
53 Const char *szWM_TOOL_CLASS = DtWM_TOOL_CLASS;
54
55
56 \f
57 /******************************<->*************************************
58  *
59  *  dtInitialize (char * program_name, XtAppContext appContext)
60  *
61  *  Description:
62  *  -----------
63  *  Initialize the messaging mechanism
64  *
65  *  Inputs:
66  *  ------
67  *  program_name - argv[0]
68  *  appContext   - used throughout the WM
69  *
70  *  Outputs:
71  *  -------
72  *
73  *  Comments:
74  *  --------
75  *
76  ******************************<->***********************************/
77 void 
78 dtInitialize(
79         char *program_name,
80         XtAppContext appContext )
81 {
82     
83     (void) DtAppInitialize(appContext, DISPLAY1, wmGD.topLevelW1, 
84                                 program_name, (char *)szWM_TOOL_CLASS);
85
86     /* 
87      * Load action definitions from the action database.
88      */
89 #ifdef DT_PERFORMANCE
90 _DtPerfChkpntMsgSend("Begin action database load");
91 #endif
92
93     DtDbLoad(); 
94
95 #ifdef DT_PERFORMANCE
96 _DtPerfChkpntMsgSend("End   action database load");
97 #endif
98
99 } /* END OF FUNCTION dtInitialize */
100
101 /******************************<->*************************************
102  *
103  *  dtInitializeMessaging (Widget)
104  *
105  *  Description:
106  *  -----------
107  *  Initialize the messaging mechanisms
108  *
109  *  Inputs:
110  *  ------
111  *
112  *  Outputs:
113  *  -------
114  *
115  *  Comments:
116  *  --------
117  *
118  ******************************<->***********************************/
119
120 void
121 dtInitializeMessaging(Widget toplevel)
122 {
123     int                 i;
124     WmScreenData *      pSD;
125     String              sName;
126
127     Tt_status           status;
128     Tt_pattern          notice_pattern, request_pattern;
129     char                *default_session;
130
131     int                 fd;
132     char                *procId;
133     char                *errfmt;
134
135     Tt_callback_action NoticeMsgCB(
136         Tt_message m,
137         Tt_pattern p);
138     Tt_callback_action RequestMsgCB(
139         Tt_message m,
140         Tt_pattern p);
141
142     /*
143      * Makef sure we have a ToolTalk connection
144      */
145     procId = tt_open();
146     status = tt_ptr_error(procId);
147     if (status != TT_OK) {
148         errfmt =
149           GETMESSAGE(2, 2, "Could not connect to ToolTalk:\n%s\n");
150         ToolTalkError(toplevel, errfmt, status);
151         return;
152     }
153     fd = tt_fd();
154     status = tt_int_error(fd);
155     if (status == TT_OK) {
156         XtAppAddInput(XtWidgetToApplicationContext(wmGD.topLevelW), fd,
157                 (XtPointer)XtInputReadMask, tttk_Xt_input_handler, procId);
158     } else {
159         ToolTalkError(toplevel, "tt_fd()", status);
160     }
161
162
163     default_session = tt_default_session();
164     status = tt_ptr_error(default_session);
165     if (status != TT_OK) {
166         GETMESSAGE(2, 4, "Could not get default ToolTalk session:\n%s\n");
167         ToolTalkError(toplevel, errfmt, status);
168         return;
169     }
170
171     errfmt = GETMESSAGE(2, 5, "Error constructing ToolTalk pattern:\n%s\n");
172     notice_pattern = tt_pattern_create();
173     status = tt_ptr_error(notice_pattern);
174     if (status != TT_OK) {
175         ToolTalkError(toplevel, errfmt, status);
176         return;
177     }
178     request_pattern = tt_pattern_create();
179     status = tt_ptr_error(request_pattern);
180     if (status != TT_OK) {
181         ToolTalkError(toplevel, errfmt, status);
182         return;
183     }
184
185     status = tt_pattern_category_set(notice_pattern, TT_OBSERVE);
186     if (status != TT_OK) {
187         ToolTalkError(toplevel, errfmt, status);
188         return;
189     }
190     status = tt_pattern_category_set(request_pattern, TT_HANDLE);
191     if (status != TT_OK) {
192         ToolTalkError(toplevel, errfmt, status);
193         return;
194     }
195     status = tt_pattern_scope_add(notice_pattern, TT_SESSION);
196     if (status != TT_OK) {
197         ToolTalkError(toplevel, errfmt, status);
198         return;
199     }
200     status = tt_pattern_scope_add(request_pattern, TT_SESSION);
201     if (status != TT_OK) {
202         ToolTalkError(toplevel, errfmt, status);
203         return;
204     }
205     status = tt_pattern_session_add(notice_pattern, default_session);
206     if (status != TT_OK) {
207         ToolTalkError(toplevel, errfmt, status);
208         return;
209     }
210     status = tt_pattern_session_add(request_pattern, default_session);
211     if (status != TT_OK) {
212         ToolTalkError(toplevel, errfmt, status);
213         return;
214     }
215     tt_free( default_session );
216     status = tt_pattern_class_add(notice_pattern, TT_NOTICE);
217     if (status != TT_OK) {
218         ToolTalkError(toplevel, errfmt, status);
219         return;
220     }
221     status = tt_pattern_state_add(notice_pattern, TT_SENT);
222     if (status != TT_OK) {
223         ToolTalkError(toplevel, errfmt, status);
224         return;
225     }
226     status = tt_pattern_class_add(request_pattern, TT_REQUEST);
227     if (status != TT_OK) {
228         ToolTalkError(toplevel, errfmt, status);
229         return;
230     }
231     status = tt_pattern_state_add(request_pattern, TT_SENT);
232     if (status != TT_OK) {
233         ToolTalkError(toplevel, errfmt, status);
234         return;
235     }
236
237
238     /*
239      * Ops handled by the notice_pattern
240      */
241     status = tt_pattern_op_add(notice_pattern, "DtActivity_Beginning");
242     if (status != TT_OK) {
243         ToolTalkError(toplevel, errfmt, status);
244         return;
245     }
246     status = tt_pattern_op_add(notice_pattern, "DtActivity_Began");
247     if (status != TT_OK) {
248         ToolTalkError(toplevel, errfmt, status);
249         return;
250     }
251     status = tt_pattern_op_add(notice_pattern, "DtTypes_Reloaded");
252     if (status != TT_OK) {
253         ToolTalkError(toplevel, errfmt, status);
254         return;
255     }
256
257     /*
258      * Ops handled by the request_pattern
259      */
260     status = tt_pattern_op_add(request_pattern, "DtPanel_Restore");
261     if (status != TT_OK) {
262         ToolTalkError(toplevel, errfmt, status);
263         return;
264     }
265     status = tt_pattern_op_add(request_pattern, "DtWorkspace_SetCurrent");
266     if (status != TT_OK) {
267         ToolTalkError(toplevel, errfmt, status);
268         return;
269     }
270     status = tt_pattern_op_add(request_pattern, "DtWorkspace_Title_Set");
271     if (status != TT_OK) {
272         ToolTalkError(toplevel, errfmt, status);
273         return;
274     }
275     status = tt_pattern_op_add(request_pattern, "DtWorkspace_Add");
276     if (status != TT_OK) {
277         ToolTalkError(toplevel, errfmt, status);
278         return;
279     }
280     status = tt_pattern_op_add(request_pattern, "DtWorkspace_Delete");
281     if (status != TT_OK) {
282         ToolTalkError(toplevel, errfmt, status);
283         return;
284     }
285     status = tt_pattern_op_add(request_pattern, "GetWsmClients");
286     if (status != TT_OK) {
287         ToolTalkError(toplevel, errfmt, status);
288         return;
289     }
290
291     /*
292      * Register callback for the notice_pattern
293      */
294     status = tt_pattern_callback_add(notice_pattern, NoticeMsgCB);
295     if (status != TT_OK) {
296         ToolTalkError(toplevel, errfmt, status);
297         return;
298     }
299
300     /*
301      * Register callback for the request_pattern
302      */
303     status = tt_pattern_callback_add(request_pattern, RequestMsgCB);
304     if (status != TT_OK) {
305         ToolTalkError(toplevel, errfmt, status);
306         return;
307     }
308
309     status = tt_pattern_register(notice_pattern);
310     if (status != TT_OK) {
311         ToolTalkError(toplevel, errfmt, status);
312         return;
313     }
314     status = tt_pattern_register(request_pattern);
315     if (status != TT_OK) {
316         ToolTalkError(toplevel, errfmt, status);
317         return;
318     }
319
320 } /* END OF FUNCTION dtInitializeMessaging */
321
322 \f
323 /******************************<->*************************************
324  *
325  *  dtCloseIPC ()
326  *
327  *  Description:
328  *  -----------
329  *  Shuts down the messaging mechanism
330  *
331  *  Inputs:
332  *  ------
333  *
334  *  Outputs:
335  *  -------
336  *
337  *  Comments:
338  *  --------
339  *  Should be done before exiting
340  *
341  ******************************<->***********************************/
342 void 
343 dtCloseIPC( void )
344 {
345 } /* END OF FUNCTION dtCloseIPC */
346
347
348 \f
349 /******************************<->*************************************
350  *  
351  * void dtReadyNotification()
352  *  
353  *  Description:
354  *  -----------
355  *  Tells the world that we're up and ready.
356  *
357  *  Inputs:
358  *  ------
359  * 
360  *  Outputs:
361  *  -------
362  *
363  *  Comments:
364  *  --------
365  *  Invoked as the fitting culmination of dtwm initialization
366  *
367  ******************************<->***********************************/
368 void 
369 dtReadyNotification( void )
370 {
371     SendClientMsg( wmGD.dtSmWindow,
372                   (long) wmGD.xa_DT_SM_WM_PROTOCOL,
373                   (long) wmGD.xa_DT_WM_READY,
374                   CurrentTime, NULL, 0);
375
376 } /* END OF FUNCTION dtReadyNotification */
377
378 \f
379 /******************************<->*************************************
380  *
381  *  WmStopWaiting ()
382  *
383  *  Description:
384  *  -----------
385  *  This is called to turn off "system busy" activity
386  *
387  *  Inputs:
388  *  ------
389  * 
390  *  Outputs:
391  *  -------
392  *  None
393  *
394  *  Comments:
395  *  ---------
396  *  This routine relies on two globals, blinkerPCW and dtSD,
397  *  on the major assumptions that:
398  *     - there is just one DT Screen, with the front panel enabled
399  *     - there is just one dtwmbusy control in that front panel
400  ******************************<->***********************************/
401 void 
402 WmStopWaiting( void )
403 {
404 #ifdef PANELIST 
405      if (wmGD.dtSD)
406      {
407          WmFrontPanelSetBusy (False);
408      }
409 #endif /* PANELIST */
410 } /* END OF FUNCTION WmStopWaiting */
411
412
413 \f
414 /******************************<->*************************************
415  *
416  *  dtSendWorkspaceModifyNotification ()
417  *
418  *  Description:
419  *  -----------
420  *  This is called to announce that the workspace set has been
421  *  modified
422  *
423  *  Inputs:
424  *  ------
425  *  pSD         - pointer to screen data
426  *  aWs         - id of workspace just modified
427  *  iType       - type of modification
428  * 
429  *  Outputs:
430  *  -------
431  *  None
432  *
433  *  Comments:
434  *  ---------
435  *  Sends the message:
436  *
437  *    "MODIFY_WORKSPACE"  "<atom_for_wsname>" "<modify_type>"
438  *
439  *    <modify_type> is one of:
440  *                              ADD
441  *                              DELETE
442  *                              BACKDROP
443  *                              TITLE
444  ******************************<->***********************************/
445 void
446 dtSendWorkspaceModifyNotification(
447         WmScreenData *pSD,
448         Atom aWs,
449         int iType)
450 {
451     char        sNum[40];
452     char        pch[40];
453     char        pchType[40];
454     Tt_message  msg;
455     Tt_status   status;
456
457     msg = tt_pnotice_create(TT_SESSION, "DtWorkspace_Modified");
458     status = tt_ptr_error(msg);
459     if (status != TT_OK) {
460         return;
461     }
462     sprintf(sNum, "%d", pSD->screen);
463     status = tt_message_arg_add(msg, TT_IN, Tttk_string, sNum);
464     if (status != TT_OK) {
465         return;
466     }
467     sprintf (pch, "%ld", aWs);
468     status = tt_message_arg_add(msg, TT_IN, Tttk_string, pch);
469     if (status != TT_OK) {
470         return;
471     }
472     sprintf (pchType, "%d", iType);
473     status = tt_message_arg_add(msg, TT_IN, Tttk_string, pchType);
474     if (status != TT_OK) {
475         return;
476     }
477     status = tt_message_send(msg);
478     if (status != TT_OK) {
479         return;
480     }
481     tt_message_destroy(msg);
482 }
483
484 \f
485 /******************************<->*************************************
486  *
487  *  dtSendMarqueeSelectionNotification ()
488  *
489  *  Description:
490  *  -----------
491  *  This is called to announce marquee selection state
492  *
493  *  Inputs:
494  *  ------
495  *  pSD         - pointer to screen data
496  *  type        - id of workspace just modified
497  *  x           - x position of UL corner of rectangle
498  *  y           - y position of UL corner of rectangle
499  *  width       - width of rectangle
500  *  heigth      - height of rectangle
501  * 
502  *  Outputs:
503  *  -------
504  *  None
505  *
506  *  Comments:
507  *  ---------
508  *  Sends the message:
509  *
510  *    "MARQUEE_SELECTION"  "<type>" "<x>" "<y>" "<width>" "<height>"
511  *
512  *    <modify_type> is one of:
513  *                              BEGIN
514  *                              END
515  *                              CONTINUE
516  *                              CANCEL
517  ******************************<->***********************************/
518 void
519 dtSendMarqueeSelectionNotification(
520         WmScreenData *pSD,
521         int     type,
522         Position x,
523         Position y,
524         Dimension width,
525         Dimension height)
526 {
527     Tt_message  msg;
528     Tt_status   status;
529     char        sNum[40];
530
531     msg = tt_pnotice_create(TT_SESSION, "DtMarquee_Selection");
532     status = tt_ptr_error(msg);
533     if (status != TT_OK) {
534         return;
535     }
536
537     sprintf(sNum, "%d", pSD->screen);
538     status = tt_message_arg_add(msg, TT_IN, Tttk_string, sNum);
539     if (status != TT_OK) {
540         return;
541     }
542     if (tt_message_arg_add(msg, TT_IN, "integer", NULL) != TT_OK) {
543         return;
544     }
545     if (tt_message_arg_ival_set(msg, 1, type) != TT_OK) {
546         return;
547     }
548     if (tt_message_arg_add(msg, TT_IN, "integer", NULL) != TT_OK) {
549         return;
550     }
551     if (tt_message_arg_ival_set(msg, 2, x) != TT_OK) {
552         return;
553     }
554     if (tt_message_arg_add(msg, TT_IN, "integer", NULL) != TT_OK) {
555         return;
556     }
557     if (tt_message_arg_ival_set(msg, 3, y) != TT_OK) {
558         return;
559     }
560     if (tt_message_arg_add(msg, TT_IN, "integer", NULL) != TT_OK) {
561         return;
562     }
563     if (tt_message_arg_ival_set(msg, 4, width) != TT_OK) {
564         return;
565     }
566     if (tt_message_arg_add(msg, TT_IN, "integer", NULL) != TT_OK) {
567         return;
568     }
569     if (tt_message_arg_ival_set(msg, 5, height) != TT_OK) {
570         return;
571     }
572     status = tt_message_send(msg);
573     if (status != TT_OK) {
574         return;
575     }
576     tt_message_destroy(msg);
577 }
578
579 \f
580 /******************************<->*************************************
581  *
582  *  NoticeMsgCB ()
583  *
584  *
585  *  Description:
586  *  -----------
587  *  This is called to handle busy and stopbusy message
588  *
589  *  Inputs:
590  *  ------
591  *  m = ToolTalk message
592  *  p = ToolTalk pattern
593  * 
594  *  Outputs:
595  *  -------
596  *  TT_CALLBACK_PROCESSED
597  *  TT_CALLBACK_CINTINUE
598  *
599  *  Comments:
600  *  ---------
601  ******************************<->***********************************/
602 Tt_callback_action
603 NoticeMsgCB(Tt_message m, Tt_pattern p)
604 {
605     char        *op;
606     Tt_status   status;
607
608     if (tt_message_state(m) != TT_SENT) {
609         return TT_CALLBACK_CONTINUE;
610     }
611     op = tt_message_op(m);
612     status = tt_ptr_error(op);
613     if (status != TT_OK) {
614         return TT_CALLBACK_CONTINUE;
615     }
616     if (!strcmp(op, "DtActivity_Began")) {
617         WmStopWaiting();
618
619         /* CDExc21081 */
620         tt_message_destroy(m);
621     }
622 #ifdef PANELIST 
623     else if (!strcmp(op, "DtActivity_Beginning")) {
624         if (wmGD.dtSD) {
625            WmFrontPanelSetBusy (True);
626         }
627
628         /* CDExc21081 */
629         tt_message_destroy(m);
630     }
631 #endif /* PANELIST */
632     else if (!strcmp(op, "DtTypes_Reloaded")) {
633         /*
634          * Blink busy light during reload.
635          */
636         WmFrontPanelSetBusy (True);
637
638         /* 
639          * Load action definitions from the action database.
640          */
641         DtDbLoad(); 
642
643         UpdateFileTypeControlFields();
644
645         /*
646          * Turn off busy light.
647          */
648         WmFrontPanelSetBusy (False);
649
650         /* CDExc21081 */
651         tt_message_destroy(m);
652     }
653
654     tt_free(op);
655     return TT_CALLBACK_PROCESSED;
656
657 } /* END OF FUNCTION NoticeMsgCB */
658
659 \f
660 /******************************<->*************************************
661  *
662  *  RequestMsgCB ()
663  *
664  *
665  *  Description:
666  *  -----------
667  *  This is called to handle busy and stopbusy message
668  *
669  *  Inputs:
670  *  ------
671  *  m = ToolTalk message
672  *  p = ToolTalk pattern
673  * 
674  *  Outputs:
675  *  -------
676  *  TT_CALLBACK_PROCESSED
677  *  TT_CALLBACK_CINTINUE
678  *
679  *  Comments:
680  *  ---------
681  ******************************<->***********************************/
682 Tt_callback_action
683 RequestMsgCB(Tt_message m, Tt_pattern p)
684 {
685     char        *op;
686     Tt_status   status;
687
688     int                 screen_num;
689     WmScreenData        *pSD;
690     WmWorkspaceData     *pWS = NULL;
691     Atom                aWs;
692     char                *pch;
693     String              sName;
694
695     if (tt_message_state(m) != TT_SENT) {
696         return TT_CALLBACK_CONTINUE;
697     }
698     op = tt_message_op(m);
699     status = tt_ptr_error(op);
700     if (status != TT_OK) {
701         return TT_CALLBACK_CONTINUE;
702     }
703     if (!strcmp(op, "DtPanel_Restore")) {
704         tt_message_reply(m);
705         tt_message_destroy(m);
706
707         SessionDeleteAll();
708
709         F_Restart( DTWM_REQP_NO_CONFIRM, NULL, NULL );
710     }
711     else if (!strcmp(op, "DtWorkspace_SetCurrent")) {
712         /*
713          * 1st arg: integer, screen number
714          * 2nd arg: string, atom of workspace name
715          */
716
717         /* get the first arg from the message */
718         tt_message_arg_ival(m, 0, &screen_num);
719         pSD = &wmGD.Screens[screen_num];
720
721         /* get the second arg from the message */
722         pch = tt_message_arg_val(m, 1);
723
724         /* retrieve the selected workspace */
725         aWs = strtoul (pch, (char **) NULL, 0);
726         tt_free( pch );
727         pWS = GetWorkspaceData (pSD, aWs);
728
729         if (pWS) {
730             ChangeToWorkspace (pWS);
731         }
732
733         tt_message_reply(m);
734         tt_message_destroy(m);
735     }
736     else if (!strcmp(op, "DtWorkspace_Title_Set")) {
737         /*
738          * 1st arg: integer, screen number
739          * 2nd arg: string, atom of workspace name
740          * 3rd arg: string, new name for the workspace
741          */
742
743         /* get the first arg from the message */
744         tt_message_arg_ival(m, 0, &screen_num);
745         pSD = &wmGD.Screens[screen_num];
746
747         /* get the second arg from the message */
748         pch = tt_message_arg_val(m, 1);
749
750         /* retrieve the selected workspace */
751         aWs = strtoul (pch, (char **) NULL, 0);
752         tt_free( pch );
753         pWS = GetWorkspaceData (pSD, aWs);
754
755         /* get the third arg from the message */
756         pch = tt_message_arg_val(m, 2);
757
758         if (pWS) {
759             ChangeWorkspaceTitle (pWS, pch);
760         }
761         tt_free( pch );
762
763         tt_message_reply(m);
764         tt_message_destroy(m);
765     }
766     else if (!strcmp(op, "DtWorkspace_Add")) {
767         /*
768          * 1st arg: string, user-visible title of the workspace
769          */
770         pch = tt_message_arg_val(m, 0);
771
772         F_CreateWorkspace( pch, NULL, NULL );
773         tt_free( pch );
774
775         tt_message_reply(m);
776         tt_message_destroy(m);
777     }
778     else if (!strcmp(op, "DtWorkspace_Delete")) {
779         /*
780          * 1st arg: string, atom of workspace name
781          */
782         pch = tt_message_arg_val(m, 0);
783
784         /* retrieve the selected workspace */
785         aWs = strtoul (pch, (char **) NULL, 0);
786         tt_free( pch );
787         sName = (String) XmGetAtomName (DISPLAY1, aWs);
788
789         F_DeleteWorkspace( sName, NULL, NULL );
790
791         tt_message_reply(m);
792         tt_message_destroy(m);
793
794         XtFree(sName);
795     }
796     else if (!strcmp(op, "GetWsmClients")) {
797         /* No TT_IN args. */
798         ClientData **clients;
799         int nClients;
800
801         if (GetSmClientIdClientList(&clients, &nClients))
802         {
803             char *clientIds = (char *)NULL;
804             int *clientWorkspaces = (int *)NULL;
805             int clientIdLen = 0;
806
807             SortClientListByWorkspace(clients, nClients);
808
809             tt_message_arg_ival_set(m, 0, nClients);
810             if (nClients > 0)
811             {
812                 int i;
813                 char *ptr;
814                 ClientData *pCD;
815
816                 clientIdLen = 0;
817                 for (i = 0; i < nClients; i++)
818                     clientIdLen += strlen(clients[i]->smClientID) + 1;
819
820                 if (((clientIds =
821                       (char *)XtMalloc(clientIdLen * sizeof(char)))
822                      == (char *)NULL) ||
823                     ((clientWorkspaces =
824                       (int *)XtMalloc(nClients * sizeof(int)))
825                      == (int *)NULL))
826                 {
827                     if (clientIds != (char *)NULL)
828                         XtFree(clientIds);
829
830                     /* LATER - Right way to handle errors? */
831                     tt_message_fail(m);
832                     tt_message_destroy(m);
833                     tt_free(op);
834                     return TT_CALLBACK_PROCESSED;
835                 }
836                 else
837                 {
838                     for (i = 0, ptr = clientIds;
839                          i < nClients;
840                          ptr += strlen(pCD->smClientID) + 1, i++)
841                     {
842                         pCD = clients[i];
843                         strcpy(ptr, pCD->smClientID);
844                         clientWorkspaces[i] =
845 #ifdef WSM
846                             pCD->pWsList[pCD->currentWsc].wsID;
847 #else
848                             pCD->pSD->pWS->id;
849 #endif
850                     }
851                 }
852             }
853             tt_message_arg_bval_set(m, 1, (unsigned char *)clientIds,
854                                     clientIdLen * sizeof(char));
855             tt_message_arg_bval_set(m, 2, (unsigned char *)clientWorkspaces,
856                                     nClients * sizeof(int));
857
858             if (clientIds != (char *)NULL)
859                 XtFree(clientIds);
860             if (clientWorkspaces != (int *)NULL)
861                 XtFree((char *)clientWorkspaces);
862             XtFree((char *)clients);
863         }
864
865         tt_message_reply(m);
866         tt_message_destroy(m);
867     } else {
868         tt_free( op );
869         return TT_CALLBACK_CONTINUE;
870     }
871
872     tt_free(op);
873     return TT_CALLBACK_PROCESSED;
874
875 } /* END OF FUNCTION RequestMsgCB */
876
877
878 \f
879 /******************************<->*************************************
880  *
881  *  ToolTalkError ()
882  *
883  *
884  *  Description:
885  *  -----------
886  *
887  *  Inputs:
888  *  ------
889  * 
890  *  Outputs:
891  *  -------
892  *
893  *  Comments:
894  *  ---------
895  ******************************<->***********************************/
896 #define GETXMSTRING(s, m, d)    XmStringCreateLocalized(GETMESSAGE(s,m,d))
897
898 static void
899 OKCB (Widget dialog, XtPointer client_data, XtPointer call_data)
900 {
901     XtUnmanageChild((Widget) client_data);
902 }
903
904 static void
905 ToolTalkError(Widget parent, char *errfmt, Tt_status status)
906 {
907     Arg          args[10];
908     Widget       dialog, dialogShell;
909     char        *errmsg, *statmsg, *title;
910     XmString     xms_errmsg, xms_ok, xms_title;
911     int          n;
912
913     if (! tt_is_err(status)) return;
914
915     statmsg = tt_status_message(status);
916     errmsg = XtMalloc(strlen(errfmt) + strlen(statmsg) + 2);
917     sprintf(errmsg, errfmt, statmsg);
918
919     xms_ok = GETXMSTRING(2, 3, "OK");
920     xms_errmsg = XmStringCreateLocalized(errmsg);
921     xms_title = GETXMSTRING(2, 1, "Dtwm - Error");
922
923     n = 0;
924     XtSetArg(args[n], XmNautoUnmanage, False); n++;
925     XtSetArg(args[n], XmNokLabelString, xms_ok); n++;
926     XtSetArg(args[n], XmNdialogTitle, xms_title); n++;
927     XtSetArg(args[n], XmNmessageString, xms_errmsg); n++;
928     XtSetArg(args[n], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); n++;
929
930     dialog = XmCreateErrorDialog(parent, "IconEditorError", args, n);
931     XtAddCallback(dialog, XmNokCallback, OKCB, (XtPointer) dialog);
932     XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON));
933     XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));
934
935     /*
936      * Disable the frame menu from dialog since we don't want the user
937      * to be able to close dialogs with the frame menu
938      */
939     dialogShell = XtParent(dialog);
940     n = 0;
941     XtSetArg(args[n], XmNmwmDecorations, MWM_DECOR_BORDER | MWM_DECOR_TITLE); n++;
942     XtSetValues(dialogShell, args, n);
943     XtManageChild(dialog);
944     XtRealizeWidget(dialogShell);
945
946     _DtSimpleError("Dtwm", DtFatalError, NULL, errmsg);
947
948     XtFree(errmsg);
949     XmStringFree(xms_ok);
950     XmStringFree(xms_errmsg);
951     XmStringFree(xms_title);
952 }
953 /****************************   eof    ***************************/