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