c3fb6bc01194168e6f28dfff45d28be94b1e3c92
[oweals/cde.git] / cde / programs / dtinfo / dtinfo / src / Managers / TtIpcMgr.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  * $TOG: TtIpcMgr.C /main/16 1999/09/20 13:30:40 mgreess $
25  *
26  * Copyright (c) 1992 HaL Computer Systems, Inc.  All rights reserved.
27  * UNPUBLISHED -- rights reserved under the Copyright Laws of the United
28  * States.  Use of a copyright notice is precautionary only and does not
29  * imply publication or disclosure.
30  * 
31  * This software contains confidential information and trade secrets of HaL
32  * Computer Systems, Inc.  Use, disclosure, or reproduction is prohibited
33  * without the prior express written permission of HaL Computer Systems, Inc.
34  * 
35  *                         RESTRICTED RIGHTS LEGEND
36  * Use, duplication, or disclosure by the Government is subject to
37  * restrictions as set forth in subparagraph (c)(l)(ii) of the Rights in
38  * Technical Data and Computer Software clause at DFARS 252.227-7013.
39  *                        HaL Computer Systems, Inc.
40  *                  1315 Dell Avenue, Campbell, CA  95008
41  * 
42  */
43
44 #define C_LibraryAgent
45 #define C_PrintPanelAgent
46 #define C_UrlAgent
47 #define L_Agents
48
49 #define C_Long_Lived
50 #define L_Basic
51
52 #define C_EnvMgr
53 #define C_TtIpcMgr
54 #define C_NodeMgr
55 #define C_MessageMgr
56 #define C_WorkspaceMgr
57 #define L_Managers
58
59 #define C_WindowSystem
60 #define L_Other
61
62 #include "Prelude.h"
63
64 #include "Managers/CatMgr.hh"
65 #include "Registration.hh"
66
67 #include "utility/mmdb_exception.h"
68 #include "utility/funcs.h"
69
70 #include <string.h>
71 #include <stdio.h>
72
73 #include <X11/Intrinsic.h>
74
75 //  the Session include file(s) are for locale_of_desktop()
76 //#include <Dt/SessionP.h>
77 #include <Dt/SessionM.h>
78
79 #include <Dt/EnvControlP.h>
80 #include <Dt/Action.h>
81 #include <Dt/DtGetMessageP.h>
82 #include <Dt/MsgLog.h>
83
84 #include <Tt/tt_c.h>
85 #include <Tt/tttk.h>
86
87
88
89 LONG_LIVED_CC( TtIpcMgr, tt_manager )
90
91 #if 0
92 #  define RCS_DEBUG(statement) cerr << statement << endl
93 #else
94 #  define RCS_DEBUG(statement) 
95 #endif
96
97 // the following defines for tt msg opnums must match those in the tttypes
98 // declaration for associated (Dtinfo) ptype use
99 #define LOAD_INFO_LIB           1
100 #define SHOW_INFO_AT_LOC        2
101 #define QUIT_DTINFO             3
102 #define PRINT_INFO_AT_LOC       4
103
104 // the following defines are for message index per catalog
105 // Set_AddLibraryAgent:
106 #define ERR_INFOLIB_SPEC_FORMAT 5
107 // Set_TtIpcMgr:
108 #define ERR_TT_DISPLAY_AS_SESSION       1
109 #define ERR_TT_DEFAULT_AS_SESSION       2
110 #define ERR_TT_OPEN                     3
111 #define ERR_TT_PTYPE_DECLARE            4
112
113 #define DFLTXT_DISPLAY_AS_SESSION "Can't get tt session for X display:\n%s"
114 #define DFLTXT_DEFAULT_AS_SESSION "Could not set default tooltalk session:\n%s"
115 #define DFLTXT_OPEN                "Failed to open ToolTalk connection:\n%s"
116 #define DFLTXT_PTYPE_DECLARE       "Could not declare ptype DtInfo:\n%s"
117
118 // the last message handled, for sanity checking
119 Tt_message prior_tt_msg ;
120
121 // temp internal tracking of curr workspace at time tt msg received
122 Atom       curr_ws_tt ;
123
124
125 // /////////////////////////////////////////////////////////////////
126 // LogToolTalkMessage - records messages to log
127 // /////////////////////////////////////////////////////////////////
128
129 static char *
130 LogToolTalkMessage (
131     DtMsgLogType        msg_type,
132     int                 msg_num,
133     char                * dflt_txt,
134     Tt_status           status)
135 {
136     char                * errfmt;
137     char                * statmsg;
138     char                * errmsg;
139     int                 errmsglen;
140     
141     if (! tt_is_err(status)) return XtsNewString("");;
142
143     errfmt = CATGETS(Set_TtIpcMgr, msg_num, dflt_txt);
144     statmsg = tt_status_message(status);
145     errmsglen = strlen(errfmt) + strlen(statmsg) + 2;
146     errmsg = XtMalloc(errmsglen);
147     if (! strlen(errfmt))
148       errfmt = (char*)"%s";
149     snprintf(errmsg, errmsglen, errfmt, statmsg);
150
151     DtMsgLogMessage ("Dtinfo", msg_type, errfmt, errmsg);
152     return errmsg;
153 }
154
155
156 // /////////////////////////////////////////////////////////////////
157 // class constructor
158 // /////////////////////////////////////////////////////////////////
159
160 // TtIpcMgr constructor
161 //
162 // It is highly recommended that this be invoked only after event
163 // loop entry, or at least as much as possible deferred until then.
164 // It is the creator's responsibility to do this at the first level
165 // via work proc or similar.
166 //
167 TtIpcMgr::TtIpcMgr()
168 {
169   int           mark ;
170   int           ttfd ;
171   char *        xsession ;
172   char *        errmsg ;
173
174
175   // Initialize ToolTalk
176
177   window_system().wait_cursor();    // this tt stuff Can take a while
178
179   mark = tt_mark() ;
180
181   xsession = tt_X_session(
182        (const char *)(XDisplayString((window_system().display()))) ) ;
183
184   if( tt_ptr_error( xsession ) != TT_OK )
185   {
186       errmsg = LogToolTalkMessage (DtMsgLogError, 
187                                    ERR_TT_DISPLAY_AS_SESSION,
188                                    (char*)DFLTXT_DISPLAY_AS_SESSION,
189                                    tt_state);
190       message_mgr().error_dialog( (char*)UAS_String(errmsg) ) ;
191       XtFree (errmsg);
192       tt_release( mark ) ;
193       return ;
194   }
195
196   // set up to actually join the "default" session for any
197   // patterns registered below to take effect there-in
198   XtAppAddWorkProc( window_system().app_context(),
199                     ipc_init_wp1, this ) ;
200
201   if( (tt_state = tt_default_session_set( xsession )) == TT_OK )
202   {
203       procid = ttdt_open( &ttfd, "Dtinfo", "Fujitsu", "CDE", True ) ;
204       
205       if( (tt_state = tt_pointer_error( procid ))
206           == TT_OK )
207       {
208           // declare Dtinfo Ptype
209           if( (tt_state = tt_ptype_declare( "DtInfo" )) == TT_OK )
210           {
211               // success -- add an input handler for tooltalk msgs
212               XtAppAddInput( window_system().app_context(), ttfd,
213                          (XtPointer) XtInputReadMask,
214                          receive_tt_msg, this ) ;
215
216               // declare DtinfoPrint ptype (non-fatal if prior ptype ok).
217               // Also can be broken out & deferred via the work proc.
218               XtAppAddWorkProc( window_system().app_context(),
219                                 ipc_init_wp0, this ) ;
220           }
221           else
222           {
223               // HEY! No matter what exit you take from here, it must
224               // return True! -- its a work proc!
225
226               errmsg = LogToolTalkMessage (DtMsgLogError, 
227                                            ERR_TT_PTYPE_DECLARE,
228                                            (char*)DFLTXT_PTYPE_DECLARE,
229                                            tt_state);
230               message_mgr().error_dialog( (char*)UAS_String(errmsg) );
231               XtFree(errmsg);
232           }
233       }
234       else
235       {
236         errmsg = LogToolTalkMessage (DtMsgLogError,
237                                      ERR_TT_OPEN,
238                                      (char*)DFLTXT_OPEN,
239                                      tt_state);
240         message_mgr().error_dialog( (char*)UAS_String(errmsg) );
241         XtFree(errmsg);
242       }
243   }
244   else
245   {
246     errmsg = LogToolTalkMessage (DtMsgLogError, 
247                                  ERR_TT_DEFAULT_AS_SESSION,
248                                  (char*)DFLTXT_DEFAULT_AS_SESSION,
249                                  tt_state);
250     message_mgr().error_dialog( (char*)UAS_String(errmsg) );
251     XtFree(errmsg);
252   }
253   if( tt_state != TT_OK )
254   {
255       XtAppAddWorkProc( window_system().app_context(),
256                         ipc_error_wp, &tt_state ) ;
257   }
258   // else -- ipc_init_wp1 will attempt to join the session
259
260   tt_release( mark ) ;
261   window_system().reset_cursor();
262 }
263
264
265 // /////////////////////////////////////////////////////////////////
266 // ipc_init_wp0()
267 // 2nd-level tt init functions, set by class constructor as XtWorkProc
268 // /////////////////////////////////////////////////////////////////
269
270 Boolean
271 TtIpcMgr::ipc_init_wp0( XtPointer /* theIpcObj */ )
272 {
273   int           mark ;
274
275   mark = tt_mark() ;
276
277   Tt_status tstp = tt_ptype_declare("DtInfoPrint");
278   if(tstp != TT_OK )
279   {    
280       DtMsgLogMessage("dtinfo", DtMsgLogError,
281                     "%s: %s", "tt_ptype_declare",
282                     (char *) CATGETS(
283                     Set_TtIpcMgr, 9, 
284    "The process type 'DtInfoPrint' is not the\nname of an installed process type."));
285   }
286   tt_release( mark ) ;
287   return True ;         // do workproc once
288 }
289
290
291 // /////////////////////////////////////////////////////////////////
292 // ipc_init_wp1()
293 // 3rd-level tt init functions, set by class constructor as XtWorkProc
294 // /////////////////////////////////////////////////////////////////
295
296 Boolean
297 TtIpcMgr::ipc_init_wp1( XtPointer theIpcObj )
298 {
299   if( ((TtIpcMgr*)theIpcObj)->tt_state == TT_OK )
300   {
301       window_system().wait_cursor();    // this tt Can take a while
302
303       int mark = tt_mark() ;
304
305       // actually join the "default" session for all previously
306       // registered patterns to take effect there-in
307       // Tt_pattern *sess_patterns =
308              ttdt_session_join( NULL, NULL,
309                          window_system().toplevel(), theIpcObj, True ) ;
310       // invoke msg handler explicitly in case a message already queued
311       XtAppAddWorkProc( window_system().app_context(),
312                         receive_tt_msg_wp, theIpcObj ) ;
313       tt_release( mark ) ;
314       window_system().reset_cursor();
315   }
316   return True ;         // do workproc once
317 }
318
319
320 // /////////////////////////////////////////////////////////////////
321 // class destructor
322 // /////////////////////////////////////////////////////////////////
323
324 TtIpcMgr::~TtIpcMgr()
325 {
326   // char  *dfile;
327
328   // send a Dtinfo_Quit message to whomever may be observing
329   notify_quit() ;
330
331   // if ((dfile = tt_default_file()) != (char *)0)
332   // {
333   //   tt_file_quit(dfile) ;
334   // }
335   // ttdt_session_quit( NULL, sess_patterns, True ) ;
336   // ttdt_close( NULL, NULL, True ) ;
337 }
338
339
340 // /////////////////////////////////////////////////////////////////
341 // establish_server - for any coordination purposes (future)
342 // /////////////////////////////////////////////////////////////////
343
344 void
345 TtIpcMgr::establish_server()
346 {
347 }
348
349
350 // /////////////////////////////////////////////////////////////////
351 // do_infolib
352 //
353 // load of infolib requested, so do it here if infolib ID valid
354 // /////////////////////////////////////////////////////////////////
355
356 int
357 TtIpcMgr::do_infolib( char *lib_path )
358 {
359   int   sts = ID_SUCCESS ;
360
361   if( !lib_path )
362   {
363       // if no file argument specified, get the default
364       if( !(lib_path = env().infolibDefault()) )
365       {
366           message_mgr().error_dialog( (char*)UAS_String(CATGETS(
367                     Set_AddLibraryAgent, ERR_INFOLIB_SPEC_FORMAT,
368                     "Infolib specification format error." )) ) ;
369           return (sts = BAD_ARG_FORMAT);
370       }
371       sts = LibraryAgent::add_library( lib_path ) ;
372       XtFree( lib_path ) ;  // this path only
373   }
374   else
375       sts = LibraryAgent::add_library( lib_path ) ;
376
377   // possible returns ID_SUCCESS, NOT_FOUND, BAD_ARG_FORMAT, LOAD_ERROR
378   return sts ;
379 }
380
381
382 // /////////////////////////////////////////////////////////////////
383 // do_locator
384 //
385 // view of specific doc requested, so do it here if locator ID valid
386 //
387 // Check for NULL locator pointer before passing it.
388 // /////////////////////////////////////////////////////////////////
389
390 int
391 TtIpcMgr::do_locator( char      *locator,
392                       Boolean   new_window )
393 {
394   return UrlAgent::document( locator, new_window ) ;
395 }
396
397 // /////////////////////////////////////////////////////////////////
398 // do_print
399 // 
400 // takes a section locators and prints it
401 //
402 // Prerequisites: Load any infolibs separately specified first.
403 // /////////////////////////////////////////////////////////////////
404 int
405 TtIpcMgr::do_print(Tt_message msg)
406 {
407     UAS_Pointer<UAS_Common> d = NULL ;
408     char *filepath = tt_message_file(msg);
409     FILE *fp;
410     char locator[512];
411     int bufferlen;
412     
413     fprintf(stderr, "TtIpcMgr::do_print: filepath = %s.\n", filepath);
414     
415     //  Open the file containing the list of sections to be printed for reading
416     
417     if ((fp = fopen(filepath, "r")) == NULL) {
418         fprintf(stderr, "Cannot open file %s.\n", filepath);
419     }
420
421     //  Get a handle to the AppPrintData allocated in the WindowSystem class
422
423     AppPrintData* p = window_system().GetAppPrintData();
424
425     //  Create a list of items to be printed
426
427     xList<UAS_Pointer<UAS_Common> > * print_list = new  xList<UAS_Pointer<UAS_Common> >;
428
429     // each line of the temporary file contains a locator.  create a UAS_Common buffer
430     // for each locator and add it to the print list
431     
432     while (fgets(locator, sizeof(locator), fp) != NULL) {
433    
434         if( !strchr( locator, ':' ) && !strchr( locator, '/' ) )
435         {
436             // assume given a unique locator ID for the target.
437             // construct a fully-qualified form and pass it on.
438
439             bufferlen = strlen("mmdb:LOCATOR=") + strlen(locator) + 1;
440             char *buffer = new char[bufferlen];
441             snprintf (buffer, bufferlen, "mmdb:LOCATOR=%s", locator);
442             d = UAS_Common::create (buffer);
443             delete [] buffer;
444         }
445         else
446         {
447             // assume to have a fully-qualified locator
448             d = UAS_Common::create(locator);
449         }
450
451         //  add UAS_Common pointer to list of sections to print
452
453         if (d != (const int)0)
454         {
455             print_list->append(d);
456         }
457         else {
458             fprintf(stderr, "Wow!  Null section!\n");
459         }
460             
461     }    // end locators in file
462
463     p->f_outline_element = NULL;
464     p->f_print_list = print_list;
465
466     XtAppAddWorkProc(window_system().app_context(), ipc_print_wp, p) ;
467     
468     fclose(fp);
469     fprintf(stderr, "do_print: exiting\n");    
470     return 1 ;
471 }
472
473
474 // /////////////////////////////////////////////////////////////////
475 // handle
476 //
477 // based on message type, initiate the appropriate response
478 // /////////////////////////////////////////////////////////////////
479
480 int
481 TtIpcMgr::handle( Tt_message msg_in )
482 {
483   int   opstatus = UNKNOWN_MSG ;
484   char *info_file ;
485   char *info_uuid ;
486   Tt_status     tst ;
487
488   {
489     switch( tt_message_opnum(msg_in) )
490     {
491       case SHOW_INFO_AT_LOC :
492
493         // - arg for locator required (any valid format).
494         // - if File provided, an infolib Add is attempted first. 
495         // - The infolib path may be provided via the locator part,
496         //   but the infolib will not be Added if only this is the case.
497
498         if( (opstatus = check_locale( msg_in, 2 )) == ID_SUCCESS )
499         {
500             // get the locator value, per spec'd position
501             info_uuid = tt_message_arg_val( msg_in, 3 ) ;
502             if( (tst = tt_ptr_error( info_uuid )) != TT_OK ) 
503             {
504               XtAppAddWorkProc( window_system().app_context(),
505                                 ipc_error_wp, &tst ) ;
506               return (opstatus = MSG_SYNTAX_ERROR) ;
507             }
508
509             // check to see if an optional File arg is supplied for infolib
510
511             info_file = tt_message_file( msg_in ) ;
512             if( (tst = tt_ptr_error( info_file )) != TT_OK )
513             {
514               XtAppAddWorkProc( window_system().app_context(),
515                                 ipc_error_wp, &tst ) ;
516               return (opstatus = MSG_SYNTAX_ERROR) ;
517             }
518             else
519             {
520               do_infolib( info_file ) ;   // load infolib per File, first
521             }
522                        // try to get the section
523             workspace().target( curr_ws_tt ) ;
524             opstatus = do_locator( info_uuid, True ) ;
525         }
526         break ;
527
528       case LOAD_INFO_LIB :
529
530         if( (opstatus = check_locale( msg_in, 2 )) == ID_SUCCESS )
531         {
532             info_uuid = tt_message_file( msg_in ) ;
533             if( (tst = tt_ptr_error( info_uuid )) != TT_OK )
534             {
535               XtAppAddWorkProc( window_system().app_context(),
536                                 ipc_error_wp, &tst ) ;
537               return (opstatus = MSG_SYNTAX_ERROR) ;
538             }
539
540             workspace().target( curr_ws_tt ) ;
541             opstatus = do_infolib( info_uuid ) ;
542         }
543         break ;
544
545       case PRINT_INFO_AT_LOC :    
546           opstatus = do_print(msg_in);
547         break ;
548
549       case QUIT_DTINFO :        // ignored
550         break ;
551
552       default :
553         /* don't know what else to do with this message */
554         opstatus = UNKNOWN_MSG ;
555         break ;
556     }
557   }
558   return opstatus ;
559 }
560
561
562 // /////////////////////////////////////////////////////////////////
563 // check_locale
564 //
565 // 
566 // /////////////////////////////////////////////////////////////////
567 int
568 TtIpcMgr::check_locale( Tt_message msg_in,
569                         int        locale_arg_pos )
570 {
571   int       sts = ID_SUCCESS ;
572   Tt_status tst ;
573   char * target_locale ;
574
575   // test for locale match -- can't display data for different locale.
576   // NULL locale is OK.
577   target_locale = tt_message_arg_val( msg_in, locale_arg_pos ) ;
578
579   if( (tst = tt_ptr_error( target_locale )) != TT_OK ) 
580   {
581       XtAppAddWorkProc( window_system().app_context(),
582                         ipc_error_wp, &tst ) ;
583       return (sts = MSG_SYNTAX_ERROR) ;
584   }
585   if(    *target_locale != '\0'
586       && strcmp( target_locale, env().lang() ) != 0
587       && getenv( "LANG" ) != NULL
588       && strcmp( target_locale, getenv( "LANG" ) ) != 0 )
589   { sts = NOT_OWNER ; }
590
591   return (sts) ;
592 }
593
594
595 char * locale_of_desktop() ;
596
597 // /////////////////////////////////////////////////////////////////
598 // receive_tt_msg
599 //
600 // a static member function of the TtIpcMgr class.
601 // used as an input handler per X
602 //
603 // gets the msg, invokes handler for class, and makes the appropriate
604 // tt response per handler disposition status
605 // /////////////////////////////////////////////////////////////////
606
607 // /*ARGSUSED*/
608 void
609 TtIpcMgr::receive_tt_msg( XtPointer client_data,
610                           int *fid,
611                           XtInputId *id )
612 {
613   int           mark;
614   Tt_status     tst ;
615
616   mark = tt_mark();
617
618   Tt_message msg_in = tt_message_receive() ;
619
620   if( msg_in == NULL )
621   {
622     // NULL msg pointer input is "normal" in certain tt cases,
623     // and in typical non-tt start-up of dtinfo
624     tt_release(mark);
625     return ;
626   }
627   if( msg_in == prior_tt_msg )
628   {
629     // A single instance of dtinfo should never get the same message
630     // handle invocation twice, unless it is a reply to the msg which
631     // we sent (and none are currently expected).  This check
632     // should prevent any infinite loop conditions (which are possible
633     // between tt and joined processes, under certain error conditions).
634     tttk_message_fail( msg_in,
635                        TT_ERR_PROCID, NULL, 1 ) ;
636     tt_release(mark);
637     return ;
638   }
639
640   // record the current desktop workspace now
641   // (this should approximate tt requestor's workspace)
642   workspace().current( &curr_ws_tt ) ;
643
644   if( (tst = tt_pointer_error( msg_in )) == TT_ERR_NOMP )
645   {
646     // fprintf(stderr,"ToolTalk server down.\n");
647     XtAppAddWorkProc( window_system().app_context(),
648                       ipc_error_wp, &tst ) ;
649     return ;   // should not be fatal, but need feedback...
650   }
651
652   switch( ((TtIpcMgr*)client_data)->handle(msg_in) )
653   {
654     case ID_SUCCESS :
655
656         if( ( tt_message_class( msg_in ) == TT_REQUEST )
657             || ( id == NULL ) )
658         {
659             tt_message_reply( msg_in ) ;
660         }
661         break ;
662
663     case MSG_SYNTAX_ERROR :
664     case BAD_ARG_FORMAT :
665     case LOAD_ERROR :
666     case NOT_FOUND :
667
668            // *Only at This point* for "NOT_FOUND" case could we decide
669            // that "exec_host" might be relevant for a subsequent remote
670            // access attempt (were we handling that from dtinfo to kick
671            // off a fallback process...)
672
673         // arg format, not found, or
674         // load errors have already been "handled" with an error dialog,
675         // so if we did a fail here, there will be redundant and less
676         // specific dialog presented by the messaging system. Thus, reply.
677
678         if( ( tt_message_class( msg_in ) == TT_REQUEST )
679             || ( fid == NULL ) )
680         {
681             tt_message_reply( msg_in ) ;
682         }
683         // tttk_message_fail( msg_in,   // can't process message
684         //                 TT_ERR_FILE, NULL, 1 ) ;
685         break ;
686
687     case NOT_OWNER :
688
689         // exec host has to be detected prior to the dtinfo start to
690         // have any effect. locale is also expected to be set correctly
691         // prior to dtinfo invocation. However, if locale was specified
692         // it is checked, and in any case for which it does not match,
693         // the message must be rejected so that tt can pass it to another
694         // instance or launch an instance to handle it. Since this dtinfo
695         // instance may be the only handler currently available, we could
696         // also launch a dtinfo instance in the requested locale before
697         // rejecting the message. Else, if we are in the default
698         // (desktop's) locale, ttsession may go into an infinite
699         // loop creating default dtinfo instances (depending on
700         // the ptype definition), trying to find a handler...
701         // But... if this instance is Not running in the default locale,
702         // we want tt to go ahead and start such a copy! Need to determine
703         // whether this instance is running in the default/desktop locale,
704         // and based on that do fail or reject... jcb
705       {
706         char *ref_locale = locale_of_desktop();
707         if(   ref_locale
708            && strcmp( ref_locale, env().lang() ) != 0
709            && getenv( "LANG" ) != NULL
710            && strcmp( ref_locale, getenv( "LANG" ) ) != 0 )
711         {
712             // don't want to process nor kill message, so reject to
713             // let tooltalk start a default instance. If that instance
714             // also cannot service the request precisely, it will kill
715             // the message.
716             tttk_message_reject( msg_in, TT_ERR_NOTHANDLER, NULL, 0 ) ;
717         }
718         else                   // can't process message
719             tttk_message_fail( msg_in,
720                                TT_ERR_PROCID, NULL, 1 ) ;
721
722         if( ref_locale )  XFree( ref_locale );
723       }
724         break;
725
726     default:
727     case UNKNOWN_MSG :
728
729         tttk_message_abandon( msg_in ) ;        // don't understand message
730         break ;
731   }
732
733   // tt_mark/tt_release tags memory allocated by tt for a given
734   // msg cycle, to ensure that it is all freed when done.
735
736   tt_release(mark);
737
738   return;
739 }
740
741
742 // receive_tt_msg_wp
743 //
744 // Background task to check explicitly for tt message input
745 //
746 Boolean
747 TtIpcMgr::receive_tt_msg_wp( XtPointer theIpcObj )
748 {
749   receive_tt_msg( theIpcObj, NULL, NULL ) ;
750   return True ;
751 }
752
753
754 // ipc_print_wp
755 //
756 // Display print dialog
757 //
758 Boolean
759 TtIpcMgr::ipc_print_wp( XtPointer client_data )
760 {
761     AppPrintData* p = (AppPrintData *)client_data;
762  
763     CreatePrintSetup(p->f_pshell_parent, p);
764     
765     XtManageChild(p->f_print_dialog); /* popup dialog each time */
766     
767     return True ;
768 }
769
770 // ipc_error_wp
771 //
772 // Translate any tooltalk error message numbers and post for user.
773 // Probables: TT_ERR_SESSION TT_ERR_NOMP TT_ERR_PROCID TT_ERR_PTYPE
774 //
775 Boolean
776 TtIpcMgr::ipc_error_wp( XtPointer client_data )
777 {
778   message_mgr().error_dialog(
779                   tt_status_message( *((Tt_status*)client_data) ) ) ;
780   return True ;
781 }
782
783
784 void
785 TtIpcMgr::notify_quit()
786 {
787   Tt_message msg_out;
788
789   // create and send a "quit" notice message for any observers
790
791   msg_out = tt_pnotice_create( TT_SESSION, "DtInfo_Quit" ) ;
792
793   tt_message_send( msg_out ) ;
794   
795   // no reply expected since this was a notice, so no longer need
796   // handle for the message
797
798   tt_message_destroy( msg_out ) ;
799 }
800
801
802 // get the Dt session manager's locale context property as a reliable
803 // reference point with which to compare to the dtinfo instance's
804 // current locale. Caller needs to free the string memory returned
805 // with XFree().
806 //
807 // Note: this function should really reside in the EnvMgr class
808 //
809 char *
810 locale_of_desktop()
811 {
812         static Atom _DT_SM_WINDOW_INFO = None;
813         static Atom WM_LOCALE_NAME = None;
814
815         Atom type = None;
816         int format;
817         unsigned long nitems, after;
818         // WM_LOCALE_NAME Atom (string data)
819         char    *dt_locale;
820         // _DT_SM_WINDOW_INFO Atom (PropDtSmWindowInfo structure data)
821         Window  *sm_prop_window;
822
823         Display *dpy = window_system().display();
824
825
826         if(WM_LOCALE_NAME == None) {
827             WM_LOCALE_NAME = XInternAtom(dpy, "WM_LOCALE_NAME", True);
828         }
829 #ifdef DEBUG
830         if (!WM_LOCALE_NAME)
831             printf( "Atom WM_LOCALE_NAME not interned\n" );
832 #endif
833
834         if (!WM_LOCALE_NAME)    return (char *)NULL;
835
836         if(_DT_SM_WINDOW_INFO == None) {
837             _DT_SM_WINDOW_INFO =
838                          XInternAtom(dpy, _XA_DT_SM_WINDOW_INFO, False);
839         }
840 #ifdef DEBUG
841         if (!_DT_SM_WINDOW_INFO)
842             printf( "Atom _DT_SM_WINDOW_INFO not interned\n" );
843 #endif
844
845         if (!_DT_SM_WINDOW_INFO)  return (char *)NULL;
846
847         XGetWindowProperty( dpy,
848                             XDefaultRootWindow(dpy),
849                             _DT_SM_WINDOW_INFO,
850                             1L, 1L, False,
851                             _DT_SM_WINDOW_INFO,
852                             &type, &format, &nitems, &after,
853                             (unsigned char **)(void*)&sm_prop_window) ;
854
855 #ifdef DEBUG
856 // property.smWindow = (unsigned long) smGD.topLevelWindow;
857         if (!sm_prop_window)    
858             printf(
859              "null value from Atom _DT_SM_WINDOW_INFO for SM window ID\n" );
860         else
861             printf( "dtsession window is %lx\n", *sm_prop_window );
862 #endif
863
864         if (!sm_prop_window)    return (char *)NULL;
865
866         type = None;
867         XGetWindowProperty( dpy,
868                             *sm_prop_window,
869                             WM_LOCALE_NAME,
870                             0L, (long)8, False,
871                             XA_STRING,
872                             &type, &format, &nitems, &after,
873                             (unsigned char **)(void*)&dt_locale) ;
874
875 #ifdef DEBUG
876         printf( "desktop's locale is %s\n", dt_locale ) ;
877 #endif
878
879         if (!dt_locale)   return (char *)NULL;
880         else              return dt_locale;
881 }
882
883