2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
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
24 * $TOG: TtIpcMgr.C /main/16 1999/09/20 13:30:40 mgreess $
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.
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.
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
44 #define C_LibraryAgent
45 #define C_PrintPanelAgent
56 #define C_WorkspaceMgr
59 #define C_WindowSystem
64 #include "Managers/CatMgr.hh"
65 #include "Registration.hh"
67 #include "utility/mmdb_exception.h"
68 #include "utility/funcs.h"
73 #include <X11/Intrinsic.h>
75 // the Session include file(s) are for locale_of_desktop()
76 //#include <Dt/SessionP.h>
77 #include <Dt/SessionM.h>
79 #include <Dt/EnvControlP.h>
80 #include <Dt/Action.h>
81 #include <Dt/DtGetMessageP.h>
82 #include <Dt/MsgLog.h>
89 LONG_LIVED_CC( TtIpcMgr, tt_manager )
92 # define RCS_DEBUG(statement) cerr << statement << endl
94 # define RCS_DEBUG(statement)
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
104 // the following defines are for message index per catalog
105 // Set_AddLibraryAgent:
106 #define ERR_INFOLIB_SPEC_FORMAT 5
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
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"
118 // the last message handled, for sanity checking
119 Tt_message prior_tt_msg ;
121 // temp internal tracking of curr workspace at time tt msg received
125 // /////////////////////////////////////////////////////////////////
126 // LogToolTalkMessage - records messages to log
127 // /////////////////////////////////////////////////////////////////
131 DtMsgLogType msg_type,
141 if (! tt_is_err(status)) return XtsNewString("");;
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);
151 DtMsgLogMessage ("Dtinfo", msg_type, errfmt, errmsg);
156 // /////////////////////////////////////////////////////////////////
158 // /////////////////////////////////////////////////////////////////
160 // TtIpcMgr constructor
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.
175 // Initialize ToolTalk
177 window_system().wait_cursor(); // this tt stuff Can take a while
181 xsession = tt_X_session(
182 (const char *)(XDisplayString((window_system().display()))) ) ;
184 if( tt_ptr_error( xsession ) != TT_OK )
186 errmsg = LogToolTalkMessage (DtMsgLogError,
187 ERR_TT_DISPLAY_AS_SESSION,
188 (char*)DFLTXT_DISPLAY_AS_SESSION,
190 message_mgr().error_dialog( (char*)UAS_String(errmsg) ) ;
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 ) ;
201 if( (tt_state = tt_default_session_set( xsession )) == TT_OK )
203 procid = ttdt_open( &ttfd, "Dtinfo", "Fujitsu", "CDE", True ) ;
204 //why is fujitsu mentioned here? 05/15/18 - C
206 if( (tt_state = tt_pointer_error( procid ))
209 // declare Dtinfo Ptype
210 if( (tt_state = tt_ptype_declare( "DtInfo" )) == TT_OK )
212 // success -- add an input handler for tooltalk msgs
213 XtAppAddInput( window_system().app_context(), ttfd,
214 (XtPointer) XtInputReadMask,
215 receive_tt_msg, this ) ;
217 // declare DtinfoPrint ptype (non-fatal if prior ptype ok).
218 // Also can be broken out & deferred via the work proc.
219 XtAppAddWorkProc( window_system().app_context(),
220 ipc_init_wp0, this ) ;
224 // HEY! No matter what exit you take from here, it must
225 // return True! -- its a work proc!
227 errmsg = LogToolTalkMessage (DtMsgLogError,
228 ERR_TT_PTYPE_DECLARE,
229 (char*)DFLTXT_PTYPE_DECLARE,
231 message_mgr().error_dialog( (char*)UAS_String(errmsg) );
237 errmsg = LogToolTalkMessage (DtMsgLogError,
241 message_mgr().error_dialog( (char*)UAS_String(errmsg) );
247 errmsg = LogToolTalkMessage (DtMsgLogError,
248 ERR_TT_DEFAULT_AS_SESSION,
249 (char*)DFLTXT_DEFAULT_AS_SESSION,
251 message_mgr().error_dialog( (char*)UAS_String(errmsg) );
254 if( tt_state != TT_OK )
256 XtAppAddWorkProc( window_system().app_context(),
257 ipc_error_wp, &tt_state ) ;
259 // else -- ipc_init_wp1 will attempt to join the session
262 window_system().reset_cursor();
266 // /////////////////////////////////////////////////////////////////
268 // 2nd-level tt init functions, set by class constructor as XtWorkProc
269 // /////////////////////////////////////////////////////////////////
272 TtIpcMgr::ipc_init_wp0( XtPointer /* theIpcObj */ )
278 Tt_status tstp = tt_ptype_declare("DtInfoPrint");
281 DtMsgLogMessage("dtinfo", DtMsgLogError,
282 "%s: %s", "tt_ptype_declare",
285 "The process type 'DtInfoPrint' is not the\nname of an installed process type."));
288 return True ; // do workproc once
292 // /////////////////////////////////////////////////////////////////
294 // 3rd-level tt init functions, set by class constructor as XtWorkProc
295 // /////////////////////////////////////////////////////////////////
298 TtIpcMgr::ipc_init_wp1( XtPointer theIpcObj )
300 if( ((TtIpcMgr*)theIpcObj)->tt_state == TT_OK )
302 window_system().wait_cursor(); // this tt Can take a while
304 int mark = tt_mark() ;
306 // actually join the "default" session for all previously
307 // registered patterns to take effect there-in
308 // Tt_pattern *sess_patterns =
309 ttdt_session_join( NULL, NULL,
310 window_system().toplevel(), theIpcObj, True ) ;
311 // invoke msg handler explicitly in case a message already queued
312 XtAppAddWorkProc( window_system().app_context(),
313 receive_tt_msg_wp, theIpcObj ) ;
315 window_system().reset_cursor();
317 return True ; // do workproc once
321 // /////////////////////////////////////////////////////////////////
323 // /////////////////////////////////////////////////////////////////
325 TtIpcMgr::~TtIpcMgr()
329 // send a Dtinfo_Quit message to whomever may be observing
332 // if ((dfile = tt_default_file()) != (char *)0)
334 // tt_file_quit(dfile) ;
336 // ttdt_session_quit( NULL, sess_patterns, True ) ;
337 // ttdt_close( NULL, NULL, True ) ;
341 // /////////////////////////////////////////////////////////////////
342 // establish_server - for any coordination purposes (future)
343 // /////////////////////////////////////////////////////////////////
346 TtIpcMgr::establish_server()
351 // /////////////////////////////////////////////////////////////////
354 // load of infolib requested, so do it here if infolib ID valid
355 // /////////////////////////////////////////////////////////////////
358 TtIpcMgr::do_infolib( char *lib_path )
360 int sts = ID_SUCCESS ;
364 // if no file argument specified, get the default
365 if( !(lib_path = env().infolibDefault()) )
367 message_mgr().error_dialog( (char*)UAS_String(CATGETS(
368 Set_AddLibraryAgent, ERR_INFOLIB_SPEC_FORMAT,
369 "Infolib specification format error." )) ) ;
370 return (sts = BAD_ARG_FORMAT);
372 sts = LibraryAgent::add_library( lib_path ) ;
373 XtFree( lib_path ) ; // this path only
376 sts = LibraryAgent::add_library( lib_path ) ;
378 // possible returns ID_SUCCESS, NOT_FOUND, BAD_ARG_FORMAT, LOAD_ERROR
383 // /////////////////////////////////////////////////////////////////
386 // view of specific doc requested, so do it here if locator ID valid
388 // Check for NULL locator pointer before passing it.
389 // /////////////////////////////////////////////////////////////////
392 TtIpcMgr::do_locator( char *locator,
395 return UrlAgent::document( locator, new_window ) ;
398 // /////////////////////////////////////////////////////////////////
401 // takes a section locators and prints it
403 // Prerequisites: Load any infolibs separately specified first.
404 // /////////////////////////////////////////////////////////////////
406 TtIpcMgr::do_print(Tt_message msg)
408 UAS_Pointer<UAS_Common> d = NULL ;
409 char *filepath = tt_message_file(msg);
414 fprintf(stderr, "TtIpcMgr::do_print: filepath = %s.\n", filepath);
416 // Open the file containing the list of sections to be printed for reading
418 if ((fp = fopen(filepath, "r")) == NULL) {
419 fprintf(stderr, "Cannot open file %s.\n", filepath);
422 // Get a handle to the AppPrintData allocated in the WindowSystem class
424 AppPrintData* p = window_system().GetAppPrintData();
426 // Create a list of items to be printed
428 xList<UAS_Pointer<UAS_Common> > * print_list = new xList<UAS_Pointer<UAS_Common> >;
430 // each line of the temporary file contains a locator. create a UAS_Common buffer
431 // for each locator and add it to the print list
433 while (fgets(locator, sizeof(locator), fp) != NULL) {
435 if( !strchr( locator, ':' ) && !strchr( locator, '/' ) )
437 // assume given a unique locator ID for the target.
438 // construct a fully-qualified form and pass it on.
440 bufferlen = strlen("mmdb:LOCATOR=") + strlen(locator) + 1;
441 char *buffer = new char[bufferlen];
442 snprintf (buffer, bufferlen, "mmdb:LOCATOR=%s", locator);
443 d = UAS_Common::create (buffer);
448 // assume to have a fully-qualified locator
449 d = UAS_Common::create(locator);
452 // add UAS_Common pointer to list of sections to print
454 if (d != (const int)0)
456 print_list->append(d);
459 fprintf(stderr, "Wow! Null section!\n");
462 } // end locators in file
464 p->f_outline_element = NULL;
465 p->f_print_list = print_list;
467 XtAppAddWorkProc(window_system().app_context(), ipc_print_wp, p) ;
470 fprintf(stderr, "do_print: exiting\n");
475 // /////////////////////////////////////////////////////////////////
478 // based on message type, initiate the appropriate response
479 // /////////////////////////////////////////////////////////////////
482 TtIpcMgr::handle( Tt_message msg_in )
484 int opstatus = UNKNOWN_MSG ;
490 switch( tt_message_opnum(msg_in) )
492 case SHOW_INFO_AT_LOC :
494 // - arg for locator required (any valid format).
495 // - if File provided, an infolib Add is attempted first.
496 // - The infolib path may be provided via the locator part,
497 // but the infolib will not be Added if only this is the case.
499 if( (opstatus = check_locale( msg_in, 2 )) == ID_SUCCESS )
501 // get the locator value, per spec'd position
502 info_uuid = tt_message_arg_val( msg_in, 3 ) ;
503 if( (tst = tt_ptr_error( info_uuid )) != TT_OK )
505 XtAppAddWorkProc( window_system().app_context(),
506 ipc_error_wp, &tst ) ;
507 return (opstatus = MSG_SYNTAX_ERROR) ;
510 // check to see if an optional File arg is supplied for infolib
512 info_file = tt_message_file( msg_in ) ;
513 if( (tst = tt_ptr_error( info_file )) != TT_OK )
515 XtAppAddWorkProc( window_system().app_context(),
516 ipc_error_wp, &tst ) ;
517 return (opstatus = MSG_SYNTAX_ERROR) ;
521 do_infolib( info_file ) ; // load infolib per File, first
523 // try to get the section
524 workspace().target( curr_ws_tt ) ;
525 opstatus = do_locator( info_uuid, True ) ;
531 if( (opstatus = check_locale( msg_in, 2 )) == ID_SUCCESS )
533 info_uuid = tt_message_file( msg_in ) ;
534 if( (tst = tt_ptr_error( info_uuid )) != TT_OK )
536 XtAppAddWorkProc( window_system().app_context(),
537 ipc_error_wp, &tst ) ;
538 return (opstatus = MSG_SYNTAX_ERROR) ;
541 workspace().target( curr_ws_tt ) ;
542 opstatus = do_infolib( info_uuid ) ;
546 case PRINT_INFO_AT_LOC :
547 opstatus = do_print(msg_in);
550 case QUIT_DTINFO : // ignored
554 /* don't know what else to do with this message */
555 opstatus = UNKNOWN_MSG ;
563 // /////////////////////////////////////////////////////////////////
567 // /////////////////////////////////////////////////////////////////
569 TtIpcMgr::check_locale( Tt_message msg_in,
572 int sts = ID_SUCCESS ;
574 char * target_locale ;
576 // test for locale match -- can't display data for different locale.
577 // NULL locale is OK.
578 target_locale = tt_message_arg_val( msg_in, locale_arg_pos ) ;
580 if( (tst = tt_ptr_error( target_locale )) != TT_OK )
582 XtAppAddWorkProc( window_system().app_context(),
583 ipc_error_wp, &tst ) ;
584 return (sts = MSG_SYNTAX_ERROR) ;
586 if( *target_locale != '\0'
587 && strcmp( target_locale, env().lang() ) != 0
588 && getenv( "LANG" ) != NULL
589 && strcmp( target_locale, getenv( "LANG" ) ) != 0 )
590 { sts = NOT_OWNER ; }
596 char * locale_of_desktop() ;
598 // /////////////////////////////////////////////////////////////////
601 // a static member function of the TtIpcMgr class.
602 // used as an input handler per X
604 // gets the msg, invokes handler for class, and makes the appropriate
605 // tt response per handler disposition status
606 // /////////////////////////////////////////////////////////////////
610 TtIpcMgr::receive_tt_msg( XtPointer client_data,
619 Tt_message msg_in = tt_message_receive() ;
623 // NULL msg pointer input is "normal" in certain tt cases,
624 // and in typical non-tt start-up of dtinfo
628 if( msg_in == prior_tt_msg )
630 // A single instance of dtinfo should never get the same message
631 // handle invocation twice, unless it is a reply to the msg which
632 // we sent (and none are currently expected). This check
633 // should prevent any infinite loop conditions (which are possible
634 // between tt and joined processes, under certain error conditions).
635 tttk_message_fail( msg_in,
636 TT_ERR_PROCID, NULL, 1 ) ;
641 // record the current desktop workspace now
642 // (this should approximate tt requestor's workspace)
643 workspace().current( &curr_ws_tt ) ;
645 if( (tst = tt_pointer_error( msg_in )) == TT_ERR_NOMP )
647 // fprintf(stderr,"ToolTalk server down.\n");
648 XtAppAddWorkProc( window_system().app_context(),
649 ipc_error_wp, &tst ) ;
650 return ; // should not be fatal, but need feedback...
653 switch( ((TtIpcMgr*)client_data)->handle(msg_in) )
657 if( ( tt_message_class( msg_in ) == TT_REQUEST )
660 tt_message_reply( msg_in ) ;
664 case MSG_SYNTAX_ERROR :
665 case BAD_ARG_FORMAT :
669 // *Only at This point* for "NOT_FOUND" case could we decide
670 // that "exec_host" might be relevant for a subsequent remote
671 // access attempt (were we handling that from dtinfo to kick
672 // off a fallback process...)
674 // arg format, not found, or
675 // load errors have already been "handled" with an error dialog,
676 // so if we did a fail here, there will be redundant and less
677 // specific dialog presented by the messaging system. Thus, reply.
679 if( ( tt_message_class( msg_in ) == TT_REQUEST )
682 tt_message_reply( msg_in ) ;
684 // tttk_message_fail( msg_in, // can't process message
685 // TT_ERR_FILE, NULL, 1 ) ;
690 // exec host has to be detected prior to the dtinfo start to
691 // have any effect. locale is also expected to be set correctly
692 // prior to dtinfo invocation. However, if locale was specified
693 // it is checked, and in any case for which it does not match,
694 // the message must be rejected so that tt can pass it to another
695 // instance or launch an instance to handle it. Since this dtinfo
696 // instance may be the only handler currently available, we could
697 // also launch a dtinfo instance in the requested locale before
698 // rejecting the message. Else, if we are in the default
699 // (desktop's) locale, ttsession may go into an infinite
700 // loop creating default dtinfo instances (depending on
701 // the ptype definition), trying to find a handler...
702 // But... if this instance is Not running in the default locale,
703 // we want tt to go ahead and start such a copy! Need to determine
704 // whether this instance is running in the default/desktop locale,
705 // and based on that do fail or reject... jcb
707 char *ref_locale = locale_of_desktop();
709 && strcmp( ref_locale, env().lang() ) != 0
710 && getenv( "LANG" ) != NULL
711 && strcmp( ref_locale, getenv( "LANG" ) ) != 0 )
713 // don't want to process nor kill message, so reject to
714 // let tooltalk start a default instance. If that instance
715 // also cannot service the request precisely, it will kill
717 tttk_message_reject( msg_in, TT_ERR_NOTHANDLER, NULL, 0 ) ;
719 else // can't process message
720 tttk_message_fail( msg_in,
721 TT_ERR_PROCID, NULL, 1 ) ;
723 if( ref_locale ) XFree( ref_locale );
730 tttk_message_abandon( msg_in ) ; // don't understand message
734 // tt_mark/tt_release tags memory allocated by tt for a given
735 // msg cycle, to ensure that it is all freed when done.
745 // Background task to check explicitly for tt message input
748 TtIpcMgr::receive_tt_msg_wp( XtPointer theIpcObj )
750 receive_tt_msg( theIpcObj, NULL, NULL ) ;
757 // Display print dialog
760 TtIpcMgr::ipc_print_wp( XtPointer client_data )
762 AppPrintData* p = (AppPrintData *)client_data;
764 CreatePrintSetup(p->f_pshell_parent, p);
766 XtManageChild(p->f_print_dialog); /* popup dialog each time */
773 // Translate any tooltalk error message numbers and post for user.
774 // Probables: TT_ERR_SESSION TT_ERR_NOMP TT_ERR_PROCID TT_ERR_PTYPE
777 TtIpcMgr::ipc_error_wp( XtPointer client_data )
779 message_mgr().error_dialog(
780 tt_status_message( *((Tt_status*)client_data) ) ) ;
786 TtIpcMgr::notify_quit()
790 // create and send a "quit" notice message for any observers
792 msg_out = tt_pnotice_create( TT_SESSION, "DtInfo_Quit" ) ;
794 tt_message_send( msg_out ) ;
796 // no reply expected since this was a notice, so no longer need
797 // handle for the message
799 tt_message_destroy( msg_out ) ;
803 // get the Dt session manager's locale context property as a reliable
804 // reference point with which to compare to the dtinfo instance's
805 // current locale. Caller needs to free the string memory returned
808 // Note: this function should really reside in the EnvMgr class
813 static Atom _DT_SM_WINDOW_INFO = None;
814 static Atom WM_LOCALE_NAME = None;
818 unsigned long nitems, after;
819 // WM_LOCALE_NAME Atom (string data)
821 // _DT_SM_WINDOW_INFO Atom (PropDtSmWindowInfo structure data)
822 Window *sm_prop_window;
824 Display *dpy = window_system().display();
827 if(WM_LOCALE_NAME == None) {
828 WM_LOCALE_NAME = XInternAtom(dpy, "WM_LOCALE_NAME", True);
832 printf( "Atom WM_LOCALE_NAME not interned\n" );
835 if (!WM_LOCALE_NAME) return (char *)NULL;
837 if(_DT_SM_WINDOW_INFO == None) {
839 XInternAtom(dpy, _XA_DT_SM_WINDOW_INFO, False);
842 if (!_DT_SM_WINDOW_INFO)
843 printf( "Atom _DT_SM_WINDOW_INFO not interned\n" );
846 if (!_DT_SM_WINDOW_INFO) return (char *)NULL;
848 XGetWindowProperty( dpy,
849 XDefaultRootWindow(dpy),
853 &type, &format, &nitems, &after,
854 (unsigned char **)(void*)&sm_prop_window) ;
857 // property.smWindow = (unsigned long) smGD.topLevelWindow;
860 "null value from Atom _DT_SM_WINDOW_INFO for SM window ID\n" );
862 printf( "dtsession window is %lx\n", *sm_prop_window );
865 if (!sm_prop_window) return (char *)NULL;
868 XGetWindowProperty( dpy,
873 &type, &format, &nitems, &after,
874 (unsigned char **)(void*)&dt_locale) ;
877 printf( "desktop's locale is %s\n", dt_locale ) ;
880 if (!dt_locale) return (char *)NULL;
881 else return dt_locale;