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