242
void GotoWorkSpaceByName(VirtualScreen *vs, char *wname)
246
if(! Scr->workSpaceManagerActive) {
252
ws = GetWorkspace(wname);
256
GotoWorkSpace(vs, ws);
259
void GotoWorkSpaceByNumber(VirtualScreen *vs, int workspacenum)
262
if(! Scr->workSpaceManagerActive) {
268
for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
269
if(ws->number == workspacenum) {
276
GotoWorkSpace(vs, ws);
280
void GotoPrevWorkSpace(VirtualScreen *vs)
282
WorkSpace *ws1, *ws2;
284
if(! Scr->workSpaceManagerActive) {
290
ws1 = Scr->workSpaceMgr.workSpaceList;
296
while((ws2 != vs->wsw->currentwspc) && (ws2 != NULL)) {
300
GotoWorkSpace(vs, ws1);
303
void GotoNextWorkSpace(VirtualScreen *vs)
306
if(! Scr->workSpaceManagerActive) {
313
ws = vs->wsw->currentwspc;
314
ws = (ws->next != NULL) ? ws->next : Scr->workSpaceMgr.workSpaceList;
315
GotoWorkSpace(vs, ws);
318
void GotoRightWorkSpace(VirtualScreen *vs)
321
int number, columns, count;
323
if(!Scr->workSpaceManagerActive) {
330
ws = vs->wsw->currentwspc;
332
columns = Scr->workSpaceMgr.columns;
333
count = Scr->workSpaceMgr.count;
335
if((number % columns) == 0) {
338
else if(number >= count) {
339
number = (number / columns) * columns;
342
GotoWorkSpaceByNumber(vs, number);
345
void GotoLeftWorkSpace(VirtualScreen *vs)
348
int number, columns, count;
350
if(!Scr->workSpaceManagerActive) {
357
ws = vs->wsw->currentwspc;
359
columns = Scr->workSpaceMgr.columns;
360
count = Scr->workSpaceMgr.count;
361
number += (number % columns) ? -1 : (columns - 1);
362
if(number >= count) {
365
GotoWorkSpaceByNumber(vs, number);
368
void GotoUpWorkSpace(VirtualScreen *vs)
371
int number, lines, columns, count;
373
if(!Scr->workSpaceManagerActive) {
380
ws = vs->wsw->currentwspc;
382
lines = Scr->workSpaceMgr.lines;
383
columns = Scr->workSpaceMgr.columns;
384
count = Scr->workSpaceMgr.count;
387
number += lines * columns;
388
/* If the number of workspaces is not a multiple of nr of columns */
389
if(number >= count) {
393
GotoWorkSpaceByNumber(vs, number);
396
void GotoDownWorkSpace(VirtualScreen *vs)
399
int number, columns, count;
401
if(!Scr->workSpaceManagerActive) {
408
ws = vs->wsw->currentwspc;
410
columns = Scr->workSpaceMgr.columns;
411
count = Scr->workSpaceMgr.count;
413
if(number >= count) {
416
GotoWorkSpaceByNumber(vs, number);
420
* Show the background (by hiding all windows) or undo it.
421
* f.showbackground, also can be called via EWMH bits.
423
* newstate is the desired showing state.
424
* Pass -1 to toggle, 1 to show the background,
425
* or 0 to re-show the windows.
427
* XXX Doesn't really belong here; more of a functions.c-ish thing
428
* probably. But left here for the moment.
430
void ShowBackground(VirtualScreen *vs, int newstate)
432
static int state = 0;
435
if(newstate == state) {
440
for(twmWin = Scr->FirstWindow; twmWin != NULL; twmWin = twmWin->next) {
441
if(twmWin->savevs == vs) {
442
DisplayWin(vs, twmWin);
444
twmWin->savevs = NULL;
449
for(twmWin = Scr->FirstWindow; twmWin != NULL; twmWin = twmWin->next) {
452
/* leave wt_Desktop and wt_Dock visible */
453
&& twmWin->ewmhWindowType == wt_Normal
456
twmWin->savevs = twmWin->vs;
463
EwmhSet_NET_SHOWING_DESKTOP(state);
467
void GotoWorkSpace(VirtualScreen *vs, WorkSpace *ws)
470
WorkSpace *oldws, *newws;
473
XSetWindowAttributes attr;
474
XWindowAttributes winattrs;
475
unsigned long eventMask;
479
TwmWindow *focuswindow;
480
VirtualScreen *tmpvs;
482
if(! Scr->workSpaceManagerActive) {
485
for(tmpvs = Scr->vScreenList; tmpvs != NULL; tmpvs = tmpvs->next) {
486
if(ws == tmpvs->wsw->currentwspc) {
491
oldws = vs->wsw->currentwspc;
497
attr.backing_store = NotUseful;
498
attr.save_under = False;
500
if(useBackgroundInfo && ! Scr->DontPaintRootWindow) {
501
if(newws->image == NULL) {
502
XSetWindowBackground(dpy, vs->window, newws->backcp.back);
505
XSetWindowBackgroundPixmap(dpy, vs->window, newws->image->pixmap);
507
XClearWindow(dpy, vs->window);
510
/* If SaveWorkspaceFocus is on, save the focus of the last window. */
511
if(Scr->SaveWorkspaceFocus) {
512
oldws->save_focus = Scr->Focus;
516
/* For better visual effect, the order or map/unmap is important:
517
- map from top to bottom.
518
- unmap from bottom to top.
519
- unmap after mapping.
520
The guiding factor: at any point during the transition, something
521
should be visible only if it was visible before the transition or if
522
it will be visible at the end. */
523
OtpCheckConsistency();
525
for(twmWin = OtpTopWin(); twmWin != NULL;
526
twmWin = OtpNextWinDown(twmWin)) {
528
if(OCCUPY(twmWin, newws)) {
530
DisplayWin(vs, twmWin);
533
if(OCCUPY(twmWin, oldws)) {
535
* If the window remains visible, re-order the workspace
536
* numbers in NET_WM_DESKTOP.
538
EwmhSet_NET_WM_DESKTOP_ws(twmWin, newws);
544
for(twmWin = OtpBottomWin(); twmWin != NULL;
545
twmWin = OtpNextWinUp(twmWin)) {
546
if(twmWin->vs == vs) {
547
if(!OCCUPY(twmWin, newws)) {
552
* Now that the window has Vanished from one virtual screen,
553
* check to see if it is wanted on another one.
554
* This is relatively rare, so don't bother with the
555
* top-to-bottom order here.
557
if(Scr->numVscreens > 1) {
558
for(tvs = Scr->vScreenList; tvs != NULL; tvs = tvs->next) {
559
if(tvs == vs) { /* no, not back on the old one */
562
if(OCCUPY(twmWin, tvs->wsw->currentwspc)) {
563
DisplayWin(tvs, twmWin);
569
else if(twmWin->hasfocusvisible) {
570
focuswindow = twmWin;
571
SetFocusVisualAttributes(focuswindow, false);
575
OtpCheckConsistency();
578
Reorganize icon manager window lists
580
for(twmWin = Scr->FirstWindow; twmWin != NULL; twmWin = twmWin->next) {
581
wl = twmWin->iconmanagerlist;
585
if(OCCUPY(wl->iconmgr->twm_win, newws)) {
591
if(OCCUPY(wl->iconmgr->twm_win, newws)) {
598
wl1->nextv = wl->nextv;
599
wl->nextv = twmWin->iconmanagerlist;
600
twmWin->iconmanagerlist = wl;
604
for(iconmgr = newws->iconmgr; iconmgr; iconmgr = iconmgr->next) {
610
CurrentIconManagerEntry(wl);
612
SetFocusVisualAttributes(focuswindow, true);
614
vs->wsw->currentwspc = newws;
615
if(Scr->ReverseCurrentWorkspace && vs->wsw->state == WMS_map) {
616
MapSubwindow *msw = vs->wsw->mswl [oldws->number];
617
for(winl = msw->wl; winl != NULL; winl = winl->next) {
618
WMapRedrawName(vs, winl);
620
msw = vs->wsw->mswl [newws->number];
621
for(winl = msw->wl; winl != NULL; winl = winl->next) {
622
WMapRedrawName(vs, winl);
625
else if(vs->wsw->state == WMS_buttons) {
626
ButtonSubwindow *bsw = vs->wsw->bswl [oldws->number];
627
PaintWsButton(WSPCWINDOW, vs, bsw->w, oldws->label, oldws->cp, off);
628
bsw = vs->wsw->bswl [newws->number];
629
PaintWsButton(WSPCWINDOW, vs, bsw->w, newws->label, newws->cp, on);
631
oldws->iconmgr = Scr->iconmgr;
632
Scr->iconmgr = newws->iconmgr;
634
oldw = vs->wsw->mswl [oldws->number]->w;
635
neww = vs->wsw->mswl [newws->number]->w;
636
if(useBackgroundInfo) {
637
if(oldws->image == NULL || Scr->NoImagesInWorkSpaceManager) {
638
XSetWindowBackground(dpy, oldw, oldws->backcp.back);
641
XSetWindowBackgroundPixmap(dpy, oldw, oldws->image->pixmap);
645
if(Scr->workSpaceMgr.defImage == NULL || Scr->NoImagesInWorkSpaceManager) {
646
XSetWindowBackground(dpy, oldw, Scr->workSpaceMgr.defColors.back);
649
XSetWindowBackgroundPixmap(dpy, oldw, Scr->workSpaceMgr.defImage->pixmap);
652
attr.border_pixel = Scr->workSpaceMgr.defBorderColor;
653
XChangeWindowAttributes(dpy, oldw, CWBorderPixel, &attr);
655
if(Scr->workSpaceMgr.curImage == NULL) {
656
if(Scr->workSpaceMgr.curPaint) {
657
XSetWindowBackground(dpy, neww, Scr->workSpaceMgr.curColors.back);
661
XSetWindowBackgroundPixmap(dpy, neww, Scr->workSpaceMgr.curImage->pixmap);
663
attr.border_pixel = Scr->workSpaceMgr.curBorderColor;
664
XChangeWindowAttributes(dpy, neww, CWBorderPixel, &attr);
666
XClearWindow(dpy, oldw);
667
XClearWindow(dpy, neww);
669
XGetWindowAttributes(dpy, Scr->Root, &winattrs);
670
eventMask = winattrs.your_event_mask;
671
XSelectInput(dpy, Scr->Root, eventMask & ~PropertyChangeMask);
673
XChangeProperty(dpy, Scr->Root, XA_WM_CURRENTWORKSPACE, XA_STRING, 8,
674
PropModeReplace, (unsigned char *) newws->name, strlen(newws->name));
677
long number = newws->number;
679
* TODO: this should probably not use Scr->Root but ->XineramaRoot.
680
* That is the real root window if we're using virtual screens.
681
* Also, on the real root it would need values for each of the
682
* virtual roots, but that doesn't fit in the EWMH ideas.
684
XChangeProperty(dpy, Scr->Root, XA__NET_CURRENT_DESKTOP,
686
PropModeReplace, (unsigned char *) &number, 1);
689
XSelectInput(dpy, Scr->Root, eventMask);
691
/* XDestroyWindow (dpy, cachew);*/
692
if(Scr->ChangeWorkspaceFunction.func != 0) {
696
action = Scr->ChangeWorkspaceFunction.item ?
697
Scr->ChangeWorkspaceFunction.item->action : NULL;
698
ExecuteFunction(Scr->ChangeWorkspaceFunction.func, action,
699
(Window) 0, NULL, &event, C_ROOT, false);
702
/* If SaveWorkspaceFocus is on, try to restore the focus to the last
703
window which was focused when we left this workspace. */
704
if(Scr->SaveWorkspaceFocus && newws->save_focus) {
705
twmWin = newws->save_focus;
706
if(OCCUPY(twmWin, newws)) { /* check should not even be needed anymore */
707
WarpToWindow(twmWin, false);
710
newws->save_focus = NULL;
714
/* keep track of the order of the workspaces across restarts */
715
CtwmSetVScreenMap(dpy, Scr->Root, Scr->vScreenList);
718
if(Scr->ClickToFocus || Scr->SloppyFocus) {
719
set_last_window(newws);
724
char *GetCurrentWorkSpaceName(VirtualScreen *vs)
726
if(! Scr->workSpaceManagerActive) {
730
vs = Scr->vScreenList;
732
return vs->wsw->currentwspc->name;
737
* Create a workspace. This is what gets called when parsing
738
* WorkSpaces {} config file entries.
741
* "One" { name background foreground backback backfore "backpix.jpg" }
743
* # WS name | Button Text | Map/Root FG |
744
* # Button BG Map BG Map/Root BG img
748
AddWorkSpace(const char *name, const char *background, const char *foreground,
749
const char *backback, const char *backfore, const char *backpix)
753
/* XXX Shouldn't just silently return if we're already at max... */
754
if(Scr->workSpaceMgr.count == MAXWORKSPACE) {
758
/* Init. Label can change over time, but starts the same a name. */
759
ws = calloc(1, sizeof(WorkSpace));
760
ws->name = strdup(name);
761
ws->label = strdup(name);
762
ws->number = Scr->workSpaceMgr.count++;
764
/* We're a new entry on the "everything" list */
765
fullOccupation |= (1 << ws->number);
769
* FB/BG colors for the button state may be specified, or fallback to
770
* the icon manager's if not.
772
if(background == NULL) {
773
ws->cp.back = Scr->IconManagerC.back;
776
GetColor(Scr->Monochrome, &(ws->cp.back), background);
779
if(foreground == NULL) {
780
ws->cp.fore = Scr->IconManagerC.fore;
783
GetColor(Scr->Monochrome, &(ws->cp.fore), foreground);
786
/* Shadows for 3d buttons derived from that */
787
#ifdef COLOR_BLIND_USER
788
ws->cp.shadc = Scr->White;
789
ws->cp.shadd = Scr->Black;
791
if(!Scr->BeNiceToColormap) {
792
GetShadeColors(&ws->cp);
798
* Map-state fb/bg color, as well as root win background.
800
if(backback == NULL) {
801
GetColor(Scr->Monochrome, &(ws->backcp.back), "Black");
804
GetColor(Scr->Monochrome, &(ws->backcp.back), backback);
805
useBackgroundInfo = true;
808
if(backfore == NULL) {
809
GetColor(Scr->Monochrome, &(ws->backcp.fore), "White");
812
GetColor(Scr->Monochrome, &(ws->backcp.fore), backfore);
813
useBackgroundInfo = true;
817
/* Maybe there's an image to stick on the root as well */
818
ws->image = GetImage(backpix, ws->backcp);
819
if(ws->image != NULL) {
820
useBackgroundInfo = true;
824
/* Put ourselves on the end of the workspace list */
825
if(Scr->workSpaceMgr.workSpaceList == NULL) {
826
Scr->workSpaceMgr.workSpaceList = ws;
829
WorkSpace *wstmp = Scr->workSpaceMgr.workSpaceList;
830
while(wstmp->next != NULL) {
836
/* There's at least one defined WS now */
837
Scr->workSpaceManagerActive = true;
844
GetWorkspace(char *wname)
854
for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
855
if(strcmp(ws->label, wname) == 0) {
861
for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
862
if(strcmp(ws->name, wname) == 0) {
873
ReparentFrameAndIcon(TwmWindow *tmp_win)
875
VirtualScreen *vs = tmp_win->vs; /* which virtual screen we want it in */
877
/* parent_vs is the current real parent of the window */
878
if(vs != tmp_win->parent_vs) {
879
struct Icon *icon = tmp_win->icon;
881
tmp_win->parent_vs = vs;
883
if(icon && icon->w) {
884
ReparentWindowAndIcon(dpy, tmp_win, vs->window,
885
tmp_win->frame_x, tmp_win->frame_y,
886
icon->w_x, icon->w_y);
889
ReparentWindow(dpy, tmp_win, WinWin, vs->window,
890
tmp_win->frame_x, tmp_win->frame_y);
897
* Get this window outta here. Note that despite naming, this is
898
* unrelated to f.vanish.
901
Vanish(VirtualScreen *vs, TwmWindow *tmp_win)
903
if(vs && tmp_win->vs && tmp_win->vs != vs) {
906
if(tmp_win->UnmapByMovingFarAway) {
907
XMoveWindow(dpy, tmp_win->frame, Scr->rootw + 1, Scr->rooth + 1);
909
else if(tmp_win->mapped) {
910
XWindowAttributes winattrs;
911
unsigned long eventMask;
913
XGetWindowAttributes(dpy, tmp_win->w, &winattrs);
914
eventMask = winattrs.your_event_mask;
915
XSelectInput(dpy, tmp_win->w, eventMask & ~StructureNotifyMask);
916
XUnmapWindow(dpy, tmp_win->w);
917
XUnmapWindow(dpy, tmp_win->frame);
918
XSelectInput(dpy, tmp_win->w, eventMask);
920
if(!tmp_win->DontSetInactive) {
921
SetMapStateProp(tmp_win, InactiveState);
924
else if(tmp_win->icon_on && tmp_win->icon && tmp_win->icon->w) {
925
XUnmapWindow(dpy, tmp_win->icon->w);
931
* The purpose of this is in the event of a ctwm death/restart,
932
* geometries of windows that were on unmapped workspaces will show
933
* up where they belong.
934
* XXX - I doubt its usefulness, since still-mapped windows won't
935
* enjoy this "protection", making it suboptimal at best.
936
* XXX - XReparentWindow() messes up the stacking order of windows.
937
* It should be avoided as much as possible. This already affects
938
* switching away from and back to a workspace. Therefore do this only
939
* if there are at least 2 virtual screens AND the new one (firstvs)
940
* differs from where the window currently is. (Olaf Seibert).
943
if(Scr->numVscreens > 1) {
946
Window junkW, w = tmp_win->frame;
947
VirtualScreen *firstvs = NULL;
949
for(firstvs = Scr->vScreenList; firstvs; firstvs = firstvs->next)
950
if(firstvs->x == 0 && firstvs->y == 0) {
953
if(firstvs && firstvs != vs) {
954
tmp_win->vs = firstvs;
955
ReparentFrameAndIcon(tmp_win);
964
DisplayWin(VirtualScreen *vs, TwmWindow *tmp_win)
966
OtpCheckConsistency();
967
DisplayWinUnchecked(vs, tmp_win);
968
OtpCheckConsistency();
971
static void DisplayWinUnchecked(VirtualScreen *vs, TwmWindow *tmp_win)
973
XWindowAttributes winattrs;
974
unsigned long eventMask;
977
* A window cannot be shown in multiple virtual screens, even if
978
* it occupies both corresponding workspaces.
980
if(vs && tmp_win->vs) {
986
if(!tmp_win->mapped) {
987
ReparentFrameAndIcon(tmp_win);
989
if(tmp_win->isicon) {
990
if(tmp_win->icon_on) {
991
if(tmp_win->icon && tmp_win->icon->w) {
994
XMapWindow(dpy, tmp_win->icon->w);
1001
if(tmp_win->UnmapByMovingFarAway) {
1002
if(vs) { /* XXX I don't believe the handling of UnmapByMovingFarAway is quite correct */
1003
XReparentWindow(dpy, tmp_win->frame, vs->window,
1004
tmp_win->frame_x, tmp_win->frame_y);
1007
XMoveWindow(dpy, tmp_win->frame, tmp_win->frame_x, tmp_win->frame_y);
1011
if(!tmp_win->squeezed) {
1012
XGetWindowAttributes(dpy, tmp_win->w, &winattrs);
1013
eventMask = winattrs.your_event_mask;
1014
XSelectInput(dpy, tmp_win->w, eventMask & ~StructureNotifyMask);
1015
XMapWindow(dpy, tmp_win->w);
1016
XSelectInput(dpy, tmp_win->w, eventMask);
1019
ReparentFrameAndIcon(tmp_win);
1021
XMapWindow(dpy, tmp_win->frame);
1022
SetMapStateProp(tmp_win, NormalState);
1027
static void CreateWorkSpaceManagerWindow(VirtualScreen *vs)
1030
int lines, vspace, hspace, count, columns;
1031
unsigned int width, height, bwidth, bheight;
1032
char *name, *icon_name, *geometry;
1037
int x, y, strWid, wid;
1038
unsigned long border;
1040
XSetWindowAttributes attr;
1041
XWindowAttributes wattr;
1042
unsigned long attrmask;
1043
XSizeHints sizehints;
1046
XRectangle inc_rect;
1047
XRectangle logical_rect;
1049
name = Scr->workSpaceMgr.name;
1050
icon_name = Scr->workSpaceMgr.icon_name;
1051
geometry = Scr->workSpaceMgr.geometry;
1052
columns = Scr->workSpaceMgr.columns;
1053
vspace = Scr->workSpaceMgr.vspace;
1054
hspace = Scr->workSpaceMgr.hspace;
1055
font = Scr->workSpaceMgr.buttonFont;
1056
cp = Scr->workSpaceMgr.cp;
1057
border = Scr->workSpaceMgr.defBorderColor;
1060
for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1063
Scr->workSpaceMgr.count = count;
249
* Put together the actual window for the workspace manager. Called as
250
* part of CreateWorkSpaceManager() during startup, once per vscreen
251
* (since there's a separate window for each).
254
CreateWorkSpaceManagerWindow(VirtualScreen *vs)
256
unsigned int width, height;
260
const int vspace = Scr->workSpaceMgr.vspace;
261
const int hspace = Scr->workSpaceMgr.hspace;
262
const long count = Scr->workSpaceMgr.count;
264
/* No workspaces? Nothing to do. */
1064
265
if(count == 0) {
1070
columns = ((count - 1) / lines) + 1;
1073
lines = ((count - 1) / columns) + 1;
1075
Scr->workSpaceMgr.lines = lines;
1076
Scr->workSpaceMgr.columns = columns;
1079
for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1080
XmbTextExtents(font.font_set, ws->label, strlen(ws->label),
1081
&inc_rect, &logical_rect);
1082
wid = logical_rect.width;
1087
if(geometry != NULL) {
1088
mask = XParseGeometry(geometry, &x, &y, &width, &height);
1089
bwidth = (mask & WidthValue) ? ((width - (columns * hspace)) / columns) :
1091
bheight = (mask & HeightValue) ? ((height - (lines * vspace)) / lines) : 22;
1092
width = columns * (bwidth + hspace);
1093
height = lines * (bheight + vspace);
1095
if(!(mask & YValue)) {
1100
if(mask & XNegative) {
1102
gravity = (mask & YNegative) ? SouthEastGravity : NorthEastGravity;
270
* Work out grid. wSM.columns will be filled if specified in
271
* WorkSpaceManageGeometry, or uninitialized (0) if not.
275
columns = Scr->workSpaceMgr.columns;
278
columns = ((count - 1) / lines) + 1;
281
lines = ((count - 1) / columns) + 1;
283
Scr->workSpaceMgr.lines = lines;
284
Scr->workSpaceMgr.columns = columns;
288
/* Work out dimensions of stuff */
290
unsigned int bwidth, bheight;
291
unsigned short strWid;
293
const char *geometry = Scr->workSpaceMgr.geometry;
294
const int lines = Scr->workSpaceMgr.lines;
295
const int columns = Scr->workSpaceMgr.columns;
297
/* Figure longest label */
299
for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
301
XRectangle logical_rect;
303
const MyFont font = Scr->workSpaceMgr.buttonFont;
305
XmbTextExtents(font.font_set, ws->label, strlen(ws->label),
306
&inc_rect, &logical_rect);
307
wid = logical_rect.width;
314
* If WorkSpaceManagerGeometry is given, work from that. Else,
315
* create a workable minimum ourselves.
317
if(geometry != NULL) {
320
/* Base button/subwindow sizes */
321
bwidth = strWid + 10;
324
/* Adjust to WSMGeometry if specified */
325
mask = RLayoutXParseGeometry(Scr->Layout, geometry, &x, &y, &width, &height);
326
if(mask & WidthValue) {
327
bwidth = (width - (columns * hspace)) / columns;
329
if(mask & HeightValue) {
330
bheight = (height - (lines * vspace)) / lines;
333
/* Size of the whole thing is based off those */
334
width = columns * (bwidth + hspace);
335
height = lines * (bheight + vspace);
338
* If no Y given, put it at the bottom of the screen. If one
339
* is, just accept it. If it's a negative, we have to figure
340
* out where that actually is on this vscreen.
342
if(!(mask & YValue)) {
346
if(mask & YNegative) {
351
* If X is given, tweak as necessary for the vscreen
352
* location. Otherwise, put it in in something like the
356
if(mask & XNegative) {
358
gravity = (mask & YNegative) ? SouthEastGravity : NorthEastGravity;
361
gravity = (mask & YNegative) ? SouthWestGravity : NorthWestGravity;
1105
gravity = (mask & YNegative) ? SouthWestGravity : NorthWestGravity;
365
x = (vs->w - width) / 2;
366
gravity = (mask & YValue) ? ((mask & YNegative) ?
367
SouthGravity : NorthGravity) : SouthGravity;
1109
x = (vs->w - width) / 2;
1110
gravity = (mask & YValue) ? ((mask & YNegative) ?
1111
SouthGravity : NorthGravity) : SouthGravity;
1113
if(mask & YNegative) {
1114
y += vs->h - height;
1118
bwidth = strWid + 2 * Scr->WMgrButtonShadowDepth + 6;
1120
width = columns * (bwidth + hspace);
1121
height = lines * (bheight + vspace);
1122
x = (vs->w - width) / 2;
1124
gravity = NorthWestGravity;
1129
vs->wsw->width = Dummy;
1130
vs->wsw->height = Dummy;
1131
vs->wsw->bswl = calloc(Scr->workSpaceMgr.count, sizeof(ButtonSubwindow *));
1132
vs->wsw->mswl = calloc(Scr->workSpaceMgr.count, sizeof(MapSubwindow *));
371
/* No geom specified, come up with one */
372
bwidth = strWid + 2 * Scr->WMgrButtonShadowDepth + 6;
374
width = columns * (bwidth + hspace);
375
height = lines * (bheight + vspace);
376
x = (vs->w - width) / 2;
378
gravity = NorthWestGravity;
382
/* Set w/h to dummy values; ResizeWorkSpaceManager() writes real ones */
386
/* Allocate structs for map/button subwindows */
387
vs->wsw->bswl = calloc(count, sizeof(ButtonSubwindow *));
388
vs->wsw->mswl = calloc(count, sizeof(MapSubwindow *));
390
/* Create main window */
1134
391
vs->wsw->w = XCreateSimpleWindow(dpy, Scr->Root, x, y, width, height, 0,
1135
Scr->Black, cp.back);
1138
for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1139
Window mapsw, butsw;
1141
ButtonSubwindow *bsw;
1143
vs->wsw->bswl [ws->number] = bsw = malloc(sizeof(ButtonSubwindow));
1144
vs->wsw->mswl [ws->number] = msw = malloc(sizeof(MapSubwindow));
1147
XCreateSimpleWindow(dpy, vs->wsw->w,
1148
Dummy /* x */, Dummy /* y */,
1149
Dummy /* width */, Dummy /* height */,
1150
0, Scr->Black, ws->cp.back);
1153
XCreateSimpleWindow(dpy, vs->wsw->w,
1154
Dummy /* x */, Dummy /* y */,
1155
Dummy /* width */, Dummy /* height */,
1156
1, border, ws->cp.back);
1158
if(vs->wsw->state == WMS_buttons) {
1159
XMapWindow(dpy, butsw);
1162
XMapWindow(dpy, mapsw);
1165
vs->wsw->mswl [ws->number]->wl = NULL;
1166
if(useBackgroundInfo) {
1167
if(ws->image == NULL || Scr->NoImagesInWorkSpaceManager) {
1168
XSetWindowBackground(dpy, mapsw, ws->backcp.back);
1171
XSetWindowBackgroundPixmap(dpy, mapsw, ws->image->pixmap);
1175
if(Scr->workSpaceMgr.defImage == NULL || Scr->NoImagesInWorkSpaceManager) {
1176
XSetWindowBackground(dpy, mapsw, Scr->workSpaceMgr.defColors.back);
1179
XSetWindowBackgroundPixmap(dpy, mapsw, Scr->workSpaceMgr.defImage->pixmap);
1182
XClearWindow(dpy, butsw);
1190
sizehints.flags = USPosition | PBaseSize | PMinSize | PResizeInc |
1194
sizehints.base_width = columns * hspace;
1195
sizehints.base_height = lines * vspace;
1196
sizehints.width_inc = columns;
1197
sizehints.height_inc = lines;
1198
sizehints.min_width = columns * (hspace + 2);
1199
sizehints.min_height = lines * (vspace + 2);
1200
sizehints.win_gravity = gravity;
1202
wmhints.flags = InputHint | StateHint;
1203
wmhints.input = True;
1204
wmhints.initial_state = NormalState;
1206
XmbSetWMProperties(dpy, vs->wsw->w, name, icon_name, NULL, 0,
1207
&sizehints, &wmhints, NULL);
392
Scr->Black, Scr->workSpaceMgr.cp.back);
396
* Create the map and button subwindows for each workspace
401
for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
403
ButtonSubwindow *bsw;
405
const unsigned long border = Scr->workSpaceMgr.defBorderColor;
408
vs->wsw->bswl[ws->number] = bsw
409
= calloc(1, sizeof(ButtonSubwindow));
410
vs->wsw->mswl[ws->number] = msw = calloc(1, sizeof(MapSubwindow));
413
* Create windows for button/map. ResizeWorkSpaceManager()
414
* sets the real sizes and positions, so we dummy 'em.
416
bsw->w = XCreateSimpleWindow(dpy, vs->wsw->w,
417
Dummy, Dummy, Dummy, Dummy,
418
0, Scr->Black, ws->cp.back);
420
msw->w = XCreateSimpleWindow(dpy, vs->wsw->w,
421
Dummy, Dummy, Dummy, Dummy,
422
1, border, ws->cp.back);
424
/* Map whichever is up by default */
425
if(vs->wsw->state == WMS_buttons) {
426
XMapWindow(dpy, bsw->w);
429
XMapWindow(dpy, msw->w);
432
/* Setup background on map-state window */
433
/* XXX X-ref CTAG_BGDRAW in CreateWorkSpaceManager() */
434
if(useBackgroundInfo) {
435
if(ws->image == NULL || Scr->NoImagesInWorkSpaceManager) {
436
XSetWindowBackground(dpy, msw->w, ws->backcp.back);
439
XSetWindowBackgroundPixmap(dpy, msw->w, ws->image->pixmap);
443
if(Scr->workSpaceMgr.defImage == NULL || Scr->NoImagesInWorkSpaceManager) {
444
XSetWindowBackground(dpy, msw->w, Scr->workSpaceMgr.defColors.back);
447
XSetWindowBackgroundPixmap(dpy, msw->w, Scr->workSpaceMgr.defImage->pixmap);
452
* Clear out button subwin; PaintWorkSpaceManager() fills it
453
* in. Is this really necessary?
455
XClearWindow(dpy, bsw->w);
460
/* Set WM properties */
462
XSizeHints sizehints;
464
const int lines = Scr->workSpaceMgr.lines;
465
const int columns = Scr->workSpaceMgr.columns;
466
const char *name = Scr->workSpaceMgr.name;
467
const char *icon_name = Scr->workSpaceMgr.icon_name;
469
sizehints.flags = USPosition | PBaseSize | PMinSize | PResizeInc
473
sizehints.base_width = columns * hspace;
474
sizehints.base_height = lines * vspace;
475
sizehints.width_inc = columns;
476
sizehints.height_inc = lines;
477
sizehints.min_width = columns * (hspace + 2);
478
sizehints.min_height = lines * (vspace + 2);
479
sizehints.win_gravity = gravity;
481
wmhints.flags = InputHint | StateHint;
482
wmhints.input = True;
483
wmhints.initial_state = NormalState;
485
XmbSetWMProperties(dpy, vs->wsw->w, name, icon_name, NULL, 0,
486
&sizehints, &wmhints, NULL);
490
/* Create our TwmWindow wrapping around it */
1209
491
tmp_win = AddWindow(vs->wsw->w, AWT_WORKSPACE_MANAGER,
1210
492
Scr->iconmgr, vs);
1356
801
vs->wsw->state = WMS_buttons;
1360
* Verify if a window may be added to the workspace map.
1361
* This is not allowed for
1363
* - the occupy window
1364
* - workspace manager windows
1365
* - or, optionally, windows with full occupation.
1368
WMapWindowMayBeAdded(TwmWindow *win)
1370
if(win->isiconmgr) {
1373
if(win == Scr->workSpaceMgr.occupyWindow->twm_win) {
1379
if(Scr->workSpaceMgr.noshowoccupyall &&
1380
win->occupation == fullOccupation) {
1386
void WMapAddWindow(TwmWindow *win)
1390
if(!WMapWindowMayBeAdded(win)) {
1394
for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1395
if(OCCUPY(win, ws)) {
1396
WMapAddToList(win, ws);
1401
void WMapDestroyWindow(TwmWindow *win)
1405
for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1406
if(OCCUPY(win, ws)) {
1407
WMapRemoveFromList(win, ws);
1410
/* XXX Better belongs inline in caller or separate func? */
1411
if(win == occupyWin) {
1412
OccupyWindow *occwin = Scr->workSpaceMgr.occupyWindow;
1413
XUnmapWindow(dpy, occwin->twm_win->frame);
1414
occwin->twm_win->mapped = false;
1415
occwin->twm_win->occupation = 0;
1420
void WMapMapWindow(TwmWindow *win)
1426
for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
1427
for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1428
for(wl = vs->wsw->mswl [ws->number]->wl; wl != NULL; wl = wl->next) {
1429
if(wl->twm_win == win) {
1430
XMapWindow(dpy, wl->w);
1431
WMapRedrawName(vs, wl);
1439
void WMapSetupWindow(TwmWindow *win, int x, int y, int w, int h)
1445
if(win->isiconmgr) {
1456
ResizeWorkSpaceManager(win->vs, win);
1459
if(win == Scr->workSpaceMgr.occupyWindow->twm_win) {
1463
ResizeOccupyWindow(win);
1466
for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
1467
WorkSpaceWindow *wsw = vs->wsw;
1468
float wf = (float)(wsw->wwidth - 2) / (float) vs->w;
1469
float hf = (float)(wsw->wheight - 2) / (float) vs->h;
1471
for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1472
for(wl = wsw->mswl [ws->number]->wl; wl != NULL; wl = wl->next) {
1473
if(win == wl->twm_win) {
1474
wl->x = (int)(x * wf);
1475
wl->y = (int)(y * hf);
1477
XMoveWindow(dpy, wl->w, wl->x, wl->y);
1480
wl->width = (unsigned int)((w * wf) + 0.5);
1481
wl->height = (unsigned int)((h * hf) + 0.5);
1482
if(!Scr->use3Dwmap) {
1489
if(wl->height < 1) {
1492
XMoveResizeWindow(dpy, wl->w, wl->x, wl->y, wl->width, wl->height);
1501
void WMapIconify(TwmWindow *win)
1511
for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
1512
for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1513
for(wl = vs->wsw->mswl [ws->number]->wl; wl != NULL; wl = wl->next) {
1514
if(win == wl->twm_win) {
1515
XUnmapWindow(dpy, wl->w);
1523
void WMapDeIconify(TwmWindow *win)
1533
for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
1534
for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1535
for(wl = vs->wsw->mswl [ws->number]->wl; wl != NULL; wl = wl->next) {
1536
if(win == wl->twm_win) {
1537
if(Scr->NoRaiseDeicon) {
1538
XMapWindow(dpy, wl->w);
1541
XMapRaised(dpy, wl->w);
1543
WMapRedrawName(win->vs, wl);
1551
void WMapRaiseLower(TwmWindow *win)
1555
for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1556
if(OCCUPY(win, ws)) {
1562
void WMapLower(TwmWindow *win)
1566
for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1567
if(OCCUPY(win, ws)) {
1573
void WMapRaise(TwmWindow *win)
1577
for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1578
if(OCCUPY(win, ws)) {
1584
void WMapRestack(WorkSpace *ws)
1591
Window *children, *smallws;
1592
unsigned int number;
1596
XQueryTree(dpy, Scr->Root, &root, &parent, &children, &number);
1597
smallws = calloc(number, sizeof(Window));
1599
for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
1601
for(i = number - 1; i >= 0; i--) {
1602
if(!(win = GetTwmWindow(children [i]))) {
1605
if(win->frame != children [i]) {
1606
continue; /* skip icons */
1608
if(! OCCUPY(win, ws)) {
1612
fprintf(tracefile, "WMapRestack : w = %lx, win = %p\n", children [i],
1616
for(wl = vs->wsw->mswl [ws->number]->wl; wl != NULL; wl = wl->next) {
1618
fprintf(tracefile, "WMapRestack : wl = %p, twm_win = %p\n", (void *)wl,
1619
(void *)wl->twm_win);
1622
if(win == wl->twm_win) {
1623
smallws [j++] = wl->w;
1628
XRestackWindows(dpy, smallws, j);
1635
void WMapUpdateIconName(TwmWindow *win)
1641
for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
1642
for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1643
for(wl = vs->wsw->mswl [ws->number]->wl; wl != NULL; wl = wl->next) {
1644
if(win == wl->twm_win) {
1645
WMapRedrawName(vs, wl);
1653
void WMgrHandleKeyReleaseEvent(VirtualScreen *vs, XEvent *event)
1657
keysym = XLookupKeysym((XKeyEvent *) event, 0);
1661
if(keysym == XK_Control_L || keysym == XK_Control_R) {
1662
/* DontToggleWorkSpaceManagerState added 20040607 by dl*/
1663
if(!Scr->DontToggleWorkspaceManagerState) {
1664
WMapToggleState(vs);
1670
void WMgrHandleKeyPressEvent(VirtualScreen *vs, XEvent *event)
1679
keysym = XLookupKeysym((XKeyEvent *) event, 0);
1683
if(keysym == XK_Control_L || keysym == XK_Control_R) {
1684
/* DontToggleWorkSpaceManagerState added 20040607 by dl*/
1685
if(!Scr->DontToggleWorkspaceManagerState) {
1686
WMapToggleState(vs);
808
****************************************************************
810
* Handlers for mouse/key actions in the WSM
812
****************************************************************
816
* Key press/release events in the WSM. A major use (and only for
817
* release) is the Ctrl-key switching between map and button state. The
818
* other use is on-the-fly renaming of workspaces by typing in the
822
WMgrHandleKeyReleaseEvent(VirtualScreen *vs, XEvent *event)
826
keysym = XLookupKeysym((XKeyEvent *) event, 0);
830
if(keysym == XK_Control_L || keysym == XK_Control_R) {
831
/* DontToggleWorkSpaceManagerState added 20040607 by dl*/
832
if(!Scr->DontToggleWorkspaceManagerState) {
840
WMgrHandleKeyPressEvent(VirtualScreen *vs, XEvent *event)
844
/* Check if we're using Control to toggle the state */
846
KeySym keysym = XLookupKeysym((XKeyEvent *) event, 0);
850
if(keysym == XK_Control_L || keysym == XK_Control_R) {
851
/* DontToggleWorkSpaceManagerState added 20040607 by dl*/
852
if(!Scr->DontToggleWorkspaceManagerState) {
859
/* Otherwise, key presses do nothing in map state */
1690
860
if(vs->wsw->state == WMS_map) {
865
* If we're typing in a button-state WSM, and the mouse is on one of
866
* the buttons, that means we're changing the name, so do that dance.
1694
868
for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1695
if(vs->wsw->bswl [ws->number]->w == event->xkey.subwindow) {
869
if(vs->wsw->bswl[ws->number]->w == event->xkey.subwindow) {
1699
873
if(ws == NULL) {
874
/* Not on a button, nothing to do */
1703
strcpy(name, ws->label);
1704
lname = strlen(name);
1705
len = XLookupString(&(event->xkey), key, 16, NULL, NULL);
1706
for(i = 0; i < len; i++) {
1711
else if((k == 127) || (k == 8)) {
1720
name [lname] = '\0';
1721
ws->label = realloc(ws->label, (strlen(name) + 1));
1722
strcpy(ws->label, name);
1723
if(ws == vs->wsw->currentwspc) {
1724
PaintWsButton(WSPCWINDOW, vs, vs->wsw->bswl [ws->number]->w, ws->label, ws->cp,
1728
PaintWsButton(WSPCWINDOW, vs, vs->wsw->bswl [ws->number]->w, ws->label, ws->cp,
888
/* Look up what keystrokes are queued. Arbitrary buf size */
889
nkeys = XLookupString(&(event->xkey), keys, 16, NULL, NULL);
891
/* Label length can't grow to more than cur+nkeys */
892
nlen = strlen(ws->label);
893
newname = malloc(nlen + nkeys + 1);
894
strcpy(newname, ws->label);
896
/* Iterate over the passed keystrokes */
897
for(int i = 0 ; i < nkeys ; i++) {
898
unsigned char k = keys[i];
901
/* Printable chars append to the string */
904
else if((k == 127) || (k == 8)) {
906
* DEL or BS back up a char.
908
* XXX Would it be more generally correct to do this via
909
* keysyms, in the face of changed keyboard mappings or
910
* significantly differing locales?
917
/* Any other char stops the process dead */
921
/* Now ends where it ends */
922
newname[nlen] = '\0';
930
/* Redraw the button with the new label */
932
ButtonState bs = (ws == vs->wsw->currentwspc) ? on : off;
934
PaintWsButton(WSPCWINDOW, vs, vs->wsw->bswl[ws->number]->w, ws->label,
1733
void WMgrHandleButtonEvent(VirtualScreen *vs, XEvent *event)
941
* Mouse clicking in WSM. Gets called on button press (not release). In
942
* the simple case, that's just switching workspaces. In the more
943
* complex, it's changing window occupation in various different ways, or
944
* even moving windows. When that's happening, it internally hijacks
945
* button/motion/exposure events and implements them for the moving, with
946
* magic escapes if it gets them for something else. Ew.
949
WMgrHandleButtonEvent(VirtualScreen *vs, XEvent *event)
1735
WorkSpaceWindow *mw;
1736
WorkSpace *ws, *oldws, *newws, *cws;
1740
unsigned int W0, H0, bw;
1743
Window w = 0, sw, parent;
1744
int X0, Y0, X1, Y1, XW, YW, XSW, YSW;
1745
Position newX = 0, newY = 0, winX = 0, winY = 0;
1748
unsigned int button;
1749
unsigned int modifier;
1750
XSetWindowAttributes attrs;
1752
bool alreadyvivible, realmovemode, startincurrent;
1755
parent = event->xbutton.window;
1756
sw = event->xbutton.subwindow; /* mini-window in ws manager */
1758
button = event->xbutton.button;
1759
modifier = event->xbutton.state;
1760
etime = event->xbutton.time;
951
WorkSpace *oldws, *newws;
957
Position newX = 0, newY = 0, winX = 0, winY = 0;
958
bool alreadyvivible, realmovemode;
959
const WorkSpaceWindow *mw = vs->wsw;
961
/* Shortcuts into the event */
962
const Window parent = event->xbutton.window; // Map/button for WS
963
const Window sw = event->xbutton.subwindow; // Map mini-win
964
const Time etime = event->xbutton.time;
965
const unsigned int button = event->xbutton.button;
966
const unsigned int modifier = event->xbutton.state;
969
/* If we're in button state, we're just clicking to change */
1762
970
if(vs->wsw->state == WMS_buttons) {
1763
972
for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1764
if(vs->wsw->bswl [ws->number]->w == parent) {
973
if(vs->wsw->bswl[ws->number]->w == parent) {
974
GotoWorkSpace(vs, ws);
1771
GotoWorkSpace(vs, ws);
1775
for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1776
if(vs->wsw->mswl [ws->number]->w == parent) {
982
* If we get this far, we're in map state, where things are more
983
* complicated. A simple click/release means change here too, but
984
* there's also the possibility of dragging a subwindow around to
985
* change its window's occupation.
988
/* Find what workspace we're clicking in */
989
for(oldws = Scr->workSpaceMgr.workSpaceList ; oldws != NULL ;
990
oldws = oldws->next) {
991
if(vs->wsw->mswl[oldws->number]->w == parent) {
996
/* None? We're done here. */
1001
* If clicked in the workspace but outside a window, we can only be
1002
* switching workspaces. So just do that, and we're done.
1783
1004
if(sw == (Window) 0) {
1785
* If clicked in the workspace but outside a window,
1786
* only switch workspaces.
1788
GotoWorkSpace(vs, ws);
1005
GotoWorkSpace(vs, oldws);
1009
/* Use the context to find the winlist entry for this window */
1793
1010
if(XFindContext(dpy, sw, MapWListContext, (XPointer *) &wl) == XCNOENT) {
1796
1013
win = wl->twm_win;
1016
* Sometimes we skip transients, so do so. XXX Should this
1797
1019
if((! Scr->TransientHasOccupation) && win->istransient) {
1801
XTranslateCoordinates(dpy, Scr->Root, sw, event->xbutton.x_root,
1802
event->xbutton.y_root,
1804
realmovemode = (Scr->ReallyMoveInWorkspaceManager && !(modifier & ShiftMask)) ||
1805
(!Scr->ReallyMoveInWorkspaceManager && (modifier & ShiftMask));
1806
startincurrent = (oldws == vs->wsw->currentwspc);
1024
* Are we trying to actually move the window, by moving its avatar in
1025
* the WSM? If ReallyMoveInWorkspaceManager is set, we're moving on
1026
* click, but not in shift-click. If it's not, it's the reverse.
1028
* XXX This interacts really oddly and badly when you're also moving
1029
* the window from WS to WS.
1031
realmovemode = false;
1032
if(Scr->ReallyMoveInWorkspaceManager) {
1033
if(!(modifier & ShiftMask)) {
1034
realmovemode = true;
1037
else if(modifier & ShiftMask) {
1038
realmovemode = true;
1042
* Frob screen-wide OpaqueMove as necessary for this window's
1807
1046
if(win->OpaqueMove) {
1810
sw2 = win->frame_width * win->frame_height;
1812
if(sw2 > ((ss * Scr->OpaqueMoveThreshold) / 100)) {
1813
Scr->OpaqueMove = false;
1047
if(Scr->OpaqueMoveThreshold >= 200) {
1816
1048
Scr->OpaqueMove = true;
1051
const unsigned long winsz = win->frame_width * win->frame_height;
1052
const unsigned long scrsz = vs->w * vs->h;
1053
const float sf = Scr->OpaqueMoveThreshold / 100.0;
1054
if(winsz > (scrsz * sf)) {
1055
Scr->OpaqueMove = false;
1058
Scr->OpaqueMove = true;
1820
1063
Scr->OpaqueMove = false;
1823
1067
* Buttons inside the workspace manager, when clicking on the
1824
1068
* representation of a window:
1862
1148
win->title_height + win->frame_bw3D);
1868
occupation = win->occupation & ~(1 << oldws->number);
1869
if(occupation != 0) {
1870
ChangeOccupation(win, occupation);
1157
* For the button 3 or anything else case, there's no dragging or
1158
* anything, so they do their thing and just immediately return.
1161
int newocc = win->occupation & ~(1 << oldws->number);
1163
ChangeOccupation(win, newocc);
1878
1173
* Keep dragging the representation of the window
1175
* XXX Look back at this and see if we can move it to an inner
1176
* function for readability...
1880
wf = (float)(mw->wwidth - 1) / (float) vs->w;
1881
hf = (float)(mw->wheight - 1) / (float) vs->h;
1882
XGrabPointer(dpy, mw->w, False,
1883
ButtonPressMask | ButtonMotionMask | ButtonReleaseMask,
1884
GrabModeAsync, GrabModeAsync, mw->w, Scr->MoveCursor, CurrentTime);
1886
alreadyvivible = false;
1890
XMaskEvent(dpy, ButtonPressMask | ButtonMotionMask |
1891
ButtonReleaseMask | ExposureMask, &ev);
1892
switch(ev.xany.type) {
1894
case ButtonRelease :
1895
if(ev.xbutton.button != button) {
1179
const float wf = (float)(mw->wwidth - 1) / (float) vs->w;
1180
const float hf = (float)(mw->wheight - 1) / (float) vs->h;
1185
/* Figure where in the subwindow the click was, and stash in XW/YW */
1186
XTranslateCoordinates(dpy, Scr->Root, sw, event->xbutton.x_root,
1187
event->xbutton.y_root,
1191
* Grab the pointer, lock it into the WSM, and get the events
1192
* related to buttons and movement. We don't need
1193
* PointerMotionMask, since that would only happen after buttons
1194
* are released, and we'll be done by then.
1196
XGrabPointer(dpy, mw->w, False,
1197
ButtonPressMask | ButtonMotionMask | ButtonReleaseMask,
1198
GrabModeAsync, GrabModeAsync, mw->w, Scr->MoveCursor,
1201
/* Start handling events until we're done */
1202
alreadyvivible = false;
1207
/* Grab the next event and handle */
1208
XMaskEvent(dpy, ButtonPressMask | ButtonMotionMask |
1209
ButtonReleaseMask | ExposureMask, &ev);
1210
switch(ev.xany.type) {
1212
/* Something got exposed */
1213
if(ev.xexpose.window == w) {
1215
* The win we're working with? We know how to do
1218
WMapRedrawWindow(w, W0, H0, wl->cp,
1219
wl->twm_win->icon_name);
1223
/* Else, delegate to our global dispatcher */
1899
newX = ev.xbutton.x;
1900
newY = ev.xbutton.y;
1904
newX = ev.xmotion.x;
1905
newY = ev.xmotion.y;
1230
case ButtonRelease : {
1232
* Events for buttons other than the one whose press
1233
* started this activity are totally ignored.
1235
if(ev.xbutton.button != button) {
1240
* Otherwise, this is a press/release of the button
1241
* that started things. Though I'm not sure how it
1242
* could be a press, since it was already pressed.
1243
* Regardless, this is our exit condition. Fall
1244
* through into the Motion case to handle any
1245
* remaining movement.
1249
newX = ev.xbutton.x;
1250
newY = ev.xbutton.y;
1908
for(cws = Scr->workSpaceMgr.workSpaceList;
1911
msw = vs->wsw->mswl [cws->number];
1912
if((newX >= msw->x) && (newX < msw->x + mw->wwidth) &&
1913
(newY >= msw->y) && (newY < msw->y + mw->wheight)) {
1253
/* Everything remaining is motion handling */
1254
case MotionNotify : {
1255
/* If we fell through from above, no new movement */
1257
newX = ev.xmotion.x;
1258
newY = ev.xmotion.y;
1261
/* Lots to do if we're moving the window for real */
1267
/* Did the move start in the currently visible WS? */
1268
bool startincurrent = (oldws == vs->wsw->currentwspc);
1270
/* Find the workspace we wound up in */
1271
for(cws = Scr->workSpaceMgr.workSpaceList ;
1274
msw = vs->wsw->mswl [cws->number];
1276
&& (newX < msw->x + mw->wwidth)
1278
&& (newY < msw->y + mw->wheight)) {
1922
msw = vs->wsw->mswl [cws->number];
1923
XTranslateCoordinates(dpy, mw->w, msw->w,
1924
winX, winY, &XSW, &YSW, &junkW);
1925
winX = (int)(XSW / wf);
1926
winY = (int)(YSW / hf);
1927
if(Scr->DontMoveOff) {
1928
int width = win->frame_width;
1929
int height = win->frame_height;
1931
if((winX < Scr->BorderLeft) && ((Scr->MoveOffResistance < 0) ||
1932
(winX > Scr->BorderLeft - Scr->MoveOffResistance))) {
1933
winX = Scr->BorderLeft;
1934
newX = msw->x + XW + Scr->BorderLeft * mw->wwidth / vs->w;
1936
if(((winX + width) > vs->w - Scr->BorderRight) &&
1937
((Scr->MoveOffResistance < 0) ||
1938
((winX + width) < vs->w - Scr->BorderRight + Scr->MoveOffResistance))) {
1939
winX = vs->w - Scr->BorderRight - width;
1940
newX = msw->x + mw->wwidth *
1941
(1 - Scr->BorderRight / (double) vs->w) - wl->width + XW - 2;
1943
if((winY < Scr->BorderTop) && ((Scr->MoveOffResistance < 0) ||
1944
(winY > Scr->BorderTop - Scr->MoveOffResistance))) {
1945
winY = Scr->BorderTop;
1946
newY = msw->y + YW + Scr->BorderTop * mw->height / vs->h;
1948
if(((winY + height) > vs->h - Scr->BorderBottom) &&
1949
((Scr->MoveOffResistance < 0) ||
1950
((winY + height) < vs->h - Scr->BorderBottom + Scr->MoveOffResistance))) {
1951
winY = vs->h - Scr->BorderBottom - height;
1952
newY = msw->y + mw->wheight *
1953
(1 - Scr->BorderBottom / (double) vs->h) - wl->height + YW - 2;
1956
WMapSetupWindow(win, winX, winY, -1, -1);
1957
if(Scr->ShowWinWhenMovingInWmgr) {
1960
if(cws == vs->wsw->currentwspc) {
1961
if(alreadyvivible) {
1288
* Mouse is wherever it started inside the
1289
* subwindow, so figure the X/Y of the top left
1290
* of the subwindow from there. (coords relative
1291
* to the whole WSM because of grab)
1296
/* XXX redundant w/previous? */
1297
msw = vs->wsw->mswl[cws->number];
1300
* Figure where those coords are relative to the
1301
* per-workspace window.
1303
XTranslateCoordinates(dpy, mw->w, msw->w,
1304
winX, winY, &XSW, &YSW, &junkW);
1307
* Now rework the win[XY] to be the coordinates
1308
* the window would be in the whole screen, based
1309
* on the [XY]SW inside the map, using our scale
1312
winX = (int)(XSW / wf);
1313
winY = (int)(YSW / hf);
1316
* Clip to the screen if DontMoveOff is set.
1318
* XXX Can we use the Constrain*() functions for
1319
* this, instead of implementing icky magic
1322
if(Scr->DontMoveOff) {
1323
const int width = win->frame_width;
1324
const int height = win->frame_height;
1326
if((winX < Scr->BorderLeft) && ((Scr->MoveOffResistance < 0) ||
1327
(winX > Scr->BorderLeft - Scr->MoveOffResistance))) {
1328
winX = Scr->BorderLeft;
1329
newX = msw->x + XW + Scr->BorderLeft * mw->wwidth / vs->w;
1331
if(((winX + width) > vs->w - Scr->BorderRight) &&
1332
((Scr->MoveOffResistance < 0) ||
1333
((winX + width) < vs->w - Scr->BorderRight + Scr->MoveOffResistance))) {
1334
winX = vs->w - Scr->BorderRight - width;
1335
newX = msw->x + mw->wwidth *
1336
(1 - Scr->BorderRight / (double) vs->w) - wl->width + XW - 2;
1338
if((winY < Scr->BorderTop) && ((Scr->MoveOffResistance < 0) ||
1339
(winY > Scr->BorderTop - Scr->MoveOffResistance))) {
1340
winY = Scr->BorderTop;
1341
newY = msw->y + YW + Scr->BorderTop * mw->height / vs->h;
1343
if(((winY + height) > vs->h - Scr->BorderBottom) &&
1344
((Scr->MoveOffResistance < 0) ||
1345
((winY + height) < vs->h - Scr->BorderBottom + Scr->MoveOffResistance))) {
1346
winY = vs->h - Scr->BorderBottom - height;
1347
newY = msw->y + mw->wheight
1348
* (1 - Scr->BorderBottom / (double) vs->h)
1349
* - wl->height + YW - 2;
1354
/* Setup the avatar for the new position of win */
1355
WMapSetupWindow(win, winX, winY, -1, -1);
1358
* If SWWMIW, we already made sure above the
1359
* window is always visible on the screen. So we
1360
* don't need to do any of the following steps to
1361
* maybe show it or maybe un-show it, since we
1362
* know it's already always shown.
1364
if(Scr->ShowWinWhenMovingInWmgr) {
1369
* If we wound up in the same workspace as is
1370
* being displayed on the screen, we need to make
1371
* sure that window is showing up on the screen
1372
* as a "about to be occupied here if you release
1373
* the button" indication.
1375
if(cws == vs->wsw->currentwspc) {
1376
if(alreadyvivible) {
1377
/* Unless it's already there */
1380
if(Scr->OpaqueMove) {
1381
XMoveWindow(dpy, win->frame, winX, winY);
1382
DisplayWin(vs, win);
1385
MoveOutline(Scr->Root,
1386
winX - win->frame_bw,
1387
winY - win->frame_bw,
1388
win->frame_width + 2 * win->frame_bw,
1389
win->frame_height + 2 * win->frame_bw,
1391
win->title_height + win->frame_bw3D);
1393
alreadyvivible = true;
1396
* We already moved it, skip past the other
1397
* code trying to move it in other cases.
1403
* If it's for whatever reason not being shown on
1404
* the screen, then we don't need to move it; hop
1405
* straight to moving the avatar.
1407
if(!alreadyvivible) {
1412
* So it _is_ being shown. If it's not supposed
1413
* to be here, hide it away (don't need to worry
1414
* about AlwaysShow, it would have skipped past
1415
* us from ab0ve). Also, if we started moving
1416
* the window out of the visible workspace with
1417
* button 1, it's gonna not be here if you
1418
* release, so hide it away.
1420
if(!OCCUPY(win, vs->wsw->currentwspc) ||
1421
(startincurrent && (button == 1))) {
1422
if(Scr->OpaqueMove) {
1424
XMoveWindow(dpy, win->frame, winX, winY);
1427
MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
1429
alreadyvivible = false;
1435
* However we get here, the real window is
1436
* visible and needs to be moved. So move it.
1964
1438
if(Scr->OpaqueMove) {
1965
1439
XMoveWindow(dpy, win->frame, winX, winY);
1966
DisplayWin(vs, win);
1969
1442
MoveOutline(Scr->Root,
1970
winX - win->frame_bw, winY - win->frame_bw,
1443
winX - win->frame_bw,
1444
winY - win->frame_bw,
1971
1445
win->frame_width + 2 * win->frame_bw,
1972
1446
win->frame_height + 2 * win->frame_bw,
1974
1448
win->title_height + win->frame_bw3D);
1976
alreadyvivible = true;
1979
if(!alreadyvivible) {
1982
if(!OCCUPY(win, vs->wsw->currentwspc) ||
1983
(startincurrent && (button == 1))) {
1984
if(Scr->OpaqueMove) {
1986
XMoveWindow(dpy, win->frame, winX, winY);
1989
MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
1991
alreadyvivible = false;
1995
if(Scr->OpaqueMove) {
1996
XMoveWindow(dpy, win->frame, winX, winY);
1999
MoveOutline(Scr->Root,
2000
winX - win->frame_bw, winY - win->frame_bw,
2001
win->frame_width + 2 * win->frame_bw,
2002
win->frame_height + 2 * win->frame_bw,
2004
win->title_height + win->frame_bw3D);
2008
XMoveWindow(dpy, w, newX - XW, newY - YW);
2011
if(ev.xexpose.window == w) {
2012
WMapRedrawWindow(w, W0, H0, wl->cp, wl->twm_win->icon_name);
1454
* Just move the subwindow in the map to the new
1457
XMoveWindow(dpy, w, newX - XW, newY - YW);
1459
/* And we're done. Next event! */
2021
1467
* Finished with dragging (button released).
2023
1469
if(realmovemode) {
1470
/* Moving the real window? Move the real window. */
2024
1471
if(Scr->ShowWinWhenMovingInWmgr || alreadyvivible) {
2025
1472
if(Scr->OpaqueMove && !OCCUPY(win, vs->wsw->currentwspc)) {
2026
1473
Vanish(vs, win);
2103
1631
WMapRestack(newws);
1637
* Should actually never hit this state; only 1/2 would have
1638
* gotten this far into the code...
1644
/* Clean up our temporary moving-around-in the WSM window */
2110
1645
XDestroyWindow(dpy, w);
2114
* This is really more util.c fodder, but leaving it here for now because
2115
* it's only used once in the below func. If we start finding external
2116
* uses for it, it should be moved.
1652
****************************************************************
1654
* Functions for doing things with subwindows in the WSM in map state
1656
****************************************************************
1660
* Backend for mapping up windows in the WSM map.
2119
InvertColorPair(ColorPair *cp)
2124
cp->fore = cp->back;
2127
cp->shadc = cp->shadd;
2131
void WMapRedrawName(VirtualScreen *vs, WinList wl)
2138
label = wl->twm_win->icon_name;
1663
wmap_mapwin_backend(TwmWindow *win, bool handleraise)
1669
for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
1670
for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1671
for(wl = vs->wsw->mswl[ws->number]->wl; wl != NULL; wl = wl->next) {
1672
if(win == wl->twm_win) {
1674
* When called via deiconify, we might have to do
1675
* stuff related to auto-raising the window while we
1676
* de-iconify. When called via a map request, the
1677
* window is always wherever it previously was in the
1680
if(!handleraise || Scr->NoRaiseDeicon) {
1681
XMapWindow(dpy, wl->w);
1684
XMapRaised(dpy, wl->w);
1686
WMapRedrawName(vs, wl);
1695
* Map up a window's subwindow in the map-mode WSM. Happens as a result
1696
* of getting (or faking) a Map request event. Notably, _not_ in the
1697
* process of de-iconifying a window; mostly as a result of _creating_
1698
* windows, or when a client maps itself without a request from us.
1700
* x-ref comment on WMapDeIconify() for some subtle distinctions between
1704
WMapMapWindow(TwmWindow *win)
1706
/* We don't do raise handling */
1707
wmap_mapwin_backend(win, false);
1712
* De-iconify a window in the WSM map. The opposite of WMapIconify(),
1713
* and different from WMapMapWindow() in complicated ways. This function
1714
* winds up getting called when a window is de-iconified via a ctwm
1718
WMapDeIconify(TwmWindow *win)
1720
/* If it's not showing anywhere, nothing to do. Is this possible? */
1725
/* Loop and map, handling raises if necessary */
1726
wmap_mapwin_backend(win, true);
1731
* Hide away a window in the WSM map. Happens when win is iconified;
1732
* different from destruction.
1735
WMapIconify(TwmWindow *win)
1745
for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
1746
for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1747
for(wl = vs->wsw->mswl[ws->number]->wl; wl != NULL; wl = wl->next) {
1748
if(win == wl->twm_win) {
1749
XUnmapWindow(dpy, wl->w);
1759
* Position a window in the WSM. Happens as a result of moving things.
1762
WMapSetupWindow(TwmWindow *win, int x, int y, int w, int h)
1766
/* If it's an icon manager, or not on a vscreen, nothing to do */
1767
if(win->isiconmgr || !win->vs) {
1771
/* If it's a WSM, we may be resetting size/position, but that's it */
1776
ResizeWorkSpaceManager(win->vs, win);
1780
/* If it's an occupy window, ditto */
1781
if(win == Scr->workSpaceMgr.occupyWindow->twm_win) {
1785
ResizeOccupyWindow(win);
1790
/* For anything else, we're potentially showing something */
1791
for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
1792
WorkSpaceWindow *wsw = vs->wsw;
1795
/* Scale factors for windows in the map */
1796
float wf = (float)(wsw->wwidth - 2) / (float) vs->w;
1797
float hf = (float)(wsw->wheight - 2) / (float) vs->h;
1800
* Loop around windows in each WS to find all the places the
1801
* requested window should show up.
1803
for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1804
MapSubwindow *msw = wsw->mswl[ws->number];
1806
for(WinList *wl = msw->wl; wl != NULL; wl = wl->next) {
1807
if(win == wl->twm_win) {
1809
wl->x = (int)(x * wf);
1810
wl->y = (int)(y * hf);
1812
/* Rescale if necessary and move */
1814
XMoveWindow(dpy, wl->w, wl->x, wl->y);
1817
wl->width = (unsigned int)((w * wf) + 0.5);
1818
wl->height = (unsigned int)((h * hf) + 0.5);
1819
if(!Scr->use3Dwmap) {
1826
if(wl->height < 1) {
1829
XMoveResizeWindow(dpy, wl->w, wl->x, wl->y,
1830
wl->width, wl->height);
1841
* Frontends for changing the stacking of windows in the WSM.
1843
* Strictly speaker, we have no ability to raise or lower a window in the
1844
* map; we only draw the whole stack. And these functions don't actually
1845
* change the stacking of a window, they're called as a _result_ of
1846
* changing the stacking, to notify the WSM to re-check and update
1847
* itself. So while conceptually we maintain a separation for our
1848
* callers between various reasons this is being called, the
1849
* implementations are identical.
1852
WMapRaiseLower(TwmWindow *win)
1856
for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1857
if(OCCUPY(win, ws)) {
1864
WMapLower(TwmWindow *win)
1866
WMapRaiseLower(win);
1870
WMapRaise(TwmWindow *win)
1872
WMapRaiseLower(win);
1877
* Backend for redoing the stacking of a window in the WSM.
1879
* XXX Since this tends to get called iteratively, there's probably
1880
* something better we can do than doing all this relatively expensive
1881
* stuff over and over...
1884
WMapRestack(WorkSpace *ws)
1887
Window root, parent; // Dummy
1888
Window *children, *smallws;
1889
unsigned int nchildren;
1891
/* Get a whole list of the windows on the screen */
1893
XQueryTree(dpy, Scr->Root, &root, &parent, &children, &nchildren);
1896
* We're presumably dealing with a [often very small] subset of them,
1897
* but just allocate space for the whole list; easier than trying to
1898
* shrink down, and really, how big can it possibly be?
1900
smallws = calloc(nchildren, sizeof(Window));
1902
/* Work it up per vscreen */
1903
for(VirtualScreen *vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
1905
const MapSubwindow *msw = vs->wsw->mswl[ws->number];
1907
/* Loop backward (from top to bottom of stack) */
1908
for(int i = nchildren - 1; i >= 0; i--) {
1909
TwmWindow *win = GetTwmWindow(children[i]);
1912
* Only care about certain windows. If it's not a window we
1913
* know about, or not a frame (e.g., an icon), or doesn't
1914
* occupy this workspace, skip it.
1916
if(win == NULL || win->frame != children[i] || !OCCUPY(win, ws)) {
1922
fprintf(tracefile, "WMapRestack : w = %lx, win = %p\n",
1923
children[i], (void *)win);
1927
/* Find this window in the list for the map of this WS */
1928
for(wl = msw->wl; wl != NULL; wl = wl->next) {
1931
fprintf(tracefile, "WMapRestack : wl = %p, twm_win = %p\n",
1932
(void *)wl, (void *)wl->twm_win);
1936
if(win == wl->twm_win) {
1937
/* There you are. Add into our list to restack. */
1938
smallws[j++] = wl->w;
1945
* Restack the windows in the map. Note that the order is
1946
* reversed from earlier; XQueryTree() returns bottom->top,
1947
* XRestackWindows() is passed top->bottom.
1949
XRestackWindows(dpy, smallws, j);
1962
****************************************************************
1964
* Bits related to the actual drawing of the windows in the map.
1966
****************************************************************
1970
* Update stuff in the WSM when win's icon name changes
1973
WMapUpdateIconName(TwmWindow *win)
1979
for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
1980
for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1981
for(wl = vs->wsw->mswl[ws->number]->wl; wl != NULL; wl = wl->next) {
1982
if(win == wl->twm_win) {
1983
WMapRedrawName(vs, wl);
1993
* Draw a window name into the window's representation in the map-state
1997
WMapRedrawName(VirtualScreen *vs, WinList *wl)
1999
ColorPair cp = wl->cp;
2141
2001
if(Scr->ReverseCurrentWorkspace && wl->wlist == vs->wsw->currentwspc) {
2142
2002
InvertColorPair(&cp);
2144
WMapRedrawWindow(wl->w, w, h, cp, label);
2004
WMapRedrawWindow(wl->w, wl->width, wl->height, cp, wl->twm_win->icon_name);
2147
static void WMapRedrawWindow(Window window, int width, int height,
2148
ColorPair cp, char *label)
2009
* Draw up a window's representation in the map-state WSM, with the
2012
* The drawing of the window name could probably be done a bit better.
2013
* The font size is based on a tiny fraction of the window's height, so
2014
* is probably usually too small to be useful, and often appears just as
2015
* some odd colored pixels at the top of the window.
2018
WMapRedrawWindow(Window window, int width, int height,
2019
ColorPair cp, const char *label)
2150
int x, y, strhei, strwid;
2152
XRectangle inc_rect;
2153
XRectangle logical_rect;
2154
XFontStruct **xfonts;
2022
const MyFont font = Scr->workSpaceMgr.windowFont;
2024
/* Blank out window background color */
2160
2025
XClearWindow(dpy, window);
2161
font = Scr->workSpaceMgr.windowFont;
2163
XmbTextExtents(font.font_set, label, strlen(label),
2164
&inc_rect, &logical_rect);
2165
strwid = logical_rect.width;
2166
strhei = logical_rect.height;
2167
if(strhei > height) {
2171
x = (width - strwid) / 2;
2176
fnum = XFontsOfFontSet(font.font_set, &xfonts, &font_names);
2177
for(i = 0, descent = 0; i < fnum; i++) {
2178
/* xf = xfonts[i]; */
2179
descent = ((descent < (xfonts[i]->max_bounds.descent)) ?
2180
(xfonts[i]->max_bounds.descent) : descent);
2183
y = ((height + strhei) / 2) - descent;
2027
/* Figure out where to position the name */
2029
XRectangle inc_rect;
2030
XRectangle logical_rect;
2033
XFontStruct **xfonts;
2037
XmbTextExtents(font.font_set, label, strlen(label),
2038
&inc_rect, &logical_rect);
2039
strwid = logical_rect.width;
2040
strhei = logical_rect.height;
2043
* If it's too tall to fit, just give up now.
2044
* XXX Probably should still do border stuff below...
2046
if(strhei > height) {
2050
x = (width - strwid) / 2;
2055
fnum = XFontsOfFontSet(font.font_set, &xfonts, &font_names);
2056
for(i = 0, descent = 0; i < fnum; i++) {
2057
/* xf = xfonts[i]; */
2058
descent = ((descent < (xfonts[i]->max_bounds.descent)) ?
2059
(xfonts[i]->max_bounds.descent) : descent);
2062
y = ((height + strhei) / 2) - descent;
2065
/* Draw up borders around the win */
2185
2066
if(Scr->use3Dwmap) {
2186
2067
Draw3DBorder(window, 0, 0, width, height, 1, cp, off, true, false);
2187
2068
FB(cp.fore, cp.back);
2191
2072
XFillRectangle(dpy, window, Scr->NormalGC, 0, 0, width, height);
2192
2073
FB(cp.fore, cp.back);
2076
/* Write in the name */
2194
2077
if(Scr->Monochrome != COLOR) {
2195
XmbDrawImageString(dpy, window, font.font_set, Scr->NormalGC, x, y, label,
2078
XmbDrawImageString(dpy, window, font.font_set, Scr->NormalGC, x, y,
2079
label, strlen(label));
2199
XmbDrawString(dpy, window, font.font_set, Scr->NormalGC, x, y, label,
2205
WMapAddToList(TwmWindow *win, WorkSpace *ws)
2082
XmbDrawString(dpy, window, font.font_set, Scr->NormalGC, x, y,
2083
label, strlen(label));
2091
* Processes for adding/removing windows from the WSM
2095
* Add a window into any appropriate WSMs' maps. Called during
2099
WMapAddWindow(TwmWindow *win)
2103
if(!WMapWindowMayBeAdded(win)) {
2107
for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
2108
if(OCCUPY(win, ws)) {
2109
WMapAddWindowToWorkspace(win, ws);
2116
* Create WSM representation of a given window in a given WS. Called
2117
* when windows get added to a workspace, either via WMapAddWindow()
2118
* during the AddWindow() process, or via an occupation change.
2120
* (previously: WMapAddToList())
2123
WMapAddWindowToWorkspace(TwmWindow *win, WorkSpace *ws)
2211
XSetWindowAttributes attr;
2212
unsigned long attrmask;
2127
/* Setup coloring for the window */
2215
2128
cp.back = win->title.back;
2216
2129
cp.fore = win->title.fore;
2217
2130
if(Scr->workSpaceMgr.windowcpgiven) {
2218
2131
cp.back = Scr->workSpaceMgr.windowcp.back;
2219
2132
GetColorFromList(Scr->workSpaceMgr.windowBackgroundL,
2220
win->full_name, &win->class, &cp.back);
2133
win->name, &win->class, &cp.back);
2221
2134
cp.fore = Scr->workSpaceMgr.windowcp.fore;
2222
2135
GetColorFromList(Scr->workSpaceMgr.windowForegroundL,
2223
win->full_name, &win->class, &cp.fore);
2136
win->name, &win->class, &cp.fore);
2225
2138
if(Scr->use3Dwmap && !Scr->BeNiceToColormap) {
2226
2139
GetShadeColors(&cp);
2228
for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
2229
wf = (float)(vs->wsw->wwidth - 2) / (float) vs->w;
2230
hf = (float)(vs->wsw->wheight - 2) / (float) vs->h;
2142
/* We need a copy in each VS */
2143
for(VirtualScreen *vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
2146
const float wf = (float)(vs->wsw->wwidth - 2) / (float) vs->w;
2147
const float hf = (float)(vs->wsw->wheight - 2) / (float) vs->h;
2148
MapSubwindow *msw = vs->wsw->mswl[ws->number];
2150
/* Put together its winlist entry */
2231
2151
wl = malloc(sizeof(struct winList));
2232
2152
wl->wlist = ws;
2233
2153
wl->x = (int)(win->frame_x * wf);
2234
2154
wl->y = (int)(win->frame_y * hf);
2235
2155
wl->width = (unsigned int)((win->frame_width * wf) + 0.5);
2236
2156
wl->height = (unsigned int)((win->frame_height * hf) + 0.5);
2160
/* Size the window bits */
2238
2162
if(!Scr->use3Dwmap) {
2240
2164
wl->width -= 2;
2241
2165
wl->height -= 2;
2246
2170
if(wl->height < 1) {
2247
2171
wl->height = 1;
2249
wl->w = XCreateSimpleWindow(dpy, vs->wsw->mswl [ws->number]->w, wl->x, wl->y,
2250
wl->width, wl->height, bw, Scr->Black, cp.back);
2252
if(Scr->BackingStore) {
2253
attr.backing_store = WhenMapped;
2254
attrmask |= CWBackingStore;
2174
/* Create its little window */
2175
wl->w = XCreateSimpleWindow(dpy, msw->w, wl->x, wl->y,
2176
wl->width, wl->height, bw,
2177
Scr->Black, cp.back);
2179
/* Setup cursor and attributes for it */
2181
XSetWindowAttributes attr;
2182
unsigned long attrmask;
2184
attr.cursor = handCursor;
2185
attrmask = CWCursor;
2187
if(Scr->BackingStore) {
2188
attr.backing_store = WhenMapped;
2189
attrmask |= CWBackingStore;
2192
XChangeWindowAttributes(dpy, wl->w, attrmask, &attr);
2256
attr.cursor = handCursor;
2257
attrmask |= CWCursor;
2258
XChangeWindowAttributes(dpy, wl->w, attrmask, &attr);
2195
/* Setup events and stash context bits */
2259
2196
XSelectInput(dpy, wl->w, ExposureMask);
2260
2197
XSaveContext(dpy, wl->w, TwmContext, (XPointer) vs->wsw->twm_win);
2261
2198
XSaveContext(dpy, wl->w, ScreenContext, (XPointer) Scr);
2262
2199
XSaveContext(dpy, wl->w, MapWListContext, (XPointer) wl);
2265
wl->next = vs->wsw->mswl [ws->number]->wl;
2266
vs->wsw->mswl [ws->number]->wl = wl;
2201
/* Link it onto the front of the list */
2206
* And map it, if its window is mapped. That'll kick an expose
2207
* event, which will work its way down to WMapRedrawWindow(), and
2267
2210
if(win->mapped) {
2268
2211
XMapWindow(dpy, wl->w);
2274
WMapRemoveFromList(TwmWindow *win, WorkSpace *ws)
2213
} // And around to the next vscreen
2218
* Remove a window from any WSM maps it's in. Called during window
2219
* destruction process.
2221
* (previously: WMapDestroyWindow())
2224
WMapRemoveWindow(TwmWindow *win)
2228
for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
2229
if(OCCUPY(win, ws)) {
2230
WMapRemoveWindowFromWorkspace(win, ws);
2235
* If it's a mapped occupy window, manually hide aways its bits in
2238
* XXX Better belongs inline in caller or separate func? This is the
2239
* only thing exposing occupyWin out of occupation.c.
2241
if(win == occupyWin) {
2242
OccupyWindow *occwin = Scr->workSpaceMgr.occupyWindow;
2243
XUnmapWindow(dpy, occwin->twm_win->frame);
2244
occwin->twm_win->mapped = false;
2245
occwin->twm_win->occupation = 0;
2252
* Remove window's WSM representation. Happens from WMapRemoveWindow()
2253
* as part of the window destruction process, and in the occupation
2256
* (previously: WMapRemoveFromList())
2259
WMapRemoveWindowFromWorkspace(TwmWindow *win, WorkSpace *ws)
2276
2261
VirtualScreen *vs;
2279
2263
for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
2280
prev = &vs->wsw->mswl [ws->number]->wl;
2283
if(win == wl->twm_win) {
2285
XDeleteContext(dpy, wl->w, TwmContext);
2286
XDeleteContext(dpy, wl->w, ScreenContext);
2287
XDeleteContext(dpy, wl->w, MapWListContext);
2288
XDestroyWindow(dpy, wl->w);
2264
WinList **prev = &vs->wsw->mswl[ws->number]->wl;
2266
/* Pull it out of the list and destroy it */
2267
for(WinList *wl = *prev ; wl != NULL ; wl = wl->next) {
2268
if(win != wl->twm_win) {
2298
static void ResizeWorkSpaceManager(VirtualScreen *vs, TwmWindow *win)
2300
int bwidth, bheight;
2301
int wwidth, wheight;
2311
neww = win->attr.width;
2312
newh = win->attr.height;
2313
if(neww == vs->wsw->width && newh == vs->wsw->height) {
2317
hspace = Scr->workSpaceMgr.hspace;
2318
vspace = Scr->workSpaceMgr.vspace;
2319
lines = Scr->workSpaceMgr.lines;
2320
columns = Scr->workSpaceMgr.columns;
2321
bwidth = (neww - (columns * hspace)) / columns;
2322
bheight = (newh - (lines * vspace)) / lines;
2323
wwidth = neww / columns;
2324
wheight = newh / lines;
2325
wf = (float)(wwidth - 2) / (float) vs->w;
2326
hf = (float)(wheight - 2) / (float) vs->h;
2330
for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
2331
MapSubwindow *msw = vs->wsw->mswl [ws->number];
2332
XMoveResizeWindow(dpy, vs->wsw->bswl [ws->number]->w,
2333
i * (bwidth + hspace) + (hspace / 2),
2334
j * (bheight + vspace) + (vspace / 2),
2336
msw->x = i * wwidth;
2337
msw->y = j * wheight;
2338
XMoveResizeWindow(dpy, msw->w, msw->x, msw->y, wwidth - 2, wheight - 2);
2339
for(wl = msw->wl; wl != NULL; wl = wl->next) {
2340
tmp_win = wl->twm_win;
2341
wl->x = (int)(tmp_win->frame_x * wf);
2342
wl->y = (int)(tmp_win->frame_y * hf);
2343
wl->width = (unsigned int)((tmp_win->frame_width * wf) + 0.5);
2344
wl->height = (unsigned int)((tmp_win->frame_height * hf) + 0.5);
2345
XMoveResizeWindow(dpy, wl->w, wl->x, wl->y, wl->width, wl->height);
2353
vs->wsw->bwidth = bwidth;
2354
vs->wsw->bheight = bheight;
2355
vs->wsw->width = neww;
2356
vs->wsw->height = newh;
2357
vs->wsw->wwidth = wwidth;
2358
vs->wsw->wheight = wheight;
2359
PaintWorkSpaceManager(vs);
2363
void WMapCreateCurrentBackGround(char *border,
2364
char *background, char *foreground,
2368
WorkSpaceMgr *ws = &Scr->workSpaceMgr;
2370
ws->curBorderColor = Scr->Black;
2371
ws->curColors.back = Scr->White;
2372
ws->curColors.fore = Scr->Black;
2373
ws->curImage = NULL;
2375
if(border == NULL) {
2378
GetColor(Scr->Monochrome, &ws->curBorderColor, border);
2379
if(background == NULL) {
2382
ws->curPaint = true;
2383
GetColor(Scr->Monochrome, &ws->curColors.back, background);
2384
if(foreground == NULL) {
2387
GetColor(Scr->Monochrome, &ws->curColors.fore, foreground);
2389
if(pixmap == NULL) {
2392
if((image = GetImage(pixmap, Scr->workSpaceMgr.curColors)) == NULL) {
2393
fprintf(stderr, "Can't find pixmap %s\n", pixmap);
2396
ws->curImage = image;
2399
void WMapCreateDefaultBackGround(char *border,
2400
char *background, char *foreground,
2404
WorkSpaceMgr *ws = &Scr->workSpaceMgr;
2406
ws->defBorderColor = Scr->Black;
2407
ws->defColors.back = Scr->White;
2408
ws->defColors.fore = Scr->Black;
2409
ws->defImage = NULL;
2411
if(border == NULL) {
2414
GetColor(Scr->Monochrome, &ws->defBorderColor, border);
2415
if(background == NULL) {
2418
GetColor(Scr->Monochrome, &ws->defColors.back, background);
2419
if(foreground == NULL) {
2422
GetColor(Scr->Monochrome, &ws->defColors.fore, foreground);
2423
if(pixmap == NULL) {
2426
if((image = GetImage(pixmap, ws->defColors)) == NULL) {
2429
ws->defImage = image;
2274
/* There you are. Unlink and kill */
2277
XDeleteContext(dpy, wl->w, TwmContext);
2278
XDeleteContext(dpy, wl->w, ScreenContext);
2279
XDeleteContext(dpy, wl->w, MapWListContext);
2280
XDestroyWindow(dpy, wl->w);
2283
/* Around to the next vscreen */
2293
****************************************************************
2297
****************************************************************
2301
* This is really more util.c fodder, but leaving it here for now because
2302
* it's only used once in WMapRedrawName(). If we start finding external
2303
* uses for it, it should be moved.
2306
InvertColorPair(ColorPair *cp)
2311
cp->fore = cp->back;
2314
cp->shadc = cp->shadd;
2320
* Verify if a window may be added to the workspace map.
2321
* This is not allowed for
2323
* - the occupy window
2324
* - workspace manager windows
2325
* - or, optionally, windows with full occupation.
2328
WMapWindowMayBeAdded(TwmWindow *win)
2330
if(win->isiconmgr) {
2333
if(win == Scr->workSpaceMgr.occupyWindow->twm_win) {
2339
if(Scr->workSpaceMgr.noshowoccupyall &&
2340
win->occupation == fullOccupation) {