Coverity: fix WPrefs workspace negative array index read
[wmaker-crm.git] / src / session.c
blob417255bbe4eb494321c4c3aee57b6c4294a8cc7a
1 /* session.c - session state handling and R6 style session management
3 * Copyright (c) 1998-2003 Dan Pascu
4 * Copyright (c) 1998-2003 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 along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 * If defined(XSMP_ENABLED) and session manager is running then
26 * do normal stuff
27 * else
28 * do pre-R6 session management stuff (save window state and relaunch)
30 * When doing a checkpoint:
32 * = Without XSMP
33 * Open "Stop"/status Dialog
34 * Send SAVE_YOURSELF to clients and wait for reply
35 * Save restart info
36 * Save state of clients
38 * = With XSMP
39 * Send checkpoint request to sm
41 * When exiting:
42 * -------------
44 * = Without XSMP
46 * Open "Exit Now"/status Dialog
47 * Send SAVE_YOURSELF to clients and wait for reply
48 * Save restart info
49 * Save state of clients
50 * Send DELETE to all clients
51 * When no more clients are left or user hit "Exit Now", exit
53 * = With XSMP
55 * Send Shutdown request to session manager
56 * if SaveYourself message received, save state of clients
57 * if the Die message is received, exit.
60 #include "wconfig.h"
62 #include <X11/Xlib.h>
63 #include <X11/Xutil.h>
65 #include <stdlib.h>
66 #include <stdio.h>
67 #include <string.h>
68 #include <strings.h>
69 #include <unistd.h>
70 #include <time.h>
72 #include "WindowMaker.h"
73 #include "screen.h"
74 #include "window.h"
75 #include "client.h"
76 #include "session.h"
77 #include "framewin.h"
78 #include "workspace.h"
79 #include "main.h"
80 #include "properties.h"
81 #include "application.h"
82 #include "appicon.h"
83 #include "dock.h"
84 #include "misc.h"
86 #include <WINGs/WUtil.h>
89 static WMPropList *sApplications = NULL;
90 static WMPropList *sCommand;
91 static WMPropList *sName;
92 static WMPropList *sHost;
93 static WMPropList *sWorkspace;
94 static WMPropList *sShaded;
95 static WMPropList *sMiniaturized;
96 static WMPropList *sMaximized;
97 static WMPropList *sHidden;
98 static WMPropList *sGeometry;
99 static WMPropList *sShortcutMask;
101 static WMPropList *sDock;
102 static WMPropList *sYes, *sNo;
104 static void make_keys(void)
106 if (sApplications != NULL)
107 return;
109 sApplications = WMCreatePLString("Applications");
110 sCommand = WMCreatePLString("Command");
111 sName = WMCreatePLString("Name");
112 sHost = WMCreatePLString("Host");
113 sWorkspace = WMCreatePLString("Workspace");
114 sShaded = WMCreatePLString("Shaded");
115 sMiniaturized = WMCreatePLString("Miniaturized");
116 sMaximized = WMCreatePLString("Maximized");
117 sHidden = WMCreatePLString("Hidden");
118 sGeometry = WMCreatePLString("Geometry");
119 sDock = WMCreatePLString("Dock");
120 sShortcutMask = WMCreatePLString("ShortcutMask");
122 sYes = WMCreatePLString("Yes");
123 sNo = WMCreatePLString("No");
126 static int getBool(WMPropList * value)
128 char *val;
130 if (!WMIsPLString(value)) {
131 return 0;
133 val = WMGetFromPLString(value);
134 if (val == NULL)
135 return 0;
137 if ((val[1] == '\0' && (val[0] == 'y' || val[0] == 'Y'))
138 || strcasecmp(val, "YES") == 0) {
140 return 1;
141 } else if ((val[1] == '\0' && (val[0] == 'n' || val[0] == 'N'))
142 || strcasecmp(val, "NO") == 0) {
143 return 0;
144 } else {
145 int i;
146 if (sscanf(val, "%i", &i) == 1) {
147 return (i != 0);
148 } else {
149 wwarning(_("can't convert \"%s\" to boolean"), val);
150 return 0;
155 static unsigned getInt(WMPropList * value)
157 char *val;
158 unsigned n;
160 if (!WMIsPLString(value))
161 return 0;
162 val = WMGetFromPLString(value);
163 if (!val)
164 return 0;
165 if (sscanf(val, "%u", &n) != 1)
166 return 0;
168 return n;
171 static unsigned getHex(WMPropList * value)
173 char *val;
174 unsigned n;
176 if (!WMIsPLString(value))
177 return 0;
178 val = WMGetFromPLString(value);
179 if (!val)
180 return 0;
181 if (sscanf(val, "0x%04X", &n) != 1)
182 return 0;
184 return n;
187 static WMPropList *makeWindowState(WWindow * wwin, WApplication * wapp)
189 WScreen *scr = wwin->screen_ptr;
190 Window win;
191 int i;
192 unsigned mask;
193 char *class, *instance, *command = NULL, buffer[512];
194 WMPropList *win_state, *cmd, *name, *workspace;
195 WMPropList *shaded, *miniaturized, *maximized, *hidden, *geometry;
196 WMPropList *dock, *shortcut;
198 if (wwin->orig_main_window != None && wwin->orig_main_window != wwin->client_win)
199 win = wwin->orig_main_window;
200 else
201 win = wwin->client_win;
203 command = GetCommandForWindow(win);
204 if (!command) {
205 if (wapp->app_icon && wapp->app_icon->command) {
206 command = wmalloc(strlen(wapp->app_icon->command) + 1);
207 strcpy(command, wapp->app_icon->command);
208 } else
209 return NULL;
212 if (PropGetWMClass(win, &class, &instance)) {
213 if (class && instance)
214 snprintf(buffer, sizeof(buffer), "%s.%s", instance, class);
215 else if (instance)
216 snprintf(buffer, sizeof(buffer), "%s", instance);
217 else if (class)
218 snprintf(buffer, sizeof(buffer), ".%s", class);
219 else
220 snprintf(buffer, sizeof(buffer), ".");
222 name = WMCreatePLString(buffer);
223 cmd = WMCreatePLString(command);
224 workspace = WMCreatePLString(scr->workspaces[wwin->frame->workspace]->name);
226 shaded = wwin->flags.shaded ? sYes : sNo;
227 miniaturized = wwin->flags.miniaturized ? sYes : sNo;
228 snprintf(buffer, sizeof(buffer), "0x%04X", wwin->flags.maximized);
229 maximized = WMCreatePLString(buffer);
230 hidden = wwin->flags.hidden ? sYes : sNo;
231 snprintf(buffer, sizeof(buffer), "%ix%i+%i+%i",
232 wwin->client.width, wwin->client.height, wwin->frame_x, wwin->frame_y);
233 geometry = WMCreatePLString(buffer);
235 for (mask = 0, i = 0; i < MAX_WINDOW_SHORTCUTS; i++) {
236 if (scr->shortcutWindows[i] != NULL &&
237 WMGetFirstInArray(scr->shortcutWindows[i], wwin) != WANotFound)
238 mask |= 1 << i;
241 snprintf(buffer, sizeof(buffer), "%u", mask);
242 shortcut = WMCreatePLString(buffer);
244 win_state = WMCreatePLDictionary(sName, name,
245 sCommand, cmd,
246 sWorkspace, workspace,
247 sShaded, shaded,
248 sMiniaturized, miniaturized,
249 sMaximized, maximized,
250 sHidden, hidden,
251 sShortcutMask, shortcut, sGeometry, geometry, NULL);
253 WMReleasePropList(name);
254 WMReleasePropList(cmd);
255 WMReleasePropList(workspace);
256 WMReleasePropList(maximized);
257 WMReleasePropList(geometry);
258 WMReleasePropList(shortcut);
259 if (wapp && wapp->app_icon && wapp->app_icon->dock) {
260 int i;
261 char *name = NULL;
262 if (wapp->app_icon->dock == scr->dock)
263 name = "Dock";
265 /* Try the clips */
266 if (name == NULL) {
267 for (i = 0; i < scr->workspace_count; i++)
268 if (scr->workspaces[i]->clip == wapp->app_icon->dock)
269 break;
270 if (i < scr->workspace_count)
271 name = scr->workspaces[i]->name;
273 /* Try the drawers */
274 if (name == NULL) {
275 WDrawerChain *dc;
276 for (dc = scr->drawers; dc != NULL; dc = dc->next) {
277 if (dc->adrawer == wapp->app_icon->dock)
278 break;
280 assert(dc != NULL);
281 name = dc->adrawer->icon_array[0]->wm_instance;
283 dock = WMCreatePLString(name);
284 WMPutInPLDictionary(win_state, sDock, dock);
285 WMReleasePropList(dock);
287 } else {
288 win_state = NULL;
291 if (instance)
292 free(instance);
293 if (class)
294 free(class);
295 if (command)
296 wfree(command);
298 return win_state;
301 void wSessionSaveState(WScreen * scr)
303 WWindow *wwin = scr->focused_window;
304 WMPropList *win_info, *wks;
305 WMPropList *list = NULL;
306 WMArray *wapp_list = NULL;
308 make_keys();
310 if (!scr->session_state) {
311 scr->session_state = WMCreatePLDictionary(NULL, NULL);
312 if (!scr->session_state)
313 return;
316 list = WMCreatePLArray(NULL);
318 wapp_list = WMCreateArray(16);
320 while (wwin) {
321 WApplication *wapp = wApplicationOf(wwin->main_window);
322 Window appId = wwin->orig_main_window;
324 if ((wwin->transient_for == None || wwin->transient_for == wwin->screen_ptr->root_win)
325 && (WMGetFirstInArray(wapp_list, (void *)appId) == WANotFound
326 || WFLAGP(wwin, shared_appicon))
327 && !WFLAGP(wwin, dont_save_session)) {
328 /* A entry for this application was not yet saved. Save one. */
329 win_info = makeWindowState(wwin, wapp);
330 if (win_info != NULL) {
331 WMAddToPLArray(list, win_info);
332 WMReleasePropList(win_info);
333 /* If we were successful in saving the info for this window
334 * add the application the window belongs to, to the
335 * application list, so no multiple entries for the same
336 * application are saved.
338 WMAddToArray(wapp_list, (void *)appId);
341 wwin = wwin->prev;
343 WMRemoveFromPLDictionary(scr->session_state, sApplications);
344 WMPutInPLDictionary(scr->session_state, sApplications, list);
345 WMReleasePropList(list);
347 wks = WMCreatePLString(scr->workspaces[scr->current_workspace]->name);
348 WMPutInPLDictionary(scr->session_state, sWorkspace, wks);
349 WMReleasePropList(wks);
351 WMFreeArray(wapp_list);
354 void wSessionClearState(WScreen * scr)
356 make_keys();
358 if (!scr->session_state)
359 return;
361 WMRemoveFromPLDictionary(scr->session_state, sApplications);
362 WMRemoveFromPLDictionary(scr->session_state, sWorkspace);
365 static pid_t execCommand(WScreen *scr, char *command)
367 pid_t pid;
368 char **argv;
369 int argc;
371 wtokensplit(command, &argv, &argc);
373 if (!argc) {
374 wfree(argv);
375 return 0;
378 pid = fork();
379 if (pid == 0) {
380 char **args;
381 int i;
383 SetupEnvironment(scr);
385 args = malloc(sizeof(char *) * (argc + 1));
386 if (!args)
387 exit(111);
388 for (i = 0; i < argc; i++) {
389 args[i] = argv[i];
391 args[argc] = NULL;
392 execvp(argv[0], args);
393 exit(111);
395 while (argc > 0)
396 wfree(argv[--argc]);
397 wfree(argv);
398 return pid;
401 static WSavedState *getWindowState(WScreen * scr, WMPropList * win_state)
403 WSavedState *state = wmalloc(sizeof(WSavedState));
404 WMPropList *value;
405 char *tmp;
406 unsigned mask;
407 int i;
409 state->workspace = -1;
410 value = WMGetFromPLDictionary(win_state, sWorkspace);
411 if (value && WMIsPLString(value)) {
412 tmp = WMGetFromPLString(value);
413 if (sscanf(tmp, "%i", &state->workspace) != 1) {
414 state->workspace = -1;
415 for (i = 0; i < scr->workspace_count; i++) {
416 if (strcmp(scr->workspaces[i]->name, tmp) == 0) {
417 state->workspace = i;
418 break;
421 } else {
422 state->workspace--;
426 value = WMGetFromPLDictionary(win_state, sShaded);
427 if (value != NULL)
428 state->shaded = getBool(value);
430 value = WMGetFromPLDictionary(win_state, sMiniaturized);
431 if (value != NULL)
432 state->miniaturized = getBool(value);
434 value = WMGetFromPLDictionary(win_state, sMaximized);
435 if (value != NULL) {
436 state->maximized = getHex(value);
439 value = WMGetFromPLDictionary(win_state, sHidden);
440 if (value != NULL)
441 state->hidden = getBool(value);
443 value = WMGetFromPLDictionary(win_state, sShortcutMask);
444 if (value != NULL) {
445 mask = getInt(value);
446 state->window_shortcuts = mask;
449 value = WMGetFromPLDictionary(win_state, sGeometry);
450 if (value && WMIsPLString(value)) {
451 if (!(sscanf(WMGetFromPLString(value), "%ix%i+%i+%i",
452 &state->w, &state->h, &state->x, &state->y) == 4 && (state->w > 0 && state->h > 0))) {
453 state->w = 0;
454 state->h = 0;
458 return state;
461 static inline int is_same(const char *x, const char *y)
463 if ((x == NULL) && (y == NULL))
464 return 1;
466 if ((x == NULL) || (y == NULL))
467 return 0;
469 if (strcmp(x, y) == 0)
470 return 1;
471 else
472 return 0;
475 void wSessionRestoreState(WScreen *scr)
477 WSavedState *state;
478 char *instance, *class, *command;
479 WMPropList *win_info, *apps, *cmd, *value;
480 pid_t pid;
481 int i, count;
482 WDock *dock;
483 WAppIcon *btn = NULL;
484 int j, n, found;
485 char *tmp;
487 make_keys();
489 if (!scr->session_state)
490 return;
492 WMPLSetCaseSensitive(True);
494 apps = WMGetFromPLDictionary(scr->session_state, sApplications);
495 if (!apps)
496 return;
498 count = WMGetPropListItemCount(apps);
499 if (count == 0)
500 return;
502 for (i = 0; i < count; i++) {
503 win_info = WMGetFromPLArray(apps, i);
505 cmd = WMGetFromPLDictionary(win_info, sCommand);
506 if (!cmd || !WMIsPLString(cmd) || !(command = WMGetFromPLString(cmd))) {
507 continue;
510 value = WMGetFromPLDictionary(win_info, sName);
511 if (!value)
512 continue;
514 ParseWindowName(value, &instance, &class, "session");
515 if (!instance && !class)
516 continue;
518 state = getWindowState(scr, win_info);
520 dock = NULL;
521 value = WMGetFromPLDictionary(win_info, sDock);
522 if (value && WMIsPLString(value) && (tmp = WMGetFromPLString(value)) != NULL) {
523 if (sscanf(tmp, "%i", &n) != 1) {
524 if (!strcasecmp(tmp, "DOCK"))
525 dock = scr->dock;
527 /* Try the clips */
528 if (dock == NULL) {
529 for (j = 0; j < scr->workspace_count; j++) {
530 if (strcmp(scr->workspaces[j]->name, tmp) == 0) {
531 dock = scr->workspaces[j]->clip;
532 break;
536 if (dock == NULL) // Try the drawers
538 WDrawerChain *dc;
539 for (dc = scr->drawers; dc != NULL; dc = dc->next)
541 if (strcmp(dc->adrawer->icon_array[0]->wm_instance, tmp) == 0)
543 dock = dc->adrawer;
544 break;
548 } else {
549 if (n == 0) {
550 dock = scr->dock;
551 } else if (n > 0 && n <= scr->workspace_count) {
552 dock = scr->workspaces[n - 1]->clip;
557 found = 0;
558 if (dock != NULL) {
559 for (j = 0; j < dock->max_icons; j++) {
560 btn = dock->icon_array[j];
561 if (btn && is_same(instance, btn->wm_instance) &&
562 is_same(class, btn->wm_class) &&
563 is_same(command, btn->command) &&
564 !btn->launching) {
565 found = 1;
566 break;
571 if (found) {
572 wDockLaunchWithState(btn, state);
573 } else if ((pid = execCommand(scr, command)) > 0) {
574 wWindowAddSavedState(instance, class, command, pid, state);
575 } else {
576 wfree(state);
579 if (instance)
580 wfree(instance);
581 if (class)
582 wfree(class);
584 /* clean up */
585 WMPLSetCaseSensitive(False);
588 void wSessionRestoreLastWorkspace(WScreen * scr)
590 WMPropList *wks;
591 int w;
592 char *value;
594 make_keys();
596 if (!scr->session_state)
597 return;
599 WMPLSetCaseSensitive(True);
601 wks = WMGetFromPLDictionary(scr->session_state, sWorkspace);
602 if (!wks || !WMIsPLString(wks))
603 return;
605 value = WMGetFromPLString(wks);
607 if (!value)
608 return;
610 /* clean up */
611 WMPLSetCaseSensitive(False);
613 /* Get the workspace number for the workspace name */
614 w = wGetWorkspaceNumber(scr, value);
616 if (w != scr->current_workspace && w < scr->workspace_count)
617 wWorkspaceChange(scr, w);