10bbfda8aSnia/* 20bbfda8aSnia * Occupation handling bits 30bbfda8aSnia * 40bbfda8aSnia * This is in fact pretty tightly tied and extremely similar to the 50bbfda8aSnia * handling of the WorkSpaceManager in workmgr.c, and used to be there. 60bbfda8aSnia * It makes sense to consider them together (and indeed, many of the 70bbfda8aSnia * configs that affect how this works are really WorkSpaceManager* or 80bbfda8aSnia * WMgr* commands. But having them crammed together in one file is 90bbfda8aSnia * unwieldy. 100bbfda8aSnia */ 110bbfda8aSnia 120bbfda8aSnia#include "ctwm.h" 130bbfda8aSnia 140bbfda8aSnia#include <stdio.h> 150bbfda8aSnia#include <string.h> 160bbfda8aSnia#include <stdlib.h> 170bbfda8aSnia 180bbfda8aSnia#include <X11/Xatom.h> 190bbfda8aSnia 200bbfda8aSnia#include "add_window.h" 210bbfda8aSnia#include "ctwm_atoms.h" 220bbfda8aSnia#include "drawing.h" 230bbfda8aSnia#include "events.h" 240bbfda8aSnia#include "iconmgr.h" 250bbfda8aSnia#include "list.h" 260bbfda8aSnia#include "screen.h" 270bbfda8aSnia#include "occupation.h" 280bbfda8aSnia#include "otp.h" 290bbfda8aSnia#include "util.h" 300bbfda8aSnia#include "vscreen.h" 310bbfda8aSnia#include "win_iconify.h" 320bbfda8aSnia#include "win_regions.h" 330bbfda8aSnia#include "win_utils.h" 340bbfda8aSnia#include "workspace_manager.h" 350bbfda8aSnia#include "workspace_utils.h" 360bbfda8aSnia 370bbfda8aSnia 380bbfda8aSniastatic int GetMaskFromResource(TwmWindow *win, char *res); 390bbfda8aSniastatic char *mk_nullsep_string(const char *prop, int len); 400bbfda8aSnia 410bbfda8aSniastatic bool CanChangeOccupation(TwmWindow **twm_winp); 420bbfda8aSnia 430bbfda8aSniaint fullOccupation = 0; 440bbfda8aSnia 450bbfda8aSnia/* 460bbfda8aSnia * The window whose occupation is currently being manipulated. 470bbfda8aSnia * 480bbfda8aSnia * XXX Should probably be static, but currently needed in 490bbfda8aSnia * WMapRemoveWindow(). Revisit. 500bbfda8aSnia */ 510bbfda8aSniaTwmWindow *occupyWin = NULL; 520bbfda8aSnia 530bbfda8aSnia 540bbfda8aSnia/* XXX Share with captive.c? */ 550bbfda8aSniastatic XrmOptionDescRec table [] = { 560bbfda8aSnia {"-xrm", NULL, XrmoptionResArg, (XPointer) NULL}, 570bbfda8aSnia}; 580bbfda8aSnia 590bbfda8aSnia 600bbfda8aSnia 610bbfda8aSnia 620bbfda8aSnia/* 630bbfda8aSnia **************************************************************** 640bbfda8aSnia * 650bbfda8aSnia * First, funcs related to setting and changing a window's occupation. 660bbfda8aSnia * 670bbfda8aSnia **************************************************************** 680bbfda8aSnia */ 690bbfda8aSnia 700bbfda8aSnia 710bbfda8aSnia/* 720bbfda8aSnia * Setup the occupation of a TwmWindow. Called as part of the 730bbfda8aSnia * AddWindow() process. 740bbfda8aSnia * 750bbfda8aSnia * XXX The logic flow in this is kinda weird, and it's not at all clear 760bbfda8aSnia * to what extent it's really doing the right on on what should override 770bbfda8aSnia * what, or which things should expand/contract on others... 780bbfda8aSnia */ 790bbfda8aSniavoid 800bbfda8aSniaSetupOccupation(TwmWindow *twm_win, int occupation_hint) 810bbfda8aSnia{ 820bbfda8aSnia char **cliargv = NULL; 830bbfda8aSnia int cliargc; 840bbfda8aSnia WorkSpace *ws; 850bbfda8aSnia 860bbfda8aSnia /* If there aren't any config'd workspaces, there's only 0 */ 870bbfda8aSnia if(! Scr->workSpaceManagerActive) { 880bbfda8aSnia twm_win->occupation = 1 << 0; /* occupy workspace #0 */ 890bbfda8aSnia /* more?... */ 900bbfda8aSnia 910bbfda8aSnia return; 920bbfda8aSnia } 930bbfda8aSnia 940bbfda8aSnia /* Workspace manager window doesn't get futzed with */ 950bbfda8aSnia if(twm_win->iswspmgr) { 960bbfda8aSnia return; 970bbfda8aSnia } 980bbfda8aSnia 990bbfda8aSnia /*twm_win->occupation = twm_win->iswinbox ? fullOccupation : 0;*/ 1000bbfda8aSnia twm_win->occupation = 0; 1010bbfda8aSnia 1020bbfda8aSnia /* Specified in any Occupy{} config params? */ 1030bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 1040bbfda8aSnia if(LookInList(ws->clientlist, twm_win->name, &twm_win->class)) { 1050bbfda8aSnia twm_win->occupation |= 1 << ws->number; 1060bbfda8aSnia } 1070bbfda8aSnia } 1080bbfda8aSnia 1090bbfda8aSnia /* OccupyAll{} */ 1100bbfda8aSnia if(LookInList(Scr->OccupyAll, twm_win->name, &twm_win->class)) { 1110bbfda8aSnia twm_win->occupation = fullOccupation; 1120bbfda8aSnia } 1130bbfda8aSnia 1140bbfda8aSnia /* See if it specified in -xrm stuff */ 1150bbfda8aSnia if(XGetCommand(dpy, twm_win->w, &cliargv, &cliargc)) { 1160bbfda8aSnia Bool status; 1170bbfda8aSnia char *str_type; 1180bbfda8aSnia XrmValue value; 1190bbfda8aSnia XrmDatabase db = NULL; 1200bbfda8aSnia 1210bbfda8aSnia XrmParseCommand(&db, table, 1, "ctwm", &cliargc, cliargv); 1220bbfda8aSnia XFreeStringList(cliargv); 1230bbfda8aSnia status = XrmGetResource(db, "ctwm.workspace", "Ctwm.Workspace", 1240bbfda8aSnia &str_type, &value); 1250bbfda8aSnia if((status == True) && (value.size != 0)) { 1260bbfda8aSnia /* Copy the value.addr because it's in XRM memory not ours */ 1270bbfda8aSnia char wrkSpcList[512]; 1280bbfda8aSnia safe_strncpy(wrkSpcList, value.addr, MIN(value.size, 512)); 1290bbfda8aSnia 1300bbfda8aSnia twm_win->occupation = GetMaskFromResource(twm_win, wrkSpcList); 1310bbfda8aSnia } 1320bbfda8aSnia XrmDestroyDatabase(db); 1330bbfda8aSnia } 1340bbfda8aSnia 1350bbfda8aSnia /* Does it have a property telling us */ 1360bbfda8aSnia if(RestartPreviousState) { 1370bbfda8aSnia Atom actual_type; 1380bbfda8aSnia int actual_format; 1390bbfda8aSnia unsigned long nitems, bytesafter; 1400bbfda8aSnia unsigned char *prop; 1410bbfda8aSnia 1420bbfda8aSnia if(XGetWindowProperty(dpy, twm_win->w, XA_WM_OCCUPATION, 0L, 2500, False, 1430bbfda8aSnia XA_STRING, &actual_type, &actual_format, &nitems, 1440bbfda8aSnia &bytesafter, &prop) == Success) { 1450bbfda8aSnia if(nitems != 0) { 1460bbfda8aSnia twm_win->occupation = GetMaskFromProperty(prop, nitems); 1470bbfda8aSnia XFree(prop); 1480bbfda8aSnia } 1490bbfda8aSnia } 1500bbfda8aSnia } 1510bbfda8aSnia 1520bbfda8aSnia#ifdef EWMH 1530bbfda8aSnia /* Maybe EWMH has something to tell us? */ 1540bbfda8aSnia if(twm_win->occupation == 0) { 1550bbfda8aSnia twm_win->occupation = EwmhGetOccupation(twm_win); 1560bbfda8aSnia } 1570bbfda8aSnia#endif /* EWMH */ 1580bbfda8aSnia 1590bbfda8aSnia /* Icon Managers shouldn't get altered */ 1600bbfda8aSnia /* XXX Should this be up near the top? */ 1610bbfda8aSnia if(twm_win->isiconmgr) { 1620bbfda8aSnia return; /* someone tried to modify occupation of icon managers */ 1630bbfda8aSnia } 1640bbfda8aSnia 1650bbfda8aSnia 1660bbfda8aSnia /* 1670bbfda8aSnia * Transient-ish things go with their parents unless 1680bbfda8aSnia * TransientHasOccupation set in the config. 1690bbfda8aSnia */ 1700bbfda8aSnia if(! Scr->TransientHasOccupation) { 1710bbfda8aSnia TwmWindow *t; 1720bbfda8aSnia 1730bbfda8aSnia if(twm_win->istransient) { 1740bbfda8aSnia t = GetTwmWindow(twm_win->transientfor); 1750bbfda8aSnia if(t != NULL) { 1760bbfda8aSnia twm_win->occupation = t->occupation; 1770bbfda8aSnia } 1780bbfda8aSnia } 1790bbfda8aSnia else if(twm_win->group != 0) { 1800bbfda8aSnia t = GetTwmWindow(twm_win->group); 1810bbfda8aSnia if(t != NULL) { 1820bbfda8aSnia twm_win->occupation = t->occupation; 1830bbfda8aSnia } 1840bbfda8aSnia } 1850bbfda8aSnia } 1860bbfda8aSnia 1870bbfda8aSnia 1880bbfda8aSnia /* If we were told something specific, go with that */ 1890bbfda8aSnia if(occupation_hint != 0) { 1900bbfda8aSnia twm_win->occupation = occupation_hint; 1910bbfda8aSnia } 1920bbfda8aSnia 1930bbfda8aSnia /* If it's apparently-nonsensical, put it in its vs's workspace */ 1940bbfda8aSnia if((twm_win->occupation & fullOccupation) == 0) { 1950bbfda8aSnia twm_win->occupation = 1 << twm_win->vs->wsw->currentwspc->number; 1960bbfda8aSnia } 1970bbfda8aSnia 1980bbfda8aSnia /* 1990bbfda8aSnia * If the occupation would not show it in the current vscreen, 2000bbfda8aSnia * make it vanish. 2010bbfda8aSnia * 2020bbfda8aSnia * If it could be shown in one of the other vscreens, change the vscreen. 2030bbfda8aSnia */ 2040bbfda8aSnia if(!OCCUPY(twm_win, twm_win->vs->wsw->currentwspc)) { 2050bbfda8aSnia 2060bbfda8aSnia twm_win->vs = NULL; 2070bbfda8aSnia 208b18c2d1eSnia#ifdef VSCREEN 2090bbfda8aSnia if(Scr->numVscreens > 1) { 210b18c2d1eSnia VirtualScreen *vs; 2110bbfda8aSnia for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) { 2120bbfda8aSnia if(OCCUPY(twm_win, vs->wsw->currentwspc)) { 2130bbfda8aSnia twm_win->vs = vs; 2140bbfda8aSnia twm_win->parent_vs = vs; 2150bbfda8aSnia break; 2160bbfda8aSnia } 2170bbfda8aSnia } 2180bbfda8aSnia } 219b18c2d1eSnia#endif 2200bbfda8aSnia } 2210bbfda8aSnia 2220bbfda8aSnia 2230bbfda8aSnia /* Set the property for the occupation */ 2240bbfda8aSnia { 2250bbfda8aSnia long eventMask; 2260bbfda8aSnia char *wsstr; 2270bbfda8aSnia int len; 2280bbfda8aSnia 2290bbfda8aSnia /* Ignore the PropertyChange we're about to do */ 2300bbfda8aSnia if((eventMask = mask_out_event(twm_win->w, PropertyChangeMask)) < 0) { 2310bbfda8aSnia /* Window is horked, not much we can do */ 2320bbfda8aSnia return; 2330bbfda8aSnia } 2340bbfda8aSnia 2350bbfda8aSnia /* Set the property for the occupation */ 2360bbfda8aSnia len = GetPropertyFromMask(twm_win->occupation, &wsstr); 2370bbfda8aSnia XChangeProperty(dpy, twm_win->w, XA_WM_OCCUPATION, XA_STRING, 8, 2380bbfda8aSnia PropModeReplace, (unsigned char *) wsstr, len); 2390bbfda8aSnia free(wsstr); 2400bbfda8aSnia 2410bbfda8aSnia#ifdef EWMH 2420bbfda8aSnia EwmhSet_NET_WM_DESKTOP(twm_win); 2430bbfda8aSnia#endif 2440bbfda8aSnia 2450bbfda8aSnia /* Restore event mask */ 2460bbfda8aSnia restore_mask(twm_win->w, eventMask); 2470bbfda8aSnia } 2480bbfda8aSnia 2490bbfda8aSnia /* Set WM_STATE prop */ 2500bbfda8aSnia { 2510bbfda8aSnia int state = NormalState; 2520bbfda8aSnia Window icon; 2530bbfda8aSnia 2540bbfda8aSnia if(!(RestartPreviousState 2550bbfda8aSnia && GetWMState(twm_win->w, &state, &icon) 2560bbfda8aSnia && (state == NormalState || state == IconicState 2570bbfda8aSnia || state == InactiveState))) { 2580bbfda8aSnia if(twm_win->wmhints->flags & StateHint) { 2590bbfda8aSnia state = twm_win->wmhints->initial_state; 2600bbfda8aSnia } 2610bbfda8aSnia } 2620bbfda8aSnia if(visible(twm_win)) { 2630bbfda8aSnia if(state == InactiveState) { 2640bbfda8aSnia SetMapStateProp(twm_win, NormalState); 2650bbfda8aSnia } 2660bbfda8aSnia } 2670bbfda8aSnia else { 2680bbfda8aSnia if(state == NormalState) { 2690bbfda8aSnia SetMapStateProp(twm_win, InactiveState); 2700bbfda8aSnia } 2710bbfda8aSnia } 2720bbfda8aSnia } 2730bbfda8aSnia} 2740bbfda8aSnia 2750bbfda8aSnia 2760bbfda8aSnia/* 2770bbfda8aSnia * Make sure a window is marked in a given workspace. f.addtoworkspace. 2780bbfda8aSnia * Also gets called as part of the process of mapping a window; if we're 2790bbfda8aSnia * mapping it here, it should know that it's here. And Xinerama magic 2800bbfda8aSnia * moves. 2810bbfda8aSnia */ 2820bbfda8aSniavoid 2830bbfda8aSniaAddToWorkSpace(char *wname, TwmWindow *twm_win) 2840bbfda8aSnia{ 2850bbfda8aSnia WorkSpace *ws; 2860bbfda8aSnia int newoccupation; 2870bbfda8aSnia 2880bbfda8aSnia if(!CanChangeOccupation(&twm_win)) { 2890bbfda8aSnia return; 2900bbfda8aSnia } 2910bbfda8aSnia ws = GetWorkspace(wname); 2920bbfda8aSnia if(!ws) { 2930bbfda8aSnia return; 2940bbfda8aSnia } 2950bbfda8aSnia 2960bbfda8aSnia if(twm_win->occupation & (1 << ws->number)) { 2970bbfda8aSnia return; 2980bbfda8aSnia } 2990bbfda8aSnia newoccupation = twm_win->occupation | (1 << ws->number); 3000bbfda8aSnia ChangeOccupation(twm_win, newoccupation); 3010bbfda8aSnia} 3020bbfda8aSnia 3030bbfda8aSnia 3040bbfda8aSnia/* 3050bbfda8aSnia * Converse of the above. f.removefromworkspace, also called from 3060bbfda8aSnia * Xinerama-related magic. 3070bbfda8aSnia */ 3080bbfda8aSniavoid 3090bbfda8aSniaRemoveFromWorkSpace(char *wname, TwmWindow *twm_win) 3100bbfda8aSnia{ 3110bbfda8aSnia WorkSpace *ws; 3120bbfda8aSnia int newoccupation; 3130bbfda8aSnia 3140bbfda8aSnia if(!CanChangeOccupation(&twm_win)) { 3150bbfda8aSnia return; 3160bbfda8aSnia } 3170bbfda8aSnia ws = GetWorkspace(wname); 3180bbfda8aSnia if(!ws) { 3190bbfda8aSnia return; 3200bbfda8aSnia } 3210bbfda8aSnia 3220bbfda8aSnia newoccupation = twm_win->occupation & ~(1 << ws->number); 3230bbfda8aSnia if(!newoccupation) { 3240bbfda8aSnia return; 3250bbfda8aSnia } 3260bbfda8aSnia ChangeOccupation(twm_win, newoccupation); 3270bbfda8aSnia} 3280bbfda8aSnia 3290bbfda8aSnia 3300bbfda8aSnia/* f.toggleoccupation - flip setting for [current] workspace */ 3310bbfda8aSniavoid 3320bbfda8aSniaToggleOccupation(char *wname, TwmWindow *twm_win) 3330bbfda8aSnia{ 3340bbfda8aSnia WorkSpace *ws; 3350bbfda8aSnia int newoccupation; 3360bbfda8aSnia 3370bbfda8aSnia if(!CanChangeOccupation(&twm_win)) { 3380bbfda8aSnia return; 3390bbfda8aSnia } 3400bbfda8aSnia ws = GetWorkspace(wname); 3410bbfda8aSnia if(!ws) { 3420bbfda8aSnia return; 3430bbfda8aSnia } 3440bbfda8aSnia 3450bbfda8aSnia newoccupation = twm_win->occupation ^ (1 << ws->number); 3460bbfda8aSnia if(!newoccupation) { 3470bbfda8aSnia /* Don't allow de-occupying _every_ ws */ 3480bbfda8aSnia return; 3490bbfda8aSnia } 3500bbfda8aSnia ChangeOccupation(twm_win, newoccupation); 3510bbfda8aSnia} 3520bbfda8aSnia 3530bbfda8aSnia 3540bbfda8aSnia/* f.movetonextworkspace */ 3550bbfda8aSniavoid 3560bbfda8aSniaMoveToNextWorkSpace(VirtualScreen *vs, TwmWindow *twm_win) 3570bbfda8aSnia{ 3580bbfda8aSnia WorkSpace *wlist1, *wlist2; 3590bbfda8aSnia int newoccupation; 3600bbfda8aSnia 3610bbfda8aSnia if(!CanChangeOccupation(&twm_win)) { 3620bbfda8aSnia return; 3630bbfda8aSnia } 3640bbfda8aSnia 3650bbfda8aSnia wlist1 = vs->wsw->currentwspc; 3660bbfda8aSnia wlist2 = wlist1->next; 3670bbfda8aSnia wlist2 = wlist2 ? wlist2 : Scr->workSpaceMgr.workSpaceList; 3680bbfda8aSnia 3690bbfda8aSnia /* Out of (here), into (here+1) */ 3700bbfda8aSnia newoccupation = (twm_win->occupation ^ (1 << wlist1->number)) 3710bbfda8aSnia | (1 << wlist2->number); 3720bbfda8aSnia ChangeOccupation(twm_win, newoccupation); 3730bbfda8aSnia} 3740bbfda8aSnia 3750bbfda8aSnia 3760bbfda8aSnia/* f.movetonextworkspaceandfollow */ 3770bbfda8aSniavoid 3780bbfda8aSniaMoveToNextWorkSpaceAndFollow(VirtualScreen *vs, TwmWindow *twm_win) 3790bbfda8aSnia{ 3800bbfda8aSnia if(!CanChangeOccupation(&twm_win)) { 3810bbfda8aSnia return; 3820bbfda8aSnia } 3830bbfda8aSnia 3840bbfda8aSnia MoveToNextWorkSpace(vs, twm_win); 3850bbfda8aSnia GotoNextWorkSpace(vs); 3860bbfda8aSnia#if 0 3870bbfda8aSnia OtpRaise(twm_win, WinWin); /* XXX really do this? */ 3880bbfda8aSnia#endif 3890bbfda8aSnia} 3900bbfda8aSnia 3910bbfda8aSnia 3920bbfda8aSnia/* f.movetoprevworkspaceand */ 3930bbfda8aSniavoid 3940bbfda8aSniaMoveToPrevWorkSpace(VirtualScreen *vs, TwmWindow *twm_win) 3950bbfda8aSnia{ 3960bbfda8aSnia WorkSpace *wlist1, *wlist2; 3970bbfda8aSnia int newoccupation; 3980bbfda8aSnia 3990bbfda8aSnia if(!CanChangeOccupation(&twm_win)) { 4000bbfda8aSnia return; 4010bbfda8aSnia } 4020bbfda8aSnia 4030bbfda8aSnia wlist1 = Scr->workSpaceMgr.workSpaceList; 4040bbfda8aSnia wlist2 = vs->wsw->currentwspc; 4050bbfda8aSnia if(wlist1 == NULL) { 4060bbfda8aSnia return; 4070bbfda8aSnia } 4080bbfda8aSnia 4090bbfda8aSnia while(wlist1->next != wlist2 && wlist1->next != NULL) { 4100bbfda8aSnia wlist1 = wlist1->next; 4110bbfda8aSnia } 4120bbfda8aSnia 4130bbfda8aSnia /* Out of (here), into (here-1) */ 4140bbfda8aSnia newoccupation = (twm_win->occupation ^ (1 << wlist2->number)) 4150bbfda8aSnia | (1 << wlist1->number); 4160bbfda8aSnia ChangeOccupation(twm_win, newoccupation); 4170bbfda8aSnia} 4180bbfda8aSnia 4190bbfda8aSnia 4200bbfda8aSnia/* f.movetoprevworkspaceandfollow */ 4210bbfda8aSniavoid 4220bbfda8aSniaMoveToPrevWorkSpaceAndFollow(VirtualScreen *vs, TwmWindow *twm_win) 4230bbfda8aSnia{ 4240bbfda8aSnia if(!CanChangeOccupation(&twm_win)) { 4250bbfda8aSnia return; 4260bbfda8aSnia } 4270bbfda8aSnia 4280bbfda8aSnia MoveToPrevWorkSpace(vs, twm_win); 4290bbfda8aSnia GotoPrevWorkSpace(vs); 4300bbfda8aSnia#if 0 4310bbfda8aSnia OtpRaise(twm_win, WinWin); /* XXX really do this? */ 4320bbfda8aSnia#endif 4330bbfda8aSnia} 4340bbfda8aSnia 4350bbfda8aSnia 4360bbfda8aSnia/* 4370bbfda8aSnia * Set the occupation based on the window name. This is called if 4380bbfda8aSnia * AutoOccupy is set, when we get a notification about a window name 4390bbfda8aSnia * change. 4400bbfda8aSnia */ 4410bbfda8aSniavoid 4420bbfda8aSniaWmgrRedoOccupation(TwmWindow *win) 4430bbfda8aSnia{ 4440bbfda8aSnia WorkSpace *ws; 4450bbfda8aSnia int newoccupation; 4460bbfda8aSnia 4470bbfda8aSnia if(LookInList(Scr->OccupyAll, win->name, &win->class)) { 4480bbfda8aSnia newoccupation = fullOccupation; 4490bbfda8aSnia } 4500bbfda8aSnia else { 4510bbfda8aSnia newoccupation = 0; 4520bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 4530bbfda8aSnia if(LookInList(ws->clientlist, win->name, &win->class)) { 4540bbfda8aSnia newoccupation |= 1 << ws->number; 4550bbfda8aSnia } 4560bbfda8aSnia } 4570bbfda8aSnia } 4580bbfda8aSnia if(newoccupation != 0) { 4590bbfda8aSnia ChangeOccupation(win, newoccupation); 4600bbfda8aSnia } 4610bbfda8aSnia} 4620bbfda8aSnia 4630bbfda8aSnia 4640bbfda8aSnia/* f.vanish */ 4650bbfda8aSniavoid 4660bbfda8aSniaWMgrRemoveFromCurrentWorkSpace(VirtualScreen *vs, TwmWindow *win) 4670bbfda8aSnia{ 4680bbfda8aSnia WorkSpace *ws; 4690bbfda8aSnia int newoccupation; 4700bbfda8aSnia 4710bbfda8aSnia ws = vs->wsw->currentwspc; 4720bbfda8aSnia if(!ws) { 4730bbfda8aSnia /* Impossible? */ 4740bbfda8aSnia return; 4750bbfda8aSnia } 4760bbfda8aSnia if(! OCCUPY(win, ws)) { 4770bbfda8aSnia return; 4780bbfda8aSnia } 4790bbfda8aSnia 4800bbfda8aSnia newoccupation = win->occupation & ~(1 << ws->number); 4810bbfda8aSnia if(newoccupation == 0) { 4820bbfda8aSnia return; 4830bbfda8aSnia } 4840bbfda8aSnia 4850bbfda8aSnia ChangeOccupation(win, newoccupation); 4860bbfda8aSnia} 4870bbfda8aSnia 4880bbfda8aSnia 4890bbfda8aSnia/* f.warphere */ 4900bbfda8aSniavoid 4910bbfda8aSniaWMgrAddToCurrentWorkSpaceAndWarp(VirtualScreen *vs, char *winname) 4920bbfda8aSnia{ 4930bbfda8aSnia TwmWindow *tw; 4940bbfda8aSnia int newoccupation; 4950bbfda8aSnia 4960bbfda8aSnia /* Find named window on this screen */ 4970bbfda8aSnia for(tw = Scr->FirstWindow; tw != NULL; tw = tw->next) { 4980bbfda8aSnia if(match(winname, tw->name)) { 4990bbfda8aSnia break; 5000bbfda8aSnia } 5010bbfda8aSnia } 5020bbfda8aSnia 5030bbfda8aSnia /* Didn't find it by name? Try by class */ 5040bbfda8aSnia if(!tw) { 5050bbfda8aSnia for(tw = Scr->FirstWindow; tw != NULL; tw = tw->next) { 5060bbfda8aSnia if(match(winname, tw->class.res_name)) { 5070bbfda8aSnia break; 5080bbfda8aSnia } 5090bbfda8aSnia } 5100bbfda8aSnia } 5110bbfda8aSnia if(!tw) { 5120bbfda8aSnia for(tw = Scr->FirstWindow; tw != NULL; tw = tw->next) { 5130bbfda8aSnia if(match(winname, tw->class.res_class)) { 5140bbfda8aSnia break; 5150bbfda8aSnia } 5160bbfda8aSnia } 5170bbfda8aSnia } 5180bbfda8aSnia 5190bbfda8aSnia /* Still didn't find? Beep at the user and bail. */ 5200bbfda8aSnia if(!tw) { 5210bbfda8aSnia XBell(dpy, 0); 5220bbfda8aSnia return; 5230bbfda8aSnia } 5240bbfda8aSnia 5250bbfda8aSnia /* If WarpUnmapped isn't set and this isn't mapped, beep and bail */ 5260bbfda8aSnia if((! Scr->WarpUnmapped) && (! tw->mapped)) { 5270bbfda8aSnia XBell(dpy, 0); 5280bbfda8aSnia return; 5290bbfda8aSnia } 5300bbfda8aSnia 5310bbfda8aSnia /* Move it here if it's not */ 5320bbfda8aSnia if(! OCCUPY(tw, vs->wsw->currentwspc)) { 5330bbfda8aSnia newoccupation = tw->occupation | (1 << vs->wsw->currentwspc->number); 5340bbfda8aSnia ChangeOccupation(tw, newoccupation); 5350bbfda8aSnia } 5360bbfda8aSnia 5370bbfda8aSnia /* If we get here, WarpUnmapped is set, so map it if we need to */ 5380bbfda8aSnia if(! tw->mapped) { 5390bbfda8aSnia DeIconify(tw); 5400bbfda8aSnia } 5410bbfda8aSnia 5420bbfda8aSnia /* And go */ 5430bbfda8aSnia WarpToWindow(tw, Scr->RaiseOnWarp); 5440bbfda8aSnia} 5450bbfda8aSnia 5460bbfda8aSnia 5470bbfda8aSnia/* f.occupyall backend */ 5480bbfda8aSniavoid 5490bbfda8aSniaOccupyAll(TwmWindow *twm_win) 5500bbfda8aSnia{ 5510bbfda8aSnia IconMgr *save; 5520bbfda8aSnia 5530bbfda8aSnia if(!CanChangeOccupation(&twm_win)) { 5540bbfda8aSnia return; 5550bbfda8aSnia } 5560bbfda8aSnia 5570bbfda8aSnia /* 5580bbfda8aSnia * Temporarily alter Scr->iconmgr because stuff down in 5590bbfda8aSnia * ChangeOccupation winds up adding/removing bits, and that doesn't 5600bbfda8aSnia * work right when we're setting all? XXX Investigate further. 5610bbfda8aSnia */ 5620bbfda8aSnia save = Scr->iconmgr; 5630bbfda8aSnia Scr->iconmgr = Scr->workSpaceMgr.workSpaceList->iconmgr; 5640bbfda8aSnia ChangeOccupation(twm_win, fullOccupation); 5650bbfda8aSnia Scr->iconmgr = save; 5660bbfda8aSnia} 5670bbfda8aSnia 5680bbfda8aSnia 5690bbfda8aSnia 5700bbfda8aSnia/* 5710bbfda8aSnia **************************************************************** 5720bbfda8aSnia * 5730bbfda8aSnia * Pieces related to the Occupy window 5740bbfda8aSnia * 5750bbfda8aSnia **************************************************************** 5760bbfda8aSnia */ 5770bbfda8aSnia 5780bbfda8aSniastatic ColorPair occupyButtoncp; 5790bbfda8aSnia 5800bbfda8aSniastatic char *ok_string = "OK", 5810bbfda8aSnia *cancel_string = "Cancel", 5820bbfda8aSnia *everywhere_string = "All"; 5830bbfda8aSnia 5840bbfda8aSnia/* 5850bbfda8aSnia * Create the Occupy window. Part of startup process. 5860bbfda8aSnia * 5870bbfda8aSnia * Do not do the layout of the parts, only calculate the initial total 5880bbfda8aSnia * size. For the layout, call ResizeOccupyWindow() at the end. 5890bbfda8aSnia * 5900bbfda8aSnia * There is only one Occupy window (per Screen), it is reparented to each 5910bbfda8aSnia * virtual screen as needed. 5920bbfda8aSnia */ 5930bbfda8aSniavoid 5940bbfda8aSniaCreateOccupyWindow(void) 5950bbfda8aSnia{ 5960bbfda8aSnia int width; // Caculated and altered, unlike most others 5970bbfda8aSnia int Dummy = 1; 5980bbfda8aSnia TwmWindow *tmp_win; 5990bbfda8aSnia /* Shorthands for the Occupy window */ 6000bbfda8aSnia OccupyWindow *occwin = Scr->workSpaceMgr.occupyWindow; 6010bbfda8aSnia Window w; // occwin->w 6020bbfda8aSnia /* Misc other shorthands */ 6030bbfda8aSnia const int lines = Scr->workSpaceMgr.lines; 6040bbfda8aSnia const int columns = Scr->workSpaceMgr.columns; 6050bbfda8aSnia const int bwidth = Scr->vScreenList->wsw->bwidth; 6060bbfda8aSnia const int bheight = Scr->vScreenList->wsw->bheight; 6070bbfda8aSnia const int vspace = occwin->vspace; 6080bbfda8aSnia const int hspace = occwin->hspace; 6090bbfda8aSnia const int height = ((bheight + vspace) * lines) + bheight + (2 * vspace); 6100bbfda8aSnia 6110bbfda8aSnia /* Struct embedded in [struct embedded in] Scr, so memory's waiting */ 6120bbfda8aSnia 6130bbfda8aSnia /* There isn't anything we should do without workspaces... */ 6140bbfda8aSnia if(!Scr->workSpaceManagerActive) { 6150bbfda8aSnia return; 6160bbfda8aSnia } 6170bbfda8aSnia 6180bbfda8aSnia /* Initialize font and colorpair bits */ 6190bbfda8aSnia occwin->font = Scr->IconManagerFont; 6200bbfda8aSnia occwin->cp = Scr->IconManagerC; 6210bbfda8aSnia#ifdef COLOR_BLIND_USER 6220bbfda8aSnia occwin->cp.shadc = Scr->White; 6230bbfda8aSnia occwin->cp.shadd = Scr->Black; 6240bbfda8aSnia#else 6250bbfda8aSnia if(!Scr->BeNiceToColormap) { 6260bbfda8aSnia GetShadeColors(&occwin->cp); 6270bbfda8aSnia } 6280bbfda8aSnia#endif 6290bbfda8aSnia 6300bbfda8aSnia /* We already know that these should be too */ 6310bbfda8aSnia occwin->lines = lines; 6320bbfda8aSnia occwin->columns = columns; 6330bbfda8aSnia 6340bbfda8aSnia 6350bbfda8aSnia /* 6360bbfda8aSnia * Work out the necessary size of the OK/Cancel/All buttons at the 6370bbfda8aSnia * bottom. 6380bbfda8aSnia */ 6390bbfda8aSnia { 6400bbfda8aSnia XRectangle inc_rect; 6410bbfda8aSnia XRectangle logical_rect; 6420bbfda8aSnia MyFont font = occwin->font; 6430bbfda8aSnia int bbwidth; // Bottom button width 6440bbfda8aSnia /* Window min width based on bottom vs. workspace btns */ 6450bbfda8aSnia int bb_width, ws_width; 6460bbfda8aSnia 6470bbfda8aSnia /* Buttons gotta be as wide as the biggest of the three strings */ 6480bbfda8aSnia XmbTextExtents(font.font_set, ok_string, strlen(ok_string), 6490bbfda8aSnia &inc_rect, &logical_rect); 6500bbfda8aSnia bbwidth = logical_rect.width; 6510bbfda8aSnia 6520bbfda8aSnia XmbTextExtents(font.font_set, cancel_string, strlen(cancel_string), 6530bbfda8aSnia &inc_rect, &logical_rect); 6540bbfda8aSnia bbwidth = MAX(bbwidth, logical_rect.width); 6550bbfda8aSnia 6560bbfda8aSnia XmbTextExtents(font.font_set, everywhere_string, 6570bbfda8aSnia strlen(everywhere_string), 6580bbfda8aSnia &inc_rect, &logical_rect); 6590bbfda8aSnia bbwidth = MAX(bbwidth, logical_rect.width); 6600bbfda8aSnia 6610bbfda8aSnia /* Plus the padding width */ 6620bbfda8aSnia bbwidth += hspace; 6630bbfda8aSnia 6640bbfda8aSnia /* 6650bbfda8aSnia * So, the final width of those bottom buttons is that, plus the 6660bbfda8aSnia * 3d button look extra on both sides, plus a little extra. I 6670bbfda8aSnia * guess that extra + 2 is similar to TitlePadding or 6680bbfda8aSnia * ButtonIndent on titlebars, but we don't have a config param 6690bbfda8aSnia * for it on the workspace manager (which is the config used for 6700bbfda8aSnia * the occupy window), so leave it as a magic constant for now. 6710bbfda8aSnia */ 6720bbfda8aSnia occwin->owidth = bbwidth + 2 * Scr->WMgrButtonShadowDepth + 2; 6730bbfda8aSnia 6740bbfda8aSnia /* 6750bbfda8aSnia * The whole thing has to be at least triple the min width of 6760bbfda8aSnia * those bottom buttons, since there are three of them. The 6770bbfda8aSnia * layout is "hspace button hspace button [...] hspace", to pad 6780bbfda8aSnia * between and on both sides. 6790bbfda8aSnia */ 6800bbfda8aSnia bb_width = 3 * (bbwidth + hspace) + hspace; 6810bbfda8aSnia 6820bbfda8aSnia /* 6830bbfda8aSnia * It also has to be the width of our per-WS buttons. Per-ws 6840bbfda8aSnia * buttons are sized the same as in the button-state WSM, and 6850bbfda8aSnia * then we add the padding to them as above. 6860bbfda8aSnia */ 6870bbfda8aSnia ws_width = columns * (bwidth + hspace) + hspace; 6880bbfda8aSnia 6890bbfda8aSnia /* So the window has to be as wide as the wider of those */ 6900bbfda8aSnia width = MAX(bb_width, ws_width); 6910bbfda8aSnia } 6920bbfda8aSnia 6930bbfda8aSnia 6940bbfda8aSnia /* Now we know the size, so make the window */ 6950bbfda8aSnia w = occwin->w = XCreateSimpleWindow(dpy, Scr->Root, 0, 0, width, height, 6960bbfda8aSnia 1, Scr->Black, occwin->cp.back); 6970bbfda8aSnia 6980bbfda8aSnia /* Take those base sizes as a minimum */ 6990bbfda8aSnia occwin->minwidth = width; 7000bbfda8aSnia occwin->minheight = height; 7010bbfda8aSnia 7020bbfda8aSnia 7030bbfda8aSnia /* 7040bbfda8aSnia * Make subwindows as buttons for the workspaces. They're laid out 7050bbfda8aSnia * in a grid mirroring the workspace manager's. 7060bbfda8aSnia */ 7070bbfda8aSnia { 7080bbfda8aSnia int i = 0, j = 0; 7090bbfda8aSnia WorkSpace *ws; 7100bbfda8aSnia 7110bbfda8aSnia occwin->obuttonw = calloc(Scr->workSpaceMgr.count, sizeof(Window)); 7120bbfda8aSnia 7130bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 7140bbfda8aSnia int idx = (j * columns) + i; 7150bbfda8aSnia 7160bbfda8aSnia /* 7170bbfda8aSnia * Make and map. Note that we're not setting the size or 7180bbfda8aSnia * location at all here; ResizeOccupyWindow() does all that. 7190bbfda8aSnia * We just make 'em. 7200bbfda8aSnia */ 7210bbfda8aSnia occwin->obuttonw[idx] = XCreateSimpleWindow(dpy, w, 7220bbfda8aSnia Dummy /* x */, 7230bbfda8aSnia Dummy /* y */, 7240bbfda8aSnia Dummy /* width */, 7250bbfda8aSnia Dummy /* height */, 7260bbfda8aSnia 0, Scr->Black, ws->cp.back); 7270bbfda8aSnia XMapWindow(dpy, occwin->obuttonw[idx]); 7280bbfda8aSnia 7290bbfda8aSnia /* Inc around to the next location */ 7300bbfda8aSnia i++; 7310bbfda8aSnia if(i == columns) { 7320bbfda8aSnia i = 0; 7330bbfda8aSnia j++; 7340bbfda8aSnia } 7350bbfda8aSnia } 7360bbfda8aSnia } 7370bbfda8aSnia 7380bbfda8aSnia 7390bbfda8aSnia /* 7400bbfda8aSnia * Now start putting together the OK/Cancel/All buttons 7410bbfda8aSnia */ 7420bbfda8aSnia 7430bbfda8aSnia /* Background for them is hardcoded */ 7440bbfda8aSnia GetColor(Scr->Monochrome, &(occupyButtoncp.back), "gray50"); 7450bbfda8aSnia 7460bbfda8aSnia /* Foreground (not used here) is too */ 7470bbfda8aSnia occupyButtoncp.fore = Scr->White; 7480bbfda8aSnia 7490bbfda8aSnia /* Override (probably historical */ 7500bbfda8aSnia if(!Scr->BeNiceToColormap) { 7510bbfda8aSnia GetShadeColors(&occupyButtoncp); 7520bbfda8aSnia } 7530bbfda8aSnia 7540bbfda8aSnia /* Make 'em */ 7550bbfda8aSnia { 7560bbfda8aSnia Window tw; 7570bbfda8aSnia 7580bbfda8aSnia tw = XCreateSimpleWindow(dpy, w, Dummy, Dummy, Dummy, Dummy, 0, 7590bbfda8aSnia Scr->Black, occupyButtoncp.back); 7600bbfda8aSnia XMapWindow(dpy, tw); 7610bbfda8aSnia occwin->OK = tw; 7620bbfda8aSnia 7630bbfda8aSnia tw = XCreateSimpleWindow(dpy, w, Dummy, Dummy, Dummy, Dummy, 0, 7640bbfda8aSnia Scr->Black, occupyButtoncp.back); 7650bbfda8aSnia XMapWindow(dpy, tw); 7660bbfda8aSnia occwin->cancel = tw; 7670bbfda8aSnia 7680bbfda8aSnia tw = XCreateSimpleWindow(dpy, w, Dummy, Dummy, Dummy, Dummy, 0, 7690bbfda8aSnia Scr->Black, occupyButtoncp.back); 7700bbfda8aSnia XMapWindow(dpy, tw); 7710bbfda8aSnia occwin->allworkspc = tw; 7720bbfda8aSnia } 7730bbfda8aSnia 7740bbfda8aSnia 7750bbfda8aSnia /* Setup various window properties */ 7760bbfda8aSnia { 7770bbfda8aSnia XSizeHints sizehints; 7780bbfda8aSnia XWMHints wmhints; 7790bbfda8aSnia 7800bbfda8aSnia sizehints.flags = PBaseSize | PMinSize | PMaxSize; 7810bbfda8aSnia sizehints.min_width = width; 7820bbfda8aSnia sizehints.min_height = height; 7830bbfda8aSnia sizehints.base_width = width; 7840bbfda8aSnia sizehints.base_height = height; 7850bbfda8aSnia sizehints.max_width = width; 7860bbfda8aSnia sizehints.max_height = height; 7870bbfda8aSnia 7880bbfda8aSnia wmhints.flags = InputHint | StateHint; 7890bbfda8aSnia wmhints.input = True; 7900bbfda8aSnia wmhints.initial_state = NormalState; 7910bbfda8aSnia 7920bbfda8aSnia XmbSetWMProperties(dpy, w, occwin->name, occwin->icon_name, 7930bbfda8aSnia NULL, 0, &sizehints, &wmhints, NULL); 7940bbfda8aSnia } 7950bbfda8aSnia 7960bbfda8aSnia 7970bbfda8aSnia /* 7980bbfda8aSnia * Create the TwmWindow wrapping around it, with decorations etc. We 7990bbfda8aSnia * do this so early in startup that we're not listening for window 8000bbfda8aSnia * creation events yet. 8010bbfda8aSnia */ 8020bbfda8aSnia tmp_win = AddWindow(w, AWT_OCCUPY, Scr->iconmgr, Scr->currentvs); 8030bbfda8aSnia if(! tmp_win) { 8040bbfda8aSnia fprintf(stderr, "cannot create occupy window, exiting...\n"); 8050bbfda8aSnia exit(1); 8060bbfda8aSnia } 8070bbfda8aSnia tmp_win->vs = NULL; 8080bbfda8aSnia tmp_win->occupation = 0; 8090bbfda8aSnia 8100bbfda8aSnia /* tmp_win is more convenient the rest of the func, but put in place */ 8110bbfda8aSnia occwin->twm_win = tmp_win; 8120bbfda8aSnia 8130bbfda8aSnia 8140bbfda8aSnia /* 8150bbfda8aSnia * Setup the window to have a button-pushing cursor and listen for 8160bbfda8aSnia * clicks. 8170bbfda8aSnia */ 8180bbfda8aSnia { 8190bbfda8aSnia unsigned long attrmask; 8200bbfda8aSnia XSetWindowAttributes attr; 8210bbfda8aSnia XWindowAttributes wattr; 8220bbfda8aSnia 8230bbfda8aSnia attr.cursor = Scr->ButtonCursor; 8240bbfda8aSnia attrmask = CWCursor; 8250bbfda8aSnia XChangeWindowAttributes(dpy, w, attrmask, &attr); 8260bbfda8aSnia 8270bbfda8aSnia XGetWindowAttributes(dpy, w, &wattr); 8280bbfda8aSnia attrmask = wattr.your_event_mask | KeyPressMask | KeyReleaseMask 8290bbfda8aSnia | ExposureMask; 8300bbfda8aSnia XSelectInput(dpy, w, attrmask); 8310bbfda8aSnia } 8320bbfda8aSnia 8330bbfda8aSnia 8340bbfda8aSnia /* 8350bbfda8aSnia * Now for each of the buttons (workspaces + OK/Cancel/All), we mark 8360bbfda8aSnia * them as listening to click and exposure events. We also stash 8370bbfda8aSnia * away the screen and wrapping TwmWindow in contexts so other code 8380bbfda8aSnia * can dredge them up. 8390bbfda8aSnia */ 8400bbfda8aSnia#define EVT (ButtonPressMask | ButtonReleaseMask | ExposureMask) 8410bbfda8aSnia#define BTN_IPT_CTX(win) \ 8420bbfda8aSnia XSelectInput(dpy, (win), EVT); \ 8430bbfda8aSnia XSaveContext(dpy, (win), TwmContext, (XPointer) tmp_win); \ 8440bbfda8aSnia XSaveContext(dpy, (win), ScreenContext, (XPointer) Scr); 8450bbfda8aSnia 8460bbfda8aSnia for(WorkSpace *ws = Scr->workSpaceMgr.workSpaceList 8470bbfda8aSnia ; ws != NULL ; ws = ws->next) { 8480bbfda8aSnia BTN_IPT_CTX(occwin->obuttonw[ws->number]); 8490bbfda8aSnia } 8500bbfda8aSnia 8510bbfda8aSnia BTN_IPT_CTX(occwin->OK); 8520bbfda8aSnia BTN_IPT_CTX(occwin->cancel); 8530bbfda8aSnia BTN_IPT_CTX(occwin->allworkspc); 8540bbfda8aSnia 8550bbfda8aSnia#undef BTN_IPT_CTX 8560bbfda8aSnia#undef EVT 8570bbfda8aSnia 8580bbfda8aSnia 8590bbfda8aSnia /* Mark that we're not mapped */ 8600bbfda8aSnia SetMapStateProp(tmp_win, WithdrawnState); 8610bbfda8aSnia 8620bbfda8aSnia /* Now call that func that sizes all the buttons */ 8630bbfda8aSnia ResizeOccupyWindow(tmp_win); 8640bbfda8aSnia} 8650bbfda8aSnia 8660bbfda8aSnia 8670bbfda8aSnia/* 8680bbfda8aSnia * Slightly misleading name: layout the internals of the Occupy window 8690bbfda8aSnia * based on its current size. That does happen when it's resized, but 8700bbfda8aSnia * also when it's initially created. I guess you could call "creation" a 8710bbfda8aSnia * resize of a sort... 8720bbfda8aSnia */ 8730bbfda8aSniavoid 8740bbfda8aSniaResizeOccupyWindow(TwmWindow *win) 8750bbfda8aSnia{ 8760bbfda8aSnia int bwidth, bheight, owidth, oheight; 8770bbfda8aSnia int hspace, vspace; 8780bbfda8aSnia int lines, columns; 8790bbfda8aSnia int neww, newh; 8800bbfda8aSnia WorkSpace *ws; 8810bbfda8aSnia int i, j, x, y; 8820bbfda8aSnia OccupyWindow *occwin = Scr->workSpaceMgr.occupyWindow; 8830bbfda8aSnia 8840bbfda8aSnia /* Floor at the original size */ 8850bbfda8aSnia neww = MAX(win->attr.width, occwin->minwidth); 8860bbfda8aSnia newh = MAX(win->attr.height, occwin->minheight); 8870bbfda8aSnia if(occwin->width == neww && occwin->height == newh) { 8880bbfda8aSnia return; 8890bbfda8aSnia } 8900bbfda8aSnia 8910bbfda8aSnia /* Space between WS buttons. From WMgr{Horiz,Vert}ButtonIndent. */ 8920bbfda8aSnia hspace = occwin->hspace; 8930bbfda8aSnia vspace = occwin->vspace; 8940bbfda8aSnia 8950bbfda8aSnia /* Lines/cols in the layout. Same as WorkspaceManager's */ 8960bbfda8aSnia lines = Scr->workSpaceMgr.lines; 8970bbfda8aSnia columns = Scr->workSpaceMgr.columns; 8980bbfda8aSnia 8990bbfda8aSnia /* Width/height of each button, based on the above and window size */ 9000bbfda8aSnia bwidth = (neww - columns * hspace) / columns; 9010bbfda8aSnia bheight = (newh - (lines + 2) * vspace) / (lines + 1); 9020bbfda8aSnia 9030bbfda8aSnia /* Width/height of the OK/Cancel/All buttons */ 9040bbfda8aSnia owidth = occwin->owidth; 9050bbfda8aSnia oheight = bheight; 9060bbfda8aSnia 9070bbfda8aSnia 9080bbfda8aSnia /* 9090bbfda8aSnia * Lay out the workspace buttons 9100bbfda8aSnia */ 9110bbfda8aSnia i = 0; 9120bbfda8aSnia j = 0; 9130bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 9140bbfda8aSnia XMoveResizeWindow(dpy, occwin->obuttonw [j * columns + i], 9150bbfda8aSnia i * (bwidth + hspace) + (hspace / 2), 9160bbfda8aSnia j * (bheight + vspace) + (vspace / 2), 9170bbfda8aSnia bwidth, bheight); 9180bbfda8aSnia i++; 9190bbfda8aSnia if(i == columns) { 9200bbfda8aSnia i = 0; 9210bbfda8aSnia j++; 9220bbfda8aSnia } 9230bbfda8aSnia } 9240bbfda8aSnia 9250bbfda8aSnia 9260bbfda8aSnia /* 9270bbfda8aSnia * Now the action buttons 9280bbfda8aSnia */ 9290bbfda8aSnia hspace = (neww - 3 * owidth) / 4; // Padding between 9300bbfda8aSnia x = hspace; 9310bbfda8aSnia y = ((bheight + vspace) * lines) + ((3 * vspace) / 2); 9320bbfda8aSnia XMoveResizeWindow(dpy, occwin->OK, x, y, owidth, oheight); 9330bbfda8aSnia x += owidth + hspace; 9340bbfda8aSnia XMoveResizeWindow(dpy, occwin->cancel, x, y, owidth, oheight); 9350bbfda8aSnia x += owidth + hspace; 9360bbfda8aSnia XMoveResizeWindow(dpy, occwin->allworkspc, x, y, owidth, oheight); 9370bbfda8aSnia 9380bbfda8aSnia 9390bbfda8aSnia /* Save all those dimensions we figured */ 9400bbfda8aSnia occwin->width = neww; 9410bbfda8aSnia occwin->height = newh; 9420bbfda8aSnia occwin->bwidth = bwidth; 9430bbfda8aSnia occwin->bheight = bheight; 9440bbfda8aSnia occwin->owidth = owidth; 9450bbfda8aSnia 9460bbfda8aSnia /* Don't need to repaint it; it'll get expose events */ 9470bbfda8aSnia} 9480bbfda8aSnia 9490bbfda8aSnia 9500bbfda8aSnia/* 9510bbfda8aSnia * Draw the window when we need to (e.g., on expose) 9520bbfda8aSnia */ 9530bbfda8aSniavoid 9540bbfda8aSniaPaintOccupyWindow(void) 9550bbfda8aSnia{ 9560bbfda8aSnia WorkSpace *ws; 9570bbfda8aSnia OccupyWindow *occwin; 9580bbfda8aSnia int width, height; 9590bbfda8aSnia 9600bbfda8aSnia occwin = Scr->workSpaceMgr.occupyWindow; 9610bbfda8aSnia width = occwin->width; 9620bbfda8aSnia height = occwin->height; 9630bbfda8aSnia 9640bbfda8aSnia Draw3DBorder(occwin->w, 0, 0, width, height, 2, occwin->cp, off, true, false); 9650bbfda8aSnia 9660bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 9670bbfda8aSnia Window bw = occwin->obuttonw [ws->number]; 9680bbfda8aSnia ButtonState bs = (occwin->tmpOccupation & (1 << ws->number)) ? on : off; 9690bbfda8aSnia 9700bbfda8aSnia PaintWsButton(OCCUPYWINDOW, NULL, bw, ws->label, ws->cp, bs); 9710bbfda8aSnia } 9720bbfda8aSnia PaintWsButton(OCCUPYBUTTON, NULL, occwin->OK, ok_string, 9730bbfda8aSnia occupyButtoncp, off); 9740bbfda8aSnia PaintWsButton(OCCUPYBUTTON, NULL, occwin->cancel, cancel_string, 9750bbfda8aSnia occupyButtoncp, off); 9760bbfda8aSnia PaintWsButton(OCCUPYBUTTON, NULL, occwin->allworkspc, everywhere_string, 9770bbfda8aSnia occupyButtoncp, off); 9780bbfda8aSnia} 9790bbfda8aSnia 9800bbfda8aSnia 9810bbfda8aSnia/* 9820bbfda8aSnia * Somebody clicked in the Occupy window 9830bbfda8aSnia */ 9840bbfda8aSniavoid 9850bbfda8aSniaOccupyHandleButtonEvent(XEvent *event) 9860bbfda8aSnia{ 9870bbfda8aSnia WorkSpace *ws; 9880bbfda8aSnia OccupyWindow *occupyW; 9890bbfda8aSnia Window buttonW; 9900bbfda8aSnia 9910bbfda8aSnia /* 9920bbfda8aSnia * Doesn't make sense that this can even happen if there are no 9930bbfda8aSnia * workspaces... 9940bbfda8aSnia */ 9950bbfda8aSnia if(! Scr->workSpaceManagerActive) { 9960bbfda8aSnia return; 9970bbfda8aSnia } 9980bbfda8aSnia 9990bbfda8aSnia /* ... or if there's no Occupy window up for anything */ 10000bbfda8aSnia if(occupyWin == NULL) { 10010bbfda8aSnia return; 10020bbfda8aSnia } 10030bbfda8aSnia 10040bbfda8aSnia /* Which sub-window (button) was clicked */ 10050bbfda8aSnia buttonW = event->xbutton.window; 10060bbfda8aSnia if(buttonW == 0) { 10070bbfda8aSnia return; /* icon */ 10080bbfda8aSnia } 10090bbfda8aSnia 10100bbfda8aSnia /* Grab onto the pointer for the duration of our action */ 10110bbfda8aSnia XGrabPointer(dpy, Scr->Root, True, 10120bbfda8aSnia ButtonPressMask | ButtonReleaseMask, 10130bbfda8aSnia GrabModeAsync, GrabModeAsync, 10140bbfda8aSnia Scr->Root, None, CurrentTime); 10150bbfda8aSnia 10160bbfda8aSnia /* Find the workspace button that was clicked */ 10170bbfda8aSnia occupyW = Scr->workSpaceMgr.occupyWindow; 10180bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 10190bbfda8aSnia if(occupyW->obuttonw [ws->number] == buttonW) { 10200bbfda8aSnia break; 10210bbfda8aSnia } 10220bbfda8aSnia } 10230bbfda8aSnia 10240bbfda8aSnia if(ws != NULL) { 10250bbfda8aSnia /* If one was, toggle it */ 10260bbfda8aSnia int mask = 1 << ws->number; 10270bbfda8aSnia ButtonState bs = (occupyW->tmpOccupation & mask) ? off : on; 10280bbfda8aSnia 10290bbfda8aSnia PaintWsButton(OCCUPYWINDOW, NULL, occupyW->obuttonw [ws->number], 10300bbfda8aSnia ws->label, ws->cp, bs); 10310bbfda8aSnia occupyW->tmpOccupation ^= mask; 10320bbfda8aSnia } 10330bbfda8aSnia else if(buttonW == occupyW->OK) { 10340bbfda8aSnia /* Else if we clicked OK, set things and close the window */ 10350bbfda8aSnia if(occupyW->tmpOccupation == 0) { 10360bbfda8aSnia return; 10370bbfda8aSnia } 10380bbfda8aSnia ChangeOccupation(occupyWin, occupyW->tmpOccupation); 10390bbfda8aSnia XUnmapWindow(dpy, occupyW->twm_win->frame); 10400bbfda8aSnia occupyW->twm_win->mapped = false; 10410bbfda8aSnia occupyW->twm_win->occupation = 0; 10420bbfda8aSnia occupyWin = NULL; 10430bbfda8aSnia XSync(dpy, 0); 10440bbfda8aSnia } 10450bbfda8aSnia else if(buttonW == occupyW->cancel) { 10460bbfda8aSnia /* Or cancel, do nothing and close the window */ 10470bbfda8aSnia XUnmapWindow(dpy, occupyW->twm_win->frame); 10480bbfda8aSnia occupyW->twm_win->mapped = false; 10490bbfda8aSnia occupyW->twm_win->occupation = 0; 10500bbfda8aSnia occupyWin = NULL; 10510bbfda8aSnia XSync(dpy, 0); 10520bbfda8aSnia } 10530bbfda8aSnia else if(buttonW == occupyW->allworkspc) { 10540bbfda8aSnia /* Or All, set 'em all */ 10550bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 10560bbfda8aSnia PaintWsButton(OCCUPYWINDOW, NULL, occupyW->obuttonw [ws->number], 10570bbfda8aSnia ws->label, ws->cp, on); 10580bbfda8aSnia } 10590bbfda8aSnia occupyW->tmpOccupation = fullOccupation; 10600bbfda8aSnia } 10610bbfda8aSnia 10620bbfda8aSnia /* Release the pointer, if ??? */ 10630bbfda8aSnia if(ButtonPressed == -1) { 10640bbfda8aSnia XUngrabPointer(dpy, CurrentTime); 10650bbfda8aSnia } 10660bbfda8aSnia} 10670bbfda8aSnia 10680bbfda8aSnia 10690bbfda8aSnia/* 10700bbfda8aSnia * f.occupy backend - pop up Occupy control for some window 10710bbfda8aSnia */ 10720bbfda8aSniavoid 10730bbfda8aSniaOccupy(TwmWindow *twm_win) 10740bbfda8aSnia{ 10750bbfda8aSnia int x, y; 10760bbfda8aSnia unsigned int width, height; 10770bbfda8aSnia Window w; 10780bbfda8aSnia struct OccupyWindow *occupyWindow; 10790bbfda8aSnia TwmWindow *occupy_twm; 10800bbfda8aSnia 10810bbfda8aSnia /* Don't pop up on stuff we can't change */ 10820bbfda8aSnia if(!CanChangeOccupation(&twm_win)) { 10830bbfda8aSnia return; 10840bbfda8aSnia } 10850bbfda8aSnia 10860bbfda8aSnia /* Grab our one screen-wide f.occupy window */ 10870bbfda8aSnia occupyWindow = Scr->workSpaceMgr.occupyWindow; 10880bbfda8aSnia occupyWindow->tmpOccupation = twm_win->occupation; 10890bbfda8aSnia w = occupyWindow->w; 10900bbfda8aSnia 10910bbfda8aSnia /* Figure where to put it so it's centered on the cursor */ 10920bbfda8aSnia XGetGeometry(dpy, w, &JunkRoot, &JunkX, &JunkY, &width, &height, 10930bbfda8aSnia &JunkBW, &JunkDepth); 10940bbfda8aSnia XQueryPointer(dpy, Scr->Root, &JunkRoot, &JunkRoot, &JunkX, &JunkY, 10950bbfda8aSnia &x, &y, &JunkMask); 10960bbfda8aSnia 10970bbfda8aSnia occupy_twm = occupyWindow->twm_win; 10980bbfda8aSnia occupy_twm->occupation = twm_win->occupation; 10990bbfda8aSnia 1100b18c2d1eSnia width += 2 * (occupy_twm->frame_bw3D + occupy_twm->frame_bw); 1101b18c2d1eSnia height += 2 * (occupy_twm->frame_bw3D + occupy_twm->frame_bw); 1102b18c2d1eSnia x -= (width / 2); 1103b18c2d1eSnia y -= (height / 2); 1104b18c2d1eSnia 1105b18c2d1eSnia /* Clip to screen */ 1106b18c2d1eSnia ConstrainByLayout(Scr->BorderedLayout, -1, &x, width, &y, height); 1107b18c2d1eSnia 11080bbfda8aSnia /* Move the occupy window to where it should be */ 11090bbfda8aSnia if(occupy_twm->parent_vs != twm_win->parent_vs) { 11100bbfda8aSnia occupy_twm->vs = twm_win->parent_vs; 11110bbfda8aSnia occupy_twm->frame_x = x; 11120bbfda8aSnia occupy_twm->frame_y = y; 11130bbfda8aSnia /* 11140bbfda8aSnia * XXX Should this be using DisplayWin() like everything else, 11150bbfda8aSnia * rather than manually grubbing beneath it? 11160bbfda8aSnia */ 11170bbfda8aSnia ReparentFrameAndIcon(occupy_twm); 11180bbfda8aSnia } 11190bbfda8aSnia else { 11200bbfda8aSnia XMoveWindow(dpy, occupyWindow->twm_win->frame, x, y); 11210bbfda8aSnia } 11220bbfda8aSnia 11230bbfda8aSnia /* And show it */ 11240bbfda8aSnia SetMapStateProp(occupy_twm, NormalState); 11250bbfda8aSnia XMapWindow(dpy, occupyWindow->w); 11260bbfda8aSnia XMapWindow(dpy, occupy_twm->frame); 11270bbfda8aSnia 11280bbfda8aSnia /* XXX Must be a better way to express "all the way on top" */ 11290bbfda8aSnia OtpSetPriority(occupy_twm, WinWin, 0, Above); 11300bbfda8aSnia 11310bbfda8aSnia /* Mark it shown, and stash what window we're showing it for */ 11320bbfda8aSnia occupyWindow->twm_win->mapped = true; 11330bbfda8aSnia occupyWin = twm_win; 11340bbfda8aSnia} 11350bbfda8aSnia 11360bbfda8aSnia 11370bbfda8aSnia 11380bbfda8aSnia 11390bbfda8aSnia/* 11400bbfda8aSnia **************************************************************** 11410bbfda8aSnia * 11420bbfda8aSnia * Backend and misc 11430bbfda8aSnia * 11440bbfda8aSnia **************************************************************** 11450bbfda8aSnia */ 11460bbfda8aSnia 11470bbfda8aSnia 11480bbfda8aSnia/* 11490bbfda8aSnia * The actual meat of occupation-changing; [re-]set the occupation for 11500bbfda8aSnia * the window. This is the func that actually sets and saves the new 11510bbfda8aSnia * occupation, moves the window where it should be, etc. Should maybe be 11520bbfda8aSnia * called something more like "SetOccupation()". 11530bbfda8aSnia */ 11540bbfda8aSniavoid 11550bbfda8aSniaChangeOccupation(TwmWindow *tmp_win, int newoccupation) 11560bbfda8aSnia{ 11570bbfda8aSnia TwmWindow *t; 11580bbfda8aSnia WorkSpace *ws; 11590bbfda8aSnia int oldoccupation; 11600bbfda8aSnia int changedoccupation; 11610bbfda8aSnia 11620bbfda8aSnia if((newoccupation == 0) 11630bbfda8aSnia || (newoccupation == tmp_win->occupation)) { 11640bbfda8aSnia /* 11650bbfda8aSnia * occupation=0 we interpret as "leave it alone". == current, 11660bbfda8aSnia * ditto. Go ahead and re-set the WM_OCCUPATION property though, 11670bbfda8aSnia * in case it's been broken by another client. 11680bbfda8aSnia */ 11690bbfda8aSnia char *namelist; 11700bbfda8aSnia int len; 11710bbfda8aSnia long eventMask; 11720bbfda8aSnia 11730bbfda8aSnia /* Mask out the PropertyChange events while we change the prop */ 11740bbfda8aSnia eventMask = mask_out_event(tmp_win->w, PropertyChangeMask); 11750bbfda8aSnia 11760bbfda8aSnia len = GetPropertyFromMask(tmp_win->occupation, &namelist); 11770bbfda8aSnia XChangeProperty(dpy, tmp_win->w, XA_WM_OCCUPATION, XA_STRING, 8, 11780bbfda8aSnia PropModeReplace, (unsigned char *) namelist, len); 11790bbfda8aSnia free(namelist); 11800bbfda8aSnia#ifdef EWMH 11810bbfda8aSnia EwmhSet_NET_WM_DESKTOP(tmp_win); 11820bbfda8aSnia#endif 11830bbfda8aSnia 11840bbfda8aSnia /* Reset event mask */ 11850bbfda8aSnia restore_mask(tmp_win->w, eventMask); 11860bbfda8aSnia return; 11870bbfda8aSnia } 11880bbfda8aSnia 11890bbfda8aSnia /* 11900bbfda8aSnia * OK, there's something to change. Stash the current state. 11910bbfda8aSnia */ 11920bbfda8aSnia oldoccupation = tmp_win->occupation; 11930bbfda8aSnia 11940bbfda8aSnia /* 11950bbfda8aSnia * Add it to IconManager in the new WS[en], remove from old. We have 11960bbfda8aSnia * to do the rather odd dance because AddIconManager() loops through 11970bbfda8aSnia * workspaces, and will add it to any workspaces it occupies (even if 11980bbfda8aSnia * it's already there). RemoveIconManager() goes over the window's 11990bbfda8aSnia * list of what icon managers it's on and removes it from any that 12000bbfda8aSnia * don't match the current occupation, so it can just be told "here's 12010bbfda8aSnia * where I should be". 12020bbfda8aSnia */ 12030bbfda8aSnia tmp_win->occupation = newoccupation & ~oldoccupation; 12040bbfda8aSnia AddIconManager(tmp_win); 12050bbfda8aSnia tmp_win->occupation = newoccupation; 12060bbfda8aSnia RemoveIconManager(tmp_win); 12070bbfda8aSnia 12080bbfda8aSnia /* If it shouldn't be "here", vanish it */ 12090bbfda8aSnia if(tmp_win->vs && !OCCUPY(tmp_win, tmp_win->vs->wsw->currentwspc)) { 12100bbfda8aSnia Vanish(tmp_win->vs, tmp_win); 12110bbfda8aSnia } 12120bbfda8aSnia 12130bbfda8aSnia /* 12140bbfda8aSnia * Try to find an(other) virtual screen which shows a workspace 12150bbfda8aSnia * where the window has occupation, so that the window can be shown 12160bbfda8aSnia * there now. 12170bbfda8aSnia */ 12180bbfda8aSnia if(!tmp_win->vs) { 12190bbfda8aSnia VirtualScreen *vs; 12200bbfda8aSnia for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) { 12210bbfda8aSnia if(OCCUPY(tmp_win, vs->wsw->currentwspc)) { 12220bbfda8aSnia DisplayWin(vs, tmp_win); 12230bbfda8aSnia break; 12240bbfda8aSnia } 12250bbfda8aSnia } 12260bbfda8aSnia } 12270bbfda8aSnia 12280bbfda8aSnia /* 12290bbfda8aSnia * Loop over workspaces. Find the first one that it used to be in. 12300bbfda8aSnia * If it's not there anymore, take it out of the WindowRegion there 12310bbfda8aSnia * (RWFR() silently returns if we're not using WindowRegion's), and 12320bbfda8aSnia * add it the WindowRegion in the first WS it now occupies. 12330bbfda8aSnia * 12340bbfda8aSnia * XXX I'm not sure this is entirely sensible; it seems like just 12350bbfda8aSnia * unconditionally Remove/Place'ing would have the same effect? 12360bbfda8aSnia */ 12370bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 12380bbfda8aSnia int mask = 1 << ws->number; 12390bbfda8aSnia if(oldoccupation & mask) { 12400bbfda8aSnia if(!(newoccupation & mask)) { 12410bbfda8aSnia int final_x, final_y; 12420bbfda8aSnia RemoveWindowFromRegion(tmp_win); 12430bbfda8aSnia if(PlaceWindowInRegion(tmp_win, &final_x, &final_y)) { 12440bbfda8aSnia XMoveWindow(dpy, tmp_win->frame, final_x, final_y); 12450bbfda8aSnia } 12460bbfda8aSnia } 12470bbfda8aSnia break; 12480bbfda8aSnia } 12490bbfda8aSnia } 12500bbfda8aSnia 12510bbfda8aSnia /* Now set the WM_OCCUPATION property */ 12520bbfda8aSnia { 12530bbfda8aSnia char *namelist; 12540bbfda8aSnia int len; 12550bbfda8aSnia long eventMask; 12560bbfda8aSnia 12570bbfda8aSnia eventMask = mask_out_event(tmp_win->w, PropertyChangeMask); 12580bbfda8aSnia 12590bbfda8aSnia len = GetPropertyFromMask(newoccupation, &namelist); 12600bbfda8aSnia XChangeProperty(dpy, tmp_win->w, XA_WM_OCCUPATION, XA_STRING, 8, 12610bbfda8aSnia PropModeReplace, (unsigned char *) namelist, len); 12620bbfda8aSnia free(namelist); 12630bbfda8aSnia#ifdef EWMH 12640bbfda8aSnia EwmhSet_NET_WM_DESKTOP(tmp_win); 12650bbfda8aSnia#endif 12660bbfda8aSnia 12670bbfda8aSnia restore_mask(tmp_win->w, eventMask); 12680bbfda8aSnia } 12690bbfda8aSnia 12700bbfda8aSnia 12710bbfda8aSnia /* 12720bbfda8aSnia * Handle showing it up in the workspace map in the appropriate 12730bbfda8aSnia * places. 12740bbfda8aSnia * 12750bbfda8aSnia * Note that this whole block messes with the {new,old}occupation 12760bbfda8aSnia * vars. That's "safe" because they're no longer used for their 12770bbfda8aSnia * original purposes, only for the WSmap changes, but it's still 12780bbfda8aSnia * kinda fugly. Change to local vars at the drop of a hat with later 12790bbfda8aSnia * changes... 12800bbfda8aSnia */ 12810bbfda8aSnia if(!WMapWindowMayBeAdded(tmp_win)) { 12820bbfda8aSnia /* Not showing in the map, so pretend it's nowhere */ 12830bbfda8aSnia newoccupation = 0; 12840bbfda8aSnia } 12850bbfda8aSnia if(Scr->workSpaceMgr.noshowoccupyall) { 12860bbfda8aSnia /* 12870bbfda8aSnia * Don't show OccupyAll. Note that this means both OccupyAll 12880bbfda8aSnia * window, AND windows manually set to occupy everything. We 12890bbfda8aSnia * don't have to adjust newoccupation, because the above 12900bbfda8aSnia * conditional would have caught it, so we only need to edit old. 12910bbfda8aSnia */ 12920bbfda8aSnia if(oldoccupation == fullOccupation) { 12930bbfda8aSnia oldoccupation = 0; 12940bbfda8aSnia } 12950bbfda8aSnia } 12960bbfda8aSnia 12970bbfda8aSnia /* Flip the ones that need flipping */ 12980bbfda8aSnia changedoccupation = oldoccupation ^ newoccupation; 12990bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 13000bbfda8aSnia int mask = 1 << ws->number; 13010bbfda8aSnia if(changedoccupation & mask) { 13020bbfda8aSnia if(newoccupation & mask) { 13030bbfda8aSnia /* Add to WS */ 13040bbfda8aSnia WMapAddWindowToWorkspace(tmp_win, ws); 13050bbfda8aSnia } 13060bbfda8aSnia else { 13070bbfda8aSnia /* 13080bbfda8aSnia * Remove from WS. We have to take it out of saved focus 13090bbfda8aSnia * if it were there. Maybe there are other places we 13100bbfda8aSnia * might need to remove it from (warpring?)? 13110bbfda8aSnia */ 13120bbfda8aSnia WMapRemoveWindowFromWorkspace(tmp_win, ws); 13130bbfda8aSnia if(Scr->SaveWorkspaceFocus && ws->save_focus == tmp_win) { 13140bbfda8aSnia ws->save_focus = NULL; 13150bbfda8aSnia } 13160bbfda8aSnia } 13170bbfda8aSnia } 13180bbfda8aSnia } 13190bbfda8aSnia 13200bbfda8aSnia 13210bbfda8aSnia /* 13220bbfda8aSnia * If transients don't have their own occupation, find any transients 13230bbfda8aSnia * of this window and move them with it. 13240bbfda8aSnia */ 13250bbfda8aSnia if(! Scr->TransientHasOccupation) { 13260bbfda8aSnia for(t = Scr->FirstWindow; t != NULL; t = t->next) { 13270bbfda8aSnia if(t != tmp_win && 13280bbfda8aSnia ((t->istransient && t->transientfor == tmp_win->w) || 13290bbfda8aSnia t->group == tmp_win->w)) { 13300bbfda8aSnia ChangeOccupation(t, tmp_win->occupation); 13310bbfda8aSnia } 13320bbfda8aSnia } 13330bbfda8aSnia } 13340bbfda8aSnia 13350bbfda8aSnia /* All done */ 13360bbfda8aSnia return; 13370bbfda8aSnia} 13380bbfda8aSnia 13390bbfda8aSnia 13400bbfda8aSnia/* 13410bbfda8aSnia * There are various reasons you might not be able to change the 13420bbfda8aSnia * occupation of a window (either due to attributes of it, or the state 13430bbfda8aSnia * of your session/WM), so provide a function to check them all when we 13440bbfda8aSnia * try a change. 13450bbfda8aSnia * 13460bbfda8aSnia * Note that this is _not_ called from ChangeOccupation(); only from 13470bbfda8aSnia * other things that wrap it. Since CO() gets called from states where 13480bbfda8aSnia * this would [falsely] fail, it would be a bad idea to put it there. 13490bbfda8aSnia */ 13500bbfda8aSniastatic bool 13510bbfda8aSniaCanChangeOccupation(TwmWindow **twm_winp) 13520bbfda8aSnia{ 13530bbfda8aSnia TwmWindow *twm_win; 13540bbfda8aSnia 13550bbfda8aSnia /* No workspaces config'd? Changing is nonsensical. */ 13560bbfda8aSnia if(!Scr->workSpaceManagerActive) { 13570bbfda8aSnia return false; 13580bbfda8aSnia } 13590bbfda8aSnia 13600bbfda8aSnia /* 13610bbfda8aSnia * f.occupy window up? Can't change in the middle of changing. 13620bbfda8aSnia * Though if it's not mapped, still pull it up, else iconifying the 13630bbfda8aSnia * occupy window breaks it forever. 13640bbfda8aSnia */ 13650bbfda8aSnia if(occupyWin != NULL && Scr->workSpaceMgr.occupyWindow->twm_win->mapped) { 13660bbfda8aSnia return false; 13670bbfda8aSnia } 13680bbfda8aSnia 13690bbfda8aSnia /* XXX Can we jut do this in the init? Check all callers. */ 13700bbfda8aSnia twm_win = *twm_winp; 13710bbfda8aSnia 13720bbfda8aSnia /* Don't change occupation of icon managers */ 13730bbfda8aSnia if(twm_win->isiconmgr) { 13740bbfda8aSnia return false; 13750bbfda8aSnia } 13760bbfda8aSnia 13770bbfda8aSnia /* XXX Should check iswspmgr here too? */ 13780bbfda8aSnia 13790bbfda8aSnia /* 13800bbfda8aSnia * If transients don't have their own occupation, check 13810bbfda8aSnia * transient/group bits. 13820bbfda8aSnia */ 13830bbfda8aSnia if(!Scr->TransientHasOccupation) { 13840bbfda8aSnia if(twm_win->istransient) { 13850bbfda8aSnia return false; 13860bbfda8aSnia } 13870bbfda8aSnia if(twm_win->group != (Window) 0 && twm_win->group != twm_win->w) { 13880bbfda8aSnia /* 13890bbfda8aSnia * When trying to modify a group member window, 13900bbfda8aSnia * operate on the group leader instead 13910bbfda8aSnia * (and thereby on all group member windows as well). 13920bbfda8aSnia * If we can't find the group leader, pretend it isn't set. 13930bbfda8aSnia */ 13940bbfda8aSnia twm_win = GetTwmWindow(twm_win->group); 13950bbfda8aSnia if(!twm_win) { 13960bbfda8aSnia return true; 13970bbfda8aSnia } 13980bbfda8aSnia *twm_winp = twm_win; 13990bbfda8aSnia } 14000bbfda8aSnia } 14010bbfda8aSnia 14020bbfda8aSnia /* Sure, go ahead, change it */ 14030bbfda8aSnia return true; 14040bbfda8aSnia} 14050bbfda8aSnia 14060bbfda8aSnia 14070bbfda8aSnia/* 14080bbfda8aSnia * Add a client name to a list determining which workspaces it will 14090bbfda8aSnia * occupy. Used in handling the Occupy { } block in config file. 14100bbfda8aSnia */ 14110bbfda8aSniabool 14120bbfda8aSniaAddToClientsList(char *workspace, char *client) 14130bbfda8aSnia{ 14140bbfda8aSnia WorkSpace *ws; 14150bbfda8aSnia 14160bbfda8aSnia /* "all" is a magic workspace value which makes it occupy anywhere */ 14170bbfda8aSnia if(strcmp(workspace, "all") == 0) { 14180bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 14190bbfda8aSnia AddToList(&ws->clientlist, client, ""); 14200bbfda8aSnia } 14210bbfda8aSnia return true; 14220bbfda8aSnia } 14230bbfda8aSnia 14240bbfda8aSnia /* If prefixed with "ws:", strip the prefix and lookup by WS name */ 14250bbfda8aSnia if(strncmp(workspace, "ws:", 3) == 0) { 14260bbfda8aSnia if((ws = GetWorkspace(workspace + 3)) != NULL) { 14270bbfda8aSnia AddToList(&ws->clientlist, client, ""); 14280bbfda8aSnia return true; 14290bbfda8aSnia } 14300bbfda8aSnia } 14310bbfda8aSnia 14320bbfda8aSnia /* Else find that named workspace and all this to it */ 14330bbfda8aSnia if((ws = GetWorkspace(workspace)) != NULL) { 14340bbfda8aSnia AddToList(&ws->clientlist, client, ""); 14350bbfda8aSnia return true; 14360bbfda8aSnia } 14370bbfda8aSnia 14380bbfda8aSnia /* Couldn't figure where to put it */ 14390bbfda8aSnia return false; 14400bbfda8aSnia} 14410bbfda8aSnia 14420bbfda8aSnia 14430bbfda8aSnia/* 14440bbfda8aSnia * Turn a ctwm.workspace resource string into an occupation mask. n.b.; 14450bbfda8aSnia * this changes the 'res' arg in-place. 14460bbfda8aSnia */ 14470bbfda8aSniastatic int 14480bbfda8aSniaGetMaskFromResource(TwmWindow *win, char *res) 14490bbfda8aSnia{ 14500bbfda8aSnia WorkSpace *ws; 14510bbfda8aSnia int mask; 14520bbfda8aSnia enum { O_SET, O_ADD, O_REM } mode; 14530bbfda8aSnia char *wrkSpcName, *tokst; 14540bbfda8aSnia 14550bbfda8aSnia /* 14560bbfda8aSnia * This can set the occupation to a specific set of workspaces ("ws1 14570bbfda8aSnia * ws3"), add to the set it woudl have otherwise ("+ws1 ws3"), or 14580bbfda8aSnia * remove from the set it would otherwise ("-ws1 ws3"). The +/- 14590bbfda8aSnia * apply to the whole expression, not to the individual entries in 14600bbfda8aSnia * it. So first, figure out what we're doing. 14610bbfda8aSnia */ 14620bbfda8aSnia mode = O_SET; 14630bbfda8aSnia if(*res == '+') { 14640bbfda8aSnia mode = O_ADD; 14650bbfda8aSnia res++; 14660bbfda8aSnia } 14670bbfda8aSnia else if(*res == '-') { 14680bbfda8aSnia mode = O_REM; 14690bbfda8aSnia res++; 14700bbfda8aSnia } 14710bbfda8aSnia 14720bbfda8aSnia /* 14730bbfda8aSnia * Walk through the string adding the workspaces specified into the 14740bbfda8aSnia * mask of what we're doing. 14750bbfda8aSnia */ 14760bbfda8aSnia mask = 0; 14770bbfda8aSnia for(wrkSpcName = strtok_r(res, " ", &tokst) ; wrkSpcName 14780bbfda8aSnia ; wrkSpcName = strtok_r(NULL, " ", &tokst)) { 14790bbfda8aSnia if(strcmp(wrkSpcName, "all") == 0) { 14800bbfda8aSnia mask = fullOccupation; 14810bbfda8aSnia break; 14820bbfda8aSnia } 14830bbfda8aSnia if(strcmp(wrkSpcName, "current") == 0) { 14840bbfda8aSnia VirtualScreen *vs = Scr->currentvs; 14850bbfda8aSnia if(vs) { 14860bbfda8aSnia mask |= (1 << vs->wsw->currentwspc->number); 14870bbfda8aSnia } 14880bbfda8aSnia continue; 14890bbfda8aSnia } 14900bbfda8aSnia 14910bbfda8aSnia ws = GetWorkspace(wrkSpcName); 14920bbfda8aSnia if(ws != NULL) { 14930bbfda8aSnia mask |= (1 << ws->number); 14940bbfda8aSnia } 14950bbfda8aSnia else { 14960bbfda8aSnia fprintf(stderr, "unknown workspace : %s\n", wrkSpcName); 14970bbfda8aSnia } 14980bbfda8aSnia } 14990bbfda8aSnia 15000bbfda8aSnia /* 15010bbfda8aSnia * And return that mask, with necessary alterations depending on +/- 15020bbfda8aSnia * specified. 15030bbfda8aSnia */ 15040bbfda8aSnia switch(mode) { 15050bbfda8aSnia case O_SET: 15060bbfda8aSnia return (mask); 15070bbfda8aSnia case O_ADD: 15080bbfda8aSnia return (mask | win->occupation); 15090bbfda8aSnia case O_REM: 15100bbfda8aSnia return (win->occupation & ~mask); 15110bbfda8aSnia } 15120bbfda8aSnia 15130bbfda8aSnia /* Can't get here */ 15140bbfda8aSnia fprintf(stderr, "%s(): Unreachable.\n", __func__); 15150bbfda8aSnia return 0; 15160bbfda8aSnia} 15170bbfda8aSnia 15180bbfda8aSnia 15190bbfda8aSnia/* 15200bbfda8aSnia * Turns a \0-separated buffer of workspace names into an occupation 15210bbfda8aSnia * bitmask. 15220bbfda8aSnia */ 15230bbfda8aSniaunsigned int 15240bbfda8aSniaGetMaskFromProperty(unsigned char *_prop, unsigned long len) 15250bbfda8aSnia{ 15260bbfda8aSnia char wrkSpcName[256]; 15270bbfda8aSnia WorkSpace *ws; 15280bbfda8aSnia unsigned int mask; 15290bbfda8aSnia int l; 15300bbfda8aSnia char *prop; 15310bbfda8aSnia 15320bbfda8aSnia mask = 0; 15330bbfda8aSnia l = 0; 15340bbfda8aSnia prop = (char *) _prop; 15350bbfda8aSnia while(l < len) { 15360bbfda8aSnia /* If you have WS names longer than 256 chars, that's just Too Bad */ 15370bbfda8aSnia safe_strncpy(wrkSpcName, prop, 256); 15380bbfda8aSnia l += strlen(prop) + 1; 15390bbfda8aSnia prop += strlen(prop) + 1; 15400bbfda8aSnia if(strcmp(wrkSpcName, "all") == 0) { 15410bbfda8aSnia mask = fullOccupation; 15420bbfda8aSnia break; 15430bbfda8aSnia } 15440bbfda8aSnia 15450bbfda8aSnia ws = GetWorkspace(wrkSpcName); 15460bbfda8aSnia if(ws != NULL) { 15470bbfda8aSnia mask |= (1 << ws->number); 15480bbfda8aSnia } 15490bbfda8aSnia else { 15500bbfda8aSnia fprintf(stderr, "unknown workspace : %s\n", wrkSpcName); 15510bbfda8aSnia } 15520bbfda8aSnia } 15530bbfda8aSnia 15540bbfda8aSnia#if 0 15550bbfda8aSnia { 15560bbfda8aSnia char *dbs = mk_nullsep_string((char *)_prop, len); 15570bbfda8aSnia fprintf(stderr, "%s('%s') -> 0x%x\n", __func__, dbs, mask); 15580bbfda8aSnia free(dbs); 15590bbfda8aSnia } 15600bbfda8aSnia#endif 15610bbfda8aSnia 15620bbfda8aSnia return (mask); 15630bbfda8aSnia} 15640bbfda8aSnia 15650bbfda8aSnia 15660bbfda8aSnia/* 15670bbfda8aSnia * Turns an occupation mask into a \0-separated buffer (not really a 15680bbfda8aSnia * string) of the workspace names. 15690bbfda8aSnia */ 15700bbfda8aSniaint 15710bbfda8aSniaGetPropertyFromMask(unsigned int mask, char **prop) 15720bbfda8aSnia{ 15730bbfda8aSnia WorkSpace *ws; 15740bbfda8aSnia int len; 15750bbfda8aSnia char *wss[MAXWORKSPACE]; 15760bbfda8aSnia int i; 15770bbfda8aSnia 15780bbfda8aSnia /* If it's everything, just say 'all' */ 15790bbfda8aSnia if(mask == fullOccupation) { 15800bbfda8aSnia *prop = strdup("all"); 15810bbfda8aSnia return 3; 15820bbfda8aSnia } 15830bbfda8aSnia 15840bbfda8aSnia /* Stash up pointers to all the labels for WSen it's in */ 15850bbfda8aSnia memset(wss, 0, sizeof(wss)); 15860bbfda8aSnia i = 0; 15870bbfda8aSnia len = 0; 15880bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 15890bbfda8aSnia if(mask & (1 << ws->number)) { 15900bbfda8aSnia wss[i++] = ws->label; 15910bbfda8aSnia len += strlen(ws->label) + 1; 15920bbfda8aSnia } 15930bbfda8aSnia } 15940bbfda8aSnia 15950bbfda8aSnia /* Assemble them into \0-separated string */ 15960bbfda8aSnia *prop = malloc(len); 15970bbfda8aSnia len = 0; 15980bbfda8aSnia for(i = 0 ; wss[i] != NULL ; i++) { 15990bbfda8aSnia strcpy((*prop + len), wss[i]); 16000bbfda8aSnia len += strlen(wss[i]) + 1; // Skip past \0 16010bbfda8aSnia } 16020bbfda8aSnia 16030bbfda8aSnia#if 0 16040bbfda8aSnia { 16050bbfda8aSnia char *dbs = mk_nullsep_string(*prop, len); 16060bbfda8aSnia fprintf(stderr, "%s(0x%x) -> %d:'%s'\n", __func__, mask, len, dbs); 16070bbfda8aSnia free(dbs); 16080bbfda8aSnia } 16090bbfda8aSnia#endif 16100bbfda8aSnia 16110bbfda8aSnia return len; 16120bbfda8aSnia} 16130bbfda8aSnia 16140bbfda8aSnia 16150bbfda8aSnia/* 16160bbfda8aSnia * Generate a printable variant of the null-separated strings we use for 16170bbfda8aSnia * stashing in XA_WM_OCCUPATION. Used for debugging 16180bbfda8aSnia * Get{Property,Mask}From{Mask,Property}(). 16190bbfda8aSnia */ 16200bbfda8aSnia#ifdef __GNUC__ 16210bbfda8aSnia# pragma GCC diagnostic push 16220bbfda8aSnia# pragma GCC diagnostic ignored "-Wunused-function" 16230bbfda8aSnia#endif 16240bbfda8aSniastatic char * 16250bbfda8aSniamk_nullsep_string(const char *prop, int len) 16260bbfda8aSnia{ 16270bbfda8aSnia char *dbs; 16280bbfda8aSnia int i, j; 16290bbfda8aSnia 16300bbfda8aSnia /* 16310bbfda8aSnia * '\0' => "\\0" means we need longer than input; *2 is overkill, 16320bbfda8aSnia * but always sufficient, and it's cheap. 16330bbfda8aSnia */ 16340bbfda8aSnia dbs = malloc(len * 2); 16350bbfda8aSnia i = j = 0; 16360bbfda8aSnia while(i < len) { 16370bbfda8aSnia size_t slen = strlen(prop + i); 16380bbfda8aSnia 16390bbfda8aSnia strcpy(dbs + j, (prop + i)); 16400bbfda8aSnia i += slen + 1; 16410bbfda8aSnia strcpy(dbs + j + slen, "\\0"); 16420bbfda8aSnia j += slen + 2; 16430bbfda8aSnia } 16440bbfda8aSnia 16450bbfda8aSnia return dbs; 16460bbfda8aSnia} 16470bbfda8aSnia#ifdef __GNUC__ 16480bbfda8aSnia# pragma GCC diagnostic pop 16490bbfda8aSnia#endif 1650