Update to Window Maker 0.50.2
[wmaker-crm.git] / src / session.c
blobc186d5e4a9d756c60313b39e8046a199ea8bae50
1 /* session.c - session state handling and R6 style session management
3 * Copyright (c) 1998 Dan Pascu
4 * Copyright (c) 1998 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,
21 * USA.
24 #include "wconfig.h"
26 #include <X11/Xlib.h>
27 #include <X11/Xutil.h>
29 #ifdef R6SM
30 #include <X11/SM/SMlib.h>
31 #endif
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <time.h>
40 #include "WindowMaker.h"
41 #include "screen.h"
42 #include "window.h"
43 #include "session.h"
44 #include "wcore.h"
45 #include "framewin.h"
46 #include "workspace.h"
47 #include "funcs.h"
48 #include "properties.h"
49 #include "application.h"
50 #include "appicon.h"
53 #include "dock.h"
55 #include "list.h"
57 #include <proplist.h>
60 #ifdef R6SM
62 extern int wScreenCount;
64 /* requested for SaveYourselfPhase2 */
65 static Bool sWaitingPhase2 = False;
67 static SmcConn sSMCConn = NULL;
69 static WMHandlerID sSMInputHandler = NULL;
71 /* our SM client ID */
72 static char *sClientID = NULL;
73 #endif
76 static proplist_t sApplications = NULL;
77 static proplist_t sCommand;
78 static proplist_t sName;
79 static proplist_t sHost;
80 static proplist_t sWorkspace;
81 static proplist_t sShaded;
82 static proplist_t sMiniaturized;
83 static proplist_t sHidden;
84 static proplist_t sGeometry;
86 static proplist_t sDock;
88 static proplist_t sYes, sNo;
91 static void
92 make_keys()
94 if (sApplications!=NULL)
95 return;
97 sApplications = PLMakeString("Applications");
98 sCommand = PLMakeString("Command");
99 sName = PLMakeString("Name");
100 sHost = PLMakeString("Host");
101 sWorkspace = PLMakeString("Workspace");
102 sShaded = PLMakeString("Shaded");
103 sMiniaturized = PLMakeString("Miniaturized");
104 sHidden = PLMakeString("Hidden");
105 sGeometry = PLMakeString("Geometry");
106 sDock = PLMakeString("Dock");
108 sYes = PLMakeString("Yes");
109 sNo = PLMakeString("No");
114 static int
115 getBool(proplist_t value)
117 char *val;
119 if (!PLIsString(value)) {
120 return 0;
122 if (!(val = PLGetString(value))) {
123 return 0;
126 if ((val[1]=='\0' && (val[0]=='y' || val[0]=='Y'))
127 || strcasecmp(val, "YES")==0) {
129 return 1;
130 } else if ((val[1]=='\0' && (val[0]=='n' || val[0]=='N'))
131 || strcasecmp(val, "NO")==0) {
132 return 0;
133 } else {
134 int i;
135 if (sscanf(val, "%i", &i)==1) {
136 return (i!=0);
137 } else {
138 wwarning(_("can't convert \"%s\" to boolean"), val);
139 return 0;
146 static proplist_t
147 makeWindowState(WWindow *wwin, WApplication *wapp)
149 WScreen *scr = wwin->screen_ptr;
150 Window win;
151 int argc;
152 char **argv;
153 char *class, *instance, *command=NULL, buffer[256];
154 proplist_t win_state, cmd, name, workspace;
155 proplist_t shaded, miniaturized, hidden, geometry;
156 proplist_t dock;
158 if (wwin->main_window!=None && wwin->main_window!=wwin->client_win)
159 win = wwin->main_window;
160 else
161 win = wwin->client_win;
163 if (XGetCommand(dpy, win, &argv, &argc) && argc>0) {
164 command = FlattenStringList(argv, argc);
165 XFreeStringList(argv);
167 if (!command)
168 return NULL;
170 if (PropGetWMClass(win, &class, &instance)) {
171 if (class && instance)
172 sprintf(buffer, "%s.%s", instance, class);
173 else if (instance)
174 sprintf(buffer, "%s", instance);
175 else if (class)
176 sprintf(buffer, ".%s", class);
177 else
178 sprintf(buffer, ".");
180 name = PLMakeString(buffer);
181 cmd = PLMakeString(command);
182 /*sprintf(buffer, "%d", wwin->frame->workspace+1);
183 workspace = PLMakeString(buffer);*/
184 workspace = PLMakeString(scr->workspaces[wwin->frame->workspace]->name);
185 shaded = wwin->flags.shaded ? sYes : sNo;
186 miniaturized = wwin->flags.miniaturized ? sYes : sNo;
187 hidden = wwin->flags.hidden ? sYes : sNo;
188 sprintf(buffer, "%ix%i+%i+%i", wwin->client.width, wwin->client.height,
189 wwin->frame_x, wwin->frame_y);
190 geometry = PLMakeString(buffer);
192 win_state = PLMakeDictionaryFromEntries(sName, name,
193 sCommand, cmd,
194 sWorkspace, workspace,
195 sShaded, shaded,
196 sMiniaturized, miniaturized,
197 sHidden, hidden,
198 sGeometry, geometry,
199 NULL);
201 PLRelease(name);
202 PLRelease(cmd);
203 PLRelease(workspace);
204 PLRelease(geometry);
205 if (wapp && wapp->app_icon && wapp->app_icon->dock) {
206 int i;
207 char *name;
208 if (wapp->app_icon->dock == scr->dock) {
209 name="Dock";
210 } else {
211 for(i=0; i<scr->workspace_count; i++)
212 if(scr->workspaces[i]->clip == wapp->app_icon->dock)
213 break;
214 assert( i < scr->workspace_count);
215 /*n = i+1;*/
216 name = scr->workspaces[i]->name;
218 dock = PLMakeString(name);
219 PLInsertDictionaryEntry(win_state, sDock, dock);
220 PLRelease(dock);
222 } else {
223 win_state = NULL;
226 if (instance) XFree(instance);
227 if (class) XFree(class);
228 if (command) free(command);
230 return win_state;
234 void
235 wSessionSaveState(WScreen *scr)
237 WWindow *wwin = scr->focused_window;
238 proplist_t win_info, wks;
239 proplist_t list=NULL;
240 LinkedList *wapp_list=NULL;
243 make_keys();
245 if (!scr->session_state) {
246 scr->session_state = PLMakeDictionaryFromEntries(NULL, NULL, NULL);
247 if (!scr->session_state)
248 return;
251 list = PLMakeArrayFromElements(NULL);
253 while (wwin) {
254 WApplication *wapp=wApplicationOf(wwin->main_window);
256 if (wwin->transient_for==None && list_find(wapp_list, wapp)==NULL
257 && !WFLAGP(wwin, dont_save_session)) {
258 /* A entry for this application was not yet saved. Save one. */
259 if ((win_info = makeWindowState(wwin, wapp))!=NULL) {
260 list = PLAppendArrayElement(list, win_info);
261 PLRelease(win_info);
262 /* If we were succesful in saving the info for this window
263 * add the application the window belongs to, to the
264 * application list, so no multiple entries for the same
265 * application are saved.
267 wapp_list = list_cons(wapp, wapp_list);
270 wwin = wwin->prev;
272 PLRemoveDictionaryEntry(scr->session_state, sApplications);
273 PLInsertDictionaryEntry(scr->session_state, sApplications, list);
274 PLRelease(list);
276 wks = PLMakeString(scr->workspaces[scr->current_workspace]->name);
277 PLInsertDictionaryEntry(scr->session_state, sWorkspace, wks);
278 PLRelease(wks);
280 list_free(wapp_list);
284 void
285 wSessionClearState(WScreen *scr)
287 make_keys();
289 if (!scr->session_state)
290 return;
292 PLRemoveDictionaryEntry(scr->session_state, sApplications);
293 PLRemoveDictionaryEntry(scr->session_state, sWorkspace);
297 static pid_t
298 execCommand(WScreen *scr, char *command, char *host)
300 pid_t pid;
301 char **argv;
302 int argc;
304 ParseCommand(command, &argv, &argc);
306 if (argv==NULL) {
307 return 0;
310 if ((pid=fork())==0) {
311 char **args;
312 int i;
314 SetupEnvironment(scr);
316 args = malloc(sizeof(char*)*(argc+1));
317 if (!args)
318 exit(111);
319 for (i=0; i<argc; i++) {
320 args[i] = argv[i];
322 args[argc] = NULL;
323 execvp(argv[0], args);
324 exit(111);
326 while (argc > 0)
327 free(argv[--argc]);
328 free(argv);
329 return pid;
333 static WSavedState*
334 getWindowState(WScreen *scr, proplist_t win_state)
336 WSavedState *state = wmalloc(sizeof(WSavedState));
337 proplist_t value;
338 char *tmp;
339 int i;
341 memset(state, 0, sizeof(WSavedState));
342 state->workspace = -1;
343 value = PLGetDictionaryEntry(win_state, sWorkspace);
344 if (value && PLIsString(value)) {
345 tmp = PLGetString(value);
346 if (sscanf(tmp, "%i", &state->workspace)!=1) {
347 state->workspace = -1;
348 for (i=0; i < scr->workspace_count; i++) {
349 if (strcmp(scr->workspaces[i]->name, tmp)==0) {
350 state->workspace = i;
351 break;
354 } else {
355 state->workspace--;
358 if ((value = PLGetDictionaryEntry(win_state, sShaded))!=NULL)
359 state->shaded = getBool(value);
360 if ((value = PLGetDictionaryEntry(win_state, sMiniaturized))!=NULL)
361 state->miniaturized = getBool(value);
362 if ((value = PLGetDictionaryEntry(win_state, sHidden))!=NULL)
363 state->hidden = getBool(value);
365 value = PLGetDictionaryEntry(win_state, sGeometry);
366 if (value && PLIsString(value)) {
367 if (sscanf(PLGetString(value), "%ix%i+%i+%i",
368 &state->w, &state->h, &state->x, &state->y)==4 &&
369 (state->w>0 && state->h>0)) {
370 state->use_geometry = 1;
371 } else if (sscanf(PLGetString(value), "%i,%i,%i,%i",
372 &state->x, &state->y, &state->w, &state->h)==4 &&
373 (state->w>0 && state->h>0)) {
374 /* TODO: remove redundant sscanf() in version 0.20.x */
375 state->use_geometry = 1;
380 return state;
384 #define SAME(x, y) (((x) && (y) && !strcmp((x), (y))) || (!(x) && !(y)))
386 void
387 wSessionRestoreState(WScreen *scr)
389 WSavedState *state;
390 char *instance, *class, *command, *host;
391 proplist_t win_info, apps, cmd, value;
392 pid_t pid;
393 int i, count;
394 WDock *dock;
395 WAppIcon *btn=NULL;
396 int j, n, found;
397 char *tmp;
399 make_keys();
401 if (!scr->session_state)
402 return;
404 PLSetStringCmpHook(NULL);
406 apps = PLGetDictionaryEntry(scr->session_state, sApplications);
407 if (!apps)
408 return;
410 count = PLGetNumberOfElements(apps);
411 if (count==0)
412 return;
414 for (i=0; i<count; i++) {
415 win_info = PLGetArrayElement(apps, i);
417 cmd = PLGetDictionaryEntry(win_info, sCommand);
418 if (!cmd || !PLIsString(cmd) || !(command = PLGetString(cmd))) {
419 continue;
422 value = PLGetDictionaryEntry(win_info, sName);
423 if (!value)
424 continue;
426 ParseWindowName(value, &instance, &class, "session");
427 if (!instance && !class)
428 continue;
430 value = PLGetDictionaryEntry(win_info, sHost);
431 if (value && PLIsString(value))
432 host = PLGetString(value);
433 else
434 host = NULL;
436 state = getWindowState(scr, win_info);
438 dock = NULL;
439 value = PLGetDictionaryEntry(win_info, sDock);
440 if (value && PLIsString(value) && (tmp = PLGetString(value))!=NULL) {
441 if (sscanf(tmp, "%i", &n)!=1) {
442 if (!strcasecmp(tmp, "DOCK")) {
443 dock = scr->dock;
444 } else {
445 for (j=0; j < scr->workspace_count; j++) {
446 if (strcmp(scr->workspaces[j]->name, tmp)==0) {
447 dock = scr->workspaces[j]->clip;
448 break;
452 } else {
453 if (n == 0) {
454 dock = scr->dock;
455 } else if (n>0 && n<=scr->workspace_count) {
456 dock = scr->workspaces[n-1]->clip;
461 found = 0;
462 if (dock!=NULL) {
463 for (j=0; j<dock->max_icons; j++) {
464 btn = dock->icon_array[j];
465 if (btn && SAME(instance, btn->wm_instance) &&
466 SAME(class, btn->wm_class) &&
467 SAME(command, btn->command)) {
468 found = 1;
469 break;
474 if (found) {
475 wDockLaunchWithState(dock, btn, state);
476 } else if ((pid = execCommand(scr, command, host)) > 0) {
477 wWindowAddSavedState(instance, class, command, pid, state);
478 } else {
479 free(state);
482 if (instance) free(instance);
483 if (class) free(class);
485 /* clean up */
486 PLSetStringCmpHook(StringCompareHook);
490 void
491 wSessionRestoreLastWorkspace(WScreen *scr)
493 proplist_t wks;
494 int w, i;
495 char *tmp;
497 make_keys();
499 if (!scr->session_state)
500 return;
502 PLSetStringCmpHook(NULL);
504 wks = PLGetDictionaryEntry(scr->session_state, sWorkspace);
505 if (!wks || !PLIsString(wks))
506 return;
508 tmp = PLGetString(wks);
510 /* clean up */
511 PLSetStringCmpHook(StringCompareHook);
513 if (sscanf(tmp, "%i", &w)!=1) {
514 w = -1;
515 for (i=0; i < scr->workspace_count; i++) {
516 if (strcmp(scr->workspaces[i]->name, tmp)==0) {
517 w = i;
518 break;
521 } else {
522 w--;
525 if (w!=scr->current_workspace && w<scr->workspace_count) {
526 wWorkspaceChange(scr, w);
532 #ifdef R6SM
534 * With full session management support, the part of WMState
535 * that store client window state will become obsolete (maybe we can reuse
536 * the old code too),
537 * but we still need to store state info like the dock and workspaces.
538 * It is better to keep dock/wspace info in WMState because the user
539 * might want to keep the dock configuration while not wanting to
540 * resume a previously saved session.
541 * So, wmaker specific state info can be saved in
542 * ~/GNUstep/.AppInfo/WindowMaker/statename.state
543 * Its better to not put it in the defaults directory because:
544 * - its not a defaults file (having domain names like wmaker0089504baa
545 * in the defaults directory wouldn't be very neat)
546 * - this state file is not meant to be edited by users
548 * The old session code will become obsolete. When wmaker is
549 * compiled with R6 sm support compiled in, itll be better to
550 * use a totally rewritten state saving code, but we can keep
551 * the current code for when R6SM is not compiled in.
553 * This will be confusing to old users (well get lots of "SAVE_SESSION broke!"
554 * messages), but itll be better.
556 * -readme
561 * Windows are identified as:
562 * WM_CLASS(instance.class).WM_WINDOW_ROLE
564 * Saved Info:
566 * WM_CLASS.instance
567 * WM_CLASSS.class
568 * WM_WINDOW_ROLE
569 * geometry
570 * state = (miniaturized, shaded, etc)
571 * attribute
572 * workspace #
573 * app state = (which dock, hidden)
574 * window shortcut #
577 static proplist_t
578 makeAppState(WWindow *wwin)
580 WApplication *wapp;
581 proplist_t state;
582 WScreen *scr = wwin->screen_ptr;
584 state = PLMakeArrayWithElements(NULL, NULL);
586 wapp = wApplicationOf(wwin->main_window);
588 if (wapp) {
589 if (wapp->app_icon && wapp->app_icon->dock) {
591 if (wapp->app_icon->dock == scr->dock) {
592 PLAppendArrayElement(state, PLMakeString("Dock"));
593 } else {
594 int i;
596 for(i=0; i<scr->workspace_count; i++)
597 if(scr->workspaces[i]->clip == wapp->app_icon->dock)
598 break;
600 assert(i < scr->workspace_count);
602 PLAppendArrayElement(state,
603 PLMakeString(scr->workspaces[i]->name));
607 PLAppendArrayElement(state, PLMakeString(wapp->hidden ? "1" : "0"));
610 return state;
614 static proplist_t
615 makeAttributeState(WWindow *wwin)
617 unsigned int data1, data2;
618 char buffer[256];
620 #define W_FLAG(wwin, FLAG) ((wwin)->defined_user_flags.FLAG \
621 ? (wwin)->user_flags.FLAG : -1)
623 sprintf(buffer, "%i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i",
624 W_FLAG(no_titlebar),
625 W_FLAG(no_resizable),
626 W_FLAG(no_closable),
627 W_FLAG(no_miniaturizable),
628 W_FLAG(no_resizebar),
629 W_FLAG(no_close_button),
630 W_FLAG(no_miniaturize_button),
632 W_FLAG(broken_close),
633 W_FLAG(kill_close),
635 W_FLAG(no_shadeable),
636 W_FLAG(omnipresent),
637 W_FLAG(skip_window_list),
638 W_FLAG(floating),
639 W_FLAG(sunken),
640 W_FLAG(no_bind_keys),
641 W_FLAG(no_bind_mouse),
642 W_FLAG(no_hide_others),
643 W_FLAG(no_appicon),
644 W_FLAG(dont_move_off),
645 W_FLAG(no_focusable),
646 W_FLAG(always_user_icon),
647 W_FLAG(start_miniaturized),
648 W_FLAG(start_hidden),
649 W_FLAG(start_maximized),
650 W_FLAG(dont_save_session),
651 W_FLAG(emulate_appicon));
653 return PLMakeString(buffer);
657 static proplist_t
658 makeClientState(WWindow *wwin)
660 proplist_t state;
661 proplist_t tmp;
662 char *str;
663 char buffer[256];
664 int i;
666 state = PLMakeArrayWithElements(NULL, NULL);
668 /* spec */
669 PLAppendArrayElement(state, PLMakeString(wwin->wm_instance));
670 PLAppendArrayElement(state, PLMakeString(wwin->wm_class));
672 PLAppendArrayElement(state, PLMakeString(str));
674 /* geometry */
675 sprintf(buffer, "%i %i %i %i", wwin->frame_x, wwin->frame_y,
676 wwin->frame->core->width, wwin->frame->core->height);
677 PLAppendArrayElement(state, PLMakeString(buffer));
679 /* state */
680 sprintf(buffer, "%i %i %i", wwin->flags.miniaturized,
681 wwin->flags.shaded, wwin->flags.maximized);
682 PLAppendArrayElement(state, PLMakeString(buffer));
684 /* attributes */
685 PLAppendArrayElement(state, makeAttributeState(wwin));
687 /* workspace */
688 sprintf(buffer, "%i", wwin->frame->workspace);
689 PLAppendArrayElement(state, PLMakeString(buffer));
691 /* app state (repeated for all windows of the app) */
692 PLAppendArrayElement(state, makeAppState(wwin));
694 /* shortcuts */
695 tmp = PLMakeArrayWithElements(NULL, NULL);
697 for (i = 0; i < MAX_WINDOW_SHORTCUTS; i++) {
699 if (scr->shortcutWindow[i] == wwin) {
701 sprintf(buffer, "%i", i);
702 PLAppendArrayElement(tmp, PLMakeString(buffer));
705 PLAppendArrayElement(state, tmp);
707 return state;
711 static void
712 smSaveYourselfPhase2Proc(SmcConn smc_conn, SmPointer client_data)
714 SmProp props[4];
715 SmPropValue prop1val, prop2val, prop3val, prop4val;
716 char **argv = (char**)client_data;
717 int argc;
718 int i, j;
719 Bool ok = False;
720 char *statefile = NULL;
721 char *prefix;
722 Bool gsPrefix = False;
723 char *discardCmd = NULL;
724 time_t t;
725 proplist_t state;
727 #ifdef DEBUG1
728 puts("received SaveYourselfPhase2 SM message");
729 #endif
731 /* save session state */
733 /* the file that will contain the state */
734 prefix = getenv("SM_SAVE_DIR");
735 if (!prefix) {
736 prefix = wusergnusteppath();
737 if (prefix)
738 gsPrefix = True;
740 if (!prefix) {
741 prefix = getenv("HOME");
743 if (!prefix)
744 prefix = ".";
746 statefile = malloc(strlen(prefix)+64);
747 if (!statefile) {
748 if (gsPrefix)
749 free(prefix);
750 wwarning(_("end of memory while saving session state"));
751 goto fail;
754 t = time();
755 i = 0;
756 do {
757 if (gsPrefix)
758 sprintf(statefile, "%s/.AppInfo/WindowMaker/%l%i.state",
759 prefix, t, i);
760 else
761 sprintf(statefile, "%s/wmaker.%l%i.state", prefix, t, i);
762 i++;
763 } while (access(F_OK, statefile)!=-1);
765 if (gsPrefix)
766 free(prefix);
768 /* save the states of all windows we're managing */
769 state = PLMakeArrayFromElements(NULL, NULL);
772 * Format:
774 * state_file ::= dictionary with version_info ; state
775 * version_info ::= 'version' = '1';
776 * state ::= 'state' = array of screen_info
777 * screen_info ::= array of (screen number, window_info, window_info, ...)
778 * window_info ::=
780 for (i=0; i<wScreenCount; i++) {
781 WScreen *scr;
782 WWindow *wwin;
783 char buf[32];
784 proplist_t pscreen;
786 scr = wScreenWithNumber(i);
788 sprintf(buf, "%i", scr->screen);
789 pscreen = PLMakeArrayFromElements(PLMakeString(buf), NULL);
791 wwin = scr->focused_window;
792 while (wwin) {
793 proplist_t pwindow;
795 pwindow = makeClientState(wwin);
796 PLAppendArrayElement(pscreen, pwindow);
798 wwin = wwin->prev;
801 PLAppendArrayElement(state, pscreen);
805 proplist_t statefile;
807 statefile = PLMakeDictionaryFromEntries(PLMakeString("Version"),
808 PLMakeString("1.0"),
810 PLMakeString("Screens"),
811 state,
813 NULL);
815 PLSetFilename(statefile, PLMakeString(statefile));
816 PLSave(statefile, NO);
818 PLRelease(statefile);
821 /* set the remaining properties that we didn't set at
822 * startup time */
824 for (argc=0, i=0; argv[i]!=NULL; i++) {
825 if (strcmp(argv[i], "-clientid")==0
826 || strcmp(argv[i], "-restore")==0) {
827 i++;
828 } else {
829 argc++;
833 prop[0].name = SmRestartCommand;
834 prop[0].type = SmLISTofARRAY8;
835 prop[0].vals = malloc(sizeof(SmPropValue)*(argc+4));
836 prop[0].num_vals = argc+4;
838 prop[1].name = SmCloneCommand;
839 prop[1].type = SmLISTofARRAY8;
840 prop[1].vals = malloc(sizeof(SmPropValue)*(argc));
841 prop[1].num_vals = argc;
843 if (!prop[0].vals || !prop[1].vals) {
844 wwarning(_("end of memory while saving session state"));
845 goto fail;
848 for (j=0, i=0; i<argc+4; i++) {
849 if (strcmp(argv[i], "-clientid")==0
850 || strcmp(argv[i], "-restore")==0) {
851 i++;
852 } else {
853 prop[0].vals[j].value = argv[i];
854 prop[0].vals[j].length = strlen(argv[i]);
855 prop[1].vals[j].value = argv[i];
856 prop[1].vals[j].length = strlen(argv[i]);
857 j++;
860 prop[0].vals[j].value = "-clientid";
861 prop[0].vals[j].length = 9;
862 j++;
863 prop[0].vals[j].value = sClientID;
864 prop[0].vals[j].length = strlen(sClientID);
865 j++;
866 prop[0].vals[j].value = "-restore";
867 prop[0].vals[j].length = 11;
868 j++;
869 prop[0].vals[j].value = statefile;
870 prop[0].vals[j].length = strlen(statefile);
872 discardCmd = malloc(strlen(statefile)+8);
873 if (!discardCmd)
874 goto fail;
875 sprintf(discardCmd, "rm %s", statefile);
876 prop[2].name = SmDiscardCommand;
877 prop[2].type = SmARRAY8;
878 prop[2].vals[0] = discardCmd;
879 prop[2].num_vals = 1;
881 SmcSetProperties(sSMCConn, 3, prop);
883 ok = True;
884 fail:
885 SmcSaveYourselfDone(smc_conn, ok);
887 if (prop[0].vals)
888 free(prop[0].vals);
889 if (prop[1].vals)
890 free(prop[1].vals);
891 if (discardCmd)
892 free(discardCmd);
894 if (!ok) {
895 remove(statefile);
897 if (statefile)
898 free(statefile);
902 static void
903 smSaveYourselfProc(SmcConn smc_conn, SmPointer client_data, int save_type,
904 Bool shutdown, int interact_style, Bool fast)
906 #ifdef DEBUG1
907 puts("received SaveYourself SM message");
908 #endif
910 if (!SmcRequestSaveYourselfPhase2(smc_conn, smSaveYourselfPhase2Proc,
911 client_data)) {
913 SmcSaveYourselfDone(smc_conn, False);
914 sWaitingPhase2 = False;
915 } else {
916 #ifdef DEBUG1
917 puts("successfull request of SYS phase 2");
918 #endif
919 sWaitingPhase2 = True;
924 static void
925 smDieProc(SmcConn smc_conn, SmPointer client_data)
927 #ifdef DEBUG1
928 puts("received Die SM message");
929 #endif
931 wSessionDisconnectManager();
933 Shutdown(WSExitMode, True);
938 static void
939 smSaveCompleteProc(SmcConn smc_conn)
941 /* it means that we can resume doing things that can change our state */
942 #ifdef DEBUG1
943 puts("received SaveComplete SM message");
944 #endif
948 static void
949 smShutdownCancelledProc(SmcConn smc_conn, SmPointer client_data)
951 if (sWaitingPhase2) {
953 sWaitingPhase2 = False;
955 SmcSaveYourselfDone(smc_conn, False);
960 static void
961 iceMessageProc(int fd, int mask, void *clientData)
963 IceConn iceConn = (IceConn)clientData;
965 IceProcessMessages(iceConn, NULL, NULL);
969 static void
970 iceIOErrorHandler(IceConnection ice_conn)
972 /* This is not fatal but can mean the session manager exited.
973 * If the session manager exited normally we would get a
974 * Die message, so this probably means an abnormal exit.
975 * If the sm was the last client of session, then we'll die
976 * anyway, otherwise we can continue doing our stuff.
978 wwarning(_("connection to the session manager was lost"));
979 wSessionDisconnectManager();
983 void
984 wSessionConnectManager(char **argv, int argc)
986 IceConn iceConn;
987 char *previous_id = NULL;
988 char buffer[256];
989 SmcCallbacks callbacks;
990 unsigned long mask;
991 char uid[32];
992 char pid[32];
993 SmProp props[4];
994 SmPropValue prop1val, prop2val, prop3val, prop4val;
995 char restartStyle;
996 int i;
998 mask = SmcSaveYourselfProcMask|SmcDieProcMask|SmcSaveCompleteProcMask
999 |SmcShutdownCancelledProcMask;
1001 callbacks.save_yourself.callback = smSaveYourselfProc;
1002 callbacks.save_yourself.client_data = argv;
1004 callbacks.die.callback = smDieProc;
1005 callbacks.die.client_data = NULL;
1007 callbacks.save_complete.callback = smSaveCompleteProc;
1008 callbacks.save_complete.client_data = NULL;
1010 callbacks.shutdown_cancelled.callback = smShutdownCancelledProc;
1011 callbacks.shutdown_cancelled.client_data = NULL;
1013 for (i=0; i<argc; i++) {
1014 if (strcmp(argv[i], "-clientid")==0) {
1015 previous_id = argv[i+1];
1016 break;
1020 /* connect to the session manager */
1021 sSMCConn = SmcOpenConnection(NULL, NULL, SmProtoMajor, SmProtoMinor,
1022 mask, &callbacks, previous_id,
1023 &sClientID, 255, buffer);
1024 if (!sSMCConn) {
1025 return;
1027 #ifdef DEBUG1
1028 puts("connected to the session manager");
1029 #endif
1031 /* IceSetIOErrorHandler(iceIOErrorHandler);*/
1033 /* check for session manager clients */
1034 iceConn = SmcGetIceConnection(smcConn);
1036 if (fcntl(IceConnectionNumber(iceConn), F_SETFD, FD_CLOEXEC) < 0) {
1037 wsyserror("error setting close-on-exec flag for ICE connection");
1040 sSMInputHandler = WMAddInputHandler(IceConnectionNumber(iceConn),
1041 WIReadMask, iceMessageProc, iceConn);
1043 /* setup information about ourselves */
1045 /* program name */
1046 prop1val.value = argv[0];
1047 prop1val.length = strlen(argv[0]);
1048 prop[0].name = SmProgram;
1049 prop[0].type = SmARRAY8;
1050 prop[0].num_vals = 1;
1051 prop[0].vals = &prop1val;
1053 /* The XSMP doc from X11R6.1 says it contains the user name,
1054 * but every client implementation I saw places the uid # */
1055 sprintf(uid, "%i", getuid());
1056 prop2val.value = uid;
1057 prop2val.length = strlen(uid);
1058 prop[1].name = SmUserID;
1059 prop[1].type = SmARRAY8;
1060 prop[1].num_vals = 1;
1061 prop[1].vals = &prop2val;
1063 /* Restart style. We should restart only if we were running when
1064 * the previous session finished. */
1065 restartStyle = SmRestartIfRunning;
1066 prop3val.value = &restartStyle;
1067 prop3val.length = 1;
1068 prop[2].name = SmRestartStyleHint;
1069 prop[2].type = SmCARD8;
1070 prop[2].num_vals = 1;
1071 prop[2].vals = &prop3val;
1073 /* Our PID. Not required but might be usefull */
1074 sprintf(pid, "%i", getpid());
1075 prop4val.value = pid;
1076 prop4val.length = strlen(pid);
1077 prop[3].name = SmProcessID;
1078 prop[3].type = SmARRAY8;
1079 prop[3].num_vals = 1;
1080 prop[3].vals = &prop4val;
1082 /* we'll set the rest of the hints later */
1084 SmcSetProperties(sSMCConn, 4, props);
1089 void
1090 wSessionDisconnectManager(void)
1092 if (sSMCConn) {
1093 WMDeleteInputHandler(sSMInputHandler);
1094 sSMInputHandler = NULL;
1096 SmcCloseConnection(sSMCConn, 0, NULL);
1097 sSMCConn = NULL;
1101 void
1102 wSessionRequestShutdown(void)
1104 /* request a shutdown to the session manager */
1105 if (sSMCConn)
1106 SmcRequestSaveYourself(sSMCConn, SmSaveBoth, True, SmInteractStyleAny,
1107 False, True);
1110 Bool
1111 wSessionIsManaged(void)
1113 return sSMCConn!=NULL;
1116 #endif /* !R6SM */