2
* Various workspace handling and utilities.
11
#include <X11/Xatom.h>
14
#include "clicktofocus.h"
15
#include "ctwm_atoms.h"
17
#include "functions.h"
24
#include "workspace_utils.h"
27
# include "ewmh_atoms.h"
31
bool useBackgroundInfo = false;
35
* Various funcs for switching workspaces
37
void GotoWorkSpaceByName(VirtualScreen *vs, char *wname)
41
if(! Scr->workSpaceManagerActive) {
47
ws = GetWorkspace(wname);
51
GotoWorkSpace(vs, ws);
55
void GotoWorkSpaceByNumber(VirtualScreen *vs, int workspacenum)
58
if(! Scr->workSpaceManagerActive) {
64
for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
65
if(ws->number == workspacenum) {
72
GotoWorkSpace(vs, ws);
76
void GotoPrevWorkSpace(VirtualScreen *vs)
80
if(! Scr->workSpaceManagerActive) {
86
ws1 = Scr->workSpaceMgr.workSpaceList;
92
while((ws2 != vs->wsw->currentwspc) && (ws2 != NULL)) {
96
GotoWorkSpace(vs, ws1);
100
void GotoNextWorkSpace(VirtualScreen *vs)
103
if(! Scr->workSpaceManagerActive) {
110
ws = vs->wsw->currentwspc;
111
ws = (ws->next != NULL) ? ws->next : Scr->workSpaceMgr.workSpaceList;
112
GotoWorkSpace(vs, ws);
116
void GotoRightWorkSpace(VirtualScreen *vs)
119
int number, columns, count;
121
if(!Scr->workSpaceManagerActive) {
128
ws = vs->wsw->currentwspc;
130
columns = Scr->workSpaceMgr.columns;
131
count = Scr->workSpaceMgr.count;
133
if((number % columns) == 0) {
136
else if(number >= count) {
137
number = (number / columns) * columns;
140
GotoWorkSpaceByNumber(vs, number);
144
void GotoLeftWorkSpace(VirtualScreen *vs)
147
int number, columns, count;
149
if(!Scr->workSpaceManagerActive) {
156
ws = vs->wsw->currentwspc;
158
columns = Scr->workSpaceMgr.columns;
159
count = Scr->workSpaceMgr.count;
160
number += (number % columns) ? -1 : (columns - 1);
161
if(number >= count) {
164
GotoWorkSpaceByNumber(vs, number);
168
void GotoUpWorkSpace(VirtualScreen *vs)
171
int number, lines, columns, count;
173
if(!Scr->workSpaceManagerActive) {
180
ws = vs->wsw->currentwspc;
182
lines = Scr->workSpaceMgr.lines;
183
columns = Scr->workSpaceMgr.columns;
184
count = Scr->workSpaceMgr.count;
187
number += lines * columns;
188
/* If the number of workspaces is not a multiple of nr of columns */
189
if(number >= count) {
193
GotoWorkSpaceByNumber(vs, number);
197
void GotoDownWorkSpace(VirtualScreen *vs)
200
int number, columns, count;
202
if(!Scr->workSpaceManagerActive) {
209
ws = vs->wsw->currentwspc;
211
columns = Scr->workSpaceMgr.columns;
212
count = Scr->workSpaceMgr.count;
214
if(number >= count) {
217
GotoWorkSpaceByNumber(vs, number);
223
* Show the background (by hiding all windows) or undo it.
224
* f.showbackground, also can be called via EWMH bits.
226
* newstate is the desired showing state.
227
* Pass -1 to toggle, 1 to show the background,
228
* or 0 to re-show the windows.
230
* XXX Doesn't really belong here; more of a functions.c-ish thing
231
* probably. But left here for the moment.
233
void ShowBackground(VirtualScreen *vs, int newstate)
235
static int state = 0;
238
if(newstate == state) {
243
for(twmWin = Scr->FirstWindow; twmWin != NULL; twmWin = twmWin->next) {
244
if(twmWin->savevs == vs) {
245
DisplayWin(vs, twmWin);
247
twmWin->savevs = NULL;
252
for(twmWin = Scr->FirstWindow; twmWin != NULL; twmWin = twmWin->next) {
255
/* leave wt_Desktop and wt_Dock visible */
256
&& twmWin->ewmhWindowType == wt_Normal
259
twmWin->savevs = twmWin->vs;
266
EwmhSet_NET_SHOWING_DESKTOP(state);
272
* Belongs with the above GotoWorkSpace* funcs
274
void GotoWorkSpace(VirtualScreen *vs, WorkSpace *ws)
277
WorkSpace *oldws, *newws;
280
XSetWindowAttributes attr;
281
XWindowAttributes winattrs;
282
unsigned long eventMask;
286
TwmWindow *focuswindow;
287
VirtualScreen *tmpvs;
289
if(! Scr->workSpaceManagerActive) {
292
for(tmpvs = Scr->vScreenList; tmpvs != NULL; tmpvs = tmpvs->next) {
293
if(ws == tmpvs->wsw->currentwspc) {
298
oldws = vs->wsw->currentwspc;
304
attr.backing_store = NotUseful;
305
attr.save_under = False;
307
if(useBackgroundInfo && ! Scr->DontPaintRootWindow) {
308
if(newws->image == NULL) {
309
XSetWindowBackground(dpy, vs->window, newws->backcp.back);
312
XSetWindowBackgroundPixmap(dpy, vs->window, newws->image->pixmap);
314
XClearWindow(dpy, vs->window);
317
/* If SaveWorkspaceFocus is on, save the focus of the last window. */
318
if(Scr->SaveWorkspaceFocus) {
319
oldws->save_focus = Scr->Focus;
323
/* For better visual effect, the order or map/unmap is important:
324
- map from top to bottom.
325
- unmap from bottom to top.
326
- unmap after mapping.
327
The guiding factor: at any point during the transition, something
328
should be visible only if it was visible before the transition or if
329
it will be visible at the end. */
330
OtpCheckConsistency();
332
for(twmWin = OtpTopWin(); twmWin != NULL;
333
twmWin = OtpNextWinDown(twmWin)) {
335
if(OCCUPY(twmWin, newws)) {
337
DisplayWin(vs, twmWin);
340
if(OCCUPY(twmWin, oldws)) {
342
* If the window remains visible, re-order the workspace
343
* numbers in NET_WM_DESKTOP.
345
EwmhSet_NET_WM_DESKTOP_ws(twmWin, newws);
351
for(twmWin = OtpBottomWin(); twmWin != NULL;
352
twmWin = OtpNextWinUp(twmWin)) {
353
if(twmWin->vs == vs) {
354
if(!OCCUPY(twmWin, newws)) {
359
* Now that the window has Vanished from one virtual screen,
360
* check to see if it is wanted on another one.
361
* This is relatively rare, so don't bother with the
362
* top-to-bottom order here.
364
if(Scr->numVscreens > 1) {
365
for(tvs = Scr->vScreenList; tvs != NULL; tvs = tvs->next) {
366
if(tvs == vs) { /* no, not back on the old one */
369
if(OCCUPY(twmWin, tvs->wsw->currentwspc)) {
370
DisplayWin(tvs, twmWin);
376
else if(twmWin->hasfocusvisible) {
377
focuswindow = twmWin;
378
SetFocusVisualAttributes(focuswindow, false);
382
OtpCheckConsistency();
385
Reorganize icon manager window lists
387
for(twmWin = Scr->FirstWindow; twmWin != NULL; twmWin = twmWin->next) {
388
wl = twmWin->iconmanagerlist;
392
if(OCCUPY(wl->iconmgr->twm_win, newws)) {
398
if(OCCUPY(wl->iconmgr->twm_win, newws)) {
405
wl1->nextv = wl->nextv;
406
wl->nextv = twmWin->iconmanagerlist;
407
twmWin->iconmanagerlist = wl;
411
for(iconmgr = newws->iconmgr; iconmgr; iconmgr = iconmgr->next) {
417
CurrentIconManagerEntry(wl);
419
SetFocusVisualAttributes(focuswindow, true);
421
vs->wsw->currentwspc = newws;
422
if(Scr->ReverseCurrentWorkspace && vs->wsw->state == WMS_map) {
423
MapSubwindow *msw = vs->wsw->mswl [oldws->number];
424
for(winl = msw->wl; winl != NULL; winl = winl->next) {
425
WMapRedrawName(vs, winl);
427
msw = vs->wsw->mswl [newws->number];
428
for(winl = msw->wl; winl != NULL; winl = winl->next) {
429
WMapRedrawName(vs, winl);
432
else if(vs->wsw->state == WMS_buttons) {
433
ButtonSubwindow *bsw = vs->wsw->bswl [oldws->number];
434
PaintWsButton(WSPCWINDOW, vs, bsw->w, oldws->label, oldws->cp, off);
435
bsw = vs->wsw->bswl [newws->number];
436
PaintWsButton(WSPCWINDOW, vs, bsw->w, newws->label, newws->cp, on);
438
oldws->iconmgr = Scr->iconmgr;
439
Scr->iconmgr = newws->iconmgr;
441
oldw = vs->wsw->mswl [oldws->number]->w;
442
neww = vs->wsw->mswl [newws->number]->w;
443
if(useBackgroundInfo) {
444
if(oldws->image == NULL || Scr->NoImagesInWorkSpaceManager) {
445
XSetWindowBackground(dpy, oldw, oldws->backcp.back);
448
XSetWindowBackgroundPixmap(dpy, oldw, oldws->image->pixmap);
452
if(Scr->workSpaceMgr.defImage == NULL || Scr->NoImagesInWorkSpaceManager) {
453
XSetWindowBackground(dpy, oldw, Scr->workSpaceMgr.defColors.back);
456
XSetWindowBackgroundPixmap(dpy, oldw, Scr->workSpaceMgr.defImage->pixmap);
459
attr.border_pixel = Scr->workSpaceMgr.defBorderColor;
460
XChangeWindowAttributes(dpy, oldw, CWBorderPixel, &attr);
462
if(Scr->workSpaceMgr.curImage == NULL) {
463
if(Scr->workSpaceMgr.curPaint) {
464
XSetWindowBackground(dpy, neww, Scr->workSpaceMgr.curColors.back);
468
XSetWindowBackgroundPixmap(dpy, neww, Scr->workSpaceMgr.curImage->pixmap);
470
attr.border_pixel = Scr->workSpaceMgr.curBorderColor;
471
XChangeWindowAttributes(dpy, neww, CWBorderPixel, &attr);
473
XClearWindow(dpy, oldw);
474
XClearWindow(dpy, neww);
476
XGetWindowAttributes(dpy, Scr->Root, &winattrs);
477
eventMask = winattrs.your_event_mask;
478
XSelectInput(dpy, Scr->Root, eventMask & ~PropertyChangeMask);
480
XChangeProperty(dpy, Scr->Root, XA_WM_CURRENTWORKSPACE, XA_STRING, 8,
481
PropModeReplace, (unsigned char *) newws->name, strlen(newws->name));
484
long number = newws->number;
486
* TODO: this should probably not use Scr->Root but ->XineramaRoot.
487
* That is the real root window if we're using virtual screens.
488
* Also, on the real root it would need values for each of the
489
* virtual roots, but that doesn't fit in the EWMH ideas.
491
XChangeProperty(dpy, Scr->Root, XA__NET_CURRENT_DESKTOP,
493
PropModeReplace, (unsigned char *) &number, 1);
496
XSelectInput(dpy, Scr->Root, eventMask);
498
/* XDestroyWindow (dpy, cachew);*/
499
if(Scr->ChangeWorkspaceFunction.func != 0) {
503
action = Scr->ChangeWorkspaceFunction.item ?
504
Scr->ChangeWorkspaceFunction.item->action : NULL;
505
ExecuteFunction(Scr->ChangeWorkspaceFunction.func, action,
506
(Window) 0, NULL, &event, C_ROOT, false);
509
/* If SaveWorkspaceFocus is on, try to restore the focus to the last
510
window which was focused when we left this workspace. */
511
if(Scr->SaveWorkspaceFocus && newws->save_focus) {
512
twmWin = newws->save_focus;
513
if(OCCUPY(twmWin, newws)) { /* check should not even be needed anymore */
514
WarpToWindow(twmWin, false);
517
newws->save_focus = NULL;
521
/* keep track of the order of the workspaces across restarts */
522
CtwmSetVScreenMap(dpy, Scr->Root, Scr->vScreenList);
525
if(Scr->ClickToFocus || Scr->SloppyFocus) {
526
set_last_window(newws);
533
* Get the name of the currently active WS. Used in Execute() for
534
* sub'ing in $currentworkspace in executing commands.
536
char *GetCurrentWorkSpaceName(VirtualScreen *vs)
538
if(! Scr->workSpaceManagerActive) {
542
vs = Scr->vScreenList;
544
return vs->wsw->currentwspc->name;
549
* Find workspace by name
552
GetWorkspace(char *wname)
562
for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
563
if(strcmp(ws->label, wname) == 0) {
569
for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
570
if(strcmp(ws->name, wname) == 0) {
581
* Util for setting useBackgroundInfo var, to reduce its exposure across
582
* the multiple files that might touch it.
584
void ws_set_useBackgroundInfo(bool newval)
586
useBackgroundInfo = newval;