1
0
mirror of https://github.com/gryf/wmaker.git synced 2026-01-11 17:04:15 +01:00
Files
wmaker/src/workspace.c
dan 36e46831e0 For libwraster:
---------------

- Added retain/release mechanism to RImage by adding RRetainImage() and
  RReleaseImage(). RDestroyImage() is an alias to RReleaseImage() now, but
  will be removed in a future release because it no longer fits with the
  semantics. Will be kept for a while to allow a smoother transition.
  More about in wrlib/NEWS


For WINGs:
----------

- Small API change:
  1. Renamed WMSetApplicationIconImage(), WMGetApplicationIconImage() and
     WMSetWindowMiniwindowImage() to respectively WMSetApplicationIconPixmap(),
     WMGetApplicationIconPixmap() and WMSetWindowMiniwindowPixmap()
     They operate on a WMPixmap which is practically an X Pixmap with no alpha
     channel information and the new name is more suggestive and also leaves
     room for the new functions added for operating on images with alpha info.
  2. Added WMSetApplicationIconImage() and WMGetApplicationIconImage() which
     operate on an RImage and store alpha information too.
  3. Added WMGetApplicationIconBlendedPixmap() which will take the image with
     alpha set by WMSetApplicationIconImage() and will blend it with a color.
     If color is NULL it will blend using the default panel color (#aeaaae)
  All these changes will allow WINGs to handle images with alpha blending
  correctly in panels and wherever else needed. More about in WINGs/NEWS.
- updated panels to use the newly available RImages if present and fallback
  to old WMPixmaps if not, to properly show alpha blended images.
- replaced some still left malloc's with wmalloc's.


For Window Maker:
-----------------
- Fixed wrong mapping position of the "Docked Applications Panel" for some
  icons.
- Smoother animation for the smiley =)
- Made images with alpha blending be shown correctly in the panels and the
  icon chooser.
- The icon image set to be shown in panels ("Logo.WMPanel") will be
  automatically updated if its entry in WMWindowAttributes changes (without
  a need to restart as until now).


*** Note!!! ***

If you are developing applications with one of libwraster or libWINGs
then you should look to wrlib/NEWS and WINGs/NEWS to see what changed
and how should you update your code.
2001-04-21 07:12:21 +00:00

1125 lines
29 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 GNOME_STUFF
#include "gnome.h"
#endif
#ifdef KWM_HINTS
#include "kwm.h"
#endif
#include <proplist.h>
extern WPreferences wPreferences;
extern XContext wWinContext;
static proplist_t dWorkspaces=NULL;
static proplist_t dClip, dName;
#ifdef VIRTUAL_DESKTOP
static BOOL initVDesk = False;
#endif
static void
make_keys()
{
if (dWorkspaces!=NULL)
return;
dWorkspaces = PLMakeString("Workspaces");
dName = PLMakeString("Name");
dClip = PLMakeString("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
#ifdef GNOME_STUFF
wGNOMEUpdateWorkspaceHints(scr);
#endif
#ifdef KWM_HINTS
if (!scr->flags.kwm_syncing_count) {
wKWMUpdateWorkspaceCountHint(scr);
wKWMUpdateWorkspaceNameHint(scr, scr->workspace_count-1);
}
#ifdef not_used
wKWMSetUsableAreaHint(scr, scr->workspace_count-1);
#endif
#endif
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);
}
#ifdef GNOME_STUFF
wGNOMEUpdateWorkspaceHints(scr);
#endif
#ifdef KWM_HINTS
wKWMUpdateWorkspaceCountHint(scr);
#endif
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);
#ifdef GNOME_STUFF
wGNOMEUpdateCurrentWorkspaceHint(scr);
#endif
#ifdef KWM_HINTS
wKWMUpdateCurrentWorkspaceHint(scr);
#endif
/* 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);
}
}
UpdateSwitchMenuWorkspace(scr, workspace);
if (scr->clip_icon)
wClipIconPaint(scr->clip_icon);
#ifdef GNOME_STUFF
wGNOMEUpdateWorkspaceNamesHint(scr);
#endif
#ifdef KWM_HINTS
wKWMUpdateWorkspaceNameHint(scr, workspace);
#endif
}
/* 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, proplist_t old_state)
{
proplist_t parr, pstr;
proplist_t wks_state, old_wks_state;
proplist_t foo, bar;
int i;
make_keys();
old_wks_state = PLGetDictionaryEntry(old_state, dWorkspaces);
parr = PLMakeArrayFromElements(NULL);
for (i=0; i < scr->workspace_count; i++) {
pstr = PLMakeString(scr->workspaces[i]->name);
wks_state = PLMakeDictionaryFromEntries(dName, pstr, NULL);
PLRelease(pstr);
if (!wPreferences.flags.noclip) {
pstr = wClipSaveWorkspaceState(scr, i);
PLInsertDictionaryEntry(wks_state, dClip, pstr);
PLRelease(pstr);
} else if (old_wks_state!=NULL) {
if ((foo = PLGetArrayElement(old_wks_state, i))!=NULL) {
if ((bar = PLGetDictionaryEntry(foo, dClip))!=NULL) {
PLInsertDictionaryEntry(wks_state, dClip, bar);
}
}
}
PLAppendArrayElement(parr, wks_state);
PLRelease(wks_state);
}
PLInsertDictionaryEntry(scr->session_state, dWorkspaces, parr);
PLRelease(parr);
}
void
wWorkspaceRestoreState(WScreen *scr)
{
proplist_t parr, pstr, wks_state;
proplist_t clip_state;
int i, j, wscount;
make_keys();
parr = PLGetDictionaryEntry(scr->session_state, dWorkspaces);
if (!parr)
return;
wscount = scr->workspace_count;
for (i=0; i < WMIN(PLGetNumberOfElements(parr), MAX_WORKSPACES); i++) {
wks_state = PLGetArrayElement(parr, i);
if (PLIsDictionary(wks_state))
pstr = PLGetDictionaryEntry(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(PLGetString(pstr));
scr->workspace_menu->flags.realized = 0;
}
wfree(scr->workspaces[i]->name);
scr->workspaces[i]->name = wstrdup(PLGetString(pstr));
if (!wPreferences.flags.noclip) {
clip_state = PLGetDictionaryEntry(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);
}
}
}
#ifdef KWM_HINTS
wKWMUpdateWorkspaceNameHint(scr, i);
#endif
}
#ifdef GNOME_STUFF
wGNOMEUpdateWorkspaceNamesHint(scr);
#endif
}