1 /* session.c - session state handling and R6 style session management
3 * Copyright (c) 1998 Dan Pascu
4 * Copyright (c) 1998, 1999 Alfredo Kojima
6 * Window Maker window manager
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
27 * If defined(XSMP_ENABLED) and session manager is running then
30 * do pre-R6 session management stuff (save window state and relaunch)
32 * When doing a checkpoint:
35 * Open "Stop"/status Dialog
36 * Send SAVE_YOURSELF to clients and wait for reply
38 * Save state of clients
41 * Send checkpoint request to sm
48 * Open "Exit Now"/status Dialog
49 * Send SAVE_YOURSELF to clients and wait for reply
51 * Save state of clients
52 * Send DELETE to all clients
53 * When no more clients are left or user hit "Exit Now", exit
57 * Send Shutdown request to session manager
58 * if SaveYourself message received, save state of clients
59 * if the Die message is received, exit.
65 #include <X11/Xutil.h>
68 #include <X11/SM/SMlib.h>
78 #include "WindowMaker.h"
85 #include "workspace.h"
87 #include "properties.h"
88 #include "application.h"
99 extern Atom _XA_WM_SAVE_YOURSELF
;
101 extern Time LastTimestamp
;
105 extern int wScreenCount
;
107 /* requested for SaveYourselfPhase2 */
108 static Bool sWaitingPhase2
= False
;
110 static SmcConn sSMCConn
= NULL
;
112 static WMHandlerID sSMInputHandler
= NULL
;
114 /* our SM client ID */
115 static char *sClientID
= NULL
;
119 static proplist_t sApplications
= NULL
;
120 static proplist_t sCommand
;
121 static proplist_t sName
;
122 static proplist_t sHost
;
123 static proplist_t sWorkspace
;
124 static proplist_t sShaded
;
125 static proplist_t sMiniaturized
;
126 static proplist_t sHidden
;
127 static proplist_t sGeometry
;
129 static proplist_t sDock
;
131 static proplist_t sYes
, sNo
;
137 if (sApplications
!=NULL
)
140 sApplications
= PLMakeString("Applications");
141 sCommand
= PLMakeString("Command");
142 sName
= PLMakeString("Name");
143 sHost
= PLMakeString("Host");
144 sWorkspace
= PLMakeString("Workspace");
145 sShaded
= PLMakeString("Shaded");
146 sMiniaturized
= PLMakeString("Miniaturized");
147 sHidden
= PLMakeString("Hidden");
148 sGeometry
= PLMakeString("Geometry");
149 sDock
= PLMakeString("Dock");
151 sYes
= PLMakeString("Yes");
152 sNo
= PLMakeString("No");
158 getBool(proplist_t value
)
162 if (!PLIsString(value
)) {
165 if (!(val
= PLGetString(value
))) {
169 if ((val
[1]=='\0' && (val
[0]=='y' || val
[0]=='Y'))
170 || strcasecmp(val
, "YES")==0) {
173 } else if ((val
[1]=='\0' && (val
[0]=='n' || val
[0]=='N'))
174 || strcasecmp(val
, "NO")==0) {
178 if (sscanf(val
, "%i", &i
)==1) {
181 wwarning(_("can't convert \"%s\" to boolean"), val
);
190 makeWindowState(WWindow
*wwin
, WApplication
*wapp
)
192 WScreen
*scr
= wwin
->screen_ptr
;
196 char *class, *instance
, *command
=NULL
, buffer
[256];
197 proplist_t win_state
, cmd
, name
, workspace
;
198 proplist_t shaded
, miniaturized
, hidden
, geometry
;
201 if (wwin
->main_window
!=None
&& wwin
->main_window
!=wwin
->client_win
)
202 win
= wwin
->main_window
;
204 win
= wwin
->client_win
;
206 if (XGetCommand(dpy
, win
, &argv
, &argc
) && argc
>0) {
207 command
= FlattenStringList(argv
, argc
);
208 XFreeStringList(argv
);
213 if (PropGetWMClass(win
, &class, &instance
)) {
214 if (class && instance
)
215 sprintf(buffer
, "%s.%s", instance
, class);
217 sprintf(buffer
, "%s", instance
);
219 sprintf(buffer
, ".%s", class);
221 sprintf(buffer
, ".");
223 name
= PLMakeString(buffer
);
224 cmd
= PLMakeString(command
);
225 /*sprintf(buffer, "%d", wwin->frame->workspace+1);
226 workspace = PLMakeString(buffer);*/
227 workspace
= PLMakeString(scr
->workspaces
[wwin
->frame
->workspace
]->name
);
228 shaded
= wwin
->flags
.shaded
? sYes
: sNo
;
229 miniaturized
= wwin
->flags
.miniaturized
? sYes
: sNo
;
230 hidden
= wwin
->flags
.hidden
? sYes
: sNo
;
231 sprintf(buffer
, "%ix%i+%i+%i", wwin
->client
.width
, wwin
->client
.height
,
232 wwin
->frame_x
, wwin
->frame_y
);
233 geometry
= PLMakeString(buffer
);
235 win_state
= PLMakeDictionaryFromEntries(sName
, name
,
237 sWorkspace
, workspace
,
239 sMiniaturized
, miniaturized
,
246 PLRelease(workspace
);
248 if (wapp
&& wapp
->app_icon
&& wapp
->app_icon
->dock
) {
251 if (wapp
->app_icon
->dock
== scr
->dock
) {
254 for(i
=0; i
<scr
->workspace_count
; i
++)
255 if(scr
->workspaces
[i
]->clip
== wapp
->app_icon
->dock
)
257 assert( i
< scr
->workspace_count
);
259 name
= scr
->workspaces
[i
]->name
;
261 dock
= PLMakeString(name
);
262 PLInsertDictionaryEntry(win_state
, sDock
, dock
);
269 if (instance
) XFree(instance
);
270 if (class) XFree(class);
271 if (command
) free(command
);
278 wSessionSaveState(WScreen
*scr
)
280 WWindow
*wwin
= scr
->focused_window
;
281 proplist_t win_info
, wks
;
282 proplist_t list
=NULL
;
283 WMBag
*wapp_list
=NULL
;
288 if (!scr
->session_state
) {
289 scr
->session_state
= PLMakeDictionaryFromEntries(NULL
, NULL
, NULL
);
290 if (!scr
->session_state
)
294 list
= PLMakeArrayFromElements(NULL
);
296 wapp_list
= WMCreateBag(16);
299 WApplication
*wapp
=wApplicationOf(wwin
->main_window
);
301 if (wwin
->transient_for
==None
&& WMGetFirstInBag(wapp_list
, wapp
)<0
302 && !WFLAGP(wwin
, dont_save_session
)) {
303 /* A entry for this application was not yet saved. Save one. */
304 if ((win_info
= makeWindowState(wwin
, wapp
))!=NULL
) {
305 list
= PLAppendArrayElement(list
, win_info
);
307 /* If we were succesful in saving the info for this window
308 * add the application the window belongs to, to the
309 * application list, so no multiple entries for the same
310 * application are saved.
312 WMPutInBag(wapp_list
, wapp
);
317 PLRemoveDictionaryEntry(scr
->session_state
, sApplications
);
318 PLInsertDictionaryEntry(scr
->session_state
, sApplications
, list
);
321 wks
= PLMakeString(scr
->workspaces
[scr
->current_workspace
]->name
);
322 PLInsertDictionaryEntry(scr
->session_state
, sWorkspace
, wks
);
325 WMFreeBag(wapp_list
);
330 wSessionClearState(WScreen
*scr
)
334 if (!scr
->session_state
)
337 PLRemoveDictionaryEntry(scr
->session_state
, sApplications
);
338 PLRemoveDictionaryEntry(scr
->session_state
, sWorkspace
);
343 execCommand(WScreen
*scr
, char *command
, char *host
)
349 ParseCommand(command
, &argv
, &argc
);
355 if ((pid
=fork())==0) {
359 SetupEnvironment(scr
);
361 args
= malloc(sizeof(char*)*(argc
+1));
364 for (i
=0; i
<argc
; i
++) {
368 execvp(argv
[0], args
);
379 getWindowState(WScreen
*scr
, proplist_t win_state
)
381 WSavedState
*state
= wmalloc(sizeof(WSavedState
));
386 memset(state
, 0, sizeof(WSavedState
));
387 state
->workspace
= -1;
388 value
= PLGetDictionaryEntry(win_state
, sWorkspace
);
389 if (value
&& PLIsString(value
)) {
390 tmp
= PLGetString(value
);
391 if (sscanf(tmp
, "%i", &state
->workspace
)!=1) {
392 state
->workspace
= -1;
393 for (i
=0; i
< scr
->workspace_count
; i
++) {
394 if (strcmp(scr
->workspaces
[i
]->name
, tmp
)==0) {
395 state
->workspace
= i
;
403 if ((value
= PLGetDictionaryEntry(win_state
, sShaded
))!=NULL
)
404 state
->shaded
= getBool(value
);
405 if ((value
= PLGetDictionaryEntry(win_state
, sMiniaturized
))!=NULL
)
406 state
->miniaturized
= getBool(value
);
407 if ((value
= PLGetDictionaryEntry(win_state
, sHidden
))!=NULL
)
408 state
->hidden
= getBool(value
);
410 value
= PLGetDictionaryEntry(win_state
, sGeometry
);
411 if (value
&& PLIsString(value
)) {
412 if (sscanf(PLGetString(value
), "%ix%i+%i+%i",
413 &state
->w
, &state
->h
, &state
->x
, &state
->y
)==4 &&
414 (state
->w
>0 && state
->h
>0)) {
415 state
->use_geometry
= 1;
416 } else if (sscanf(PLGetString(value
), "%i,%i,%i,%i",
417 &state
->x
, &state
->y
, &state
->w
, &state
->h
)==4 &&
418 (state
->w
>0 && state
->h
>0)) {
419 /* TODO: remove redundant sscanf() in version 0.20.x */
420 state
->use_geometry
= 1;
429 #define SAME(x, y) (((x) && (y) && !strcmp((x), (y))) || (!(x) && !(y)))
432 wSessionRestoreState(WScreen
*scr
)
435 char *instance
, *class, *command
, *host
;
436 proplist_t win_info
, apps
, cmd
, value
;
446 if (!scr
->session_state
)
449 PLSetStringCmpHook(NULL
);
451 apps
= PLGetDictionaryEntry(scr
->session_state
, sApplications
);
455 count
= PLGetNumberOfElements(apps
);
459 for (i
=0; i
<count
; i
++) {
460 win_info
= PLGetArrayElement(apps
, i
);
462 cmd
= PLGetDictionaryEntry(win_info
, sCommand
);
463 if (!cmd
|| !PLIsString(cmd
) || !(command
= PLGetString(cmd
))) {
467 value
= PLGetDictionaryEntry(win_info
, sName
);
471 ParseWindowName(value
, &instance
, &class, "session");
472 if (!instance
&& !class)
475 value
= PLGetDictionaryEntry(win_info
, sHost
);
476 if (value
&& PLIsString(value
))
477 host
= PLGetString(value
);
481 state
= getWindowState(scr
, win_info
);
484 value
= PLGetDictionaryEntry(win_info
, sDock
);
485 if (value
&& PLIsString(value
) && (tmp
= PLGetString(value
))!=NULL
) {
486 if (sscanf(tmp
, "%i", &n
)!=1) {
487 if (!strcasecmp(tmp
, "DOCK")) {
490 for (j
=0; j
< scr
->workspace_count
; j
++) {
491 if (strcmp(scr
->workspaces
[j
]->name
, tmp
)==0) {
492 dock
= scr
->workspaces
[j
]->clip
;
500 } else if (n
>0 && n
<=scr
->workspace_count
) {
501 dock
= scr
->workspaces
[n
-1]->clip
;
508 for (j
=0; j
<dock
->max_icons
; j
++) {
509 btn
= dock
->icon_array
[j
];
510 if (btn
&& SAME(instance
, btn
->wm_instance
) &&
511 SAME(class, btn
->wm_class
) &&
512 SAME(command
, btn
->command
) &&
521 wDockLaunchWithState(dock
, btn
, state
);
522 } else if ((pid
= execCommand(scr
, command
, host
)) > 0) {
523 wWindowAddSavedState(instance
, class, command
, pid
, state
);
528 if (instance
) free(instance
);
529 if (class) free(class);
532 PLSetStringCmpHook(StringCompareHook
);
537 wSessionRestoreLastWorkspace(WScreen
*scr
)
545 if (!scr
->session_state
)
548 PLSetStringCmpHook(NULL
);
550 wks
= PLGetDictionaryEntry(scr
->session_state
, sWorkspace
);
551 if (!wks
|| !PLIsString(wks
))
554 tmp
= PLGetString(wks
);
557 PLSetStringCmpHook(StringCompareHook
);
559 if (sscanf(tmp
, "%i", &w
)!=1) {
561 for (i
=0; i
< scr
->workspace_count
; i
++) {
562 if (strcmp(scr
->workspaces
[i
]->name
, tmp
)==0) {
571 if (w
!=scr
->current_workspace
&& w
<scr
->workspace_count
) {
572 wWorkspaceChange(scr
, w
);
578 clearWaitingAckState(WScreen
*scr
)
583 for (wwin
= scr
->focused_window
; wwin
!= NULL
; wwin
= wwin
->prev
) {
584 wwin
->flags
.waiting_save_ack
= 0;
585 if (wwin
->main_window
!= None
) {
586 wapp
= wApplicationOf(wwin
->main_window
);
588 wapp
->main_window_desc
->flags
.waiting_save_ack
= 0;
595 wSessionSaveClients(WScreen
*scr
)
602 * With XSMP, this job is done by smproxy
605 wSessionSendSaveYourself(WScreen
*scr
)
610 /* freeze client interaction with clients */
611 XGrabKeyboard(dpy
, scr
->root_win
, False
, GrabModeAsync
, GrabModeAsync
,
613 XGrabPointer(dpy
, scr
->root_win
, False
, ButtonPressMask
|ButtonReleaseMask
,
614 GrabModeAsync
, GrabModeAsync
, scr
->root_win
, None
,
617 clearWaitingAckState(scr
);
621 /* first send SAVE_YOURSELF for everybody */
622 for (wwin
= scr
->focused_window
; wwin
!= NULL
; wwin
= wwin
->prev
) {
625 mainWin
= wWindowFor(wwin
->main_window
);
628 /* if the client is a multi-window client, only send message
629 * to the main window */
633 /* make sure the SAVE_YOURSELF flag is up-to-date */
634 PropGetProtocols(wwin
->client_win
, &wwin
->protocols
);
636 if (wwin
->protocols
.SAVE_YOURSELF
) {
637 if (!wwin
->flags
.waiting_save_ack
) {
638 wClientSendProtocol(wwin
, _XA_WM_SAVE_YOURSELF
, LastTimestamp
);
640 wwin
->flags
.waiting_save_ack
= 1;
644 wwin
->flags
.waiting_save_ack
= 0;
648 /* then wait for acknowledge */
653 XUngrabPointer(dpy
, CurrentTime
);
654 XUngrabKeyboard(dpy
, CurrentTime
);
661 * With full session management support, the part of WMState
662 * that store client window state will become obsolete (maybe we can reuse
664 * but we still need to store state info like the dock and workspaces.
665 * It is better to keep dock/wspace info in WMState because the user
666 * might want to keep the dock configuration while not wanting to
667 * resume a previously saved session.
668 * So, wmaker specific state info can be saved in
669 * ~/GNUstep/.AppInfo/WindowMaker/statename.state
670 * Its better to not put it in the defaults directory because:
671 * - its not a defaults file (having domain names like wmaker0089504baa
672 * in the defaults directory wouldn't be very neat)
673 * - this state file is not meant to be edited by users
675 * The old session code will become obsolete. When wmaker is
676 * compiled with R6 sm support compiled in, itll be better to
677 * use a totally rewritten state saving code, but we can keep
678 * the current code for when XSMP_ENABLED is not compiled in.
680 * This will be confusing to old users (well get lots of "SAVE_SESSION broke!"
681 * messages), but itll be better.
688 getWindowRole(Window window
)
691 static Atom atom
= 0;
694 atom
= XInternAtom(dpy
, "WM_WINDOW_ROLE", False
);
696 if (XGetTextProperty(dpy
, window
, &prop
, atom
)) {
697 if (prop
.encoding
== XA_STRING
&& prop
.format
== 8 && prop
.nitems
> 0)
717 * state = (miniaturized, shaded, etc)
720 * app state = (which dock, hidden)
725 makeAppState(WWindow
*wwin
)
729 WScreen
*scr
= wwin
->screen_ptr
;
731 state
= PLMakeArrayWithElements(NULL
, NULL
);
733 wapp
= wApplicationOf(wwin
->main_window
);
736 if (wapp
->app_icon
&& wapp
->app_icon
->dock
) {
738 if (wapp
->app_icon
->dock
== scr
->dock
) {
739 PLAppendArrayElement(state
, PLMakeString("Dock"));
743 for(i
=0; i
<scr
->workspace_count
; i
++)
744 if(scr
->workspaces
[i
]->clip
== wapp
->app_icon
->dock
)
747 assert(i
< scr
->workspace_count
);
749 PLAppendArrayElement(state
,
750 PLMakeString(scr
->workspaces
[i
]->name
));
754 PLAppendArrayElement(state
, PLMakeString(wapp
->hidden
? "1" : "0"));
763 wSessionGetStateFor(WWindow
*wwin
, WSessionData
*state
)
774 value
= PLGetArrayElement(slist
, index
++);
775 str
= PLGetString(value
);
777 sscanf(str
, "%i %i %i %i %i %i", &state
->x
, &state
->y
,
778 &state
->width
, &state
->height
,
779 &state
->user_changed_width
, &state
->user_changed_height
);
783 value
= PLGetArrayElement(slist
, index
++);
784 str
= PLGetString(value
);
786 sscanf(str
, "%i %i %i", &state
->miniaturized
, &state
->shaded
,
791 value
= PLGetArrayElement(slist
, index
++);
792 str
= PLGetString(value
);
794 getAttributeState(str
, &state
->mflags
, &state
->flags
);
798 value
= PLGetArrayElement(slist
, index
++);
799 str
= PLGetString(value
);
801 sscanf(str
, "%i", &state
->workspace
);
804 /* app state (repeated for all windows of the app) */
805 value
= PLGetArrayElement(slist
, index
++);
806 str
= PLGetString(value
);
811 value
= PLGetArrayElement(slist
, index
++);
812 str
= PLGetString(value
);
814 sscanf(str
, "%i", &state
->shortcuts
);
820 makeAttributeState(WWindow
*wwin
)
822 unsigned int data1
, data2
;
825 #define W_FLAG(wwin, FLAG) ((wwin)->defined_user_flags.FLAG \
826 ? (wwin)->user_flags.FLAG : -1)
829 "%i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i",
831 W_FLAG(no_resizable
),
833 W_FLAG(no_miniaturizable
),
834 W_FLAG(no_resizebar
),
835 W_FLAG(no_close_button
),
836 W_FLAG(no_miniaturize_button
),
838 W_FLAG(broken_close),
841 W_FLAG(no_shadeable
),
843 W_FLAG(skip_window_list
),
846 W_FLAG(no_bind_keys
),
847 W_FLAG(no_bind_mouse
),
848 W_FLAG(no_hide_others
),
850 W_FLAG(dont_move_off
),
851 W_FLAG(no_focusable
),
852 W_FLAG(always_user_icon
),
853 W_FLAG(start_miniaturized
),
854 W_FLAG(start_hidden
),
855 W_FLAG(start_maximized
),
856 W_FLAG(dont_save_session
),
857 W_FLAG(emulate_appicon
));
859 return PLMakeString(buffer
);
864 appendStringInArray(proplist_t array
, char *str
)
868 val
= PLMakeString(str
);
869 PLAppendArrayElement(array
, val
);
875 makeClientState(WWindow
*wwin
)
884 state
= PLMakeArrayWithElements(NULL
, NULL
);
887 str
= getWindowRole(wwin
->client_win
);
889 appendStringInArray(state
, "");
891 appendStringInArray(state
, str
);
895 /* WM_CLASS.instance */
896 appendStringInArray(state
, wwin
->wm_instance
);
899 appendStringInArray(state
, wwin
->wm_class
);
902 if (wwin
->flags
.wm_name_changed
)
903 appendStringInArray(state
, "");
905 appendStringInArray(state
, wwin
->frame
->name
);
908 sprintf(buffer
, "%i %i %i %i %i %i", wwin
->frame_x
, wwin
->frame_y
,
909 wwin
->client
.width
, wwin
->client
.height
,
910 wwin
->flags
.user_changed_width
, wwin
->flags
.user_changed_height
);
911 appendStringInArray(state
, buffer
);
914 sprintf(buffer
, "%i %i %i", wwin
->flags
.miniaturized
,
915 wwin
->flags
.shaded
, wwin
->flags
.maximized
);
916 appendStringInArray(state
, buffer
);
919 tmp
= makeAttributeState(wwin
);
920 PLAppendArrayElement(state
, tmp
);
924 sprintf(buffer
, "%i", wwin
->frame
->workspace
);
925 appendStringInArray(state
, buffer
);
927 /* app state (repeated for all windows of the app) */
928 tmp
= makeAppState(wwin
);
929 PLAppendArrayElement(state
, tmp
);
934 for (i
= 0; i
< MAX_WINDOW_SHORTCUTS
; i
++) {
935 if (scr
->shortcutWindow
[i
] == wwin
) {
939 sprintf(buffer
, "%ui", shortcuts
);
940 appendStringInArray(tmp
, buffer
);
947 smSaveYourselfPhase2Proc(SmcConn smc_conn
, SmPointer client_data
)
950 SmPropValue prop1val
, prop2val
, prop3val
, prop4val
;
951 char **argv
= (char**)client_data
;
955 char *statefile
= NULL
;
957 Bool gsPrefix
= False
;
958 char *discardCmd
= NULL
;
963 puts("received SaveYourselfPhase2 SM message");
966 /* save session state */
968 /* the file that will contain the state */
969 prefix
= getenv("SM_SAVE_DIR");
971 prefix
= wusergnusteppath();
976 prefix
= getenv("HOME");
981 statefile
= malloc(strlen(prefix
)+64);
983 wwarning(_("out of memory while saving session state"));
991 sprintf(statefile
, "%s/.AppInfo/WindowMaker/wmaker.%l%i.state",
994 sprintf(statefile
, "%s/wmaker.%l%i.state", prefix
, t
, i
);
996 } while (access(F_OK
, statefile
)!=-1);
998 /* save the states of all windows we're managing */
999 state
= PLMakeArrayFromElements(NULL
, NULL
);
1004 * state_file ::= dictionary with version_info ; state
1005 * version_info ::= 'version' = '1';
1006 * state ::= 'state' = array of screen_info
1007 * screen_info ::= array of (screen number, window_info, window_info, ...)
1010 for (i
=0; i
<wScreenCount
; i
++) {
1016 scr
= wScreenWithNumber(i
);
1018 sprintf(buf
, "%i", scr
->screen
);
1019 pscreen
= PLMakeArrayFromElements(PLMakeString(buf
), NULL
);
1021 wwin
= scr
->focused_window
;
1025 pwindow
= makeClientState(wwin
);
1026 PLAppendArrayElement(pscreen
, pwindow
);
1031 PLAppendArrayElement(state
, pscreen
);
1035 proplist_t statefile
;
1037 statefile
= PLMakeDictionaryFromEntries(PLMakeString("Version"),
1038 PLMakeString("1.0"),
1040 PLMakeString("Screens"),
1045 PLSetFilename(statefile
, PLMakeString(statefile
));
1046 PLSave(statefile
, NO
);
1048 PLRelease(statefile
);
1051 /* set the remaining properties that we didn't set at
1054 for (argc
=0, i
=0; argv
[i
]!=NULL
; i
++) {
1055 if (strcmp(argv
[i
], "-clientid")==0
1056 || strcmp(argv
[i
], "-restore")==0) {
1063 prop
[0].name
= SmRestartCommand
;
1064 prop
[0].type
= SmLISTofARRAY8
;
1065 prop
[0].vals
= malloc(sizeof(SmPropValue
)*(argc
+4));
1066 prop
[0].num_vals
= argc
+4;
1068 prop
[1].name
= SmCloneCommand
;
1069 prop
[1].type
= SmLISTofARRAY8
;
1070 prop
[1].vals
= malloc(sizeof(SmPropValue
)*(argc
));
1071 prop
[1].num_vals
= argc
;
1073 if (!prop
[0].vals
|| !prop
[1].vals
) {
1074 wwarning(_("end of memory while saving session state"));
1078 for (j
=0, i
=0; i
<argc
+4; i
++) {
1079 if (strcmp(argv
[i
], "-clientid")==0
1080 || strcmp(argv
[i
], "-restore")==0) {
1083 prop
[0].vals
[j
].value
= argv
[i
];
1084 prop
[0].vals
[j
].length
= strlen(argv
[i
]);
1085 prop
[1].vals
[j
].value
= argv
[i
];
1086 prop
[1].vals
[j
].length
= strlen(argv
[i
]);
1090 prop
[0].vals
[j
].value
= "-clientid";
1091 prop
[0].vals
[j
].length
= 9;
1093 prop
[0].vals
[j
].value
= sClientID
;
1094 prop
[0].vals
[j
].length
= strlen(sClientID
);
1096 prop
[0].vals
[j
].value
= "-restore";
1097 prop
[0].vals
[j
].length
= 11;
1099 prop
[0].vals
[j
].value
= statefile
;
1100 prop
[0].vals
[j
].length
= strlen(statefile
);
1102 discardCmd
= malloc(strlen(statefile
)+8);
1105 sprintf(discardCmd
, "rm %s", statefile
);
1106 prop
[2].name
= SmDiscardCommand
;
1107 prop
[2].type
= SmARRAY8
;
1108 prop
[2].vals
[0] = discardCmd
;
1109 prop
[2].num_vals
= 1;
1111 SmcSetProperties(sSMCConn
, 3, prop
);
1115 SmcSaveYourselfDone(smc_conn
, ok
);
1133 smSaveYourselfProc(SmcConn smc_conn
, SmPointer client_data
, int save_type
,
1134 Bool shutdown
, int interact_style
, Bool fast
)
1137 puts("received SaveYourself SM message");
1140 if (!SmcRequestSaveYourselfPhase2(smc_conn
, smSaveYourselfPhase2Proc
,
1143 SmcSaveYourselfDone(smc_conn
, False
);
1144 sWaitingPhase2
= False
;
1147 puts("successfull request of SYS phase 2");
1149 sWaitingPhase2
= True
;
1155 smDieProc(SmcConn smc_conn
, SmPointer client_data
)
1158 puts("received Die SM message");
1161 wSessionDisconnectManager();
1163 Shutdown(WSExitMode
, True
);
1169 smSaveCompleteProc(SmcConn smc_conn
)
1171 /* it means that we can resume doing things that can change our state */
1173 puts("received SaveComplete SM message");
1179 smShutdownCancelledProc(SmcConn smc_conn
, SmPointer client_data
)
1181 if (sWaitingPhase2
) {
1183 sWaitingPhase2
= False
;
1185 SmcSaveYourselfDone(smc_conn
, False
);
1191 iceMessageProc(int fd
, int mask
, void *clientData
)
1193 IceConn iceConn
= (IceConn
)clientData
;
1195 IceProcessMessages(iceConn
, NULL
, NULL
);
1200 iceIOErrorHandler(IceConnection ice_conn
)
1202 /* This is not fatal but can mean the session manager exited.
1203 * If the session manager exited normally we would get a
1204 * Die message, so this probably means an abnormal exit.
1205 * If the sm was the last client of session, then we'll die
1206 * anyway, otherwise we can continue doing our stuff.
1208 wwarning(_("connection to the session manager was lost"));
1209 wSessionDisconnectManager();
1214 wSessionConnectManager(char **argv
, int argc
)
1217 char *previous_id
= NULL
;
1219 SmcCallbacks callbacks
;
1224 SmPropValue prop1val
, prop2val
, prop3val
, prop4val
;
1228 mask
= SmcSaveYourselfProcMask
|SmcDieProcMask
|SmcSaveCompleteProcMask
1229 |SmcShutdownCancelledProcMask
;
1231 callbacks
.save_yourself
.callback
= smSaveYourselfProc
;
1232 callbacks
.save_yourself
.client_data
= argv
;
1234 callbacks
.die
.callback
= smDieProc
;
1235 callbacks
.die
.client_data
= NULL
;
1237 callbacks
.save_complete
.callback
= smSaveCompleteProc
;
1238 callbacks
.save_complete
.client_data
= NULL
;
1240 callbacks
.shutdown_cancelled
.callback
= smShutdownCancelledProc
;
1241 callbacks
.shutdown_cancelled
.client_data
= NULL
;
1243 for (i
=0; i
<argc
; i
++) {
1244 if (strcmp(argv
[i
], "-clientid")==0) {
1245 previous_id
= argv
[i
+1];
1250 /* connect to the session manager */
1251 sSMCConn
= SmcOpenConnection(NULL
, NULL
, SmProtoMajor
, SmProtoMinor
,
1252 mask
, &callbacks
, previous_id
,
1253 &sClientID
, 255, buffer
);
1258 puts("connected to the session manager");
1261 /* IceSetIOErrorHandler(iceIOErrorHandler);*/
1263 /* check for session manager clients */
1264 iceConn
= SmcGetIceConnection(smcConn
);
1266 if (fcntl(IceConnectionNumber(iceConn
), F_SETFD
, FD_CLOEXEC
) < 0) {
1267 wsyserror("error setting close-on-exec flag for ICE connection");
1270 sSMInputHandler
= WMAddInputHandler(IceConnectionNumber(iceConn
),
1271 WIReadMask
, iceMessageProc
, iceConn
);
1273 /* setup information about ourselves */
1276 prop1val
.value
= argv
[0];
1277 prop1val
.length
= strlen(argv
[0]);
1278 prop
[0].name
= SmProgram
;
1279 prop
[0].type
= SmARRAY8
;
1280 prop
[0].num_vals
= 1;
1281 prop
[0].vals
= &prop1val
;
1283 /* The XSMP doc from X11R6.1 says it contains the user name,
1284 * but every client implementation I saw places the uid # */
1285 sprintf(uid
, "%i", getuid());
1286 prop2val
.value
= uid
;
1287 prop2val
.length
= strlen(uid
);
1288 prop
[1].name
= SmUserID
;
1289 prop
[1].type
= SmARRAY8
;
1290 prop
[1].num_vals
= 1;
1291 prop
[1].vals
= &prop2val
;
1293 /* Restart style. We should restart only if we were running when
1294 * the previous session finished. */
1295 restartStyle
= SmRestartIfRunning
;
1296 prop3val
.value
= &restartStyle
;
1297 prop3val
.length
= 1;
1298 prop
[2].name
= SmRestartStyleHint
;
1299 prop
[2].type
= SmCARD8
;
1300 prop
[2].num_vals
= 1;
1301 prop
[2].vals
= &prop3val
;
1303 /* Our PID. Not required but might be usefull */
1304 sprintf(pid
, "%i", getpid());
1305 prop4val
.value
= pid
;
1306 prop4val
.length
= strlen(pid
);
1307 prop
[3].name
= SmProcessID
;
1308 prop
[3].type
= SmARRAY8
;
1309 prop
[3].num_vals
= 1;
1310 prop
[3].vals
= &prop4val
;
1312 /* we'll set the rest of the hints later */
1314 SmcSetProperties(sSMCConn
, 4, props
);
1320 wSessionDisconnectManager(void)
1323 WMDeleteInputHandler(sSMInputHandler
);
1324 sSMInputHandler
= NULL
;
1326 SmcCloseConnection(sSMCConn
, 0, NULL
);
1332 wSessionRequestShutdown(void)
1334 /* request a shutdown to the session manager */
1336 SmcRequestSaveYourself(sSMCConn
, SmSaveBoth
, True
, SmInteractStyleAny
,
1342 wSessionIsManaged(void)
1344 return sSMCConn
!=NULL
;
1347 #endif /* !XSMP_ENABLED */