1 /* session.c - session state handling
3 * Copyright (c) 1998 Dan Pascu
5 * Window Maker window manager
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
26 #include <X11/Xutil.h>
32 #include "WindowMaker.h"
38 #include "workspace.h"
40 #include "properties.h"
41 #include "application.h"
51 static proplist_t sApplications
= NULL
;
52 static proplist_t sCommand
;
53 static proplist_t sName
;
54 static proplist_t sHost
;
55 static proplist_t sWorkspace
;
56 static proplist_t sShaded
;
57 static proplist_t sMiniaturized
;
58 static proplist_t sHidden
;
59 static proplist_t sGeometry
;
61 static proplist_t sDock
;
63 static proplist_t sYes
, sNo
;
69 if (sApplications
!=NULL
)
72 sApplications
= PLMakeString("Applications");
73 sCommand
= PLMakeString("Command");
74 sName
= PLMakeString("Name");
75 sHost
= PLMakeString("Host");
76 sWorkspace
= PLMakeString("Workspace");
77 sShaded
= PLMakeString("Shaded");
78 sMiniaturized
= PLMakeString("Miniaturized");
79 sHidden
= PLMakeString("Hidden");
80 sGeometry
= PLMakeString("Geometry");
81 sDock
= PLMakeString("Dock");
83 sYes
= PLMakeString("Yes");
84 sNo
= PLMakeString("No");
90 getBool(proplist_t value
)
94 if (!PLIsString(value
)) {
97 if (!(val
= PLGetString(value
))) {
101 if ((val
[1]=='\0' && (val
[0]=='y' || val
[0]=='Y'))
102 || strcasecmp(val
, "YES")==0) {
105 } else if ((val
[1]=='\0' && (val
[0]=='n' || val
[0]=='N'))
106 || strcasecmp(val
, "NO")==0) {
110 if (sscanf(val
, "%i", &i
)==1) {
113 wwarning(_("can't convert \"%s\" to boolean"), val
);
122 makeWindowState(WWindow
*wwin
, WApplication
*wapp
)
124 WScreen
*scr
= wwin
->screen_ptr
;
128 char *class, *instance
, *command
=NULL
, buffer
[256];
129 proplist_t win_state
, cmd
, name
, workspace
;
130 proplist_t shaded
, miniaturized
, hidden
, geometry
;
133 if (wwin
->main_window
!=None
&& wwin
->main_window
!=wwin
->client_win
)
134 win
= wwin
->main_window
;
136 win
= wwin
->client_win
;
138 if (XGetCommand(dpy
, win
, &argv
, &argc
) && argc
>0) {
139 command
= FlattenStringList(argv
, argc
);
140 XFreeStringList(argv
);
145 if (PropGetWMClass(win
, &class, &instance
)) {
146 if (class && instance
)
147 sprintf(buffer
, "%s.%s", instance
, class);
149 sprintf(buffer
, "%s", instance
);
151 sprintf(buffer
, ".%s", class);
153 sprintf(buffer
, ".");
155 name
= PLMakeString(buffer
);
156 cmd
= PLMakeString(command
);
157 /*sprintf(buffer, "%d", wwin->frame->workspace+1);
158 workspace = PLMakeString(buffer);*/
159 workspace
= PLMakeString(scr
->workspaces
[wwin
->frame
->workspace
]->name
);
160 shaded
= wwin
->flags
.shaded
? sYes
: sNo
;
161 miniaturized
= wwin
->flags
.miniaturized
? sYes
: sNo
;
162 hidden
= wwin
->flags
.hidden
? sYes
: sNo
;
163 sprintf(buffer
, "%ix%i+%i+%i", wwin
->client
.width
, wwin
->client
.height
,
164 wwin
->frame_x
, wwin
->frame_y
);
165 geometry
= PLMakeString(buffer
);
167 win_state
= PLMakeDictionaryFromEntries(sName
, name
,
169 sWorkspace
, workspace
,
171 sMiniaturized
, miniaturized
,
178 PLRelease(workspace
);
180 if (wapp
&& wapp
->app_icon
&& wapp
->app_icon
->dock
) {
183 if (wapp
->app_icon
->dock
== scr
->dock
) {
186 for(i
=0; i
<scr
->workspace_count
; i
++)
187 if(scr
->workspaces
[i
]->clip
== wapp
->app_icon
->dock
)
189 assert( i
< scr
->workspace_count
);
191 name
= scr
->workspaces
[i
]->name
;
193 dock
= PLMakeString(name
);
194 PLInsertDictionaryEntry(win_state
, sDock
, dock
);
201 if (instance
) XFree(instance
);
202 if (class) XFree(class);
203 if (command
) free(command
);
210 wSessionSaveState(WScreen
*scr
)
212 WWindow
*wwin
= scr
->focused_window
;
213 proplist_t win_info
, wks
;
214 proplist_t list
=NULL
;
215 LinkedList
*wapp_list
=NULL
;
220 if (!scr
->session_state
) {
221 scr
->session_state
= PLMakeDictionaryFromEntries(NULL
, NULL
, NULL
);
222 if (!scr
->session_state
)
226 list
= PLMakeArrayFromElements(NULL
);
229 WApplication
*wapp
=wApplicationOf(wwin
->main_window
);
231 if (wwin
->transient_for
==None
&& list_find(wapp_list
, wapp
)==NULL
232 && !wwin
->window_flags
.dont_save_session
) {
233 /* A entry for this application was not yet saved. Save one. */
234 if ((win_info
= makeWindowState(wwin
, wapp
))!=NULL
) {
235 list
= PLAppendArrayElement(list
, win_info
);
237 /* If we were succesful in saving the info for this window
238 * add the application the window belongs to, to the
239 * application list, so no multiple entries for the same
240 * application are saved.
242 wapp_list
= list_cons(wapp
, wapp_list
);
247 PLRemoveDictionaryEntry(scr
->session_state
, sApplications
);
248 PLInsertDictionaryEntry(scr
->session_state
, sApplications
, list
);
251 wks
= PLMakeString(scr
->workspaces
[scr
->current_workspace
]->name
);
252 PLInsertDictionaryEntry(scr
->session_state
, sWorkspace
, wks
);
255 list_free(wapp_list
);
260 wSessionClearState(WScreen
*scr
)
264 if (!scr
->session_state
)
267 PLRemoveDictionaryEntry(scr
->session_state
, sApplications
);
268 PLRemoveDictionaryEntry(scr
->session_state
, sWorkspace
);
273 execCommand(WScreen
*scr
, char *command
, char *host
)
279 ParseCommand(command
, &argv
, &argc
);
285 if ((pid
=fork())==0) {
289 SetupEnvironment(scr
);
291 close(ConnectionNumber(dpy
));
293 args
= malloc(sizeof(char*)*(argc
+1));
296 for (i
=0; i
<argc
; i
++) {
300 execvp(argv
[0], args
);
311 getWindowState(WScreen
*scr
, proplist_t win_state
)
313 WSavedState
*state
= wmalloc(sizeof(WSavedState
));
318 memset(state
, 0, sizeof(WSavedState
));
319 state
->workspace
= -1;
320 value
= PLGetDictionaryEntry(win_state
, sWorkspace
);
321 if (value
&& PLIsString(value
)) {
322 tmp
= PLGetString(value
);
323 if (sscanf(tmp
, "%i", &state
->workspace
)!=1) {
324 state
->workspace
= -1;
325 for (i
=0; i
< scr
->workspace_count
; i
++) {
326 if (strcmp(scr
->workspaces
[i
]->name
, tmp
)==0) {
327 state
->workspace
= i
;
335 if ((value
= PLGetDictionaryEntry(win_state
, sShaded
))!=NULL
)
336 state
->shaded
= getBool(value
);
337 if ((value
= PLGetDictionaryEntry(win_state
, sMiniaturized
))!=NULL
)
338 state
->miniaturized
= getBool(value
);
339 if ((value
= PLGetDictionaryEntry(win_state
, sHidden
))!=NULL
)
340 state
->hidden
= getBool(value
);
342 value
= PLGetDictionaryEntry(win_state
, sGeometry
);
343 if (value
&& PLIsString(value
)) {
344 if (sscanf(PLGetString(value
), "%ix%i+%i+%i",
345 &state
->w
, &state
->h
, &state
->x
, &state
->y
)==4 &&
346 (state
->w
>0 && state
->h
>0)) {
347 state
->use_geometry
= 1;
348 } else if (sscanf(PLGetString(value
), "%i,%i,%i,%i",
349 &state
->x
, &state
->y
, &state
->w
, &state
->h
)==4 &&
350 (state
->w
>0 && state
->h
>0)) {
351 /* TODO: remove redundant sscanf() in version 0.20.x */
352 state
->use_geometry
= 1;
361 #define SAME(x, y) (((x) && (y) && !strcmp((x), (y))) || (!(x) && !(y)))
365 wSessionRestoreState(WScreen
*scr
)
368 char *instance
, *class, *command
, *host
;
369 proplist_t win_info
, apps
, cmd
, value
;
379 if (!scr
->session_state
)
382 PLSetStringCmpHook(NULL
);
384 apps
= PLGetDictionaryEntry(scr
->session_state
, sApplications
);
388 count
= PLGetNumberOfElements(apps
);
392 for (i
=0; i
<count
; i
++) {
393 win_info
= PLGetArrayElement(apps
, i
);
395 cmd
= PLGetDictionaryEntry(win_info
, sCommand
);
396 if (!cmd
|| !PLIsString(cmd
) || !(command
= PLGetString(cmd
))) {
400 value
= PLGetDictionaryEntry(win_info
, sName
);
404 ParseWindowName(value
, &instance
, &class, "session");
405 if (!instance
&& !class)
408 value
= PLGetDictionaryEntry(win_info
, sHost
);
409 if (value
&& PLIsString(value
))
410 host
= PLGetString(value
);
414 state
= getWindowState(scr
, win_info
);
417 value
= PLGetDictionaryEntry(win_info
, sDock
);
418 if (value
&& PLIsString(value
) && (tmp
= PLGetString(value
))!=NULL
) {
419 if (sscanf(tmp
, "%i", &n
)!=1) {
420 if (!strcasecmp(tmp
, "DOCK")) {
423 for (j
=0; j
< scr
->workspace_count
; j
++) {
424 if (strcmp(scr
->workspaces
[j
]->name
, tmp
)==0) {
425 dock
= scr
->workspaces
[j
]->clip
;
433 } else if (n
>0 && n
<=scr
->workspace_count
) {
434 dock
= scr
->workspaces
[n
-1]->clip
;
441 for (j
=0; j
<dock
->max_icons
; j
++) {
442 btn
= dock
->icon_array
[j
];
443 if (btn
&& SAME(instance
, btn
->wm_instance
) &&
444 SAME(class, btn
->wm_class
) &&
445 SAME(command
, btn
->command
)) {
453 wDockLaunchWithState(dock
, btn
, state
);
454 } else if ((pid
= execCommand(scr
, command
, host
)) > 0) {
455 wWindowAddSavedState(instance
, class, command
, pid
, state
);
460 if (instance
) free(instance
);
461 if (class) free(class);
464 PLSetStringCmpHook(StringCompareHook
);
469 wSessionRestoreLastWorkspace(WScreen
*scr
)
477 if (!scr
->session_state
)
480 PLSetStringCmpHook(NULL
);
482 wks
= PLGetDictionaryEntry(scr
->session_state
, sWorkspace
);
483 if (!wks
|| !PLIsString(wks
))
486 tmp
= PLGetString(wks
);
489 PLSetStringCmpHook(StringCompareHook
);
491 if (sscanf(tmp
, "%i", &w
)!=1) {
493 for (i
=0; i
< scr
->workspace_count
; i
++) {
494 if (strcmp(scr
->workspaces
[i
]->name
, tmp
)==0) {
503 if (w
!=scr
->current_workspace
&& w
<scr
->workspace_count
) {
504 wWorkspaceChange(scr
, w
);