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 * (c) Copyright 1995 Digital Equipment Corporation.
25 * (c) Copyright 1993, 1994, 1995 Hewlett-Packard Company
26 * (c) Copyright 1993, 1994, 1995 International Business Machines Corp.
27 * (c) Copyright 1993, 1994, 1995 Sun Microsystems, Inc.
28 * (c) Copyright 1993, 1994, 1995 Novell, Inc.
29 * (c) Copyright 1995 FUJITSU LIMITED.
30 * (c) Copyright 1995 Hitachi.
32 * $TOG: SmXSMP.c /main/40 1999/01/18 15:42:07 samborn $
35 /*************************************<+>*************************************
36 *****************************************************************************
40 ** Project: DT Session Manager (dtsession)
42 *****************************************************************************
43 *************************************<+>*************************************/
56 #include "SmRestore.h"
57 #include "SmGlobals.h"
60 #include <X11/Intrinsic.h>
61 #include <X11/Xatom.h>
62 #include <X11/SM/SMlib.h>
64 #include <Dt/MsgLog.h>
73 #define ERRORMSGLEN 256
74 #define GET_CLIENT_WORKSPACE_MSG "GetWsmClients"
80 static Boolean authenticationInitialized = False;
81 static char * networkIds;
86 static void InitializeXSMPGlobals ();
88 static void PutSessionManagerOnRootWindow (
91 static void InitializeSaveState (
94 static Boolean SendGetWsmClientsMessage ();
96 static int GetCurrentWorkspaceNumber ();
98 static void ProcessInteract (
100 Boolean getWsmClientOK);
102 static void CancelShutdown ();
104 static void FreeProps (
105 PropertyRecPtr pProp);
107 static void ProcessSaveYourselfResponses ();
114 ClientRecPtr connectedList;
121 void InstallIOErrorHandler ();
123 Status NewClientProc (
125 SmPointer managerData,
126 unsigned long *maskRet,
127 SmsCallbacks *callbacksRet,
128 char **failureReasonRet);
130 void NewConnectionXtProc (
131 XtPointer client_data,
135 Status RegisterClientProc (
137 SmPointer managerData,
140 void InteractRequestProc (
142 SmPointer managerData,
145 void InteractDoneProc (
147 SmPointer managerData,
148 Bool cancelShutdown);
150 void SaveYourselfReqProc (
152 SmPointer managerData,
159 void SaveYourselfPhase2ReqProc (
161 SmPointer managerData);
163 void SaveYourselfDoneProc (
165 SmPointer managerData,
168 void CloseConnectionProc (
170 SmPointer managerData,
174 void CompleteXSMPSave ();
176 void CloseDownClient (
177 ClientRecPtr client );
180 * List manipulation functions
183 ClientRecPtr newClient);
189 Boolean InitXSMP (void)
191 char errorMsg[ERRORMSGLEN];
195 InitializeXSMPGlobals ();
197 InstallIOErrorHandler ();
199 if (!SmsInitialize (SM_VENDOR_NAME, SM_RELEASE_NAME,
202 ERRORMSGLEN, errorMsg)) {
203 DtMsgLogMessage (smGD.programName, DtMsgLogError, errorMsg);
204 PostXSMPFailureDialog (XSMP_FAILURE_SMS_INITIALIZE, True);
207 if (!IceListenForConnections (&smXSMP.numTransports,
209 ERRORMSGLEN, errorMsg)) {
210 DtMsgLogMessage (smGD.programName, DtMsgLogError, errorMsg);
211 PostXSMPFailureDialog (XSMP_FAILURE_ICE_LISTEN, True);
214 if (!SetAuthentication (smXSMP.numTransports,
216 &smXSMP.authDataEntries))
217 PostXSMPFailureDialog (XSMP_FAILURE_AUTHENTICATION, False);
219 authenticationInitialized = True;
221 if (!InitWatchProcs (smGD.appCon))
222 PostXSMPFailureDialog (XSMP_FAILURE_ICE_ADD_WATCH, False);
224 for (i = 0; i < smXSMP.numTransports; i++) {
225 XtAppAddInput (smGD.appCon,
226 IceGetListenConnectionNumber (smXSMP.listenObjs[i]),
227 (XtPointer) XtInputReadMask,
228 NewConnectionXtProc, (XtPointer) smXSMP.listenObjs[i]);
231 networkIds = IceComposeNetworkIdList (smXSMP.numTransports,
234 PostXSMPFailureDialog (XSMP_FAILURE_ICE_COMPOSE_IDS, False);
236 env = (char *) XtMalloc (strlen (SM_SESSION_MANAGER) +
237 strlen (networkIds) + 2);
240 PostXSMPFailureDialog (XSMP_FAILURE_MALLOC, False);
242 (void) sprintf (env, "%s=%s", SM_SESSION_MANAGER, networkIds);
246 PutSessionManagerOnRootWindow (networkIds);
248 XaSmClientId = XInternAtom(smGD.display, SM_CLIENT_ID, False);
251 printf ("%s\n", env);
259 PutSessionManagerOnRootWindow (
264 sessionManager = XInternAtom(smGD.display, SM_SESSION_MANAGER, False);
266 XChangeProperty(smGD.display, RootWindow(smGD.display, 0),
267 sessionManager, XA_STRING, 8, PropModeReplace,
268 (unsigned char *) networkIds, strlen((char *)networkIds));
273 InitializeSaveState (
276 smXSMP.saveState.global = False;
277 smXSMP.saveState.shutdown = False;
278 smXSMP.saveState.interactStyle = SmInteractStyleAny;
279 smXSMP.saveState.clientInteracting = False;
280 smXSMP.saveState.inProgress = False;
281 smXSMP.saveState.doneSuccess = True;
282 smXSMP.saveState.saveComplete = False;
283 smXSMP.saveState.interactCount = 0;
284 smXSMP.saveState.numClientIds = 0;
285 smXSMP.saveState.interactClient = NULL;
287 smXSMP.saveState.clientIds = NULL;
288 smXSMP.saveState.workspaceNums = NULL;
290 if (smXSMP.saveState.clientIds) {
291 free (smXSMP.saveState.clientIds);
292 smXSMP.saveState.clientIds = NULL;
294 if (smXSMP.saveState.workspaceNums) {
295 free (smXSMP.saveState.workspaceNums);
296 smXSMP.saveState.workspaceNums = NULL;
302 InitializeXSMPGlobals (void)
304 smXSMP.authDataEntries = NULL;
306 connectedList = NULL;
308 smXSMP.xsmpDbList = NULL;
310 smXSMP.dbVersion = SM_VENDOR_NAME;
312 smXSMP.dbSessionId = SM_RELEASE_NAME;
314 InitializeSaveState (True);
322 SmPointer managerData,
323 unsigned long *maskRet,
324 SmsCallbacks *callbacksRet,
325 char **failureReasonRet)
327 ClientRecPtr newClient;
330 (void) printf ("\nNewClientProc: IceConn fd = %d\n",
331 IceConnectionNumber (SmsGetIceConnection (smsConn)));
334 newClient = (ClientRecPtr) XtMalloc (sizeof (ClientRec));
338 str = strdup ((char *) GETMESSAGE (4, 5,
339 "Unable to malloc memory for operation."));
341 if ((*failureReasonRet = (char *)
342 XtMalloc ( strlen (str) + 1)) != NULL)
343 strcpy (*failureReasonRet, str);
345 DtMsgLogMessage (smGD.programName, DtMsgLogError, str);
354 newClient->smConn = smsConn;
355 newClient->iceConn = SmsGetIceConnection (smsConn);
356 newClient->clientId = NULL;
357 newClient->clientHost = NULL;
358 newClient->screenNum = 0;
359 newClient->restartHint = SmRestartIfRunning;
360 newClient->props = NULL;
361 newClient->active = False;
362 newClient->saveYourselfDone = False;
363 newClient->saveYourselfP2Requested = False;
364 newClient->interactRequested = False;
365 newClient->next = NULL;
367 AddClient (newClient);
369 *maskRet |= SmsRegisterClientProcMask;
370 callbacksRet->register_client.callback = RegisterClientProc;
371 callbacksRet->register_client.manager_data = (SmPointer) newClient;
373 *maskRet |= SmsInteractRequestProcMask;
374 callbacksRet->interact_request.callback = InteractRequestProc;
375 callbacksRet->interact_request.manager_data = (SmPointer) newClient;
377 *maskRet |= SmsInteractDoneProcMask;
378 callbacksRet->interact_done.callback = InteractDoneProc;
379 callbacksRet->interact_done.manager_data = (SmPointer) newClient;
381 *maskRet |= SmsSaveYourselfRequestProcMask;
382 callbacksRet->save_yourself_request.callback = SaveYourselfReqProc;
383 callbacksRet->save_yourself_request.manager_data =
384 (SmPointer) newClient;
386 *maskRet |= SmsSaveYourselfP2RequestProcMask;
387 callbacksRet->save_yourself_phase2_request.callback =
388 SaveYourselfPhase2ReqProc;
389 callbacksRet->save_yourself_phase2_request.manager_data =
390 (SmPointer) newClient;
392 *maskRet |= SmsSaveYourselfDoneProcMask;
393 callbacksRet->save_yourself_done.callback = SaveYourselfDoneProc;
394 callbacksRet->save_yourself_done.manager_data = (SmPointer) newClient;
396 *maskRet |= SmsCloseConnectionProcMask;
397 callbacksRet->close_connection.callback = CloseConnectionProc;
398 callbacksRet->close_connection.manager_data = (SmPointer) newClient;
400 *maskRet |= SmsSetPropertiesProcMask;
401 callbacksRet->set_properties.callback = SetPropertiesProc;
402 callbacksRet->set_properties.manager_data = (SmPointer) newClient;
404 *maskRet |= SmsDeletePropertiesProcMask;
405 callbacksRet->delete_properties.callback = DeletePropertiesProc;
406 callbacksRet->delete_properties.manager_data = (SmPointer) newClient;
408 *maskRet |= SmsGetPropertiesProcMask;
409 callbacksRet->get_properties.callback = GetPropertiesProc;
410 callbacksRet->get_properties.manager_data = (SmPointer) newClient;
418 NewConnectionXtProc (
419 XtPointer client_data,
424 IceAcceptStatus status;
427 (void) printf ("NewConnectionXtProc [fd = %d]\n", *source);
430 if (smXSMP.saveState.shutdown == True)
433 * Don't accept new connections if we are in the middle
440 ice_conn = IceAcceptConnection((IceListenObj) client_data, &status);
445 message = strdup ((char *) GETMESSAGE (40, 20,
446 "IceAcceptConnection failed."));
449 DtMsgLogMessage (smGD.programName, DtMsgLogError,
454 IceConnectStatus cstatus;
456 while ((cstatus = IceConnectionStatus (ice_conn)) ==
458 XtAppProcessEvent (smGD.appCon, XtIMAll);
461 if (cstatus == IceConnectAccepted) {
464 printf ("ICE Connection opened IceConn fd = %d, ",
465 IceConnectionNumber (ice_conn));
466 connstr = IceConnectionString (ice_conn);
467 printf ("\tAccept at networkId %s\n\n", connstr);
474 if (cstatus == IceConnectIOError)
475 printf ("IO error opening ICE Connection!\n");
477 printf ("ICE Connection rejected!\n");
488 SmPointer managerData,
491 ClientRec *client = (ClientRec *) managerData;
492 char *id = previousId;
493 Boolean sendSave = False;
500 (void) printf ("Received REGISTER CLIENT [%d] - id = %s\n",
501 smsConn, previousId ? previousId : "New Client");
505 id = SmsGenerateClientID (smsConn);
509 ClientRecPtr pClientRec;
510 XSMPClientDBRecPtr pDbRec;
511 Boolean found = False;
513 for (pClientRec = connectedList; pClientRec != NULL;
514 pClientRec = pClientRec->next) {
515 if (!strcmp (pClientRec->clientId, previousId)) {
517 (void) printf ("\tAlready connected.\n");
519 if (!pClientRec->active)
521 * A client that terminated is
529 for (pDbRec = smXSMP.xsmpDbList;
530 pDbRec != NULL && found == False;
531 pDbRec = pDbRec->next) {
532 if (!strcmp (pDbRec->clientId, previousId)) {
534 (void) printf ("\tClient in DB.\n");
542 * The client is using an invalid id or
543 * this clientID is already being used.
544 * Reject the connection.
547 (void) printf ("\tID is NOT valid.\n");
554 client->clientId = strdup (id);
555 pchar = SmsClientHostName (smsConn);
557 client->clientHost = (strchr (pchar, '/')) + 1;
559 client->clientHost = pchar;
560 client->active = True;
562 SmsRegisterClientReply (smsConn, id);
565 SmsSaveYourself (smsConn, SmSaveLocal, False,
566 SmInteractStyleNone, False);
569 (void) printf ("CLIENTS REGISTERED:\n");
571 for (i = 1, client = connectedList;
573 i++, client = client->next) {
576 (void) printf ("\t[%2d] = %s\n", i, client->clientId);
586 InteractRequestProc (
588 SmPointer managerData,
591 ClientRecPtr client = (ClientRecPtr) managerData;
592 Boolean getWsmClientOK = True;
595 (void) printf ("Received INTERACT REQUEST [%d]\n", smsConn);
596 if (dialogType == SmDialogError)
597 (void) printf ("\tSmDialogError\n");
598 else if (dialogType == SmDialogNormal)
599 (void) printf ("\tSmDialogNormal\n");
601 (void) printf ("\tSMlib Error: should have checked for bad value\n");
604 client->interactRequested = True;
606 if (smXSMP.saveState.interactCount == 0) {
608 * Only need to get the Wkspace list once for a save
610 smXSMP.saveState.interactCount++;
612 if (!SendGetWsmClientsMessage ()) {
615 pch = strdup ((char *) GETMESSAGE (40, 17,
616 "An attempt to get a client list from the 'Window Manager' failed."));
618 DtMsgLogMessage (smGD.programName,
619 DtMsgLogWarning, pch);
622 getWsmClientOK = False;
625 * Cann't do anything else until the GetWsmClients
626 * message handler is invoked.
628 * Must cache this client because it is needed in the
629 * GetWsmClients callback and ToolTalk apparently
630 * doesn't allow 'client_data' to be assigned to its
633 smXSMP.saveState.interactClient = client;
638 ProcessInteract (client, getWsmClientOK);
646 SmPointer managerData,
649 ClientRecPtr client = (ClientRecPtr) managerData;
652 (void) printf ("Received INTERACT DONE [%d] - Cancel Shutdown = %s\n",
653 smsConn, cancelShutdown ? "True" : "False");
656 client->interactRequested = False;
657 smXSMP.saveState.clientInteracting = False;
660 smXSMP.saveState.shutdownCanceled = True;
662 if (cancelShutdown &&
663 smXSMP.saveState.shutdown == True &&
664 (smXSMP.saveState.interactStyle == SmInteractStyleErrors ||
665 (smXSMP.saveState.interactStyle == SmInteractStyleAny))) {
667 ClientRecPtr pClientRec;
670 for (pClientRec = connectedList; pClientRec != NULL;
671 pClientRec = pClientRec->next) {
673 SmsShutdownCancelled (pClientRec->smConn);
675 (void) printf ("Sent ShutdownCancelled to %d\n",
680 pch = strdup ((char *) GETMESSAGE (40, 22, "A session shutdown was cancelled by the application '%s'."));
682 DtMsgLogMessage (smGD.programName,
685 GetArrayPropertyValue (client,
693 ProcessInteract (client, True);
699 SaveYourselfReqProc (
701 SmPointer managerData,
708 ClientRecPtr tmpClient;
709 ClientRecPtr pClientRec;
710 Boolean notify = True;
713 (void) printf ("Received SAVE YOURSELF REQUEST [%d].\n", smsConn);
714 (void) printf ("\tglobal = %s\n", global ? "True" : "False");
715 (void) printf ("\tshutdown = %s\n", shutdown ? "True" : "False");
716 (void) printf ("\tfast = %s\n", fast ? "True" : "False");
717 (void) printf ("\tsaveType = ");
719 case SmSaveLocal: printf ("SmSaveLocal\n"); break;
720 case SmSaveGlobal: printf ("SmSaveGlobal\n"); break;
721 case SmSaveBoth: printf ("SmSaveBoth\n"); break;
722 default: printf ("save type NOT supported\n");
724 (void) printf ("\tinteractStyle = ");
726 case SmInteractStyleNone: printf ("SmInteractStyleNone\n");
728 case SmInteractStyleErrors: printf ("SmInteractStyleErrors\n");
730 case SmInteractStyleAny: printf ("SmInteractStyleAny\n");
732 default: printf ("interact style NOT supported\n");
736 if (smXSMP.saveState.inProgress) {
739 pch = strdup ((char *) GETMESSAGE (40, 21, "The session will not be saved because a Save Session is in progress."));
741 DtMsgLogMessage (smGD.programName, DtMsgLogError, pch);
749 * The client wants to be told to save itself but
750 * no other clients should be notified. [smsConn
751 * will be NULL if this non-global save came from
752 * a non-XSMP client (e.g via a ToolTalk message).
755 SmsSaveYourself (smsConn, saveType, shutdown,
756 interactStyle, fast);
758 (void) printf ("\tSent SaveYourself to %d\n", smsConn);
764 smXSMP.saveState.inProgress = True;
765 smXSMP.saveState.shutdown = shutdown;
766 smXSMP.saveState.shutdownCanceled = False;
767 smXSMP.saveState.interactStyle = interactStyle;
768 smXSMP.saveState.global = global;
771 * Before notifying the clients, setup a directory
772 * for them to save their state.
774 if (smGD.homeSave || (smGD.sessionType == HOME_SESSION &&
775 smSettings.startState == DtSM_HOME_STATE)) {
776 if (smXSMP.saveState.shutdown)
778 * Leave the old session dir in place. It
779 * will only be used by XSMP apps.
783 SetupSaveState (True, DtSM_HOME_STATE);
786 if (smGD.sessionType == CURRENT_SESSION ||
787 smGD.sessionType == DEFAULT_SESSION)
788 SetupSaveState (False, DtSM_CURRENT_STATE);
789 else if (smGD.sessionType == HOME_SESSION &&
790 smSettings.startState == DtSM_CURRENT_STATE)
791 SetupSaveState (False, DtSM_HOME_STATE);
793 SetupSaveState (False, DtSM_HOME_STATE);
797 * Before the XSMP clients are saved, the ICCC apps must be
798 * sent a WM_SAVE_YOURSELF message. This needs to be done because some
799 * apps do not update their geometry information until they
800 * get this message. If an ICCC app doesn't update their geometry,
801 * then an XSMP-based Window Manager will not have the appropriate
802 * geometry information and the app will not be restore in the
803 * appropriate location.
807 NotifyProxyClients ();
808 ShowWaitState(False);
811 for (pClientRec = connectedList; pClientRec != NULL;
812 pClientRec = pClientRec->next) {
814 if (pClientRec->active) {
815 SmsSaveYourself (pClientRec->smConn, saveType,
816 shutdown, interactStyle, fast);
818 (void) printf ("\tSent saveyourself to %d\n",
825 * If all of the clients are P2 clients, then process
826 * the save now because these clients won't send a
827 * SaveYourselfDone msg until after they have processed
832 for (pClientRec = connectedList; pClientRec != NULL;
833 pClientRec = pClientRec->next) {
835 if (pClientRec->active) {
836 if (pClientRec->saveYourselfP2Requested)
837 tmpClient = pClientRec;
844 SmsSaveYourselfPhase2 (tmpClient->smConn);
846 (void) printf ("\tSent SaveYourselfPhase2 to %d\n",
855 SaveYourselfPhase2ReqProc (
857 SmPointer managerData)
859 ClientRecPtr client = (ClientRecPtr) managerData;
862 (void) printf ("Received SAVE YOURSELF PHASE 2 REQUEST [%d]\n",
866 client->saveYourselfP2Requested = True;
869 * A client may have sent this message in response to
870 * the SM's start-up SaveYourself message. So if
871 * a session isn't currently being saved, return.
873 if (!smXSMP.saveState.inProgress) {
875 * The client is responding to the start-up SaveYourself
876 * message - this isn't a user-initiated save.
879 SmsSaveComplete (smsConn);
883 ProcessSaveYourselfResponses ();
889 SaveYourselfDoneProc (
891 SmPointer managerData,
894 ClientRecPtr pClientRec = (ClientRec *) managerData;
897 (void) printf ("Received SAVE YOURSELF DONE [%d] - Success = %s\n",
898 smsConn, success ? "True" : "False");
901 if (!smXSMP.saveState.inProgress) {
903 * The client is responding to the start-up SaveYourself
904 * message - this isn't a user-initiated save.
906 SmsSaveComplete (smsConn);
911 * Cache success if it is a failure - it will be needed later
913 if (success == False)
914 smXSMP.saveState.doneSuccess = False;
916 pClientRec->saveYourselfDone = True;
918 ProcessSaveYourselfResponses ();
923 ProcessSaveYourselfResponses (void)
925 ClientRecPtr pClientRec;
926 Boolean done = False;
929 * If all clients are marked as saveYourselfDone, complete
932 for (done = True, pClientRec = connectedList;
933 pClientRec != NULL; pClientRec = pClientRec->next) {
935 if (pClientRec->active &&
936 pClientRec->saveYourselfDone == False) {
943 if (smXSMP.saveState.shutdownCanceled)
951 * If any client is marked as not having sent a
952 * SaveYourselfDone message and it is has not been
953 * marked as having requested a SaveYourselfP2,
956 for (pClientRec = connectedList; pClientRec != NULL;
957 pClientRec = pClientRec->next) {
959 if (pClientRec->active &&
960 pClientRec->saveYourselfDone == False &&
961 pClientRec->saveYourselfP2Requested == False)
966 * Only clients which requested a SaveYourselfP2 have not
967 * responded with a SaveYourselfDone message.
969 * Tell the P2 clients to save themselves.
971 for (pClientRec = connectedList; pClientRec != NULL;
972 pClientRec = pClientRec->next) {
974 if (pClientRec->active) {
975 if (pClientRec->saveYourselfP2Requested &&
976 !pClientRec->saveYourselfDone) {
978 (void) printf ("\tSent SaveYourselfPhase2 to %d\n",
981 SmsSaveYourselfPhase2 (pClientRec->smConn);
990 CloseConnectionProc (
992 SmPointer managerData,
996 ClientRecPtr pClientRec = (ClientRec *) managerData;
997 ClientRecPtr tmp = pClientRec;
1002 (void) printf ("Received CONNECTION CLOSED [%d]\n", smsConn);
1004 for (i = 0; i < count; i++)
1005 (void) printf ("\tReason [%2d]: %s\n", i+1, reasonMsgs[i]);
1009 PostReasonsDialog (GetArrayPropertyValue (tmp, SmProgram), count, reasonMsgs, True);
1010 SmFreeReasons (count, reasonMsgs);
1013 CloseDownClient (pClientRec);
1017 CompleteXSMPSave (void)
1019 ClientRecPtr pClientRec;
1022 * Save the XSMP clients' state and the Proxy clients' state
1023 * and save the rest of the settings, resources, etc.
1028 * If this isn't a shutdown, tell the clients that the save
1031 if (!smXSMP.saveState.shutdown) {
1032 for (pClientRec = connectedList; pClientRec != NULL;
1033 pClientRec = pClientRec->next) {
1035 if (pClientRec->active) {
1036 SmsSaveComplete (pClientRec->smConn);
1038 printf ("SENT SmsSaveComplete to: %d\n",
1039 pClientRec->smConn);
1045 if (!smXSMP.saveState.shutdown) {
1046 for (pClientRec = connectedList; pClientRec != NULL;
1047 pClientRec = pClientRec->next) {
1049 if (pClientRec->active) {
1050 pClientRec->saveYourselfDone = False;
1051 pClientRec->saveYourselfP2Requested = False;
1052 pClientRec->interactRequested = False;
1056 InitializeSaveState (False);
1062 for (pClientRec = connectedList; pClientRec != NULL;
1063 pClientRec = pClientRec->next) {
1065 if (pClientRec->active) {
1066 SmsDie (pClientRec->smConn);
1068 printf ("SENT SmsDie to: %d\n",
1069 pClientRec->smConn);
1073 if (!GetCardPropertyValue (pClientRec,
1076 restartHint = pClientRec->restartHint;
1078 if (restartHint == SmRestartAnyway)
1079 ExecuteCommandProperty (SmShutdownCommand,
1083 * Cannot exit until all of the clients go away.
1085 smXSMP.saveState.saveComplete = True;
1092 PropertyRecPtr pProp)
1095 PropertyRecPtr trail;
1098 for (tmp = pProp; tmp != NULL; ) {
1100 for (i = 0; i < tmp->prop.num_vals; i++)
1101 XtFree (tmp->prop.vals[i].value);
1102 if (tmp->prop.num_vals > 0)
1103 XtFree ((char *) tmp->prop.vals);
1106 XtFree ((char *) trail);
1111 void CloseDownClient (
1112 ClientRecPtr pClientRec )
1115 ClientRecPtr tmp, trail;
1118 SmsCleanUp (pClientRec->smConn);
1119 IceSetShutdownNegotiation (pClientRec->iceConn, False);
1120 IceCloseConnection (pClientRec->iceConn);
1122 /* save connection information for later compare */
1123 oldConn = pClientRec->smConn;
1125 pClientRec->iceConn = NULL;
1126 pClientRec->smConn = NULL;
1127 pClientRec->active = False;
1129 if (!GetCardPropertyValue (pClientRec, SmRestartStyleHint,
1131 restartHint = pClientRec->restartHint;
1133 if (!smXSMP.saveState.inProgress && restartHint == SmRestartImmediately)
1134 ExecuteCommandProperty (SmRestartCommand, pClientRec);
1136 if (restartHint == SmRestartAnyway)
1137 ExecuteCommandProperty (SmResignCommand, pClientRec);
1139 if (restartHint == SmRestartNever) {
1141 * Remove the client from the list
1143 for (tmp = trail = connectedList; tmp != NULL;
1144 trail = tmp, tmp = tmp->next) {
1145 if (tmp->smConn == oldConn) {
1146 FreeProps (pClientRec->props);
1147 if (tmp == connectedList)
1148 connectedList = tmp->next;
1149 trail->next = tmp->next;
1150 XtFree ((char *) tmp);
1157 * If a shutdown is occurring and all of the clients
1158 * are inactive, exit.
1160 if (smXSMP.saveState.shutdown) {
1162 * Return if any clients are still active
1164 for (tmp = connectedList; tmp != NULL; tmp = tmp->next) {
1171 * All clients are inactive - its time to exit
1173 _DtReleaseLock (smGD.display, SM_RUNNING_LOCK);
1181 Tt_callback_action GetWsmClientsHandler(
1186 int num_args = tt_message_args_count (message);
1192 if (num_args != 3) {
1193 smXSMP.saveState.numClientIds = 0;
1194 smXSMP.saveState.clientIds = NULL;
1195 smXSMP.saveState.workspaceNums = NULL;
1196 ProcessInteract (smXSMP.saveState.interactClient, False);
1197 return (TT_CALLBACK_PROCESSED);
1201 * Before extracting the new values from this message, free any
1204 if (smXSMP.saveState.clientIds)
1205 free (smXSMP.saveState.clientIds);
1206 if (smXSMP.saveState.workspaceNums)
1207 free (smXSMP.saveState.workspaceNums);
1209 tt_message_arg_ival (message, 0,
1210 &smXSMP.saveState.numClientIds);
1211 tt_message_arg_bval (message, 1,
1212 (unsigned char **) &smXSMP.saveState.clientIds,
1214 tt_message_arg_bval (message, 2,
1215 (unsigned char **) &smXSMP.saveState.workspaceNums,
1217 tt_message_reply (message);
1218 tt_message_destroy (message);
1221 (void) printf("GetWsmClientsHandler: num clients = %d\n",
1222 smXSMP.saveState.numClientIds);
1223 for (i = 0, pchar = smXSMP.saveState.clientIds;
1224 i < smXSMP.saveState.numClientIds;
1225 i++, pchar += strlen (pchar) + 1) {
1226 (void) printf("\tclient [%2d]: workspace = %2d, id = %s\n",
1227 i+1, smXSMP.saveState.workspaceNums[i], pchar);
1231 ProcessInteract (smXSMP.saveState.interactClient, True);
1233 return (TT_CALLBACK_PROCESSED);
1238 Boolean SendGetWsmClientsMessage (void)
1243 message = tt_message_create ();
1244 status = tt_ptr_error (message);
1245 if (status != TT_OK)
1248 tt_message_class_set (message, TT_REQUEST);
1249 tt_message_scope_set (message, TT_SESSION);
1250 tt_message_address_set (message, TT_PROCEDURE);
1252 tt_message_session_set (message, tt_default_session());
1253 tt_message_op_set (message, GET_CLIENT_WORKSPACE_MSG);
1254 tt_message_callback_add (message, GetWsmClientsHandler);
1257 * Three arguments are expected in the reply so apparently
1258 * they must be accounted for now.
1260 tt_message_iarg_add (message, TT_OUT, "integer", 0);
1261 tt_message_barg_add (message, TT_OUT, "stringlist", 0, 0);
1262 tt_message_barg_add (message, TT_OUT, "intlist", 0, 0);
1264 status = tt_message_send (message);
1265 if (status != TT_OK)
1273 int GetCurrentWorkspaceNumber (void)
1275 Atom currentWorkspace;
1276 Atom *workspaceList;
1282 root = XDefaultRootWindow (smGD.display);
1284 rval = DtWsmGetCurrentWorkspace(smGD.display, root, ¤tWorkspace);
1285 if (rval != Success)
1288 rval = DtWsmGetWorkspaceList (smGD.display, root, &workspaceList,
1289 (int *) &numWorkspaces);
1290 if (rval != Success)
1293 for (i = 0; i < numWorkspaces; i++) {
1294 if (currentWorkspace == workspaceList[i])
1295 return (currentWorkspace);
1303 void CancelShutdown (void)
1305 ClientRecPtr pClientRec;
1308 for (pClientRec = connectedList; pClientRec != NULL;
1309 pClientRec = pClientRec->next) {
1311 if (pClientRec->active) {
1313 ExecuteCommandProperty (SmDiscardCommand, pClientRec);
1315 pClientRec->saveYourselfDone = False;
1316 pClientRec->saveYourselfP2Requested = False;
1317 pClientRec->interactRequested = False;
1323 InitializeSaveState (False);
1328 * This function can be invoked via different paths:
1330 * 1. From the InteractRequest callback
1331 * 2. From the InteractDone callback
1332 * 3. From the GetWsmClients message callback
1335 void ProcessInteract (
1336 ClientRecPtr client,
1337 Boolean getWsmClientOK)
1339 int currentWorkspace;
1341 ClientRecPtr pClientRec;
1342 ClientRecPtr tmp = NULL;
1345 if (!getWsmClientOK) {
1346 smXSMP.saveState.clientInteracting = True;
1347 SmsInteract (client->smConn);
1352 * If a client wants to interact and its workspace matches
1353 * the current workspace, then let it interact.
1355 currentWorkspace = GetCurrentWorkspaceNumber ();
1357 for (pClientRec = connectedList;
1359 pClientRec = pClientRec->next) {
1361 if (pClientRec->interactRequested) {
1364 for (i = 0, pchar = smXSMP.saveState.clientIds;
1365 i < smXSMP.saveState.numClientIds;
1366 i++, pchar += strlen (pchar) + 1) {
1368 if ((currentWorkspace ==
1369 smXSMP.saveState.workspaceNums[i]) &&
1370 (!strcmp (pchar, pClientRec->clientId))) {
1372 smXSMP.saveState.clientInteracting =
1374 SmsInteract (pClientRec->smConn);
1382 * Tmp didn't meet all of the requirements but it does
1383 * want to interact so let it.
1386 smXSMP.saveState.clientInteracting = True;
1387 SmsInteract (tmp->smConn);
1393 * List manipulation functions
1396 ClientRecPtr newClient)
1398 ClientRecPtr pClient;
1400 if (!connectedList) {
1401 connectedList = newClient;
1406 * Find the end of the list
1408 for (pClient = connectedList; pClient->next != NULL;
1409 pClient = pClient->next);
1411 pClient->next = newClient;
1416 * The real way to handle IO errors is to check the return status
1417 * of IceProcessMessages. dtsession properly does this.
1419 * Unfortunately, a design flaw exists in the ICE library in which
1420 * a default IO error handler is invoked if no IO error handler is
1421 * installed. This default handler exits. We must avoid this.
1423 * To get around this problem, we install an IO error handler that
1424 * does a little magic. Since a previous IO handler might have been
1425 * installed, when we install our IO error handler, we do a little
1426 * trick to get both the previous IO error handler and the default
1427 * IO error handler. When our IO error handler is called, if the
1428 * previous handler is not the default handler, we call it. This
1429 * way, everyone's IO error handler gets called except the stupid
1430 * default one which does an exit!
1433 static IceIOErrorHandler prev_handler;
1440 (*prev_handler) (ice_conn);
1444 InstallIOErrorHandler (void)
1446 IceIOErrorHandler default_handler;
1448 prev_handler = IceSetIOErrorHandler (NULL);
1449 default_handler = IceSetIOErrorHandler (MyIoErrorHandler);
1450 if (prev_handler == default_handler)
1451 prev_handler = NULL;
1455 void XSMPExit (void)
1459 if (authenticationInitialized)
1460 FreeAuthenticationData (smXSMP.numTransports,
1461 smXSMP.authDataEntries);
1464 * If the local socket file exists, remove it.
1466 * Assume the format of networkIds is:
1468 * local/<host_name>:/<socket_file_name>,<other_stuff>
1470 if (!strncmp (networkIds, "local/", 6)) {
1471 if (pchar = strchr (networkIds, ':')) {
1473 if (pchar && *pchar != '\000') {
1476 if (pchar2 = strchr (pchar, ',')) {
1479 * This modifies networkIds but
1480 * that's OK because an exit is
1484 if ((stat (pchar, &buf)) == 0) {
1485 (void) unlink (pchar);