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