1 /* session.c - session state handling and R6 style session management
3 * Copyright (c) 1998-2002 Dan Pascu
4 * Copyright (c) 1998-2002 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"
95 #include <WINGs/WUtil.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 WMPropList
*sApplications
= NULL
;
120 static WMPropList
*sCommand
;
121 static WMPropList
*sName
;
122 static WMPropList
*sHost
;
123 static WMPropList
*sWorkspace
;
124 static WMPropList
*sShaded
;
125 static WMPropList
*sMiniaturized
;
126 static WMPropList
*sHidden
;
127 static WMPropList
*sGeometry
;
128 static WMPropList
*sShortcutMask
;
130 static WMPropList
*sDock
;
132 static WMPropList
*sYes
, *sNo
;
138 if (sApplications
!=NULL
)
141 sApplications
= WMCreatePLString("Applications");
142 sCommand
= WMCreatePLString("Command");
143 sName
= WMCreatePLString("Name");
144 sHost
= WMCreatePLString("Host");
145 sWorkspace
= WMCreatePLString("Workspace");
146 sShaded
= WMCreatePLString("Shaded");
147 sMiniaturized
= WMCreatePLString("Miniaturized");
148 sHidden
= WMCreatePLString("Hidden");
149 sGeometry
= WMCreatePLString("Geometry");
150 sDock
= WMCreatePLString("Dock");
151 sShortcutMask
= WMCreatePLString("ShortcutMask");
153 sYes
= WMCreatePLString("Yes");
154 sNo
= WMCreatePLString("No");
160 getBool(WMPropList
*value
)
164 if (!WMIsPLString(value
)) {
167 if (!(val
= WMGetFromPLString(value
))) {
171 if ((val
[1]=='\0' && (val
[0]=='y' || val
[0]=='Y'))
172 || strcasecmp(val
, "YES")==0) {
175 } else if ((val
[1]=='\0' && (val
[0]=='n' || val
[0]=='N'))
176 || strcasecmp(val
, "NO")==0) {
180 if (sscanf(val
, "%i", &i
)==1) {
183 wwarning(_("can't convert \"%s\" to boolean"), val
);
191 getInt(WMPropList
*value
)
196 if (!WMIsPLString(value
))
198 val
= WMGetFromPLString(value
);
201 if (sscanf(val
, "%u", &n
) != 1)
210 makeWindowState(WWindow
*wwin
, WApplication
*wapp
)
212 WScreen
*scr
= wwin
->screen_ptr
;
218 char *class, *instance
, *command
=NULL
, buffer
[512];
219 WMPropList
*win_state
, *cmd
, *name
, *workspace
;
220 WMPropList
*shaded
, *miniaturized
, *hidden
, *geometry
;
221 WMPropList
*dock
, *shortcut
;
223 if (wwin
->orig_main_window
!=None
&& wwin
->orig_main_window
!=wwin
->client_win
)
224 win
= wwin
->orig_main_window
;
226 win
= wwin
->client_win
;
228 if (XGetCommand(dpy
, win
, &argv
, &argc
) && argc
>0) {
229 command
= wtokenjoin(argv
, argc
);
230 XFreeStringList(argv
);
235 if (PropGetWMClass(win
, &class, &instance
)) {
236 if (class && instance
)
237 snprintf(buffer
, sizeof(buffer
), "%s.%s", instance
, class);
239 snprintf(buffer
, sizeof(buffer
), "%s", instance
);
241 snprintf(buffer
, sizeof(buffer
), ".%s", class);
243 snprintf(buffer
, sizeof(buffer
), ".");
245 name
= WMCreatePLString(buffer
);
246 cmd
= WMCreatePLString(command
);
247 /*sprintf(buffer, "%d", wwin->frame->workspace+1);
248 workspace = WMCreatePLString(buffer);*/
249 workspace
= WMCreatePLString(scr
->workspaces
[wwin
->frame
->workspace
]->name
);
250 shaded
= wwin
->flags
.shaded
? sYes
: sNo
;
251 miniaturized
= wwin
->flags
.miniaturized
? sYes
: sNo
;
252 hidden
= wwin
->flags
.hidden
? sYes
: sNo
;
253 snprintf(buffer
, sizeof(buffer
), "%ix%i+%i+%i",
254 wwin
->client
.width
, wwin
->client
.height
,
255 wwin
->frame_x
, wwin
->frame_y
);
256 geometry
= WMCreatePLString(buffer
);
258 for (mask
= 0, i
= 0; i
< MAX_WINDOW_SHORTCUTS
; i
++) {
259 if (scr
->shortcutWindows
[i
] != NULL
&&
260 WMGetFirstInArray(scr
->shortcutWindows
[i
], wwin
) != WANotFound
) {
265 snprintf(buffer
, sizeof(buffer
), "%u", mask
);
266 shortcut
= WMCreatePLString(buffer
);
268 win_state
= WMCreatePLDictionary(sName
, name
,
270 sWorkspace
, workspace
,
272 sMiniaturized
, miniaturized
,
274 sShortcutMask
, shortcut
,
278 WMReleasePropList(name
);
279 WMReleasePropList(cmd
);
280 WMReleasePropList(workspace
);
281 WMReleasePropList(geometry
);
282 WMReleasePropList(shortcut
);
283 if (wapp
&& wapp
->app_icon
&& wapp
->app_icon
->dock
) {
286 if (wapp
->app_icon
->dock
== scr
->dock
) {
289 for(i
=0; i
<scr
->workspace_count
; i
++)
290 if(scr
->workspaces
[i
]->clip
== wapp
->app_icon
->dock
)
292 assert( i
< scr
->workspace_count
);
294 name
= scr
->workspaces
[i
]->name
;
296 dock
= WMCreatePLString(name
);
297 WMPutInPLDictionary(win_state
, sDock
, dock
);
298 WMReleasePropList(dock
);
304 if (instance
) XFree(instance
);
305 if (class) XFree(class);
306 if (command
) wfree(command
);
313 wSessionSaveState(WScreen
*scr
)
315 WWindow
*wwin
= scr
->focused_window
;
316 WMPropList
*win_info
, *wks
;
317 WMPropList
*list
=NULL
;
318 WMArray
*wapp_list
=NULL
;
323 if (!scr
->session_state
) {
324 scr
->session_state
= WMCreatePLDictionary(NULL
, NULL
, NULL
);
325 if (!scr
->session_state
)
329 list
= WMCreatePLArray(NULL
);
331 wapp_list
= WMCreateArray(16);
334 WApplication
*wapp
=wApplicationOf(wwin
->main_window
);
335 Window appId
= wwin
->orig_main_window
;
337 if ((wwin
->transient_for
==None
338 || wwin
->transient_for
==wwin
->screen_ptr
->root_win
)
339 && WMGetFirstInArray(wapp_list
, (void*)appId
)==WANotFound
340 && !WFLAGP(wwin
, dont_save_session
)) {
341 /* A entry for this application was not yet saved. Save one. */
342 if ((win_info
= makeWindowState(wwin
, wapp
))!=NULL
) {
343 WMAddToPLArray(list
, win_info
);
344 WMReleasePropList(win_info
);
345 /* If we were succesful in saving the info for this window
346 * add the application the window belongs to, to the
347 * application list, so no multiple entries for the same
348 * application are saved.
350 WMAddToArray(wapp_list
, (void*)appId
);
355 WMRemoveFromPLDictionary(scr
->session_state
, sApplications
);
356 WMPutInPLDictionary(scr
->session_state
, sApplications
, list
);
357 WMReleasePropList(list
);
359 wks
= WMCreatePLString(scr
->workspaces
[scr
->current_workspace
]->name
);
360 WMPutInPLDictionary(scr
->session_state
, sWorkspace
, wks
);
361 WMReleasePropList(wks
);
363 WMFreeArray(wapp_list
);
368 wSessionClearState(WScreen
*scr
)
372 if (!scr
->session_state
)
375 WMRemoveFromPLDictionary(scr
->session_state
, sApplications
);
376 WMRemoveFromPLDictionary(scr
->session_state
, sWorkspace
);
381 execCommand(WScreen
*scr
, char *command
, char *host
)
387 wtokensplit(command
, &argv
, &argc
);
393 if ((pid
=fork())==0) {
397 SetupEnvironment(scr
);
399 args
= malloc(sizeof(char*)*(argc
+1));
402 for (i
=0; i
<argc
; i
++) {
406 execvp(argv
[0], args
);
417 getWindowState(WScreen
*scr
, WMPropList
*win_state
)
419 WSavedState
*state
= wmalloc(sizeof(WSavedState
));
425 memset(state
, 0, sizeof(WSavedState
));
426 state
->workspace
= -1;
427 value
= WMGetFromPLDictionary(win_state
, sWorkspace
);
428 if (value
&& WMIsPLString(value
)) {
429 tmp
= WMGetFromPLString(value
);
430 if (sscanf(tmp
, "%i", &state
->workspace
)!=1) {
431 state
->workspace
= -1;
432 for (i
=0; i
< scr
->workspace_count
; i
++) {
433 if (strcmp(scr
->workspaces
[i
]->name
, tmp
)==0) {
434 state
->workspace
= i
;
442 if ((value
= WMGetFromPLDictionary(win_state
, sShaded
))!=NULL
)
443 state
->shaded
= getBool(value
);
444 if ((value
= WMGetFromPLDictionary(win_state
, sMiniaturized
))!=NULL
)
445 state
->miniaturized
= getBool(value
);
446 if ((value
= WMGetFromPLDictionary(win_state
, sHidden
))!=NULL
)
447 state
->hidden
= getBool(value
);
448 if ((value
= WMGetFromPLDictionary(win_state
, sShortcutMask
))!=NULL
) {
449 mask
= getInt(value
);
450 state
->window_shortcuts
= mask
;
453 value
= WMGetFromPLDictionary(win_state
, sGeometry
);
454 if (value
&& WMIsPLString(value
)) {
455 if (!(sscanf(WMGetFromPLString(value
), "%ix%i+%i+%i",
456 &state
->w
, &state
->h
, &state
->x
, &state
->y
)==4 &&
457 (state
->w
>0 && state
->h
>0))) {
467 #define SAME(x, y) (((x) && (y) && !strcmp((x), (y))) || (!(x) && !(y)))
470 wSessionRestoreState(WScreen
*scr
)
473 char *instance
, *class, *command
, *host
;
474 WMPropList
*win_info
, *apps
, *cmd
, *value
;
484 if (!scr
->session_state
)
487 WMPLSetCaseSensitive(True
);
489 apps
= WMGetFromPLDictionary(scr
->session_state
, sApplications
);
493 count
= WMGetPropListItemCount(apps
);
497 for (i
=0; i
<count
; i
++) {
498 win_info
= WMGetFromPLArray(apps
, i
);
500 cmd
= WMGetFromPLDictionary(win_info
, sCommand
);
501 if (!cmd
|| !WMIsPLString(cmd
) || !(command
= WMGetFromPLString(cmd
))) {
505 value
= WMGetFromPLDictionary(win_info
, sName
);
509 ParseWindowName(value
, &instance
, &class, "session");
510 if (!instance
&& !class)
513 value
= WMGetFromPLDictionary(win_info
, sHost
);
514 if (value
&& WMIsPLString(value
))
515 host
= WMGetFromPLString(value
);
519 state
= getWindowState(scr
, win_info
);
522 value
= WMGetFromPLDictionary(win_info
, sDock
);
523 if (value
&& WMIsPLString(value
) && (tmp
= WMGetFromPLString(value
))!=NULL
) {
524 if (sscanf(tmp
, "%i", &n
)!=1) {
525 if (!strcasecmp(tmp
, "DOCK")) {
528 for (j
=0; j
< scr
->workspace_count
; j
++) {
529 if (strcmp(scr
->workspaces
[j
]->name
, tmp
)==0) {
530 dock
= scr
->workspaces
[j
]->clip
;
538 } else if (n
>0 && n
<=scr
->workspace_count
) {
539 dock
= scr
->workspaces
[n
-1]->clip
;
546 for (j
=0; j
<dock
->max_icons
; j
++) {
547 btn
= dock
->icon_array
[j
];
548 if (btn
&& SAME(instance
, btn
->wm_instance
) &&
549 SAME(class, btn
->wm_class
) &&
550 SAME(command
, btn
->command
) &&
559 wDockLaunchWithState(dock
, btn
, state
);
560 } else if ((pid
= execCommand(scr
, command
, host
)) > 0) {
561 wWindowAddSavedState(instance
, class, command
, pid
, state
);
566 if (instance
) wfree(instance
);
567 if (class) wfree(class);
570 WMPLSetCaseSensitive(False
);
575 wSessionRestoreLastWorkspace(WScreen
*scr
)
583 if (!scr
->session_state
)
586 WMPLSetCaseSensitive(True
);
588 wks
= WMGetFromPLDictionary(scr
->session_state
, sWorkspace
);
589 if (!wks
|| !WMIsPLString(wks
))
592 tmp
= WMGetFromPLString(wks
);
595 WMPLSetCaseSensitive(False
);
597 if (sscanf(tmp
, "%i", &w
)!=1) {
599 for (i
=0; i
< scr
->workspace_count
; i
++) {
600 if (strcmp(scr
->workspaces
[i
]->name
, tmp
)==0) {
609 if (w
!=scr
->current_workspace
&& w
<scr
->workspace_count
) {
610 wWorkspaceChange(scr
, w
);
616 clearWaitingAckState(WScreen
*scr
)
621 for (wwin
= scr
->focused_window
; wwin
!= NULL
; wwin
= wwin
->prev
) {
622 wwin
->flags
.waiting_save_ack
= 0;
623 if (wwin
->main_window
!= None
) {
624 wapp
= wApplicationOf(wwin
->main_window
);
626 wapp
->main_window_desc
->flags
.waiting_save_ack
= 0;
633 wSessionSaveClients(WScreen
*scr
)
640 * With XSMP, this job is done by smproxy
643 wSessionSendSaveYourself(WScreen
*scr
)
648 /* freeze client interaction with clients */
649 XGrabKeyboard(dpy
, scr
->root_win
, False
, GrabModeAsync
, GrabModeAsync
,
651 XGrabPointer(dpy
, scr
->root_win
, False
, ButtonPressMask
|ButtonReleaseMask
,
652 GrabModeAsync
, GrabModeAsync
, scr
->root_win
, None
,
655 clearWaitingAckState(scr
);
659 /* first send SAVE_YOURSELF for everybody */
660 for (wwin
= scr
->focused_window
; wwin
!= NULL
; wwin
= wwin
->prev
) {
663 mainWin
= wWindowFor(wwin
->main_window
);
666 /* if the client is a multi-window client, only send message
667 * to the main window */
671 /* make sure the SAVE_YOURSELF flag is up-to-date */
672 PropGetProtocols(wwin
->client_win
, &wwin
->protocols
);
674 if (wwin
->protocols
.SAVE_YOURSELF
) {
675 if (!wwin
->flags
.waiting_save_ack
) {
676 wClientSendProtocol(wwin
, _XA_WM_SAVE_YOURSELF
, LastTimestamp
);
678 wwin
->flags
.waiting_save_ack
= 1;
682 wwin
->flags
.waiting_save_ack
= 0;
686 /* then wait for acknowledge */
691 XUngrabPointer(dpy
, CurrentTime
);
692 XUngrabKeyboard(dpy
, CurrentTime
);
699 * With full session management support, the part of WMState
700 * that store client window state will become obsolete (maybe we can reuse
702 * but we still need to store state info like the dock and workspaces.
703 * It is better to keep dock/wspace info in WMState because the user
704 * might want to keep the dock configuration while not wanting to
705 * resume a previously saved session.
706 * So, wmaker specific state info can be saved in
707 * ~/GNUstep/.AppInfo/WindowMaker/statename.state
708 * Its better to not put it in the defaults directory because:
709 * - its not a defaults file (having domain names like wmaker0089504baa
710 * in the defaults directory wouldn't be very neat)
711 * - this state file is not meant to be edited by users
713 * The old session code will become obsolete. When wmaker is
714 * compiled with R6 sm support compiled in, it'll be better to
715 * use a totally rewritten state saving code, but we can keep
716 * the current code for when XSMP_ENABLED is not compiled in.
718 * This will be confusing to old users (well get lots of "SAVE_SESSION broke!"
719 * messages), but it'll be better.
726 getWindowRole(Window window
)
729 static Atom atom
= 0;
732 atom
= XInternAtom(dpy
, "WM_WINDOW_ROLE", False
);
734 if (XGetTextProperty(dpy
, window
, &prop
, atom
)) {
735 if (prop
.encoding
== XA_STRING
&& prop
.format
== 8 && prop
.nitems
> 0)
755 * state = (miniaturized, shaded, etc)
758 * app state = (which dock, hidden)
763 makeAppState(WWindow
*wwin
)
767 WScreen
*scr
= wwin
->screen_ptr
;
769 state
= WMCreatePLArray(NULL
, NULL
);
771 wapp
= wApplicationOf(wwin
->main_window
);
774 if (wapp
->app_icon
&& wapp
->app_icon
->dock
) {
776 if (wapp
->app_icon
->dock
== scr
->dock
) {
777 WMAddToPLArray(state
, WMCreatePLString("Dock"));
781 for(i
=0; i
<scr
->workspace_count
; i
++)
782 if(scr
->workspaces
[i
]->clip
== wapp
->app_icon
->dock
)
785 assert(i
< scr
->workspace_count
);
787 WMAddToPLArray(state
,
788 WMCreatePLString(scr
->workspaces
[i
]->name
));
792 WMAddToPLArray(state
, WMCreatePLString(wapp
->hidden
? "1" : "0"));
801 wSessionGetStateFor(WWindow
*wwin
, WSessionData
*state
)
812 value
= WMGetFromPLArray(slist
, index
++);
813 str
= WMGetFromPLString(value
);
815 sscanf(str
, "%i %i %i %i %i %i", &state
->x
, &state
->y
,
816 &state
->width
, &state
->height
,
817 &state
->user_changed_width
, &state
->user_changed_height
);
821 value
= WMGetFromPLArray(slist
, index
++);
822 str
= WMGetFromPLString(value
);
824 sscanf(str
, "%i %i %i", &state
->miniaturized
, &state
->shaded
,
829 value
= WMGetFromPLArray(slist
, index
++);
830 str
= WMGetFromPLString(value
);
832 getAttributeState(str
, &state
->mflags
, &state
->flags
);
836 value
= WMGetFromPLArray(slist
, index
++);
837 str
= WMGetFromPLString(value
);
839 sscanf(str
, "%i", &state
->workspace
);
842 /* app state (repeated for all windows of the app) */
843 value
= WMGetFromPLArray(slist
, index
++);
844 str
= WMGetFromPLString(value
);
849 value
= WMGetFromPLArray(slist
, index
++);
850 str
= WMGetFromPLString(value
);
852 sscanf(str
, "%i", &state
->shortcuts
);
858 makeAttributeState(WWindow
*wwin
)
860 unsigned int data1
, data2
;
863 #define W_FLAG(wwin, FLAG) ((wwin)->defined_user_flags.FLAG \
864 ? (wwin)->user_flags.FLAG : -1)
866 snprintf(buffer
, sizeof(buffer
),
867 "%i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i",
869 W_FLAG(no_resizable
),
871 W_FLAG(no_miniaturizable
),
872 W_FLAG(no_resizebar
),
873 W_FLAG(no_close_button
),
874 W_FLAG(no_miniaturize_button
),
876 W_FLAG(broken_close),
879 W_FLAG(no_shadeable
),
881 W_FLAG(skip_window_list
),
884 W_FLAG(no_bind_keys
),
885 W_FLAG(no_bind_mouse
),
886 W_FLAG(no_hide_others
),
888 W_FLAG(dont_move_off
),
889 W_FLAG(no_focusable
),
890 W_FLAG(always_user_icon
),
891 W_FLAG(start_miniaturized
),
892 W_FLAG(start_hidden
),
893 W_FLAG(start_maximized
),
894 W_FLAG(dont_save_session
),
895 W_FLAG(emulate_appicon
));
897 return WMCreatePLString(buffer
);
902 appendStringInArray(WMPropList
*array
, char *str
)
906 val
= WMCreatePLString(str
);
907 WMAddToPLArray(array
, val
);
908 WMReleasePropList(val
);
913 makeClientState(WWindow
*wwin
)
922 state
= WMCreatePLArray(NULL
, NULL
);
925 str
= getWindowRole(wwin
->client_win
);
927 appendStringInArray(state
, "");
929 appendStringInArray(state
, str
);
933 /* WM_CLASS.instance */
934 appendStringInArray(state
, wwin
->wm_instance
);
937 appendStringInArray(state
, wwin
->wm_class
);
940 if (wwin
->flags
.wm_name_changed
)
941 appendStringInArray(state
, "");
943 appendStringInArray(state
, wwin
->frame
->name
);
946 snprintf(buffer
, sizeof(buffer
), "%i %i %i %i %i %i", wwin
->frame_x
, wwin
->frame_y
,
947 wwin
->client
.width
, wwin
->client
.height
,
948 wwin
->flags
.user_changed_width
, wwin
->flags
.user_changed_height
);
949 appendStringInArray(state
, buffer
);
952 snprintf(buffer
, sizeof(buffer
), "%i %i %i", wwin
->flags
.miniaturized
,
953 wwin
->flags
.shaded
, wwin
->flags
.maximized
);
954 appendStringInArray(state
, buffer
);
957 tmp
= makeAttributeState(wwin
);
958 WMAddToPLArray(state
, tmp
);
959 WMReleasePropList(tmp
);
962 snprintf(buffer
, sizeof(buffer
), "%i", wwin
->frame
->workspace
);
963 appendStringInArray(state
, buffer
);
965 /* app state (repeated for all windows of the app) */
966 tmp
= makeAppState(wwin
);
967 WMAddToPLArray(state
, tmp
);
968 WMReleasePropList(tmp
);
972 for (i
= 0; i
< MAX_WINDOW_SHORTCUTS
; i
++) {
973 if (scr
->shortcutWindow
[i
] == wwin
) {
977 snprintf(buffer
, sizeof(buffer
), "%ui", shortcuts
);
978 appendStringInArray(tmp
, buffer
);
985 smSaveYourselfPhase2Proc(SmcConn smc_conn
, SmPointer client_data
)
988 SmPropValue prop1val
, prop2val
, prop3val
, prop4val
;
989 char **argv
= (char**)client_data
;
993 char *statefile
= NULL
;
995 Bool gsPrefix
= False
;
996 char *discardCmd
= NULL
;
998 WMPropList
*state
, *plState
;
1002 puts("received SaveYourselfPhase2 SM message");
1005 /* save session state */
1007 /* the file that will contain the state */
1008 prefix
= getenv("SM_SAVE_DIR");
1010 prefix
= wusergnusteppath();
1015 prefix
= getenv("HOME");
1020 len
= strlen(prefix
)+64;
1021 statefile
= malloc(len
);
1023 wwarning(_("out of memory while saving session state"));
1031 snprintf(statefile
, len
, "%s/.AppInfo/WindowMaker/wmaker.%l%i.state",
1034 snprintf(statefile
, len
, "%s/wmaker.%l%i.state", prefix
, t
, i
);
1036 } while (access(F_OK
, statefile
)!=-1);
1038 /* save the states of all windows we're managing */
1039 state
= WMCreatePLArray(NULL
, NULL
);
1044 * state_file ::= dictionary with version_info ; state
1045 * version_info ::= 'version' = '1';
1046 * state ::= 'state' = array of screen_info
1047 * screen_info ::= array of (screen number, window_info, window_info, ...)
1050 for (i
=0; i
<wScreenCount
; i
++) {
1054 WMPropList
*pscreen
;
1056 scr
= wScreenWithNumber(i
);
1058 snprintf(buf
, sizeof(buf
), "%i", scr
->screen
);
1059 pscreen
= WMCreatePLArray(WMCreatePLString(buf
), NULL
);
1061 wwin
= scr
->focused_window
;
1063 WMPropList
*pwindow
;
1065 pwindow
= makeClientState(wwin
);
1066 WMAddToPLArray(pscreen
, pwindow
);
1071 WMAddToPLArray(state
, pscreen
);
1074 plState
= WMCreatePLDictionary(WMCreatePLString("Version"),
1075 WMCreatePLString("1.0"),
1076 WMCreatePLString("Screens"),
1079 WMWritePropListToFile(plState
, statefile
, False
);
1081 WMReleasePropList(plState
);
1083 /* set the remaining properties that we didn't set at
1086 for (argc
=0, i
=0; argv
[i
]!=NULL
; i
++) {
1087 if (strcmp(argv
[i
], "-clientid")==0
1088 || strcmp(argv
[i
], "-restore")==0) {
1095 prop
[0].name
= SmRestartCommand
;
1096 prop
[0].type
= SmLISTofARRAY8
;
1097 prop
[0].vals
= malloc(sizeof(SmPropValue
)*(argc
+4));
1098 prop
[0].num_vals
= argc
+4;
1100 prop
[1].name
= SmCloneCommand
;
1101 prop
[1].type
= SmLISTofARRAY8
;
1102 prop
[1].vals
= malloc(sizeof(SmPropValue
)*(argc
));
1103 prop
[1].num_vals
= argc
;
1105 if (!prop
[0].vals
|| !prop
[1].vals
) {
1106 wwarning(_("end of memory while saving session state"));
1110 for (j
=0, i
=0; i
<argc
+4; i
++) {
1111 if (strcmp(argv
[i
], "-clientid")==0
1112 || strcmp(argv
[i
], "-restore")==0) {
1115 prop
[0].vals
[j
].value
= argv
[i
];
1116 prop
[0].vals
[j
].length
= strlen(argv
[i
]);
1117 prop
[1].vals
[j
].value
= argv
[i
];
1118 prop
[1].vals
[j
].length
= strlen(argv
[i
]);
1122 prop
[0].vals
[j
].value
= "-clientid";
1123 prop
[0].vals
[j
].length
= 9;
1125 prop
[0].vals
[j
].value
= sClientID
;
1126 prop
[0].vals
[j
].length
= strlen(sClientID
);
1128 prop
[0].vals
[j
].value
= "-restore";
1129 prop
[0].vals
[j
].length
= 11;
1131 prop
[0].vals
[j
].value
= statefile
;
1132 prop
[0].vals
[j
].length
= strlen(statefile
);
1135 int len
= strlen(statefile
)+8;
1137 discardCmd
= malloc(len
);
1140 snprintf(discardCmd
, len
, "rm %s", statefile
);
1142 prop
[2].name
= SmDiscardCommand
;
1143 prop
[2].type
= SmARRAY8
;
1144 prop
[2].vals
[0] = discardCmd
;
1145 prop
[2].num_vals
= 1;
1147 SmcSetProperties(sSMCConn
, 3, prop
);
1151 SmcSaveYourselfDone(smc_conn
, ok
);
1154 wfree(prop
[0].vals
);
1156 wfree(prop
[1].vals
);
1169 smSaveYourselfProc(SmcConn smc_conn
, SmPointer client_data
, int save_type
,
1170 Bool shutdown
, int interact_style
, Bool fast
)
1173 puts("received SaveYourself SM message");
1176 if (!SmcRequestSaveYourselfPhase2(smc_conn
, smSaveYourselfPhase2Proc
,
1179 SmcSaveYourselfDone(smc_conn
, False
);
1180 sWaitingPhase2
= False
;
1183 puts("successfull request of SYS phase 2");
1185 sWaitingPhase2
= True
;
1191 smDieProc(SmcConn smc_conn
, SmPointer client_data
)
1194 puts("received Die SM message");
1197 wSessionDisconnectManager();
1199 Shutdown(WSExitMode
, True
);
1205 smSaveCompleteProc(SmcConn smc_conn
)
1207 /* it means that we can resume doing things that can change our state */
1209 puts("received SaveComplete SM message");
1215 smShutdownCancelledProc(SmcConn smc_conn
, SmPointer client_data
)
1217 if (sWaitingPhase2
) {
1219 sWaitingPhase2
= False
;
1221 SmcSaveYourselfDone(smc_conn
, False
);
1227 iceMessageProc(int fd
, int mask
, void *clientData
)
1229 IceConn iceConn
= (IceConn
)clientData
;
1231 IceProcessMessages(iceConn
, NULL
, NULL
);
1236 iceIOErrorHandler(IceConnection ice_conn
)
1238 /* This is not fatal but can mean the session manager exited.
1239 * If the session manager exited normally we would get a
1240 * Die message, so this probably means an abnormal exit.
1241 * If the sm was the last client of session, then we'll die
1242 * anyway, otherwise we can continue doing our stuff.
1244 wwarning(_("connection to the session manager was lost"));
1245 wSessionDisconnectManager();
1250 wSessionConnectManager(char **argv
, int argc
)
1253 char *previous_id
= NULL
;
1255 SmcCallbacks callbacks
;
1260 SmPropValue prop1val
, prop2val
, prop3val
, prop4val
;
1264 mask
= SmcSaveYourselfProcMask
|SmcDieProcMask
|SmcSaveCompleteProcMask
1265 |SmcShutdownCancelledProcMask
;
1267 callbacks
.save_yourself
.callback
= smSaveYourselfProc
;
1268 callbacks
.save_yourself
.client_data
= argv
;
1270 callbacks
.die
.callback
= smDieProc
;
1271 callbacks
.die
.client_data
= NULL
;
1273 callbacks
.save_complete
.callback
= smSaveCompleteProc
;
1274 callbacks
.save_complete
.client_data
= NULL
;
1276 callbacks
.shutdown_cancelled
.callback
= smShutdownCancelledProc
;
1277 callbacks
.shutdown_cancelled
.client_data
= NULL
;
1279 for (i
=0; i
<argc
; i
++) {
1280 if (strcmp(argv
[i
], "-clientid")==0) {
1281 previous_id
= argv
[i
+1];
1286 /* connect to the session manager */
1287 sSMCConn
= SmcOpenConnection(NULL
, NULL
, SmProtoMajor
, SmProtoMinor
,
1288 mask
, &callbacks
, previous_id
,
1289 &sClientID
, 255, buffer
);
1294 puts("connected to the session manager");
1297 /* IceSetIOErrorHandler(iceIOErrorHandler);*/
1299 /* check for session manager clients */
1300 iceConn
= SmcGetIceConnection(smcConn
);
1302 if (fcntl(IceConnectionNumber(iceConn
), F_SETFD
, FD_CLOEXEC
) < 0) {
1303 wsyserror("error setting close-on-exec flag for ICE connection");
1306 sSMInputHandler
= WMAddInputHandler(IceConnectionNumber(iceConn
),
1307 WIReadMask
, iceMessageProc
, iceConn
);
1309 /* setup information about ourselves */
1312 prop1val
.value
= argv
[0];
1313 prop1val
.length
= strlen(argv
[0]);
1314 prop
[0].name
= SmProgram
;
1315 prop
[0].type
= SmARRAY8
;
1316 prop
[0].num_vals
= 1;
1317 prop
[0].vals
= &prop1val
;
1319 /* The XSMP doc from X11R6.1 says it contains the user name,
1320 * but every client implementation I saw places the uid # */
1321 snprintf(uid
, sizeof(uid
), "%i", getuid());
1322 prop2val
.value
= uid
;
1323 prop2val
.length
= strlen(uid
);
1324 prop
[1].name
= SmUserID
;
1325 prop
[1].type
= SmARRAY8
;
1326 prop
[1].num_vals
= 1;
1327 prop
[1].vals
= &prop2val
;
1329 /* Restart style. We should restart only if we were running when
1330 * the previous session finished. */
1331 restartStyle
= SmRestartIfRunning
;
1332 prop3val
.value
= &restartStyle
;
1333 prop3val
.length
= 1;
1334 prop
[2].name
= SmRestartStyleHint
;
1335 prop
[2].type
= SmCARD8
;
1336 prop
[2].num_vals
= 1;
1337 prop
[2].vals
= &prop3val
;
1339 /* Our PID. Not required but might be usefull */
1340 snprintf(pid
, sizeof(pid
), "%i", getpid());
1341 prop4val
.value
= pid
;
1342 prop4val
.length
= strlen(pid
);
1343 prop
[3].name
= SmProcessID
;
1344 prop
[3].type
= SmARRAY8
;
1345 prop
[3].num_vals
= 1;
1346 prop
[3].vals
= &prop4val
;
1348 /* we'll set the rest of the hints later */
1350 SmcSetProperties(sSMCConn
, 4, props
);
1356 wSessionDisconnectManager(void)
1359 WMDeleteInputHandler(sSMInputHandler
);
1360 sSMInputHandler
= NULL
;
1362 SmcCloseConnection(sSMCConn
, 0, NULL
);
1368 wSessionRequestShutdown(void)
1370 /* request a shutdown to the session manager */
1372 SmcRequestSaveYourself(sSMCConn
, SmSaveBoth
, True
, SmInteractStyleAny
,
1378 wSessionIsManaged(void)
1380 return sSMCConn
!=NULL
;
1383 #endif /* !XSMP_ENABLED */