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 ) ;
205 if( (tt_state = tt_pointer_error( procid ))
208 // declare Dtinfo Ptype
209 if( (tt_state = tt_ptype_declare( "DtInfo" )) == TT_OK )
211 // success -- add an input handler for tooltalk msgs
212 XtAppAddInput( window_system().app_context(), ttfd,
213 (XtPointer) XtInputReadMask,
214 receive_tt_msg, this ) ;
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 ) ;
223 // HEY! No matter what exit you take from here, it must
224 // return True! -- its a work proc!
226 errmsg = LogToolTalkMessage (DtMsgLogError,
227 ERR_TT_PTYPE_DECLARE,
228 (char*)DFLTXT_PTYPE_DECLARE,
230 message_mgr().error_dialog( (char*)UAS_String(errmsg) );
236 errmsg = LogToolTalkMessage (DtMsgLogError,
240 message_mgr().error_dialog( (char*)UAS_String(errmsg) );
246 errmsg = LogToolTalkMessage (DtMsgLogError,
247 ERR_TT_DEFAULT_AS_SESSION,
248 (char*)DFLTXT_DEFAULT_AS_SESSION,
250 message_mgr().error_dialog( (char*)UAS_String(errmsg) );
253 if( tt_state != TT_OK )
255 XtAppAddWorkProc( window_system().app_context(),
256 ipc_error_wp, &tt_state ) ;
258 // else -- ipc_init_wp1 will attempt to join the session
261 window_system().reset_cursor();
265 // /////////////////////////////////////////////////////////////////
267 // 2nd-level tt init functions, set by class constructor as XtWorkProc
268 // /////////////////////////////////////////////////////////////////
271 TtIpcMgr::ipc_init_wp0( XtPointer /* theIpcObj */ )
277 Tt_status tstp = tt_ptype_declare("DtInfoPrint");
280 DtMsgLogMessage("dtinfo", DtMsgLogError,
281 "%s: %s", "tt_ptype_declare",
284 "The process type 'DtInfoPrint' is not the\nname of an installed process type."));
287 return True ; // do workproc once
291 // /////////////////////////////////////////////////////////////////
293 // 3rd-level tt init functions, set by class constructor as XtWorkProc
294 // /////////////////////////////////////////////////////////////////
297 TtIpcMgr::ipc_init_wp1( XtPointer theIpcObj )
299 if( ((TtIpcMgr*)theIpcObj)->tt_state == TT_OK )
301 window_system().wait_cursor(); // this tt Can take a while
303 int mark = tt_mark() ;
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 ) ;
314 window_system().reset_cursor();
316 return True ; // do workproc once
320 // /////////////////////////////////////////////////////////////////
322 // /////////////////////////////////////////////////////////////////
324 TtIpcMgr::~TtIpcMgr()
328 // send a Dtinfo_Quit message to whomever may be observing
331 // if ((dfile = tt_default_file()) != (char *)0)
333 // tt_file_quit(dfile) ;
335 // ttdt_session_quit( NULL, sess_patterns, True ) ;
336 // ttdt_close( NULL, NULL, True ) ;
340 // /////////////////////////////////////////////////////////////////
341 // establish_server - for any coordination purposes (future)
342 // /////////////////////////////////////////////////////////////////
345 TtIpcMgr::establish_server()
350 // /////////////////////////////////////////////////////////////////
353 // load of infolib requested, so do it here if infolib ID valid
354 // /////////////////////////////////////////////////////////////////
357 TtIpcMgr::do_infolib( char *lib_path )
359 int sts = ID_SUCCESS ;
363 // if no file argument specified, get the default
364 if( !(lib_path = env().infolibDefault()) )
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);
371 sts = LibraryAgent::add_library( lib_path ) ;
372 XtFree( lib_path ) ; // this path only
375 sts = LibraryAgent::add_library( lib_path ) ;
377 // possible returns ID_SUCCESS, NOT_FOUND, BAD_ARG_FORMAT, LOAD_ERROR
382 // /////////////////////////////////////////////////////////////////
385 // view of specific doc requested, so do it here if locator ID valid
387 // Check for NULL locator pointer before passing it.
388 // /////////////////////////////////////////////////////////////////
391 TtIpcMgr::do_locator( char *locator,
394 return UrlAgent::document( locator, new_window ) ;
397 // /////////////////////////////////////////////////////////////////
400 // takes a section locators and prints it
402 // Prerequisites: Load any infolibs separately specified first.
403 // /////////////////////////////////////////////////////////////////
405 TtIpcMgr::do_print(Tt_message msg)
407 UAS_Pointer<UAS_Common> d = NULL ;
408 char *filepath = tt_message_file(msg);
413 fprintf(stderr, "TtIpcMgr::do_print: filepath = %s.\n", filepath);
415 // Open the file containing the list of sections to be printed for reading
417 if ((fp = fopen(filepath, "r")) == NULL) {
418 fprintf(stderr, "Cannot open file %s.\n", filepath);
421 // Get a handle to the AppPrintData allocated in the WindowSystem class
423 AppPrintData* p = window_system().GetAppPrintData();
425 // Create a list of items to be printed
427 xList<UAS_Pointer<UAS_Common> > * print_list = new xList<UAS_Pointer<UAS_Common> >;
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
432 while (fgets(locator, sizeof(locator), fp) != NULL) {
434 if( !strchr( locator, ':' ) && !strchr( locator, '/' ) )
436 // assume given a unique locator ID for the target.
437 // construct a fully-qualified form and pass it on.
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);
447 // assume to have a fully-qualified locator
448 d = UAS_Common::create(locator);
451 // add UAS_Common pointer to list of sections to print
453 if (d != (const int)0)
455 print_list->append(d);
458 fprintf(stderr, "Wow! Null section!\n");
461 } // end locators in file
463 p->f_outline_element = NULL;
464 p->f_print_list = print_list;
466 XtAppAddWorkProc(window_system().app_context(), ipc_print_wp, p) ;
469 fprintf(stderr, "do_print: exiting\n");
474 // /////////////////////////////////////////////////////////////////
477 // based on message type, initiate the appropriate response
478 // /////////////////////////////////////////////////////////////////
481 TtIpcMgr::handle( Tt_message msg_in )
483 int opstatus = UNKNOWN_MSG ;
489 switch( tt_message_opnum(msg_in) )
491 case SHOW_INFO_AT_LOC :
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.
498 if( (opstatus = check_locale( msg_in, 2 )) == ID_SUCCESS )
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 )
504 XtAppAddWorkProc( window_system().app_context(),
505 ipc_error_wp, &tst ) ;
506 return (opstatus = MSG_SYNTAX_ERROR) ;
509 // check to see if an optional File arg is supplied for infolib
511 info_file = tt_message_file( msg_in ) ;
512 if( (tst = tt_ptr_error( info_file )) != TT_OK )
514 XtAppAddWorkProc( window_system().app_context(),
515 ipc_error_wp, &tst ) ;
516 return (opstatus = MSG_SYNTAX_ERROR) ;
520 do_infolib( info_file ) ; // load infolib per File, first
522 // try to get the section
523 workspace().target( curr_ws_tt ) ;
524 opstatus = do_locator( info_uuid, True ) ;
530 if( (opstatus = check_locale( msg_in, 2 )) == ID_SUCCESS )
532 info_uuid = tt_message_file( msg_in ) ;
533 if( (tst = tt_ptr_error( info_uuid )) != TT_OK )
535 XtAppAddWorkProc( window_system().app_context(),
536 ipc_error_wp, &tst ) ;
537 return (opstatus = MSG_SYNTAX_ERROR) ;
540 workspace().target( curr_ws_tt ) ;
541 opstatus = do_infolib( info_uuid ) ;
545 case PRINT_INFO_AT_LOC :
546 opstatus = do_print(msg_in);
549 case QUIT_DTINFO : // ignored
553 /* don't know what else to do with this message */
554 opstatus = UNKNOWN_MSG ;
562 // /////////////////////////////////////////////////////////////////
566 // /////////////////////////////////////////////////////////////////
568 TtIpcMgr::check_locale( Tt_message msg_in,
571 int sts = ID_SUCCESS ;
573 char * target_locale ;
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 ) ;
579 if( (tst = tt_ptr_error( target_locale )) != TT_OK )
581 XtAppAddWorkProc( window_system().app_context(),
582 ipc_error_wp, &tst ) ;
583 return (sts = MSG_SYNTAX_ERROR) ;
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 ; }
595 char * locale_of_desktop() ;
597 // /////////////////////////////////////////////////////////////////
600 // a static member function of the TtIpcMgr class.
601 // used as an input handler per X
603 // gets the msg, invokes handler for class, and makes the appropriate
604 // tt response per handler disposition status
605 // /////////////////////////////////////////////////////////////////
609 TtIpcMgr::receive_tt_msg( XtPointer client_data,
618 Tt_message msg_in = tt_message_receive() ;
622 // NULL msg pointer input is "normal" in certain tt cases,
623 // and in typical non-tt start-up of dtinfo
627 if( msg_in == prior_tt_msg )
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 ) ;
640 // record the current desktop workspace now
641 // (this should approximate tt requestor's workspace)
642 workspace().current( &curr_ws_tt ) ;
644 if( (tst = tt_pointer_error( msg_in )) == TT_ERR_NOMP )
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...
652 switch( ((TtIpcMgr*)client_data)->handle(msg_in) )
656 if( ( tt_message_class( msg_in ) == TT_REQUEST )
659 tt_message_reply( msg_in ) ;
663 case MSG_SYNTAX_ERROR :
664 case BAD_ARG_FORMAT :
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...)
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.
678 if( ( tt_message_class( msg_in ) == TT_REQUEST )
681 tt_message_reply( msg_in ) ;
683 // tttk_message_fail( msg_in, // can't process message
684 // TT_ERR_FILE, NULL, 1 ) ;
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
706 char *ref_locale = locale_of_desktop();
708 && strcmp( ref_locale, env().lang() ) != 0
709 && getenv( "LANG" ) != NULL
710 && strcmp( ref_locale, getenv( "LANG" ) ) != 0 )
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
716 tttk_message_reject( msg_in, TT_ERR_NOTHANDLER, NULL, 0 ) ;
718 else // can't process message
719 tttk_message_fail( msg_in,
720 TT_ERR_PROCID, NULL, 1 ) ;
722 if( ref_locale ) XFree( ref_locale );
729 tttk_message_abandon( msg_in ) ; // don't understand message
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.
744 // Background task to check explicitly for tt message input
747 TtIpcMgr::receive_tt_msg_wp( XtPointer theIpcObj )
749 receive_tt_msg( theIpcObj, NULL, NULL ) ;
756 // Display print dialog
759 TtIpcMgr::ipc_print_wp( XtPointer client_data )
761 AppPrintData* p = (AppPrintData *)client_data;
763 CreatePrintSetup(p->f_pshell_parent, p);
765 XtManageChild(p->f_print_dialog); /* popup dialog each time */
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
776 TtIpcMgr::ipc_error_wp( XtPointer client_data )
778 message_mgr().error_dialog(
779 tt_status_message( *((Tt_status*)client_data) ) ) ;
785 TtIpcMgr::notify_quit()
789 // create and send a "quit" notice message for any observers
791 msg_out = tt_pnotice_create( TT_SESSION, "DtInfo_Quit" ) ;
793 tt_message_send( msg_out ) ;
795 // no reply expected since this was a notice, so no longer need
796 // handle for the message
798 tt_message_destroy( msg_out ) ;
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
807 // Note: this function should really reside in the EnvMgr class
812 static Atom _DT_SM_WINDOW_INFO = None;
813 static Atom WM_LOCALE_NAME = None;
817 unsigned long nitems, after;
818 // WM_LOCALE_NAME Atom (string data)
820 // _DT_SM_WINDOW_INFO Atom (PropDtSmWindowInfo structure data)
821 Window *sm_prop_window;
823 Display *dpy = window_system().display();
826 if(WM_LOCALE_NAME == None) {
827 WM_LOCALE_NAME = XInternAtom(dpy, "WM_LOCALE_NAME", True);
831 printf( "Atom WM_LOCALE_NAME not interned\n" );
834 if (!WM_LOCALE_NAME) return (char *)NULL;
836 if(_DT_SM_WINDOW_INFO == None) {
838 XInternAtom(dpy, _XA_DT_SM_WINDOW_INFO, False);
841 if (!_DT_SM_WINDOW_INFO)
842 printf( "Atom _DT_SM_WINDOW_INFO not interned\n" );
845 if (!_DT_SM_WINDOW_INFO) return (char *)NULL;
847 XGetWindowProperty( dpy,
848 XDefaultRootWindow(dpy),
852 &type, &format, &nitems, &after,
853 (unsigned char **)(void*)&sm_prop_window) ;
856 // property.smWindow = (unsigned long) smGD.topLevelWindow;
859 "null value from Atom _DT_SM_WINDOW_INFO for SM window ID\n" );
861 printf( "dtsession window is %lx\n", *sm_prop_window );
864 if (!sm_prop_window) return (char *)NULL;
867 XGetWindowProperty( dpy,
872 &type, &format, &nitems, &after,
873 (unsigned char **)(void*)&dt_locale) ;
876 printf( "desktop's locale is %s\n", dt_locale ) ;
879 if (!dt_locale) return (char *)NULL;
880 else return dt_locale;