/*-
* Copyright (c) 2001 Jordan DeLong
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the author nor the names of contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "wm.h"
/*
* prepare desktop stuff for a shutdown/restart: simply
* move the current workspace to 0,0; it doesn't matter which
* desktop because 0,0 is always valid on any desktop.
*/
void desktop_shutdown() {
screen_t *screen;
TAILQ_FOREACH(screen, &screen_list, s_list)
workspace_viewport_move(screen, screen->desktop,
-screen->desktop->viewx, -screen->desktop->viewy);
}
/*
* add desktops to a screen. on error we return -1, leaving as many
* complete desktops as we could add there, and freeing up partially
* added one.
*/
int desktop_create(screen_t *screen, int width, int height, int count) {
desktop_t *desktop;
int spaces, n;
/* add count desktops of dim width x height */
while (count--) {
desktop = calloc(1, sizeof(desktop_t));
if (!desktop)
return -1;
desktop->num = screen->desktop_count++;
desktop->width = width;
desktop->height = height;
desktop->workspaces = malloc(width * height * sizeof(workspace_t *));
if (!desktop->workspaces)
goto free1;
for (n = 0; n < STACKLAYER_COUNT; n++)
TAILQ_INIT(&desktop->stacking_list[n]);
/* get all the workspaces for this desktop */
for (spaces = 0; spaces < desktop->width * desktop->height; spaces++) {
desktop->workspaces[spaces] = calloc(1, sizeof(workspace_t));
if (!desktop->workspaces[spaces])
goto free2;
desktop->workspaces[spaces]->desktop = desktop;
TAILQ_INIT(&desktop->workspaces[spaces]->w_foclist);
}
desktop->current_space = desktop->workspaces[0];
TAILQ_INSERT_TAIL(&screen->s_desklist, desktop, d_list);
}
return 0;
free2:
/* free and exit with error */
for (n = 0; n < spaces; n++)
free(desktop->workspaces[n]);
free1:
free(desktop);
return -1;
}
/* remove the desktops from a screen */
void desktop_remove(screen_t *screen) {
desktop_t *desktop, *next;
int i, numspaces;
desktop = TAILQ_FIRST(&screen->s_desklist);
while (desktop) {
numspaces = desktop->width * desktop->height;
for (i = 0; i < numspaces; i++)
free(desktop->workspaces[i]);
free(desktop->workspaces);
next = TAILQ_NEXT(desktop, d_list);
free(desktop);
desktop = next;
}
TAILQ_INIT(&screen->s_desklist);
}
/*
* perform neccesary actions when adding a client to a desktop
* call _after_ workspace_add_client
*/
void desktop_add_client(client_t *client) {
stacking_list_add(client);
}
/*
* remove a client from the desktop it is on
* call _before_ workspace_rm_client
*/
void desktop_rm_client(client_t *client) {
stacking_list_rm(client);
}
/* switch the desktop for screen to desk number num */
void desktop_switch(screen_t *screen, int num) {
client_t *focusthis = NULL;
client_t *client;
desktop_t *desktop, *olddesk;
/* find the desktop to switch to */
TAILQ_FOREACH(desktop, &screen->s_desklist, d_list)
if (desktop->num == num)
goto gotdesk;
return;
gotdesk:
if (screen->desktop == desktop)
return;
/* unmap clients on the current desktop, and map them for the new */
LIST_FOREACH(client, &client_list, c_list)
if (client->state == NormalState && client->workspace) {
if (client->workspace->desktop == screen->desktop) {
/*
* handle windows that are stuck to the glass.
* the idea is to preserve focus settings, so
* if a sticky window is focused it'll stay
* focused, and if it isn't focused it wont
* get the focus. this means we don't need
* to check flags.nofocus, because if it's
* nofocus it will never have focus in the
* first place.
*/
if (client->flags.sticky) {
if (screen->desktop->current_space->focused == client
&& focusthis == NULL)
focusthis = client;
desktop_rm_client(client);
workspace_rm_client(client);
workspace_add_client(desktop->current_space, client);
desktop_add_client(client);
} else
XUnmapWindow(display, client->frame);
} else if (client->workspace->desktop == desktop)
XMapWindow(display, client->frame);
}
/* set these up before doing focus stuff */
olddesk = screen->desktop;
screen->desktop = desktop;
/* now set the focus */
if (focusthis)
focus_client(focusthis);
else if (desktop->current_space->focused)
focus_client(desktop->current_space->focused);
else
focus_none(screen);
/* flush window stacking out to the server */
stacking_flush(desktop);
/* let plugins know about the desktop change */
plugin_desktop_change(screen, olddesk);
}
syntax highlighted by Code2HTML, v. 0.9.1