/*- * 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); }