1
0
mirror of https://github.com/gryf/wmaker.git synced 2025-12-24 15:12:32 +01:00
Files
wmaker/src/workspace.c
dan 33cc542e85 - Finished moving to the new proplist handling code in WINGs.
- Also tested the backward compatibility ability of the WINGs proplist code
  which seems to work quite well.

Starting with this moment, Window Maker no longer needs libPropList and is
now using the better and much more robust proplist code from WINGs. Also the
WINGs based proplist code is actively maintained while the old libPropList
code is practically dead and flawed by the fact that it borrowed concepts
from the UserDefaults which conflicted with the retain/release mechanism,
making some problems that libPropList had, practically unsolvable without a
complete redesign (which can be found in the more robust WINGs code).
2001-10-04 03:07:34 +00:00

1090 lines
28 KiB
C

/* workspace.c- Workspace management
*
* Window Maker window manager
*
* Copyright (c) 1997, 1998 Alfredo K. Kojima
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#include "wconfig.h"
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#ifdef SHAPE
#include <X11/extensions/shape.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#include "WindowMaker.h"
#include "wcore.h"
#include "framewin.h"
#include "window.h"
#include "icon.h"
#include "funcs.h"
#include "menu.h"
#include "application.h"
#include "dock.h"
#include "actions.h"
#include "workspace.h"
#include "appicon.h"
#ifdef KWM_HINTS
#include "kwm.h"
#endif
#include <WINGs/WUtil.h>
extern WPreferences wPreferences;
extern XContext wWinContext;
static WMPropList *dWorkspaces=NULL;
static WMPropList *dClip, *dName;
#ifdef VIRTUAL_DESKTOP
static BOOL initVDesk = False;
#endif
static void
make_keys()
{
if (dWorkspaces!=NULL)
return;
dWorkspaces = WMCreatePLString("Workspaces");
dName = WMCreatePLString("Name");
dClip = WMCreatePLString("Clip");
}
void
wWorkspaceMake(WScreen *scr, int count)
{
while (count>0) {
wWorkspaceNew(scr);
count--;
}
}
int
wWorkspaceNew(WScreen *scr)
{
WWorkspace *wspace, **list;
int i;
if (scr->workspace_count < MAX_WORKSPACES) {
scr->workspace_count++;
wspace = wmalloc(sizeof(WWorkspace));
wspace->name = NULL;
#ifdef KWM_HINTS
if (scr->flags.kwm_syncing_count) {
wspace->name = wKWMGetWorkspaceName(scr, scr->workspace_count-1);
}
#endif
if (!wspace->name) {
wspace->name = wmalloc(strlen(_("Workspace %i"))+8);
sprintf(wspace->name, _("Workspace %i"), scr->workspace_count);
}
if (!wPreferences.flags.noclip) {
wspace->clip = wDockCreate(scr, WM_CLIP);
} else
wspace->clip = NULL;
list = wmalloc(sizeof(WWorkspace*)*scr->workspace_count);
for (i=0; i<scr->workspace_count-1; i++) {
list[i] = scr->workspaces[i];
}
list[i] = wspace;
if (scr->workspaces)
wfree(scr->workspaces);
scr->workspaces = list;
wWorkspaceMenuUpdate(scr, scr->workspace_menu);
wWorkspaceMenuUpdate(scr, scr->clip_ws_menu);
#ifdef VIRTUAL_DESKTOP
wspace->view_x = wspace->view_y = 0;
wspace->height = scr->scr_height;
wspace->width = scr->scr_width;
#endif
WMPostNotificationName(WMNWorkspaceCreated, scr,
(void*)(scr->workspace_count-1));
XFlush(dpy);
return scr->workspace_count-1;
}
return -1;
}
Bool
wWorkspaceDelete(WScreen *scr, int workspace)
{
WWindow *tmp;
WWorkspace **list;
int i, j;
if (workspace<=0)
return False;
/* verify if workspace is in use by some window */
tmp = scr->focused_window;
while (tmp) {
if (!IS_OMNIPRESENT(tmp) && tmp->frame->workspace==workspace)
return False;
tmp = tmp->prev;
}
if (!wPreferences.flags.noclip) {
wDockDestroy(scr->workspaces[workspace]->clip);
scr->workspaces[workspace]->clip = NULL;
}
list = wmalloc(sizeof(WWorkspace*)*(scr->workspace_count-1));
j = 0;
for (i=0; i<scr->workspace_count; i++) {
if (i!=workspace)
list[j++] = scr->workspaces[i];
else {
if (scr->workspaces[i]->name)
wfree(scr->workspaces[i]->name);
wfree(scr->workspaces[i]);
}
}
wfree(scr->workspaces);
scr->workspaces = list;
scr->workspace_count--;
/* update menu */
wWorkspaceMenuUpdate(scr, scr->workspace_menu);
/* clip workspace menu */
wWorkspaceMenuUpdate(scr, scr->clip_ws_menu);
/* update also window menu */
if (scr->workspace_submenu) {
WMenu *menu = scr->workspace_submenu;
i = menu->entry_no;
while (i>scr->workspace_count)
wMenuRemoveItem(menu, --i);
wMenuRealize(menu);
}
/* and clip menu */
if (scr->clip_submenu) {
WMenu *menu = scr->clip_submenu;
i = menu->entry_no;
while (i>scr->workspace_count)
wMenuRemoveItem(menu, --i);
wMenuRealize(menu);
}
WMPostNotificationName(WMNWorkspaceDestroyed, scr,
(void*)(scr->workspace_count-1));
if (scr->current_workspace >= scr->workspace_count)
wWorkspaceChange(scr, scr->workspace_count-1);
return True;
}
typedef struct WorkspaceNameData {
int count;
RImage *back;
RImage *text;
time_t timeout;
} WorkspaceNameData;
static void
hideWorkpaceName(void *data)
{
WScreen *scr = (WScreen*)data;
if (!scr->workspace_name_data || scr->workspace_name_data->count == 0
|| time(NULL) > scr->workspace_name_data->timeout) {
XUnmapWindow(dpy, scr->workspace_name);
if (scr->workspace_name_data) {
RReleaseImage(scr->workspace_name_data->back);
RReleaseImage(scr->workspace_name_data->text);
wfree(scr->workspace_name_data);
scr->workspace_name_data = NULL;
}
scr->workspace_name_timer = NULL;
} else {
RImage *img = RCloneImage(scr->workspace_name_data->back);
Pixmap pix;
scr->workspace_name_timer =
WMAddTimerHandler(WORKSPACE_NAME_FADE_DELAY, hideWorkpaceName,
scr);
RCombineImagesWithOpaqueness(img, scr->workspace_name_data->text,
scr->workspace_name_data->count*255/10);
RConvertImage(scr->rcontext, img, &pix);
RReleaseImage(img);
XSetWindowBackgroundPixmap(dpy, scr->workspace_name, pix);
XClearWindow(dpy, scr->workspace_name);
XFreePixmap(dpy, pix);
XFlush(dpy);
scr->workspace_name_data->count--;
}
}
static void
showWorkspaceName(WScreen *scr, int workspace)
{
WorkspaceNameData *data;
RXImage *ximg;
Pixmap text, mask;
int w, h;
int px, py;
char *name = scr->workspaces[workspace]->name;
int len = strlen(name);
int x, y;
if (wPreferences.workspace_name_display_position == WD_NONE
|| scr->workspace_count < 2)
return;
if (scr->workspace_name_timer) {
WMDeleteTimerHandler(scr->workspace_name_timer);
XUnmapWindow(dpy, scr->workspace_name);
XFlush(dpy);
}
scr->workspace_name_timer = WMAddTimerHandler(WORKSPACE_NAME_DELAY,
hideWorkpaceName, scr);
if (scr->workspace_name_data) {
RReleaseImage(scr->workspace_name_data->back);
RReleaseImage(scr->workspace_name_data->text);
wfree(scr->workspace_name_data);
}
data = wmalloc(sizeof(WorkspaceNameData));
w = WMWidthOfString(scr->workspace_name_font, name, len);
h = WMFontHeight(scr->workspace_name_font);
switch (wPreferences.workspace_name_display_position) {
case WD_TOP:
px = (scr->scr_width - (w+4))/2;
py = 0;
break;
case WD_BOTTOM:
px = (scr->scr_width - (w+4))/2;
py = scr->scr_height - (h+4);
break;
case WD_TOPLEFT:
px = 0;
py = 0;
break;
case WD_TOPRIGHT:
px = scr->scr_width - (w+4);
py = 0;
break;
case WD_BOTTOMLEFT:
px = 0;
py = scr->scr_height - (h+4);
break;
case WD_BOTTOMRIGHT:
px = scr->scr_width - (w+4);
py = scr->scr_height - (h+4);
break;
case WD_CENTER:
default:
px = (scr->scr_width - (w+4))/2;
py = (scr->scr_height - (h+4))/2;
break;
}
XResizeWindow(dpy, scr->workspace_name, w+4, h+4);
XMoveWindow(dpy, scr->workspace_name, px, py);
text = XCreatePixmap(dpy, scr->w_win, w+4, h+4, scr->w_depth);
mask = XCreatePixmap(dpy, scr->w_win, w+4, h+4, 1);
XSetForeground(dpy, scr->draw_gc, scr->black_pixel);
XFillRectangle(dpy, text, scr->draw_gc, 0, 0, w+4, h+4);
XSetForeground(dpy, scr->mono_gc, 0);
XFillRectangle(dpy, mask, scr->mono_gc, 0, 0, w+4, h+4);
XSetForeground(dpy, scr->mono_gc, 1);
for (x = 0; x <= 4; x++) {
for (y = 0; y <= 4; y++) {
WMDrawString(scr->wmscreen, mask, scr->mono_gc,
scr->workspace_name_font, x, y, name, len);
}
}
XSetForeground(dpy, scr->draw_gc, scr->white_pixel);
WMDrawString(scr->wmscreen, text, scr->draw_gc, scr->workspace_name_font,
2, 2, scr->workspaces[workspace]->name,
strlen(scr->workspaces[workspace]->name));
#ifdef SHAPE
XShapeCombineMask(dpy, scr->workspace_name, ShapeBounding, 0, 0, mask,
ShapeSet);
#endif
XSetWindowBackgroundPixmap(dpy, scr->workspace_name, text);
XClearWindow(dpy, scr->workspace_name);
data->text = RCreateImageFromDrawable(scr->rcontext, text, None);
XFreePixmap(dpy, text);
XFreePixmap(dpy, mask);
if (!data->text) {
XMapRaised(dpy, scr->workspace_name);
XFlush(dpy);
goto erro;
}
ximg = RGetXImage(scr->rcontext, scr->root_win, px, py,
data->text->width, data->text->height);
if (!ximg || !ximg->image) {
goto erro;
}
XMapRaised(dpy, scr->workspace_name);
XFlush(dpy);
data->back = RCreateImageFromXImage(scr->rcontext, ximg->image, NULL);
RDestroyXImage(scr->rcontext, ximg);
if (!data->back) {
goto erro;
}
data->count = 10;
/* set a timeout for the effect */
data->timeout = time(NULL) + 2 +
(WORKSPACE_NAME_DELAY + WORKSPACE_NAME_FADE_DELAY*data->count)/1000;
scr->workspace_name_data = data;
return;
erro:
if (scr->workspace_name_timer)
WMDeleteTimerHandler(scr->workspace_name_timer);
if (data->text)
RReleaseImage(data->text);
if (data->back)
RReleaseImage(data->back);
wfree(data);
scr->workspace_name_data = NULL;
scr->workspace_name_timer = WMAddTimerHandler(WORKSPACE_NAME_DELAY +
10*WORKSPACE_NAME_FADE_DELAY,
hideWorkpaceName, scr);
}
void
wWorkspaceChange(WScreen *scr, int workspace)
{
if (scr->flags.startup || scr->flags.startup2) {
return;
}
if (workspace != scr->current_workspace) {
wWorkspaceForceChange(scr, workspace);
} /*else {
showWorkspaceName(scr, workspace);
}*/
}
void
wWorkspaceRelativeChange(WScreen *scr, int amount)
{
int w;
w = scr->current_workspace + amount;
if (amount < 0) {
if (w >= 0)
wWorkspaceChange(scr, w);
else if (wPreferences.ws_cycle)
wWorkspaceChange(scr, scr->workspace_count + w);
} else if (amount > 0) {
if (w < scr->workspace_count)
wWorkspaceChange(scr, w);
else if (wPreferences.ws_advance)
wWorkspaceChange(scr, WMIN(w, MAX_WORKSPACES-1));
else if (wPreferences.ws_cycle)
wWorkspaceChange(scr, w % scr->workspace_count);
}
}
void
wWorkspaceForceChange(WScreen *scr, int workspace)
{
WWindow *tmp, *foc=NULL, *foc2=NULL;
if (workspace >= MAX_WORKSPACES || workspace < 0)
return;
SendHelperMessage(scr, 'C', workspace+1, NULL);
if (workspace > scr->workspace_count-1) {
wWorkspaceMake(scr, workspace - scr->workspace_count + 1);
}
wClipUpdateForWorkspaceChange(scr, workspace);
scr->current_workspace = workspace;
wWorkspaceMenuUpdate(scr, scr->workspace_menu);
wWorkspaceMenuUpdate(scr, scr->clip_ws_menu);
if ((tmp = scr->focused_window)!= NULL) {
if ((IS_OMNIPRESENT(tmp) && !WFLAGP(tmp, skip_window_list))
|| tmp->flags.changing_workspace) {
foc = tmp;
}
/* foc2 = tmp; will fix annoyance with gnome panel
* but will create annoyance for every other application
*/
while (tmp) {
if (tmp->frame->workspace!=workspace && !tmp->flags.selected) {
/* unmap windows not on this workspace */
if ((tmp->flags.mapped||tmp->flags.shaded)
&& !IS_OMNIPRESENT(tmp)
&& !tmp->flags.changing_workspace) {
wWindowUnmap(tmp);
}
/* also unmap miniwindows not on this workspace */
if (!wPreferences.sticky_icons && tmp->flags.miniaturized &&
tmp->icon && !IS_OMNIPRESENT(tmp)) {
XUnmapWindow(dpy, tmp->icon->core->window);
tmp->icon->mapped = 0;
}
/* update current workspace of omnipresent windows */
if (IS_OMNIPRESENT(tmp)) {
WApplication *wapp = wApplicationOf(tmp->main_window);
tmp->frame->workspace = workspace;
if (wapp) {
wapp->last_workspace = workspace;
}
if (!foc2)
foc2 = tmp;
}
} else {
/* change selected windows' workspace */
if (tmp->flags.selected) {
wWindowChangeWorkspace(tmp, workspace);
if (!tmp->flags.miniaturized && !foc) {
foc = tmp;
}
} else {
if (!tmp->flags.hidden) {
if (!(tmp->flags.mapped || tmp->flags.miniaturized)) {
/* remap windows that are on this workspace */
wWindowMap(tmp);
if (!foc && !WFLAGP(tmp, skip_window_list))
foc = tmp;
}
/* Also map miniwindow if not omnipresent */
if (!wPreferences.sticky_icons &&
tmp->flags.miniaturized &&
!IS_OMNIPRESENT(tmp) && tmp->icon) {
tmp->icon->mapped = 1;
XMapWindow(dpy, tmp->icon->core->window);
}
}
}
}
tmp = tmp->prev;
}
if (!foc)
foc = foc2;
if (scr->focused_window->flags.mapped && !foc) {
foc = scr->focused_window;
}
if (wPreferences.focus_mode == WKF_CLICK) {
wSetFocusTo(scr, foc);
} else {
unsigned int mask;
int foo;
Window bar, win;
WWindow *tmp;
tmp = NULL;
if (XQueryPointer(dpy, scr->root_win, &bar, &win,
&foo, &foo, &foo, &foo, &mask)) {
tmp = wWindowFor(win);
}
if (!tmp && wPreferences.focus_mode == WKF_SLOPPY) {
wSetFocusTo(scr, foc);
} else {
wSetFocusTo(scr, tmp);
}
}
}
/* We need to always arrange icons when changing workspace, even if
* no autoarrange icons, because else the icons in different workspaces
* can be superposed.
* This can be avoided if appicons are also workspace specific.
*/
if (!wPreferences.sticky_icons)
wArrangeIcons(scr, False);
if (scr->dock)
wAppIconPaint(scr->dock->icon_array[0]);
if (scr->clip_icon) {
if (scr->workspaces[workspace]->clip->auto_collapse ||
scr->workspaces[workspace]->clip->auto_raise_lower) {
/* to handle enter notify. This will also */
XUnmapWindow(dpy, scr->clip_icon->icon->core->window);
XMapWindow(dpy, scr->clip_icon->icon->core->window);
} else {
wClipIconPaint(scr->clip_icon);
}
}
showWorkspaceName(scr, workspace);
WMPostNotificationName(WMNWorkspaceChanged, scr, (void*)workspace);
/* XSync(dpy, False); */
}
#ifdef VIRTUAL_DESKTOP
/* TODO:
* 1) Allow border around each window so the scrolling
* won't just stop at the border.
* 2) Make pager.
*/
void wWorkspaceManageEdge(WScreen *scr)
{
int w;
int vmask;
XSetWindowAttributes attribs;
/* puts("wWorkspaceManageEdge()"); */
if (wPreferences.vedge_thickness) {
initVDesk = True;
for (w = 0; w < scr->workspace_count; w++) {
/* puts("reset workspace"); */
wWorkspaceSetViewPort(scr, w, 0, 0);
}
vmask = CWEventMask|CWOverrideRedirect;
attribs.event_mask = (EnterWindowMask | LeaveWindowMask | VisibilityChangeMask);
attribs.override_redirect = True;
scr->virtual_edge_u =
XCreateWindow(dpy, scr->root_win, 0, 0,
scr->scr_width, wPreferences.vedge_thickness, 0,
CopyFromParent, InputOnly, CopyFromParent, vmask, &attribs);
scr->virtual_edge_d =
XCreateWindow(dpy, scr->root_win, 0, scr->scr_height-wPreferences.vedge_thickness,
scr->scr_width, wPreferences.vedge_thickness, 0,
CopyFromParent, InputOnly, CopyFromParent, vmask, &attribs);
scr->virtual_edge_l =
XCreateWindow(dpy, scr->root_win, 0, 0,
wPreferences.vedge_thickness, scr->scr_height, 0,
CopyFromParent, InputOnly, CopyFromParent, vmask, &attribs);
scr->virtual_edge_r =
XCreateWindow(dpy, scr->root_win, scr->scr_width-wPreferences.vedge_thickness, 0,
wPreferences.vedge_thickness, scr->scr_height, 0,
CopyFromParent, InputOnly, CopyFromParent, vmask, &attribs);
XMapWindow(dpy, scr->virtual_edge_u);
XMapWindow(dpy, scr->virtual_edge_d);
XMapWindow(dpy, scr->virtual_edge_l);
XMapWindow(dpy, scr->virtual_edge_r);
wWorkspaceRaiseEdge(scr);
}
}
void wWorkspaceRaiseEdge(WScreen *scr)
{
puts("raise edge");
if (wPreferences.vedge_thickness && initVDesk) {
XRaiseWindow(dpy, scr->virtual_edge_u);
XRaiseWindow(dpy, scr->virtual_edge_d);
XRaiseWindow(dpy, scr->virtual_edge_l);
XRaiseWindow(dpy, scr->virtual_edge_r);
}
}
void wWorkspaceLowerEdge(WScreen *scr)
{
puts("lower edge");
if (wPreferences.vedge_thickness && initVDesk) {
XLowerWindow(dpy, scr->virtual_edge_u);
XLowerWindow(dpy, scr->virtual_edge_d);
XLowerWindow(dpy, scr->virtual_edge_l);
XLowerWindow(dpy, scr->virtual_edge_r);
}
}
void wWorkspaceResizeViewPort(WScreen *scr, int workspace, int width, int height)
{
scr->workspaces[workspace]->width = WMAX(width,scr->scr_width);
scr->workspaces[workspace]->height = WMAX(height,scr->scr_height);
}
void updateWorkspaceGeometry(WScreen *scr, int workspace, int *view_x, int *view_y) {
int most_left, most_right, most_top, most_bottom;
WWindow *wwin;
/* adjust workspace layout */
wwin = scr->focused_window;
most_right = scr->scr_width;
most_bottom = scr->scr_height;
most_left = 0;
most_top = 0;
for(;wwin; wwin = wwin->prev) {
if (wwin->frame->workspace == workspace) {
if (!wwin->flags.miniaturized
&& !wwin->flags.hidden) {
if (wwin->frame_x < most_left) { /* record positions, should this be cached? */
most_left = wwin->frame_x;
}
if ((int)wwin->frame_x + (int)wwin->frame->core->width > most_right) {
most_right = wwin->frame_x + wwin->frame->core->width;
}
if (wwin->frame_y < most_top) {
most_top = wwin->frame_y;
}
if (wwin->frame_y + wwin->frame->core->height > most_bottom) {
most_bottom = wwin->frame_y + wwin->frame->core->height;
}
}
}
}
scr->workspaces[workspace]->width = WMAX(most_right, scr->scr_width) - WMIN(most_left, 0);
scr->workspaces[workspace]->height = WMAX(most_bottom, scr->scr_height) - WMIN(most_top, 0);
*view_x += -most_left - scr->workspaces[workspace]->view_x;
scr->workspaces[workspace]->view_x = -most_left;
*view_y += -most_top - scr->workspaces[workspace]->view_y;
scr->workspaces[workspace]->view_y = -most_top;
}
typedef struct _delay_configure {
WWindow *wwin;
int delay_count;
} _delay_configure;
void _sendConfigureNotify (_delay_configure *delay) {
WWindow *wwin;
delay->delay_count--;
if (!delay->delay_count) {
for (wwin = delay->wwin; wwin; wwin = wwin->prev) {
wWindowSynthConfigureNotify(wwin);
}
}
}
Bool wWorkspaceSetViewPort(WScreen *scr, int workspace, int view_x, int view_y)
{
Bool adjust_flag = False;
int diff_x, diff_y;
static _delay_configure delay_configure = {NULL, 0};
WWindow *wwin;
/*printf("wWorkspaceSetViewPort %d %d\n", view_x, view_y);*/
updateWorkspaceGeometry(scr, workspace, &view_x, &view_y);
if (view_x + scr->scr_width > scr->workspaces[workspace]->width) {
/* puts("right edge of vdesk"); */
view_x = scr->workspaces[workspace]->width - scr->scr_width;
}
if (view_x < 0) {
/* puts("left edge of vdesk"); */
view_x = 0;
}
if (view_y + scr->scr_height > scr->workspaces[workspace]->height) {
/* puts("right edge of vdesk"); */
view_y = scr->workspaces[workspace]->height - scr->scr_height;
}
if (view_y < 0) {
/* puts("left edge of vdesk"); */
view_y = 0;
}
diff_x = scr->workspaces[workspace]->view_x - view_x;
diff_y = scr->workspaces[workspace]->view_y - view_y;
if (!diff_x && !diff_y)
return False;
scr->workspaces[workspace]->view_x = view_x;
scr->workspaces[workspace]->view_y = view_y;
for (wwin = scr->focused_window; wwin; wwin = wwin->prev) {
if (wwin->frame->workspace == workspace) {
wWindowMove(wwin, wwin->frame_x + diff_x, wwin->frame_y + diff_y);
}
}
if (1) { /* if delay*/
delay_configure.delay_count++;
delay_configure.wwin = scr->focused_window;
WMAddTimerHandler(200, (WMCallback *)_sendConfigureNotify, &delay_configure);
}
return adjust_flag;
}
void wWorkspaceGetViewPosition(WScreen *scr, int workspace, int *view_x, int *view_y) {
if (view_x) *view_x = scr->workspaces[workspace]->view_x;
if (view_y) *view_y = scr->workspaces[workspace]->view_y;
}
#endif
static void
switchWSCommand(WMenu *menu, WMenuEntry *entry)
{
wWorkspaceChange(menu->frame->screen_ptr, (long)entry->clientdata);
}
static void
deleteWSCommand(WMenu *menu, WMenuEntry *entry)
{
wWorkspaceDelete(menu->frame->screen_ptr,
menu->frame->screen_ptr->workspace_count-1);
}
static void
newWSCommand(WMenu *menu, WMenuEntry *foo)
{
int ws;
ws = wWorkspaceNew(menu->frame->screen_ptr);
/* autochange workspace*/
if (ws>=0)
wWorkspaceChange(menu->frame->screen_ptr, ws);
/*
if (ws<9) {
int kcode;
if (wKeyBindings[WKBD_WORKSPACE1+ws]) {
kcode = wKeyBindings[WKBD_WORKSPACE1+ws]->keycode;
entry->rtext =
wstrdup(XKeysymToString(XKeycodeToKeysym(dpy, kcode, 0)));
}
}*/
}
static char*
cropline(char *line)
{
char *start, *end;
if (strlen(line)==0)
return line;
start = line;
end = &(line[strlen(line)])-1;
while (isspace(*line) && *line!=0) line++;
while (isspace(*end) && end!=line) {
*end=0;
end--;
}
return line;
}
void
wWorkspaceRename(WScreen *scr, int workspace, char *name)
{
char buf[MAX_WORKSPACENAME_WIDTH+1];
char *tmp;
if (workspace >= scr->workspace_count)
return;
/* trim white spaces */
tmp = cropline(name);
if (strlen(tmp)==0) {
sprintf(buf, _("Workspace %i"), workspace+1);
} else {
strncpy(buf, tmp, MAX_WORKSPACENAME_WIDTH);
}
buf[MAX_WORKSPACENAME_WIDTH] = 0;
/* update workspace */
wfree(scr->workspaces[workspace]->name);
scr->workspaces[workspace]->name = wstrdup(buf);
if (scr->clip_ws_menu) {
if (strcmp(scr->clip_ws_menu->entries[workspace+2]->text, buf)!=0) {
wfree(scr->clip_ws_menu->entries[workspace+2]->text);
scr->clip_ws_menu->entries[workspace+2]->text = wstrdup(buf);
wMenuRealize(scr->clip_ws_menu);
}
}
if (scr->workspace_menu) {
if (strcmp(scr->workspace_menu->entries[workspace+2]->text, buf)!=0) {
wfree(scr->workspace_menu->entries[workspace+2]->text);
scr->workspace_menu->entries[workspace+2]->text = wstrdup(buf);
wMenuRealize(scr->workspace_menu);
}
}
if (scr->clip_icon)
wClipIconPaint(scr->clip_icon);
WMPostNotificationName(WMNWorkspaceNameChanged, scr, (void*)workspace);
}
/* callback for when menu entry is edited */
static void
onMenuEntryEdited(WMenu *menu, WMenuEntry *entry)
{
char *tmp;
tmp = entry->text;
wWorkspaceRename(menu->frame->screen_ptr, (long)entry->clientdata, tmp);
}
WMenu*
wWorkspaceMenuMake(WScreen *scr, Bool titled)
{
WMenu *wsmenu;
wsmenu = wMenuCreate(scr, titled ? _("Workspaces") : NULL, False);
if (!wsmenu) {
wwarning(_("could not create Workspace menu"));
return NULL;
}
/* callback to be called when an entry is edited */
wsmenu->on_edit = onMenuEntryEdited;
wMenuAddCallback(wsmenu, _("New"), newWSCommand, NULL);
wMenuAddCallback(wsmenu, _("Destroy Last"), deleteWSCommand, NULL);
return wsmenu;
}
void
wWorkspaceMenuUpdate(WScreen *scr, WMenu *menu)
{
int i;
long ws;
char title[MAX_WORKSPACENAME_WIDTH+1];
WMenuEntry *entry;
int tmp;
if (!menu)
return;
if (menu->entry_no < scr->workspace_count+2) {
/* new workspace(s) added */
i = scr->workspace_count-(menu->entry_no-2);
ws = menu->entry_no - 2;
while (i>0) {
strcpy(title, scr->workspaces[ws]->name);
entry = wMenuAddCallback(menu, title, switchWSCommand, (void*)ws);
entry->flags.indicator = 1;
entry->flags.editable = 1;
i--;
ws++;
}
} else if (menu->entry_no > scr->workspace_count+2) {
/* removed workspace(s) */
for (i = menu->entry_no-1; i >= scr->workspace_count+2; i--) {
wMenuRemoveItem(menu, i);
}
}
wMenuRealize(menu);
for (i=0; i<scr->workspace_count; i++) {
menu->entries[i+2]->flags.indicator_on = 0;
}
menu->entries[scr->current_workspace+2]->flags.indicator_on = 1;
/* don't let user destroy current workspace */
if (scr->current_workspace == scr->workspace_count-1) {
wMenuSetEnabled(menu, 1, False);
} else {
wMenuSetEnabled(menu, 1, True);
}
tmp = menu->frame->top_width + 5;
/* if menu got unreachable, bring it to a visible place */
if (menu->frame_x < tmp - (int)menu->frame->core->width)
wMenuMove(menu, tmp - (int)menu->frame->core->width, menu->frame_y, False);
wMenuPaint(menu);
}
void
wWorkspaceSaveState(WScreen *scr, WMPropList *old_state)
{
WMPropList *parr, *pstr, *wks_state, *old_wks_state, *foo, *bar;
int i;
make_keys();
old_wks_state = WMGetFromPLDictionary(old_state, dWorkspaces);
parr = WMCreatePLArray(NULL);
for (i=0; i < scr->workspace_count; i++) {
pstr = WMCreatePLString(scr->workspaces[i]->name);
wks_state = WMCreatePLDictionary(dName, pstr, NULL);
WMReleasePropList(pstr);
if (!wPreferences.flags.noclip) {
pstr = wClipSaveWorkspaceState(scr, i);
WMPutInPLDictionary(wks_state, dClip, pstr);
WMReleasePropList(pstr);
} else if (old_wks_state!=NULL) {
if ((foo = WMGetFromPLArray(old_wks_state, i))!=NULL) {
if ((bar = WMGetFromPLDictionary(foo, dClip))!=NULL) {
WMPutInPLDictionary(wks_state, dClip, bar);
}
}
}
WMAddToPLArray(parr, wks_state);
WMReleasePropList(wks_state);
}
WMPutInPLDictionary(scr->session_state, dWorkspaces, parr);
WMReleasePropList(parr);
}
void
wWorkspaceRestoreState(WScreen *scr)
{
WMPropList *parr, *pstr, *wks_state, *clip_state;
int i, j, wscount;
make_keys();
parr = WMGetFromPLDictionary(scr->session_state, dWorkspaces);
if (!parr)
return;
wscount = scr->workspace_count;
for (i=0; i < WMIN(WMGetPropListItemCount(parr), MAX_WORKSPACES); i++) {
wks_state = WMGetFromPLArray(parr, i);
if (WMIsPLDictionary(wks_state))
pstr = WMGetFromPLDictionary(wks_state, dName);
else
pstr = wks_state;
if (i >= scr->workspace_count)
wWorkspaceNew(scr);
if (scr->workspace_menu) {
wfree(scr->workspace_menu->entries[i+2]->text);
scr->workspace_menu->entries[i+2]->text = wstrdup(WMGetFromPLString(pstr));
scr->workspace_menu->flags.realized = 0;
}
wfree(scr->workspaces[i]->name);
scr->workspaces[i]->name = wstrdup(WMGetFromPLString(pstr));
if (!wPreferences.flags.noclip) {
clip_state = WMGetFromPLDictionary(wks_state, dClip);
if (scr->workspaces[i]->clip)
wDockDestroy(scr->workspaces[i]->clip);
scr->workspaces[i]->clip = wDockRestoreState(scr, clip_state,
WM_CLIP);
if (i>0)
wDockHideIcons(scr->workspaces[i]->clip);
/* We set the global icons here, because scr->workspaces[i]->clip
* was not valid in wDockRestoreState().
* There we only set icon->omnipresent to know which icons we
* need to set here.
*/
for (j=0; j<scr->workspaces[i]->clip->max_icons; j++) {
WAppIcon *aicon = scr->workspaces[i]->clip->icon_array[j];
if (aicon && aicon->omnipresent) {
aicon->omnipresent = 0;
wClipMakeIconOmnipresent(aicon, True);
XMapWindow(dpy, aicon->icon->core->window);
}
}
}
WMPostNotificationName(WMNWorkspaceNameChanged, scr, (void*)i);
}
}