workspace_manager.c revision 0bbfda8a
10bbfda8aSnia/* 20bbfda8aSnia * Copyright 1992 Claude Lecommandeur. 30bbfda8aSnia */ 40bbfda8aSnia 50bbfda8aSnia#include "ctwm.h" 60bbfda8aSnia 70bbfda8aSnia#include <stdio.h> 80bbfda8aSnia#include <string.h> 90bbfda8aSnia#include <stdlib.h> 100bbfda8aSnia 110bbfda8aSnia#include <X11/Xatom.h> 120bbfda8aSnia 130bbfda8aSnia#include "ctwm_atoms.h" 140bbfda8aSnia#include "util.h" 150bbfda8aSnia#include "animate.h" 160bbfda8aSnia#include "screen.h" 170bbfda8aSnia#include "add_window.h" 180bbfda8aSnia#include "events.h" 190bbfda8aSnia#include "otp.h" 200bbfda8aSnia#include "cursor.h" 210bbfda8aSnia#include "image.h" 220bbfda8aSnia#include "drawing.h" 230bbfda8aSnia#include "list.h" 240bbfda8aSnia#include "occupation.h" 250bbfda8aSnia#include "vscreen.h" 260bbfda8aSnia#include "win_decorations.h" 270bbfda8aSnia#include "win_iconify.h" 280bbfda8aSnia#include "win_ops.h" 290bbfda8aSnia#include "win_utils.h" 300bbfda8aSnia#include "workspace_manager.h" 310bbfda8aSnia#include "workspace_utils.h" 320bbfda8aSnia 330bbfda8aSnia#include "gram.tab.h" 340bbfda8aSnia 350bbfda8aSnia 360bbfda8aSnia// Temp; x-ref desc in workspace_utils 370bbfda8aSniaextern bool useBackgroundInfo; 380bbfda8aSnia 390bbfda8aSnia 400bbfda8aSniastatic void CreateWorkSpaceManagerWindow(VirtualScreen *vs); 410bbfda8aSniastatic void ResizeWorkSpaceManager(VirtualScreen *vs, TwmWindow *win); 420bbfda8aSniastatic void PaintWorkSpaceManagerBorder(VirtualScreen *vs); 430bbfda8aSnia 440bbfda8aSniastatic void wmap_mapwin_backend(TwmWindow *win, bool handleraise); 450bbfda8aSnia 460bbfda8aSniastatic void WMapRedrawWindow(Window window, int width, int height, 470bbfda8aSnia ColorPair cp, const char *label); 480bbfda8aSnia 490bbfda8aSniastatic void InvertColorPair(ColorPair *cp); 500bbfda8aSnia 510bbfda8aSnia 520bbfda8aSniastatic XContext MapWListContext = None; 530bbfda8aSniastatic Cursor handCursor = None; 540bbfda8aSnia 550bbfda8aSnia 560bbfda8aSnia 570bbfda8aSnia/* 580bbfda8aSnia **************************************************************** 590bbfda8aSnia * 600bbfda8aSnia * First, functions related to general creation and drawing of the WSM 610bbfda8aSnia * window and its backing structs 620bbfda8aSnia * 630bbfda8aSnia **************************************************************** 640bbfda8aSnia */ 650bbfda8aSnia 660bbfda8aSnia/* 670bbfda8aSnia * Allocate an X Context for WSM stuff. 680bbfda8aSnia */ 690bbfda8aSniavoid 700bbfda8aSniaInitWorkSpaceManagerContext(void) 710bbfda8aSnia{ 720bbfda8aSnia if(MapWListContext == None) { 730bbfda8aSnia MapWListContext = XUniqueContext(); 740bbfda8aSnia } 750bbfda8aSnia} 760bbfda8aSnia 770bbfda8aSnia 780bbfda8aSnia/* 790bbfda8aSnia * Prep up structures for WSM windows in each VS. Called (for each 800bbfda8aSnia * screen) in startup after InitVirtualScreens() has setup the VS stuff 810bbfda8aSnia * (and after config file processing). 820bbfda8aSnia */ 830bbfda8aSniavoid 840bbfda8aSniaConfigureWorkSpaceManager(void) 850bbfda8aSnia{ 860bbfda8aSnia VirtualScreen *vs; 870bbfda8aSnia 880bbfda8aSnia for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) { 890bbfda8aSnia /* 900bbfda8aSnia * Make sure this is all properly initialized to nothing. Otherwise 910bbfda8aSnia * bad and undefined behavior can show up in certain cases (e.g., 920bbfda8aSnia * with no Workspaces {} defined in .ctwmrc, the only defined 930bbfda8aSnia * workspace will be random memory bytes, which can causes crashes on 940bbfda8aSnia * e.g. f.menu "TwmWindows".) 950bbfda8aSnia */ 960bbfda8aSnia WorkSpaceWindow *wsw = calloc(1, sizeof(WorkSpaceWindow)); 970bbfda8aSnia wsw->state = Scr->workSpaceMgr.initialstate; 980bbfda8aSnia vs->wsw = wsw; 990bbfda8aSnia } 1000bbfda8aSnia} 1010bbfda8aSnia 1020bbfda8aSnia 1030bbfda8aSnia/* 1040bbfda8aSnia * Create workspace manager windows for each vscreen. Called (for each 1050bbfda8aSnia * screen) late in startup, after the preceeding funcs have run their 1060bbfda8aSnia * course. 1070bbfda8aSnia */ 1080bbfda8aSniavoid 1090bbfda8aSniaCreateWorkSpaceManager(void) 1100bbfda8aSnia{ 1110bbfda8aSnia if(! Scr->workSpaceManagerActive) { 1120bbfda8aSnia return; 1130bbfda8aSnia } 1140bbfda8aSnia 1150bbfda8aSnia /* Setup basic fonts/colors/cursors */ 1160bbfda8aSnia Scr->workSpaceMgr.windowFont.basename = 1170bbfda8aSnia "-adobe-courier-medium-r-normal--10-100-75-75-m-60-iso8859-1"; 1180bbfda8aSnia Scr->workSpaceMgr.buttonFont = Scr->IconManagerFont; 1190bbfda8aSnia Scr->workSpaceMgr.cp = Scr->IconManagerC; 1200bbfda8aSnia if(!Scr->BeNiceToColormap) { 1210bbfda8aSnia GetShadeColors(&Scr->workSpaceMgr.cp); 1220bbfda8aSnia } 1230bbfda8aSnia if(handCursor == None) { 1240bbfda8aSnia NewFontCursor(&handCursor, "top_left_arrow"); 1250bbfda8aSnia } 1260bbfda8aSnia 1270bbfda8aSnia 1280bbfda8aSnia /* 1290bbfda8aSnia * Create a WSM window for each vscreen. We don't need one for each 1300bbfda8aSnia * workspace (we just reuse the same one), but we do need one for 1310bbfda8aSnia * each vscreen (since they have to be displayed simultaneously). 1320bbfda8aSnia */ 1330bbfda8aSnia { 1340bbfda8aSnia WorkSpace *ws, *fws; 1350bbfda8aSnia char *vsmapbuf, *vsmap; 1360bbfda8aSnia 1370bbfda8aSnia vsmapbuf = CtwmGetVScreenMap(dpy, Scr->Root); 1380bbfda8aSnia if(vsmapbuf != NULL) { 1390bbfda8aSnia vsmap = strtok(vsmapbuf, ","); 1400bbfda8aSnia } 1410bbfda8aSnia else { 1420bbfda8aSnia vsmap = NULL; 1430bbfda8aSnia } 1440bbfda8aSnia 1450bbfda8aSnia /* 1460bbfda8aSnia * weird things can happen if the config file is changed or the 1470bbfda8aSnia * atom returned above is messed with. Sometimes windows may 1480bbfda8aSnia * disappear in that case depending on what's changed. 1490bbfda8aSnia * (depending on where they were on the actual screen. 1500bbfda8aSnia */ 1510bbfda8aSnia ws = Scr->workSpaceMgr.workSpaceList; 1520bbfda8aSnia for(VirtualScreen *vs = Scr->vScreenList; vs != NULL; vs = vs->next) { 1530bbfda8aSnia WorkSpaceWindow *wsw = vs->wsw; 1540bbfda8aSnia if(vsmap) { 1550bbfda8aSnia fws = GetWorkspace(vsmap); 1560bbfda8aSnia } 1570bbfda8aSnia else { 1580bbfda8aSnia fws = NULL; 1590bbfda8aSnia } 1600bbfda8aSnia if(fws) { 1610bbfda8aSnia wsw->currentwspc = fws; 1620bbfda8aSnia vsmap = strtok(NULL, ","); 1630bbfda8aSnia } 1640bbfda8aSnia else { 1650bbfda8aSnia wsw->currentwspc = ws; 1660bbfda8aSnia ws = ws->next; 1670bbfda8aSnia } 1680bbfda8aSnia CreateWorkSpaceManagerWindow(vs); 1690bbfda8aSnia } 1700bbfda8aSnia 1710bbfda8aSnia free(vsmapbuf); 1720bbfda8aSnia } 1730bbfda8aSnia 1740bbfda8aSnia 1750bbfda8aSnia /* 1760bbfda8aSnia * Init background in the WSM workspace subwindow and potentially the 1770bbfda8aSnia * root window to the settings for the active workspace 1780bbfda8aSnia * 1790bbfda8aSnia * XXX CTAG_BGDRAW This process is also done in similar fashion 1800bbfda8aSnia * during CreateWorkSpaceManagerWindow(), and the two parts are done 1810bbfda8aSnia * split well apart during GotoWorkSpace(). The details of the 1820bbfda8aSnia * process should be factored out into helper functions instead of 1830bbfda8aSnia * being reimplemented in each place. That will require a little 1840bbfda8aSnia * shuffling of code, and careful thinking on the apparent 1850bbfda8aSnia * differences (which seem like they may be cosmetic). Todo. 1860bbfda8aSnia */ 1870bbfda8aSnia for(VirtualScreen *vs = Scr->vScreenList; vs != NULL; vs = vs->next) { 1880bbfda8aSnia WorkSpaceWindow *wsw = vs->wsw; // Our WSW 1890bbfda8aSnia WorkSpace *ws2 = wsw->currentwspc; // Active WS 1900bbfda8aSnia MapSubwindow *msw = wsw->mswl[ws2->number]; // Active WS's subwin 1910bbfda8aSnia 1920bbfda8aSnia /* Setup the background/border on the active workspace */ 1930bbfda8aSnia if(Scr->workSpaceMgr.curImage == NULL) { 1940bbfda8aSnia if(Scr->workSpaceMgr.curPaint) { 1950bbfda8aSnia XSetWindowBackground(dpy, msw->w, Scr->workSpaceMgr.curColors.back); 1960bbfda8aSnia } 1970bbfda8aSnia } 1980bbfda8aSnia else { 1990bbfda8aSnia XSetWindowBackgroundPixmap(dpy, msw->w, Scr->workSpaceMgr.curImage->pixmap); 2000bbfda8aSnia } 2010bbfda8aSnia XSetWindowBorder(dpy, msw->w, Scr->workSpaceMgr.curBorderColor); 2020bbfda8aSnia XClearWindow(dpy, msw->w); 2030bbfda8aSnia 2040bbfda8aSnia /* Set the root window to the color/image of that WS if we should */ 2050bbfda8aSnia if(useBackgroundInfo && ! Scr->DontPaintRootWindow) { 2060bbfda8aSnia if(ws2->image == NULL) { 2070bbfda8aSnia XSetWindowBackground(dpy, vs->window, ws2->backcp.back); 2080bbfda8aSnia } 2090bbfda8aSnia else { 2100bbfda8aSnia XSetWindowBackgroundPixmap(dpy, vs->window, ws2->image->pixmap); 2110bbfda8aSnia } 2120bbfda8aSnia XClearWindow(dpy, vs->window); 2130bbfda8aSnia } 2140bbfda8aSnia } 2150bbfda8aSnia 2160bbfda8aSnia 2170bbfda8aSnia /* 2180bbfda8aSnia * Set the property we use to store the full list of workspaces. 2190bbfda8aSnia * 2200bbfda8aSnia * XXX This isn't really part of creating the WSM windows, so doesn't 2210bbfda8aSnia * strictly belong here. It does need to happen after the config 2220bbfda8aSnia * file parsing setup the workspaces, so couldn't go into 2230bbfda8aSnia * InitWorkSpaceManager(). It could probably move into 2240bbfda8aSnia * ConfigureWorkSpaceManager() though, or could move into a separate 2250bbfda8aSnia * hypotehtical ConfigureWorkSpaces() sort of thing... 2260bbfda8aSnia */ 2270bbfda8aSnia { 2280bbfda8aSnia char *wrkSpcList; 2290bbfda8aSnia int len; 2300bbfda8aSnia 2310bbfda8aSnia len = GetPropertyFromMask(0xFFFFFFFFu, &wrkSpcList); 2320bbfda8aSnia XChangeProperty(dpy, Scr->Root, XA_WM_WORKSPACESLIST, XA_STRING, 8, 2330bbfda8aSnia PropModeReplace, (unsigned char *) wrkSpcList, len); 2340bbfda8aSnia free(wrkSpcList); 2350bbfda8aSnia } 2360bbfda8aSnia} 2370bbfda8aSnia 2380bbfda8aSnia 2390bbfda8aSnia/* 2400bbfda8aSnia * Put together the actual window for the workspace manager. Called as 2410bbfda8aSnia * part of CreateWorkSpaceManager() during startup, once per vscreen 2420bbfda8aSnia * (since there's a separate window for each). 2430bbfda8aSnia */ 2440bbfda8aSniastatic void 2450bbfda8aSniaCreateWorkSpaceManagerWindow(VirtualScreen *vs) 2460bbfda8aSnia{ 2470bbfda8aSnia unsigned int width, height; 2480bbfda8aSnia TwmWindow *tmp_win; 2490bbfda8aSnia int x, y, gravity; 2500bbfda8aSnia /* Shortcuts */ 2510bbfda8aSnia const int vspace = Scr->workSpaceMgr.vspace; 2520bbfda8aSnia const int hspace = Scr->workSpaceMgr.hspace; 2530bbfda8aSnia const long count = Scr->workSpaceMgr.count; 2540bbfda8aSnia 2550bbfda8aSnia /* No workspaces? Nothing to do. */ 2560bbfda8aSnia if(count == 0) { 2570bbfda8aSnia return; 2580bbfda8aSnia } 2590bbfda8aSnia 2600bbfda8aSnia /* 2610bbfda8aSnia * Work out grid. wSM.columns will be filled if specified in 2620bbfda8aSnia * WorkSpaceManageGeometry, or uninitialized (0) if not. 2630bbfda8aSnia */ 2640bbfda8aSnia { 2650bbfda8aSnia int lines, columns; 2660bbfda8aSnia columns = Scr->workSpaceMgr.columns; 2670bbfda8aSnia if(columns == 0) { 2680bbfda8aSnia lines = 2; 2690bbfda8aSnia columns = ((count - 1) / lines) + 1; 2700bbfda8aSnia } 2710bbfda8aSnia else { 2720bbfda8aSnia lines = ((count - 1) / columns) + 1; 2730bbfda8aSnia } 2740bbfda8aSnia Scr->workSpaceMgr.lines = lines; 2750bbfda8aSnia Scr->workSpaceMgr.columns = columns; 2760bbfda8aSnia } 2770bbfda8aSnia 2780bbfda8aSnia 2790bbfda8aSnia /* Work out dimensions of stuff */ 2800bbfda8aSnia { 2810bbfda8aSnia unsigned int bwidth, bheight; 2820bbfda8aSnia unsigned short strWid; 2830bbfda8aSnia WorkSpace *ws; 2840bbfda8aSnia const char *geometry = Scr->workSpaceMgr.geometry; 2850bbfda8aSnia const int lines = Scr->workSpaceMgr.lines; 2860bbfda8aSnia const int columns = Scr->workSpaceMgr.columns; 2870bbfda8aSnia 2880bbfda8aSnia /* Figure longest label */ 2890bbfda8aSnia strWid = 0; 2900bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 2910bbfda8aSnia XRectangle inc_rect; 2920bbfda8aSnia XRectangle logical_rect; 2930bbfda8aSnia unsigned short wid; 2940bbfda8aSnia const MyFont font = Scr->workSpaceMgr.buttonFont; 2950bbfda8aSnia 2960bbfda8aSnia XmbTextExtents(font.font_set, ws->label, strlen(ws->label), 2970bbfda8aSnia &inc_rect, &logical_rect); 2980bbfda8aSnia wid = logical_rect.width; 2990bbfda8aSnia if(wid > strWid) { 3000bbfda8aSnia strWid = wid; 3010bbfda8aSnia } 3020bbfda8aSnia } 3030bbfda8aSnia 3040bbfda8aSnia /* 3050bbfda8aSnia * If WorkSpaceManagerGeometry is given, work from that. Else, 3060bbfda8aSnia * create a workable minimum ourselves. 3070bbfda8aSnia * */ 3080bbfda8aSnia if(geometry != NULL) { 3090bbfda8aSnia int mask; 3100bbfda8aSnia 3110bbfda8aSnia /* Base button/subwindow sizes */ 3120bbfda8aSnia bwidth = strWid + 10; 3130bbfda8aSnia bheight = 22; 3140bbfda8aSnia 3150bbfda8aSnia /* Adjust to WSMGeometry if specified */ 3160bbfda8aSnia mask = XParseGeometry(geometry, &x, &y, &width, &height); 3170bbfda8aSnia if(mask & WidthValue) { 3180bbfda8aSnia bwidth = (width - (columns * hspace)) / columns; 3190bbfda8aSnia } 3200bbfda8aSnia if(mask & HeightValue) { 3210bbfda8aSnia bheight = (height - (lines * vspace)) / lines; 3220bbfda8aSnia } 3230bbfda8aSnia 3240bbfda8aSnia /* Size of the whole thing is based off those */ 3250bbfda8aSnia width = columns * (bwidth + hspace); 3260bbfda8aSnia height = lines * (bheight + vspace); 3270bbfda8aSnia 3280bbfda8aSnia /* 3290bbfda8aSnia * If no Y given, put it at the bottom of the screen. If one 3300bbfda8aSnia * is, just accept it. If it's a negative, we have to figure 3310bbfda8aSnia * out where that actually is on this vscreen. 3320bbfda8aSnia */ 3330bbfda8aSnia if(!(mask & YValue)) { 3340bbfda8aSnia y = 0; 3350bbfda8aSnia mask |= YNegative; 3360bbfda8aSnia } 3370bbfda8aSnia if(mask & YNegative) { 3380bbfda8aSnia y += vs->h - height; 3390bbfda8aSnia } 3400bbfda8aSnia 3410bbfda8aSnia /* 3420bbfda8aSnia * If X is given, tweak as necessary for the vscreen 3430bbfda8aSnia * location. Otherwise, put it in in something like the 3440bbfda8aSnia * middle. 3450bbfda8aSnia */ 3460bbfda8aSnia if(mask & XValue) { 3470bbfda8aSnia if(mask & XNegative) { 3480bbfda8aSnia x += vs->w - width; 3490bbfda8aSnia gravity = (mask & YNegative) ? SouthEastGravity : NorthEastGravity; 3500bbfda8aSnia } 3510bbfda8aSnia else { 3520bbfda8aSnia gravity = (mask & YNegative) ? SouthWestGravity : NorthWestGravity; 3530bbfda8aSnia } 3540bbfda8aSnia } 3550bbfda8aSnia else { 3560bbfda8aSnia x = (vs->w - width) / 2; 3570bbfda8aSnia gravity = (mask & YValue) ? ((mask & YNegative) ? 3580bbfda8aSnia SouthGravity : NorthGravity) : SouthGravity; 3590bbfda8aSnia } 3600bbfda8aSnia } 3610bbfda8aSnia else { 3620bbfda8aSnia /* No geom specified, come up with one */ 3630bbfda8aSnia bwidth = strWid + 2 * Scr->WMgrButtonShadowDepth + 6; 3640bbfda8aSnia bheight = 22; 3650bbfda8aSnia width = columns * (bwidth + hspace); 3660bbfda8aSnia height = lines * (bheight + vspace); 3670bbfda8aSnia x = (vs->w - width) / 2; 3680bbfda8aSnia y = vs->h - height; 3690bbfda8aSnia gravity = NorthWestGravity; 3700bbfda8aSnia } 3710bbfda8aSnia } 3720bbfda8aSnia 3730bbfda8aSnia /* Set w/h to dummy values; ResizeWorkSpaceManager() writes real ones */ 3740bbfda8aSnia vs->wsw->width = 1; 3750bbfda8aSnia vs->wsw->height = 1; 3760bbfda8aSnia 3770bbfda8aSnia /* Allocate structs for map/button subwindows */ 3780bbfda8aSnia vs->wsw->bswl = calloc(count, sizeof(ButtonSubwindow *)); 3790bbfda8aSnia vs->wsw->mswl = calloc(count, sizeof(MapSubwindow *)); 3800bbfda8aSnia 3810bbfda8aSnia /* Create main window */ 3820bbfda8aSnia vs->wsw->w = XCreateSimpleWindow(dpy, Scr->Root, x, y, width, height, 0, 3830bbfda8aSnia Scr->Black, Scr->workSpaceMgr.cp.back); 3840bbfda8aSnia 3850bbfda8aSnia 3860bbfda8aSnia /* 3870bbfda8aSnia * Create the map and button subwindows for each workspace 3880bbfda8aSnia */ 3890bbfda8aSnia { 3900bbfda8aSnia WorkSpace *ws; 3910bbfda8aSnia 3920bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 3930bbfda8aSnia MapSubwindow *msw; 3940bbfda8aSnia ButtonSubwindow *bsw; 3950bbfda8aSnia const int Dummy = 1; 3960bbfda8aSnia const unsigned long border = Scr->workSpaceMgr.defBorderColor; 3970bbfda8aSnia 3980bbfda8aSnia /* Alloc structs */ 3990bbfda8aSnia vs->wsw->bswl[ws->number] = bsw 4000bbfda8aSnia = calloc(1, sizeof(ButtonSubwindow)); 4010bbfda8aSnia vs->wsw->mswl[ws->number] = msw = calloc(1, sizeof(MapSubwindow)); 4020bbfda8aSnia 4030bbfda8aSnia /* 4040bbfda8aSnia * Create windows for button/map. ResizeWorkSpaceManager() 4050bbfda8aSnia * sets the real sizes and positions, so we dummy 'em. 4060bbfda8aSnia */ 4070bbfda8aSnia bsw->w = XCreateSimpleWindow(dpy, vs->wsw->w, 4080bbfda8aSnia Dummy, Dummy, Dummy, Dummy, 4090bbfda8aSnia 0, Scr->Black, ws->cp.back); 4100bbfda8aSnia 4110bbfda8aSnia msw->w = XCreateSimpleWindow(dpy, vs->wsw->w, 4120bbfda8aSnia Dummy, Dummy, Dummy, Dummy, 4130bbfda8aSnia 1, border, ws->cp.back); 4140bbfda8aSnia 4150bbfda8aSnia /* Map whichever is up by default */ 4160bbfda8aSnia if(vs->wsw->state == WMS_buttons) { 4170bbfda8aSnia XMapWindow(dpy, bsw->w); 4180bbfda8aSnia } 4190bbfda8aSnia else { 4200bbfda8aSnia XMapWindow(dpy, msw->w); 4210bbfda8aSnia } 4220bbfda8aSnia 4230bbfda8aSnia /* Setup background on map-state window */ 4240bbfda8aSnia /* XXX X-ref CTAG_BGDRAW in CreateWorkSpaceManager() */ 4250bbfda8aSnia if(useBackgroundInfo) { 4260bbfda8aSnia if(ws->image == NULL || Scr->NoImagesInWorkSpaceManager) { 4270bbfda8aSnia XSetWindowBackground(dpy, msw->w, ws->backcp.back); 4280bbfda8aSnia } 4290bbfda8aSnia else { 4300bbfda8aSnia XSetWindowBackgroundPixmap(dpy, msw->w, ws->image->pixmap); 4310bbfda8aSnia } 4320bbfda8aSnia } 4330bbfda8aSnia else { 4340bbfda8aSnia if(Scr->workSpaceMgr.defImage == NULL || Scr->NoImagesInWorkSpaceManager) { 4350bbfda8aSnia XSetWindowBackground(dpy, msw->w, Scr->workSpaceMgr.defColors.back); 4360bbfda8aSnia } 4370bbfda8aSnia else { 4380bbfda8aSnia XSetWindowBackgroundPixmap(dpy, msw->w, Scr->workSpaceMgr.defImage->pixmap); 4390bbfda8aSnia } 4400bbfda8aSnia } 4410bbfda8aSnia 4420bbfda8aSnia /* 4430bbfda8aSnia * Clear out button subwin; PaintWorkSpaceManager() fills it 4440bbfda8aSnia * in. Is this really necessary? 4450bbfda8aSnia */ 4460bbfda8aSnia XClearWindow(dpy, bsw->w); 4470bbfda8aSnia } 4480bbfda8aSnia } 4490bbfda8aSnia 4500bbfda8aSnia 4510bbfda8aSnia /* Set WM properties */ 4520bbfda8aSnia { 4530bbfda8aSnia XSizeHints sizehints; 4540bbfda8aSnia XWMHints wmhints; 4550bbfda8aSnia const int lines = Scr->workSpaceMgr.lines; 4560bbfda8aSnia const int columns = Scr->workSpaceMgr.columns; 4570bbfda8aSnia const char *name = Scr->workSpaceMgr.name; 4580bbfda8aSnia const char *icon_name = Scr->workSpaceMgr.icon_name; 4590bbfda8aSnia 4600bbfda8aSnia sizehints.flags = USPosition | PBaseSize | PMinSize | PResizeInc 4610bbfda8aSnia | PWinGravity; 4620bbfda8aSnia sizehints.x = x; 4630bbfda8aSnia sizehints.y = y; 4640bbfda8aSnia sizehints.base_width = columns * hspace; 4650bbfda8aSnia sizehints.base_height = lines * vspace; 4660bbfda8aSnia sizehints.width_inc = columns; 4670bbfda8aSnia sizehints.height_inc = lines; 4680bbfda8aSnia sizehints.min_width = columns * (hspace + 2); 4690bbfda8aSnia sizehints.min_height = lines * (vspace + 2); 4700bbfda8aSnia sizehints.win_gravity = gravity; 4710bbfda8aSnia 4720bbfda8aSnia wmhints.flags = InputHint | StateHint; 4730bbfda8aSnia wmhints.input = True; 4740bbfda8aSnia wmhints.initial_state = NormalState; 4750bbfda8aSnia 4760bbfda8aSnia XmbSetWMProperties(dpy, vs->wsw->w, name, icon_name, NULL, 0, 4770bbfda8aSnia &sizehints, &wmhints, NULL); 4780bbfda8aSnia } 4790bbfda8aSnia 4800bbfda8aSnia 4810bbfda8aSnia /* Create our TwmWindow wrapping around it */ 4820bbfda8aSnia tmp_win = AddWindow(vs->wsw->w, AWT_WORKSPACE_MANAGER, 4830bbfda8aSnia Scr->iconmgr, vs); 4840bbfda8aSnia if(! tmp_win) { 4850bbfda8aSnia fprintf(stderr, "cannot create workspace manager window, exiting...\n"); 4860bbfda8aSnia exit(1); 4870bbfda8aSnia } 4880bbfda8aSnia tmp_win->occupation = fullOccupation; 4890bbfda8aSnia tmp_win->attr.width = width; 4900bbfda8aSnia tmp_win->attr.height = height; 4910bbfda8aSnia vs->wsw->twm_win = tmp_win; 4920bbfda8aSnia 4930bbfda8aSnia 4940bbfda8aSnia /* Do the figuring to size and internal-layout it */ 4950bbfda8aSnia ResizeWorkSpaceManager(vs, tmp_win); 4960bbfda8aSnia 4970bbfda8aSnia 4980bbfda8aSnia /* Setup cursor/gravity and listen for events */ 4990bbfda8aSnia { 5000bbfda8aSnia XWindowAttributes wattr; 5010bbfda8aSnia XSetWindowAttributes attr; 5020bbfda8aSnia unsigned long attrmask; 5030bbfda8aSnia 5040bbfda8aSnia attr.cursor = Scr->ButtonCursor; 5050bbfda8aSnia attr.win_gravity = gravity; 5060bbfda8aSnia attrmask = CWCursor | CWWinGravity; 5070bbfda8aSnia XChangeWindowAttributes(dpy, vs->wsw->w, attrmask, &attr); 5080bbfda8aSnia 5090bbfda8aSnia XGetWindowAttributes(dpy, vs->wsw->w, &wattr); 5100bbfda8aSnia attrmask = wattr.your_event_mask | KeyPressMask | KeyReleaseMask 5110bbfda8aSnia | ExposureMask; 5120bbfda8aSnia XSelectInput(dpy, vs->wsw->w, attrmask); 5130bbfda8aSnia } 5140bbfda8aSnia 5150bbfda8aSnia 5160bbfda8aSnia /* 5170bbfda8aSnia * Mark the buttons as listening to click and exposure events, and 5180bbfda8aSnia * stash away some pointers in contexts. We stash the overall WSM 5190bbfda8aSnia * window in TwmContext, which means that when an event looks up the 5200bbfda8aSnia * window, it finds the WSM rather than the subwindow, and then falls 5210bbfda8aSnia * into the WMgrHandle*Event()'s, which then dig down into the event 5220bbfda8aSnia * to find where it happened in there. 5230bbfda8aSnia * 5240bbfda8aSnia * The map window doesn't listen to expose events; it's just empty 5250bbfda8aSnia * and background colored. The individual subwindows in the map 5260bbfda8aSnia * listen for exposes for drawing themselves. 5270bbfda8aSnia * 5280bbfda8aSnia * Dragging windows around to move or re-occupy in the map window 5290bbfda8aSnia * does rely on motion events, but we don't listen for them here. 5300bbfda8aSnia * That happens in WMgrHandleButtonEvent() after getting the initial 5310bbfda8aSnia * click. It changes the listen and runs through the action 5320bbfda8aSnia * internally; those motions never run through our main event loop. 5330bbfda8aSnia */ 5340bbfda8aSnia for(WorkSpace *ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; 5350bbfda8aSnia ws = ws->next) { 5360bbfda8aSnia Window buttonw = vs->wsw->bswl[ws->number]->w; 5370bbfda8aSnia Window mapsubw = vs->wsw->mswl[ws->number]->w; 5380bbfda8aSnia 5390bbfda8aSnia XSelectInput(dpy, buttonw, ButtonPressMask | ButtonReleaseMask 5400bbfda8aSnia | ExposureMask); 5410bbfda8aSnia XSaveContext(dpy, buttonw, TwmContext, (XPointer) tmp_win); 5420bbfda8aSnia XSaveContext(dpy, buttonw, ScreenContext, (XPointer) Scr); 5430bbfda8aSnia 5440bbfda8aSnia XSelectInput(dpy, mapsubw, ButtonPressMask | ButtonReleaseMask); 5450bbfda8aSnia XSaveContext(dpy, mapsubw, TwmContext, (XPointer) tmp_win); 5460bbfda8aSnia XSaveContext(dpy, mapsubw, ScreenContext, (XPointer) Scr); 5470bbfda8aSnia } 5480bbfda8aSnia 5490bbfda8aSnia 5500bbfda8aSnia /* Set WM_STATE prop */ 5510bbfda8aSnia SetMapStateProp(tmp_win, WithdrawnState); 5520bbfda8aSnia 5530bbfda8aSnia 5540bbfda8aSnia /* Setup root window if necessary */ 5550bbfda8aSnia /* XXX X-ref CTAG_BGDRAW in CreateWorkSpaceManager() */ 5560bbfda8aSnia if(useBackgroundInfo && ! Scr->DontPaintRootWindow) { 5570bbfda8aSnia WorkSpace *ws = Scr->workSpaceMgr.workSpaceList; 5580bbfda8aSnia if(ws->image == NULL) { 5590bbfda8aSnia XSetWindowBackground(dpy, Scr->Root, ws->backcp.back); 5600bbfda8aSnia } 5610bbfda8aSnia else { 5620bbfda8aSnia XSetWindowBackgroundPixmap(dpy, Scr->Root, ws->image->pixmap); 5630bbfda8aSnia } 5640bbfda8aSnia XClearWindow(dpy, Scr->Root); 5650bbfda8aSnia } 5660bbfda8aSnia 5670bbfda8aSnia 5680bbfda8aSnia /* 5690bbfda8aSnia * Don't have to PaintWorkSpaceManager(vs) here, because 5700bbfda8aSnia * ResizeWorkSpaceManager() already called it for us. 5710bbfda8aSnia */ 5720bbfda8aSnia} 5730bbfda8aSnia 5740bbfda8aSnia 5750bbfda8aSnia/* 5760bbfda8aSnia * Size and layout a WSM. Mostly an internal bit in the process of 5770bbfda8aSnia * setting it up. 5780bbfda8aSnia */ 5790bbfda8aSniastatic void 5800bbfda8aSniaResizeWorkSpaceManager(VirtualScreen *vs, TwmWindow *win) 5810bbfda8aSnia{ 5820bbfda8aSnia WorkSpace *ws; 5830bbfda8aSnia int i, j; 5840bbfda8aSnia /* Lots of shortcuts to ease reading */ 5850bbfda8aSnia const int neww = win->attr.width; 5860bbfda8aSnia const int newh = win->attr.height; 5870bbfda8aSnia const int hspace = Scr->workSpaceMgr.hspace; 5880bbfda8aSnia const int vspace = Scr->workSpaceMgr.vspace; 5890bbfda8aSnia const int lines = Scr->workSpaceMgr.lines; 5900bbfda8aSnia const int columns = Scr->workSpaceMgr.columns; 5910bbfda8aSnia const int bwidth = (neww - (columns * hspace)) / columns; 5920bbfda8aSnia const int bheight = (newh - (lines * vspace)) / lines; 5930bbfda8aSnia const int wwidth = neww / columns; 5940bbfda8aSnia const int wheight = newh / lines; 5950bbfda8aSnia const float wf = (float)(wwidth - 2) / (float) vs->w; 5960bbfda8aSnia const float hf = (float)(wheight - 2) / (float) vs->h; 5970bbfda8aSnia 5980bbfda8aSnia /* If nothing's changed since our last run, there's nothing to change */ 5990bbfda8aSnia if(neww == vs->wsw->width && newh == vs->wsw->height) { 6000bbfda8aSnia return; 6010bbfda8aSnia } 6020bbfda8aSnia 6030bbfda8aSnia /* Set the new overall vals */ 6040bbfda8aSnia vs->wsw->bwidth = bwidth; 6050bbfda8aSnia vs->wsw->bheight = bheight; 6060bbfda8aSnia vs->wsw->width = neww; 6070bbfda8aSnia vs->wsw->height = newh; 6080bbfda8aSnia vs->wsw->wwidth = wwidth; 6090bbfda8aSnia vs->wsw->wheight = wheight; 6100bbfda8aSnia 6110bbfda8aSnia /* Iterate over the WS's */ 6120bbfda8aSnia i = 0; 6130bbfda8aSnia j = 0; 6140bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 6150bbfda8aSnia MapSubwindow *msw = vs->wsw->mswl[ws->number]; 6160bbfda8aSnia ButtonSubwindow *bsw = vs->wsw->bswl[ws->number]; 6170bbfda8aSnia 6180bbfda8aSnia /* Move button window to its place in the grid and size appropriately */ 6190bbfda8aSnia XMoveResizeWindow(dpy, bsw->w, 6200bbfda8aSnia i * (bwidth + hspace) + (hspace / 2), 6210bbfda8aSnia j * (bheight + vspace) + (vspace / 2), 6220bbfda8aSnia bwidth, bheight); 6230bbfda8aSnia 6240bbfda8aSnia /* Move the map window as well */ 6250bbfda8aSnia msw->x = i * wwidth; 6260bbfda8aSnia msw->y = j * wheight; 6270bbfda8aSnia XMoveResizeWindow(dpy, msw->w, msw->x, msw->y, wwidth - 2, wheight - 2); 6280bbfda8aSnia 6290bbfda8aSnia /* 6300bbfda8aSnia * Redo interior sizing and placement of all the windows in the 6310bbfda8aSnia * WS in the map window 6320bbfda8aSnia */ 6330bbfda8aSnia for(WinList *wl = msw->wl; wl != NULL; wl = wl->next) { 6340bbfda8aSnia TwmWindow *tmp_win = wl->twm_win; 6350bbfda8aSnia wl->x = (int)(tmp_win->frame_x * wf); 6360bbfda8aSnia wl->y = (int)(tmp_win->frame_y * hf); 6370bbfda8aSnia wl->width = (unsigned int)((tmp_win->frame_width * wf) + 0.5); 6380bbfda8aSnia wl->height = (unsigned int)((tmp_win->frame_height * hf) + 0.5); 6390bbfda8aSnia XMoveResizeWindow(dpy, wl->w, wl->x, wl->y, wl->width, wl->height); 6400bbfda8aSnia } 6410bbfda8aSnia 6420bbfda8aSnia /* And around to the next WS */ 6430bbfda8aSnia i++; 6440bbfda8aSnia if(i == columns) { 6450bbfda8aSnia i = 0; 6460bbfda8aSnia j++; 6470bbfda8aSnia }; 6480bbfda8aSnia } 6490bbfda8aSnia 6500bbfda8aSnia 6510bbfda8aSnia /* Draw it */ 6520bbfda8aSnia PaintWorkSpaceManager(vs); 6530bbfda8aSnia} 6540bbfda8aSnia 6550bbfda8aSnia 6560bbfda8aSnia/* 6570bbfda8aSnia * Draw up the button-state pieces of a WSM window. 6580bbfda8aSnia * 6590bbfda8aSnia * Note: this is currently stubbed out and does nothing. Historically 6600bbfda8aSnia * it's been called during startup when the WSM window is put together, 6610bbfda8aSnia * and when the screen is unmasked. However, the only apparent result is 6620bbfda8aSnia * that the border and buttons get drawn a little earlier; they already 6630bbfda8aSnia * get expose events that get picked up when we start the event loop. 6640bbfda8aSnia * 6650bbfda8aSnia * If we don't find any reason to reinstate it, we should remove this in 6660bbfda8aSnia * the future. 6670bbfda8aSnia */ 6680bbfda8aSniavoid 6690bbfda8aSniaPaintWorkSpaceManager(VirtualScreen *vs) 6700bbfda8aSnia{ 6710bbfda8aSnia WorkSpace *ws; 6720bbfda8aSnia 6730bbfda8aSnia /* x-ref header comment */ 6740bbfda8aSnia return; 6750bbfda8aSnia 6760bbfda8aSnia PaintWorkSpaceManagerBorder(vs); 6770bbfda8aSnia 6780bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 6790bbfda8aSnia Window buttonw = vs->wsw->bswl[ws->number]->w; 6800bbfda8aSnia ButtonState bs = (ws == vs->wsw->currentwspc) ? on : off; 6810bbfda8aSnia 6820bbfda8aSnia PaintWsButton(WSPCWINDOW, vs, buttonw, ws->label, ws->cp, bs); 6830bbfda8aSnia } 6840bbfda8aSnia} 6850bbfda8aSnia 6860bbfda8aSnia 6870bbfda8aSnia/* 6880bbfda8aSnia * Border around the WSM 6890bbfda8aSnia */ 6900bbfda8aSniastatic void 6910bbfda8aSniaPaintWorkSpaceManagerBorder(VirtualScreen *vs) 6920bbfda8aSnia{ 6930bbfda8aSnia int width, height; 6940bbfda8aSnia 6950bbfda8aSnia width = vs->wsw->width; 6960bbfda8aSnia height = vs->wsw->height; 6970bbfda8aSnia Draw3DBorder(vs->wsw->w, 0, 0, width, height, 2, Scr->workSpaceMgr.cp, off, 6980bbfda8aSnia true, false); 6990bbfda8aSnia} 7000bbfda8aSnia 7010bbfda8aSnia 7020bbfda8aSnia/* 7030bbfda8aSnia * Draw a workspace manager window on expose. X-ref comment on 7040bbfda8aSnia * PaintWorkSpaceManager(). 7050bbfda8aSnia */ 7060bbfda8aSniavoid 7070bbfda8aSniaWMgrHandleExposeEvent(VirtualScreen *vs, XEvent *event) 7080bbfda8aSnia{ 7090bbfda8aSnia if(vs->wsw->state == WMS_buttons) { 7100bbfda8aSnia Window buttonw; 7110bbfda8aSnia WorkSpace *ws; 7120bbfda8aSnia 7130bbfda8aSnia /* Find the button we're exposing */ 7140bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 7150bbfda8aSnia buttonw = vs->wsw->bswl[ws->number]->w; 7160bbfda8aSnia if(event->xexpose.window == buttonw) { 7170bbfda8aSnia break; 7180bbfda8aSnia } 7190bbfda8aSnia } 7200bbfda8aSnia 7210bbfda8aSnia /* If none, just paint the border. Else paint the button. */ 7220bbfda8aSnia if(ws == NULL) { 7230bbfda8aSnia PaintWorkSpaceManagerBorder(vs); 7240bbfda8aSnia } 7250bbfda8aSnia else { 7260bbfda8aSnia ButtonState bs = (ws == vs->wsw->currentwspc) ? on : off; 7270bbfda8aSnia PaintWsButton(WSPCWINDOW, vs, buttonw, ws->label, ws->cp, bs); 7280bbfda8aSnia } 7290bbfda8aSnia } 7300bbfda8aSnia else { 7310bbfda8aSnia WinList *wl; 7320bbfda8aSnia 7330bbfda8aSnia /* 7340bbfda8aSnia * This is presumably exposing some individual window in the WS 7350bbfda8aSnia * subwindow; find it from the stashed context on the window, and 7360bbfda8aSnia * redraw it. 7370bbfda8aSnia */ 7380bbfda8aSnia if(XFindContext(dpy, event->xexpose.window, MapWListContext, 7390bbfda8aSnia (XPointer *) &wl) == XCNOENT) { 7400bbfda8aSnia return; 7410bbfda8aSnia } 7420bbfda8aSnia if(wl && wl->twm_win && wl->twm_win->mapped) { 7430bbfda8aSnia WMapRedrawName(vs, wl); 7440bbfda8aSnia } 7450bbfda8aSnia } 7460bbfda8aSnia} 7470bbfda8aSnia 7480bbfda8aSnia 7490bbfda8aSnia 7500bbfda8aSnia/* 7510bbfda8aSnia * Moving the WSM between button and map state 7520bbfda8aSnia */ 7530bbfda8aSniavoid 7540bbfda8aSniaWMgrToggleState(VirtualScreen *vs) 7550bbfda8aSnia{ 7560bbfda8aSnia if(vs->wsw->state == WMS_buttons) { 7570bbfda8aSnia WMgrSetMapState(vs); 7580bbfda8aSnia } 7590bbfda8aSnia else { 7600bbfda8aSnia WMgrSetButtonsState(vs); 7610bbfda8aSnia } 7620bbfda8aSnia} 7630bbfda8aSnia 7640bbfda8aSniavoid 7650bbfda8aSniaWMgrSetMapState(VirtualScreen *vs) 7660bbfda8aSnia{ 7670bbfda8aSnia WorkSpace *ws; 7680bbfda8aSnia 7690bbfda8aSnia if(vs->wsw->state == WMS_map) { 7700bbfda8aSnia return; 7710bbfda8aSnia } 7720bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 7730bbfda8aSnia XUnmapWindow(dpy, vs->wsw->bswl [ws->number]->w); 7740bbfda8aSnia XMapWindow(dpy, vs->wsw->mswl [ws->number]->w); 7750bbfda8aSnia } 7760bbfda8aSnia vs->wsw->state = WMS_map; 7770bbfda8aSnia MaybeAnimate = true; 7780bbfda8aSnia} 7790bbfda8aSnia 7800bbfda8aSniavoid 7810bbfda8aSniaWMgrSetButtonsState(VirtualScreen *vs) 7820bbfda8aSnia{ 7830bbfda8aSnia WorkSpace *ws; 7840bbfda8aSnia 7850bbfda8aSnia if(vs->wsw->state == WMS_buttons) { 7860bbfda8aSnia return; 7870bbfda8aSnia } 7880bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 7890bbfda8aSnia XUnmapWindow(dpy, vs->wsw->mswl [ws->number]->w); 7900bbfda8aSnia XMapWindow(dpy, vs->wsw->bswl [ws->number]->w); 7910bbfda8aSnia } 7920bbfda8aSnia vs->wsw->state = WMS_buttons; 7930bbfda8aSnia} 7940bbfda8aSnia 7950bbfda8aSnia 7960bbfda8aSnia 7970bbfda8aSnia 7980bbfda8aSnia/* 7990bbfda8aSnia **************************************************************** 8000bbfda8aSnia * 8010bbfda8aSnia * Handlers for mouse/key actions in the WSM 8020bbfda8aSnia * 8030bbfda8aSnia **************************************************************** 8040bbfda8aSnia */ 8050bbfda8aSnia 8060bbfda8aSnia/* 8070bbfda8aSnia * Key press/release events in the WSM. A major use (and only for 8080bbfda8aSnia * release) is the Ctrl-key switching between map and button state. The 8090bbfda8aSnia * other use is on-the-fly renaming of workspaces by typing in the 8100bbfda8aSnia * button-state WSM. 8110bbfda8aSnia */ 8120bbfda8aSniavoid 8130bbfda8aSniaWMgrHandleKeyReleaseEvent(VirtualScreen *vs, XEvent *event) 8140bbfda8aSnia{ 8150bbfda8aSnia KeySym keysym; 8160bbfda8aSnia 8170bbfda8aSnia keysym = XLookupKeysym((XKeyEvent *) event, 0); 8180bbfda8aSnia if(! keysym) { 8190bbfda8aSnia return; 8200bbfda8aSnia } 8210bbfda8aSnia if(keysym == XK_Control_L || keysym == XK_Control_R) { 8220bbfda8aSnia /* DontToggleWorkSpaceManagerState added 20040607 by dl*/ 8230bbfda8aSnia if(!Scr->DontToggleWorkspaceManagerState) { 8240bbfda8aSnia WMgrToggleState(vs); 8250bbfda8aSnia } 8260bbfda8aSnia return; 8270bbfda8aSnia } 8280bbfda8aSnia} 8290bbfda8aSnia 8300bbfda8aSniavoid 8310bbfda8aSniaWMgrHandleKeyPressEvent(VirtualScreen *vs, XEvent *event) 8320bbfda8aSnia{ 8330bbfda8aSnia WorkSpace *ws; 8340bbfda8aSnia 8350bbfda8aSnia /* Check if we're using Control to toggle the state */ 8360bbfda8aSnia { 8370bbfda8aSnia KeySym keysym = XLookupKeysym((XKeyEvent *) event, 0); 8380bbfda8aSnia if(! keysym) { 8390bbfda8aSnia return; 8400bbfda8aSnia } 8410bbfda8aSnia if(keysym == XK_Control_L || keysym == XK_Control_R) { 8420bbfda8aSnia /* DontToggleWorkSpaceManagerState added 20040607 by dl*/ 8430bbfda8aSnia if(!Scr->DontToggleWorkspaceManagerState) { 8440bbfda8aSnia WMgrToggleState(vs); 8450bbfda8aSnia } 8460bbfda8aSnia return; 8470bbfda8aSnia } 8480bbfda8aSnia } 8490bbfda8aSnia 8500bbfda8aSnia /* Otherwise, key presses do nothing in map state */ 8510bbfda8aSnia if(vs->wsw->state == WMS_map) { 8520bbfda8aSnia return; 8530bbfda8aSnia } 8540bbfda8aSnia 8550bbfda8aSnia /* 8560bbfda8aSnia * If we're typing in a button-state WSM, and the mouse is on one of 8570bbfda8aSnia * the buttons, that means we're changing the name, so do that dance. 8580bbfda8aSnia */ 8590bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 8600bbfda8aSnia if(vs->wsw->bswl[ws->number]->w == event->xkey.subwindow) { 8610bbfda8aSnia break; 8620bbfda8aSnia } 8630bbfda8aSnia } 8640bbfda8aSnia if(ws == NULL) { 8650bbfda8aSnia /* Not on a button, nothing to do */ 8660bbfda8aSnia return; 8670bbfda8aSnia } 8680bbfda8aSnia 8690bbfda8aSnia 8700bbfda8aSnia /* 8710bbfda8aSnia * Edit the label. 8720bbfda8aSnia */ 8730bbfda8aSnia { 8740bbfda8aSnia int nkeys; 8750bbfda8aSnia char keys[16]; 8760bbfda8aSnia size_t nlen; 8770bbfda8aSnia char *newname; 8780bbfda8aSnia 8790bbfda8aSnia /* Look up what keystrokes are queued. Arbitrary buf size */ 8800bbfda8aSnia nkeys = XLookupString(&(event->xkey), keys, 16, NULL, NULL); 8810bbfda8aSnia 8820bbfda8aSnia /* Label length can't grow to more than cur+nkeys */ 8830bbfda8aSnia nlen = strlen(ws->label); 8840bbfda8aSnia newname = malloc(nlen + nkeys + 1); 8850bbfda8aSnia strcpy(newname, ws->label); 8860bbfda8aSnia 8870bbfda8aSnia /* Iterate over the passed keystrokes */ 8880bbfda8aSnia for(int i = 0 ; i < nkeys ; i++) { 8890bbfda8aSnia unsigned char k = keys[i]; 8900bbfda8aSnia 8910bbfda8aSnia if(isprint(k)) { 8920bbfda8aSnia /* Printable chars append to the string */ 8930bbfda8aSnia newname[nlen++] = k; 8940bbfda8aSnia } 8950bbfda8aSnia else if((k == 127) || (k == 8)) { 8960bbfda8aSnia /* 8970bbfda8aSnia * DEL or BS back up a char. 8980bbfda8aSnia * 8990bbfda8aSnia * XXX Would it be more generally correct to do this via 9000bbfda8aSnia * keysyms, in the face of changed keyboard mappings or 9010bbfda8aSnia * significantly differing locales? 9020bbfda8aSnia */ 9030bbfda8aSnia if(nlen != 0) { 9040bbfda8aSnia nlen--; 9050bbfda8aSnia } 9060bbfda8aSnia } 9070bbfda8aSnia else { 9080bbfda8aSnia /* Any other char stops the process dead */ 9090bbfda8aSnia break; 9100bbfda8aSnia } 9110bbfda8aSnia } 9120bbfda8aSnia /* Now ends where it ends */ 9130bbfda8aSnia newname[nlen] = '\0'; 9140bbfda8aSnia 9150bbfda8aSnia /* Swap it in */ 9160bbfda8aSnia free(ws->label); 9170bbfda8aSnia ws->label = newname; 9180bbfda8aSnia } 9190bbfda8aSnia 9200bbfda8aSnia 9210bbfda8aSnia /* Redraw the button with the new label */ 9220bbfda8aSnia { 9230bbfda8aSnia ButtonState bs = (ws == vs->wsw->currentwspc) ? on : off; 9240bbfda8aSnia 9250bbfda8aSnia PaintWsButton(WSPCWINDOW, vs, vs->wsw->bswl[ws->number]->w, ws->label, 9260bbfda8aSnia ws->cp, bs); 9270bbfda8aSnia } 9280bbfda8aSnia} 9290bbfda8aSnia 9300bbfda8aSnia 9310bbfda8aSnia/* 9320bbfda8aSnia * Mouse clicking in WSM. Gets called on button press (not release). In 9330bbfda8aSnia * the simple case, that's just switching workspaces. In the more 9340bbfda8aSnia * complex, it's changing window occupation in various different ways, or 9350bbfda8aSnia * even moving windows. When that's happening, it internally hijacks 9360bbfda8aSnia * button/motion/exposure events and implements them for the moving, with 9370bbfda8aSnia * magic escapes if it gets them for something else. Ew. 9380bbfda8aSnia */ 9390bbfda8aSniavoid 9400bbfda8aSniaWMgrHandleButtonEvent(VirtualScreen *vs, XEvent *event) 9410bbfda8aSnia{ 9420bbfda8aSnia WorkSpace *oldws, *newws; 9430bbfda8aSnia WinList *wl; 9440bbfda8aSnia TwmWindow *win; 9450bbfda8aSnia unsigned int W0, H0; 9460bbfda8aSnia XEvent lastev; 9470bbfda8aSnia Window w = 0; 9480bbfda8aSnia Position newX = 0, newY = 0, winX = 0, winY = 0; 9490bbfda8aSnia bool alreadyvivible, realmovemode; 9500bbfda8aSnia const WorkSpaceWindow *mw = vs->wsw; 9510bbfda8aSnia 9520bbfda8aSnia /* Shortcuts into the event */ 9530bbfda8aSnia const Window parent = event->xbutton.window; // Map/button for WS 9540bbfda8aSnia const Window sw = event->xbutton.subwindow; // Map mini-win 9550bbfda8aSnia const Time etime = event->xbutton.time; 9560bbfda8aSnia const unsigned int button = event->xbutton.button; 9570bbfda8aSnia const unsigned int modifier = event->xbutton.state; 9580bbfda8aSnia 9590bbfda8aSnia 9600bbfda8aSnia /* If we're in button state, we're just clicking to change */ 9610bbfda8aSnia if(vs->wsw->state == WMS_buttons) { 9620bbfda8aSnia WorkSpace *ws; 9630bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 9640bbfda8aSnia if(vs->wsw->bswl[ws->number]->w == parent) { 9650bbfda8aSnia GotoWorkSpace(vs, ws); 9660bbfda8aSnia break; 9670bbfda8aSnia } 9680bbfda8aSnia } 9690bbfda8aSnia return; 9700bbfda8aSnia } 9710bbfda8aSnia 9720bbfda8aSnia /* 9730bbfda8aSnia * If we get this far, we're in map state, where things are more 9740bbfda8aSnia * complicated. A simple click/release means change here too, but 9750bbfda8aSnia * there's also the possibility of dragging a subwindow around to 9760bbfda8aSnia * change its window's occupation. 9770bbfda8aSnia */ 9780bbfda8aSnia 9790bbfda8aSnia /* Find what workspace we're clicking in */ 9800bbfda8aSnia for(oldws = Scr->workSpaceMgr.workSpaceList ; oldws != NULL ; 9810bbfda8aSnia oldws = oldws->next) { 9820bbfda8aSnia if(vs->wsw->mswl[oldws->number]->w == parent) { 9830bbfda8aSnia break; 9840bbfda8aSnia } 9850bbfda8aSnia } 9860bbfda8aSnia if(oldws == NULL) { 9870bbfda8aSnia /* None? We're done here. */ 9880bbfda8aSnia return; 9890bbfda8aSnia } 9900bbfda8aSnia 9910bbfda8aSnia /* 9920bbfda8aSnia * If clicked in the workspace but outside a window, we can only be 9930bbfda8aSnia * switching workspaces. So just do that, and we're done. 9940bbfda8aSnia */ 9950bbfda8aSnia if(sw == (Window) 0) { 9960bbfda8aSnia GotoWorkSpace(vs, oldws); 9970bbfda8aSnia return; 9980bbfda8aSnia } 9990bbfda8aSnia 10000bbfda8aSnia /* Use the context to find the winlist entry for this window */ 10010bbfda8aSnia if(XFindContext(dpy, sw, MapWListContext, (XPointer *) &wl) == XCNOENT) { 10020bbfda8aSnia return; 10030bbfda8aSnia } 10040bbfda8aSnia win = wl->twm_win; 10050bbfda8aSnia 10060bbfda8aSnia /* 10070bbfda8aSnia * Sometimes we skip transients, so do so. XXX Should this 10080bbfda8aSnia * GotoWorkSpace()? 10090bbfda8aSnia */ 10100bbfda8aSnia if((! Scr->TransientHasOccupation) && win->istransient) { 10110bbfda8aSnia return; 10120bbfda8aSnia } 10130bbfda8aSnia 10140bbfda8aSnia /* 10150bbfda8aSnia * Are we trying to actually move the window, by moving its avatar in 10160bbfda8aSnia * the WSM? If ReallyMoveInWorkspaceManager is set, we're moving on 10170bbfda8aSnia * click, but not in shift-click. If it's not, it's the reverse. 10180bbfda8aSnia * 10190bbfda8aSnia * XXX This interacts really oddly and badly when you're also moving 10200bbfda8aSnia * the window from WS to WS. 10210bbfda8aSnia */ 10220bbfda8aSnia realmovemode = false; 10230bbfda8aSnia if(Scr->ReallyMoveInWorkspaceManager) { 10240bbfda8aSnia if(!(modifier & ShiftMask)) { 10250bbfda8aSnia realmovemode = true; 10260bbfda8aSnia } 10270bbfda8aSnia } 10280bbfda8aSnia else if(modifier & ShiftMask) { 10290bbfda8aSnia realmovemode = true; 10300bbfda8aSnia } 10310bbfda8aSnia 10320bbfda8aSnia /* 10330bbfda8aSnia * Frob screen-wide OpaqueMove as necessary for this window's 10340bbfda8aSnia * details. 10350bbfda8aSnia * XXX Really? 10360bbfda8aSnia */ 10370bbfda8aSnia if(win->OpaqueMove) { 10380bbfda8aSnia if(Scr->OpaqueMoveThreshold >= 200) { 10390bbfda8aSnia Scr->OpaqueMove = true; 10400bbfda8aSnia } 10410bbfda8aSnia else { 10420bbfda8aSnia const unsigned long winsz = win->frame_width * win->frame_height; 10430bbfda8aSnia const unsigned long scrsz = vs->w * vs->h; 10440bbfda8aSnia const float sf = Scr->OpaqueMoveThreshold / 100.0; 10450bbfda8aSnia if(winsz > (scrsz * sf)) { 10460bbfda8aSnia Scr->OpaqueMove = false; 10470bbfda8aSnia } 10480bbfda8aSnia else { 10490bbfda8aSnia Scr->OpaqueMove = true; 10500bbfda8aSnia } 10510bbfda8aSnia } 10520bbfda8aSnia } 10530bbfda8aSnia else { 10540bbfda8aSnia Scr->OpaqueMove = false; 10550bbfda8aSnia } 10560bbfda8aSnia 10570bbfda8aSnia /* 10580bbfda8aSnia * Buttons inside the workspace manager, when clicking on the 10590bbfda8aSnia * representation of a window: 10600bbfda8aSnia * 1: drag window to a different workspace 10610bbfda8aSnia * 2: drag a copy of the window to a different workspace 10620bbfda8aSnia * (show it in both workspaces) 10630bbfda8aSnia * 3: remove the window from this workspace (if it isn't the last). 10640bbfda8aSnia * 10650bbfda8aSnia * XXX If you move between workspaces while also doing realmovemode, 10660bbfda8aSnia * really messed up things happen. 10670bbfda8aSnia */ 10680bbfda8aSnia switch(button) { 10690bbfda8aSnia case 1 : { 10700bbfda8aSnia /* 10710bbfda8aSnia * Moving from one to another; get rid of the old location, 10720bbfda8aSnia * then fall through to the "duplicating" case below. 10730bbfda8aSnia */ 10740bbfda8aSnia XUnmapWindow(dpy, sw); 10750bbfda8aSnia /* FALLTHRU */ 10760bbfda8aSnia } 10770bbfda8aSnia 10780bbfda8aSnia case 2 : { 10790bbfda8aSnia /* 10800bbfda8aSnia * Duplicating window to another WS. We create a copy of the 10810bbfda8aSnia * window, and start moving that. The 'moving' case above 10820bbfda8aSnia * falls through to us after unmapping that old window, 10830bbfda8aSnia * leaving just our copy, which is good enough. This is 10840bbfda8aSnia * really just setting up the visual stuff for the move; the 10850bbfda8aSnia * actual occupation changes etc. come at the end of the 10860bbfda8aSnia * motion, much lower down. 10870bbfda8aSnia */ 10880bbfda8aSnia int X0, Y0, X1, Y1; 10890bbfda8aSnia unsigned int bw; 10900bbfda8aSnia XSetWindowAttributes attrs; 10910bbfda8aSnia Window junkW; 10920bbfda8aSnia 10930bbfda8aSnia /* [XYWH]0 = size/location of the avatar in the map */ 10940bbfda8aSnia XGetGeometry(dpy, sw, &junkW, &X0, &Y0, &W0, &H0, &bw, &JunkDepth); 10950bbfda8aSnia 10960bbfda8aSnia /* 10970bbfda8aSnia * [XY]0 are the coordinates of the avatar subwindow inside 10980bbfda8aSnia * the individual workspace window in the map. Turn those 10990bbfda8aSnia * into [XY]1 as the coordinates of it relative to the whole 11000bbfda8aSnia * WSM window. 11010bbfda8aSnia */ 11020bbfda8aSnia XTranslateCoordinates(dpy, vs->wsw->mswl[oldws->number]->w, 11030bbfda8aSnia mw->w, X0, Y0, &X1, &Y1, &junkW); 11040bbfda8aSnia 11050bbfda8aSnia /* 11060bbfda8aSnia * Create the copy window to drag around, as a child of the 11070bbfda8aSnia * whole WSM (so we can move it between workspaces), and map 11080bbfda8aSnia * it. 11090bbfda8aSnia */ 11100bbfda8aSnia attrs.event_mask = ExposureMask; 11110bbfda8aSnia attrs.background_pixel = wl->cp.back; 11120bbfda8aSnia attrs.border_pixel = wl->cp.back; 11130bbfda8aSnia w = XCreateWindow(dpy, mw->w, X1, Y1, W0, H0, bw, 11140bbfda8aSnia CopyFromParent, CopyFromParent, CopyFromParent, 11150bbfda8aSnia CWEventMask | CWBackPixel | CWBorderPixel, 11160bbfda8aSnia &attrs); 11170bbfda8aSnia XMapRaised(dpy, w); 11180bbfda8aSnia 11190bbfda8aSnia /* Do our dance on it to draw the name/color/etc */ 11200bbfda8aSnia WMapRedrawWindow(w, W0, H0, wl->cp, wl->twm_win->icon_name); 11210bbfda8aSnia 11220bbfda8aSnia /* 11230bbfda8aSnia * If we're moving the real window and 11240bbfda8aSnia * AlwaysShowWindowWhenMovingFromWorkspaceManager is set in 11250bbfda8aSnia * config, we need to be sure the real window is visible 11260bbfda8aSnia * while we move it. 11270bbfda8aSnia */ 11280bbfda8aSnia if(realmovemode && Scr->ShowWinWhenMovingInWmgr) { 11290bbfda8aSnia if(Scr->OpaqueMove) { 11300bbfda8aSnia DisplayWin(vs, win); 11310bbfda8aSnia } 11320bbfda8aSnia else { 11330bbfda8aSnia MoveOutline(Scr->Root, 11340bbfda8aSnia win->frame_x - win->frame_bw, 11350bbfda8aSnia win->frame_y - win->frame_bw, 11360bbfda8aSnia win->frame_width + 2 * win->frame_bw, 11370bbfda8aSnia win->frame_height + 2 * win->frame_bw, 11380bbfda8aSnia win->frame_bw, 11390bbfda8aSnia win->title_height + win->frame_bw3D); 11400bbfda8aSnia } 11410bbfda8aSnia } 11420bbfda8aSnia 11430bbfda8aSnia /* Move onward */ 11440bbfda8aSnia break; 11450bbfda8aSnia } 11460bbfda8aSnia 11470bbfda8aSnia /* 11480bbfda8aSnia * For the button 3 or anything else case, there's no dragging or 11490bbfda8aSnia * anything, so they do their thing and just immediately return. 11500bbfda8aSnia */ 11510bbfda8aSnia case 3 : { 11520bbfda8aSnia int newocc = win->occupation & ~(1 << oldws->number); 11530bbfda8aSnia if(newocc != 0) { 11540bbfda8aSnia ChangeOccupation(win, newocc); 11550bbfda8aSnia } 11560bbfda8aSnia return; 11570bbfda8aSnia } 11580bbfda8aSnia 11590bbfda8aSnia default : 11600bbfda8aSnia return; 11610bbfda8aSnia } 11620bbfda8aSnia 11630bbfda8aSnia /* 11640bbfda8aSnia * Keep dragging the representation of the window 11650bbfda8aSnia * 11660bbfda8aSnia * XXX Look back at this and see if we can move it to an inner 11670bbfda8aSnia * function for readability... 11680bbfda8aSnia */ 11690bbfda8aSnia { 11700bbfda8aSnia const float wf = (float)(mw->wwidth - 1) / (float) vs->w; 11710bbfda8aSnia const float hf = (float)(mw->wheight - 1) / (float) vs->h; 11720bbfda8aSnia int XW, YW; 11730bbfda8aSnia bool cont; 11740bbfda8aSnia Window junkW; 11750bbfda8aSnia 11760bbfda8aSnia /* Figure where in the subwindow the click was, and stash in XW/YW */ 11770bbfda8aSnia XTranslateCoordinates(dpy, Scr->Root, sw, event->xbutton.x_root, 11780bbfda8aSnia event->xbutton.y_root, 11790bbfda8aSnia &XW, &YW, &junkW); 11800bbfda8aSnia 11810bbfda8aSnia /* 11820bbfda8aSnia * Grab the pointer, lock it into the WSM, and get the events 11830bbfda8aSnia * related to buttons and movement. We don't need 11840bbfda8aSnia * PointerMotionMask, since that would only happen after buttons 11850bbfda8aSnia * are released, and we'll be done by then. 11860bbfda8aSnia */ 11870bbfda8aSnia XGrabPointer(dpy, mw->w, False, 11880bbfda8aSnia ButtonPressMask | ButtonMotionMask | ButtonReleaseMask, 11890bbfda8aSnia GrabModeAsync, GrabModeAsync, mw->w, Scr->MoveCursor, 11900bbfda8aSnia CurrentTime); 11910bbfda8aSnia 11920bbfda8aSnia /* Start handling events until we're done */ 11930bbfda8aSnia alreadyvivible = false; 11940bbfda8aSnia cont = true; 11950bbfda8aSnia while(cont) { 11960bbfda8aSnia XEvent ev; 11970bbfda8aSnia 11980bbfda8aSnia /* Grab the next event and handle */ 11990bbfda8aSnia XMaskEvent(dpy, ButtonPressMask | ButtonMotionMask | 12000bbfda8aSnia ButtonReleaseMask | ExposureMask, &ev); 12010bbfda8aSnia switch(ev.xany.type) { 12020bbfda8aSnia case Expose : { 12030bbfda8aSnia /* Something got exposed */ 12040bbfda8aSnia if(ev.xexpose.window == w) { 12050bbfda8aSnia /* 12060bbfda8aSnia * The win we're working with? We know how to do 12070bbfda8aSnia * that. 12080bbfda8aSnia */ 12090bbfda8aSnia WMapRedrawWindow(w, W0, H0, wl->cp, 12100bbfda8aSnia wl->twm_win->icon_name); 12110bbfda8aSnia break; 12120bbfda8aSnia } 12130bbfda8aSnia 12140bbfda8aSnia /* Else, delegate to our global dispatcher */ 12150bbfda8aSnia Event = ev; 12160bbfda8aSnia DispatchEvent(); 12170bbfda8aSnia break; 12180bbfda8aSnia } 12190bbfda8aSnia 12200bbfda8aSnia case ButtonPress : 12210bbfda8aSnia case ButtonRelease : { 12220bbfda8aSnia /* 12230bbfda8aSnia * Events for buttons other than the one whose press 12240bbfda8aSnia * started this activity are totally ignored. 12250bbfda8aSnia */ 12260bbfda8aSnia if(ev.xbutton.button != button) { 12270bbfda8aSnia break; 12280bbfda8aSnia } 12290bbfda8aSnia 12300bbfda8aSnia /* 12310bbfda8aSnia * Otherwise, this is a press/release of the button 12320bbfda8aSnia * that started things. Though I'm not sure how it 12330bbfda8aSnia * could be a press, since it was already pressed. 12340bbfda8aSnia * Regardless, this is our exit condition. Fall 12350bbfda8aSnia * through into the Motion case to handle any 12360bbfda8aSnia * remaining movement. 12370bbfda8aSnia */ 12380bbfda8aSnia lastev = ev; 12390bbfda8aSnia cont = false; 12400bbfda8aSnia newX = ev.xbutton.x; 12410bbfda8aSnia newY = ev.xbutton.y; 12420bbfda8aSnia } 12430bbfda8aSnia 12440bbfda8aSnia /* Everything remaining is motion handling */ 12450bbfda8aSnia case MotionNotify : { 12460bbfda8aSnia /* If we fell through from above, no new movement */ 12470bbfda8aSnia if(cont) { 12480bbfda8aSnia newX = ev.xmotion.x; 12490bbfda8aSnia newY = ev.xmotion.y; 12500bbfda8aSnia } 12510bbfda8aSnia 12520bbfda8aSnia /* Lots to do if we're moving the window for real */ 12530bbfda8aSnia if(realmovemode) { 12540bbfda8aSnia int XSW, YSW; 12550bbfda8aSnia WorkSpace *cws; 12560bbfda8aSnia MapSubwindow *msw; 12570bbfda8aSnia 12580bbfda8aSnia /* Did the move start in the currently visible WS? */ 12590bbfda8aSnia bool startincurrent = (oldws == vs->wsw->currentwspc); 12600bbfda8aSnia 12610bbfda8aSnia /* Find the workspace we wound up in */ 12620bbfda8aSnia for(cws = Scr->workSpaceMgr.workSpaceList ; 12630bbfda8aSnia cws != NULL ; 12640bbfda8aSnia cws = cws->next) { 12650bbfda8aSnia msw = vs->wsw->mswl [cws->number]; 12660bbfda8aSnia if((newX >= msw->x) 12670bbfda8aSnia && (newX < msw->x + mw->wwidth) 12680bbfda8aSnia && (newY >= msw->y) 12690bbfda8aSnia && (newY < msw->y + mw->wheight)) { 12700bbfda8aSnia break; 12710bbfda8aSnia } 12720bbfda8aSnia } 12730bbfda8aSnia if(!cws) { 12740bbfda8aSnia /* None? Ignore. */ 12750bbfda8aSnia break; 12760bbfda8aSnia } 12770bbfda8aSnia 12780bbfda8aSnia /* 12790bbfda8aSnia * Mouse is wherever it started inside the 12800bbfda8aSnia * subwindow, so figure the X/Y of the top left 12810bbfda8aSnia * of the subwindow from there. (coords relative 12820bbfda8aSnia * to the whole WSM because of grab) 12830bbfda8aSnia */ 12840bbfda8aSnia winX = newX - XW; 12850bbfda8aSnia winY = newY - YW; 12860bbfda8aSnia 12870bbfda8aSnia /* XXX redundant w/previous? */ 12880bbfda8aSnia msw = vs->wsw->mswl[cws->number]; 12890bbfda8aSnia 12900bbfda8aSnia /* 12910bbfda8aSnia * Figure where those coords are relative to the 12920bbfda8aSnia * per-workspace window. 12930bbfda8aSnia */ 12940bbfda8aSnia XTranslateCoordinates(dpy, mw->w, msw->w, 12950bbfda8aSnia winX, winY, &XSW, &YSW, &junkW); 12960bbfda8aSnia 12970bbfda8aSnia /* 12980bbfda8aSnia * Now rework the win[XY] to be the coordinates 12990bbfda8aSnia * the window would be in the whole screen, based 13000bbfda8aSnia * on the [XY]SW inside the map, using our scale 13010bbfda8aSnia * factors. 13020bbfda8aSnia */ 13030bbfda8aSnia winX = (int)(XSW / wf); 13040bbfda8aSnia winY = (int)(YSW / hf); 13050bbfda8aSnia 13060bbfda8aSnia /* 13070bbfda8aSnia * Clip to the screen if DontMoveOff is set. 13080bbfda8aSnia * 13090bbfda8aSnia * XXX Can we use the Constrain*() functions for 13100bbfda8aSnia * this, instead of implementing icky magic 13110bbfda8aSnia * internally? 13120bbfda8aSnia */ 13130bbfda8aSnia if(Scr->DontMoveOff) { 13140bbfda8aSnia const int width = win->frame_width; 13150bbfda8aSnia const int height = win->frame_height; 13160bbfda8aSnia 13170bbfda8aSnia if((winX < Scr->BorderLeft) && ((Scr->MoveOffResistance < 0) || 13180bbfda8aSnia (winX > Scr->BorderLeft - Scr->MoveOffResistance))) { 13190bbfda8aSnia winX = Scr->BorderLeft; 13200bbfda8aSnia newX = msw->x + XW + Scr->BorderLeft * mw->wwidth / vs->w; 13210bbfda8aSnia } 13220bbfda8aSnia if(((winX + width) > vs->w - Scr->BorderRight) && 13230bbfda8aSnia ((Scr->MoveOffResistance < 0) || 13240bbfda8aSnia ((winX + width) < vs->w - Scr->BorderRight + Scr->MoveOffResistance))) { 13250bbfda8aSnia winX = vs->w - Scr->BorderRight - width; 13260bbfda8aSnia newX = msw->x + mw->wwidth * 13270bbfda8aSnia (1 - Scr->BorderRight / (double) vs->w) - wl->width + XW - 2; 13280bbfda8aSnia } 13290bbfda8aSnia if((winY < Scr->BorderTop) && ((Scr->MoveOffResistance < 0) || 13300bbfda8aSnia (winY > Scr->BorderTop - Scr->MoveOffResistance))) { 13310bbfda8aSnia winY = Scr->BorderTop; 13320bbfda8aSnia newY = msw->y + YW + Scr->BorderTop * mw->height / vs->h; 13330bbfda8aSnia } 13340bbfda8aSnia if(((winY + height) > vs->h - Scr->BorderBottom) && 13350bbfda8aSnia ((Scr->MoveOffResistance < 0) || 13360bbfda8aSnia ((winY + height) < vs->h - Scr->BorderBottom + Scr->MoveOffResistance))) { 13370bbfda8aSnia winY = vs->h - Scr->BorderBottom - height; 13380bbfda8aSnia newY = msw->y + mw->wheight 13390bbfda8aSnia * (1 - Scr->BorderBottom / (double) vs->h) 13400bbfda8aSnia * - wl->height + YW - 2; 13410bbfda8aSnia } 13420bbfda8aSnia } 13430bbfda8aSnia 13440bbfda8aSnia 13450bbfda8aSnia /* Setup the avatar for the new position of win */ 13460bbfda8aSnia WMapSetupWindow(win, winX, winY, -1, -1); 13470bbfda8aSnia 13480bbfda8aSnia /* 13490bbfda8aSnia * If SWWMIW, we already made sure above the 13500bbfda8aSnia * window is always visible on the screen. So we 13510bbfda8aSnia * don't need to do any of the following steps to 13520bbfda8aSnia * maybe show it or maybe un-show it, since we 13530bbfda8aSnia * know it's already always shown. 13540bbfda8aSnia */ 13550bbfda8aSnia if(Scr->ShowWinWhenMovingInWmgr) { 13560bbfda8aSnia goto movewin; 13570bbfda8aSnia } 13580bbfda8aSnia 13590bbfda8aSnia /* 13600bbfda8aSnia * If we wound up in the same workspace as is 13610bbfda8aSnia * being displayed on the screen, we need to make 13620bbfda8aSnia * sure that window is showing up on the screen 13630bbfda8aSnia * as a "about to be occupied here if you release 13640bbfda8aSnia * the button" indication. 13650bbfda8aSnia */ 13660bbfda8aSnia if(cws == vs->wsw->currentwspc) { 13670bbfda8aSnia if(alreadyvivible) { 13680bbfda8aSnia /* Unless it's already there */ 13690bbfda8aSnia goto movewin; 13700bbfda8aSnia } 13710bbfda8aSnia if(Scr->OpaqueMove) { 13720bbfda8aSnia XMoveWindow(dpy, win->frame, winX, winY); 13730bbfda8aSnia DisplayWin(vs, win); 13740bbfda8aSnia } 13750bbfda8aSnia else { 13760bbfda8aSnia MoveOutline(Scr->Root, 13770bbfda8aSnia winX - win->frame_bw, 13780bbfda8aSnia winY - win->frame_bw, 13790bbfda8aSnia win->frame_width + 2 * win->frame_bw, 13800bbfda8aSnia win->frame_height + 2 * win->frame_bw, 13810bbfda8aSnia win->frame_bw, 13820bbfda8aSnia win->title_height + win->frame_bw3D); 13830bbfda8aSnia } 13840bbfda8aSnia alreadyvivible = true; 13850bbfda8aSnia 13860bbfda8aSnia /* 13870bbfda8aSnia * We already moved it, skip past the other 13880bbfda8aSnia * code trying to move it in other cases. 13890bbfda8aSnia */ 13900bbfda8aSnia goto move; 13910bbfda8aSnia } 13920bbfda8aSnia 13930bbfda8aSnia /* 13940bbfda8aSnia * If it's for whatever reason not being shown on 13950bbfda8aSnia * the screen, then we don't need to move it; hop 13960bbfda8aSnia * straight to moving the avatar. 13970bbfda8aSnia */ 13980bbfda8aSnia if(!alreadyvivible) { 13990bbfda8aSnia goto move; 14000bbfda8aSnia } 14010bbfda8aSnia 14020bbfda8aSnia /* 14030bbfda8aSnia * So it _is_ being shown. If it's not supposed 14040bbfda8aSnia * to be here, hide it away (don't need to worry 14050bbfda8aSnia * about AlwaysShow, it would have skipped past 14060bbfda8aSnia * us from ab0ve). Also, if we started moving 14070bbfda8aSnia * the window out of the visible workspace with 14080bbfda8aSnia * button 1, it's gonna not be here if you 14090bbfda8aSnia * release, so hide it away. 14100bbfda8aSnia */ 14110bbfda8aSnia if(!OCCUPY(win, vs->wsw->currentwspc) || 14120bbfda8aSnia (startincurrent && (button == 1))) { 14130bbfda8aSnia if(Scr->OpaqueMove) { 14140bbfda8aSnia Vanish(vs, win); 14150bbfda8aSnia XMoveWindow(dpy, win->frame, winX, winY); 14160bbfda8aSnia } 14170bbfda8aSnia else { 14180bbfda8aSnia MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0); 14190bbfda8aSnia } 14200bbfda8aSnia alreadyvivible = false; 14210bbfda8aSnia goto move; 14220bbfda8aSnia } 14230bbfda8aSnia 14240bbfda8aSniamovewin: 14250bbfda8aSnia /* 14260bbfda8aSnia * However we get here, the real window is 14270bbfda8aSnia * visible and needs to be moved. So move it. 14280bbfda8aSnia */ 14290bbfda8aSnia if(Scr->OpaqueMove) { 14300bbfda8aSnia XMoveWindow(dpy, win->frame, winX, winY); 14310bbfda8aSnia } 14320bbfda8aSnia else { 14330bbfda8aSnia MoveOutline(Scr->Root, 14340bbfda8aSnia winX - win->frame_bw, 14350bbfda8aSnia winY - win->frame_bw, 14360bbfda8aSnia win->frame_width + 2 * win->frame_bw, 14370bbfda8aSnia win->frame_height + 2 * win->frame_bw, 14380bbfda8aSnia win->frame_bw, 14390bbfda8aSnia win->title_height + win->frame_bw3D); 14400bbfda8aSnia } 14410bbfda8aSnia } 14420bbfda8aSnia 14430bbfda8aSniamove: 14440bbfda8aSnia /* 14450bbfda8aSnia * Just move the subwindow in the map to the new 14460bbfda8aSnia * location. 14470bbfda8aSnia */ 14480bbfda8aSnia XMoveWindow(dpy, w, newX - XW, newY - YW); 14490bbfda8aSnia 14500bbfda8aSnia /* And we're done. Next event! */ 14510bbfda8aSnia break; 14520bbfda8aSnia } 14530bbfda8aSnia } 14540bbfda8aSnia } 14550bbfda8aSnia } 14560bbfda8aSnia 14570bbfda8aSnia /* 14580bbfda8aSnia * Finished with dragging (button released). 14590bbfda8aSnia */ 14600bbfda8aSnia if(realmovemode) { 14610bbfda8aSnia /* Moving the real window? Move the real window. */ 14620bbfda8aSnia if(Scr->ShowWinWhenMovingInWmgr || alreadyvivible) { 14630bbfda8aSnia if(Scr->OpaqueMove && !OCCUPY(win, vs->wsw->currentwspc)) { 14640bbfda8aSnia Vanish(vs, win); 14650bbfda8aSnia } 14660bbfda8aSnia if(!Scr->OpaqueMove) { 14670bbfda8aSnia MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0); 14680bbfda8aSnia WMapRedrawName(vs, wl); 14690bbfda8aSnia } 14700bbfda8aSnia } 14710bbfda8aSnia SetupWindow(win, winX, winY, win->frame_width, win->frame_height, -1); 14720bbfda8aSnia } 14730bbfda8aSnia 14740bbfda8aSnia /* 14750bbfda8aSnia * Last event that caused us to escape is other code's 14760bbfda8aSnia * responsibility, put it back in the queue. 14770bbfda8aSnia */ 14780bbfda8aSnia lastev.xbutton.subwindow = (Window) 0; 14790bbfda8aSnia lastev.xbutton.window = parent; 14800bbfda8aSnia XPutBackEvent(dpy, &lastev); 14810bbfda8aSnia 14820bbfda8aSnia /* End our grab */ 14830bbfda8aSnia XUngrabPointer(dpy, CurrentTime); 14840bbfda8aSnia 14850bbfda8aSnia /* 14860bbfda8aSnia * If you wanted to change workspaces, and clicked _outside_ a 14870bbfda8aSnia * window, it would have just switched way up near the top of the 14880bbfda8aSnia * function. But if you clicked _in_ a window [in the WSM map], it 14890bbfda8aSnia * would have to go through the whole fun to find out whether you 14900bbfda8aSnia * wanted to move/reoccupy the window, or were just wanting to change 14910bbfda8aSnia * WSen. 14920bbfda8aSnia * 14930bbfda8aSnia * So if it's been <250ms (completely arbitrary and non-configgable, 14940bbfda8aSnia * probably should be rethought) since you started, assume you just 14950bbfda8aSnia * wanted to switch workspaces. Don't do any occupation change, And 14960bbfda8aSnia * just switch. Also do some magic related to the map/button 14970bbfda8aSnia * toggling. 14980bbfda8aSnia * 14990bbfda8aSnia * XXX This still leaves any window _moves_ done. It seems like it 15000bbfda8aSnia * should probably revert those too? 15010bbfda8aSnia */ 15020bbfda8aSnia if((lastev.xbutton.time - etime) < 250) { 15030bbfda8aSnia KeyCode control_L_code, control_R_code; 15040bbfda8aSnia char keys [32]; 15050bbfda8aSnia 15060bbfda8aSnia /* Re-show old miniwindow, destroy the temp, and warp to WS */ 15070bbfda8aSnia XMapWindow(dpy, sw); 15080bbfda8aSnia XDestroyWindow(dpy, w); 15090bbfda8aSnia GotoWorkSpace(vs, oldws); 15100bbfda8aSnia if(!Scr->DontWarpCursorInWMap) { 15110bbfda8aSnia WarpToWindow(win, Scr->RaiseOnWarp); 15120bbfda8aSnia } 15130bbfda8aSnia 15140bbfda8aSnia /* 15150bbfda8aSnia * The control keys toggle between map and button state. If we 15160bbfda8aSnia * did a short move, and ctrl is being held at the end, flip the 15170bbfda8aSnia * state. This has several possible causes and effects. 15180bbfda8aSnia * 15190bbfda8aSnia * One is that _during_ a move, we don't do look through KeyPress 15200bbfda8aSnia * events, so we wouldn't see it happen yet. But after we're 15210bbfda8aSnia * done and return back into the event loop, that press will come 15220bbfda8aSnia * in and cause the state to change. It may be weird to the user 15230bbfda8aSnia * to see that happen, not when they hit ctrl, but _later_, after 15240bbfda8aSnia * they release the mouse button. The "best" solution may be to 15250bbfda8aSnia * find that press in the event queue and empty it out, but a 15260bbfda8aSnia * cheap solution is just to pre-flip it and then let the event 15270bbfda8aSnia * code flip it back. Flickery maybe, but easy. Now, _should_ we be 15280bbfda8aSnia * doing that? I'm a little doubtful... 15290bbfda8aSnia * 15300bbfda8aSnia * A second is that if the WSM is "naturally" in button mode, and 15310bbfda8aSnia * you temporarily ctrl-flip it into map mode and then click in a 15320bbfda8aSnia * window. This code will cause it to automatically flip back 15330bbfda8aSnia * after you release the mouse if you haven't released ctrl yet. 15340bbfda8aSnia * This is apparently needed because, unless you have 15350bbfda8aSnia * DontWarpCursorInWMap set, the previous few lines of code would 15360bbfda8aSnia * have shifted the cursor to the window you clicked, which means 15370bbfda8aSnia * you don't get a chance to release it in the WSM and flip the 15380bbfda8aSnia * state back. It seems a reasonable assumption that the user 15390bbfda8aSnia * wanted a temporary change of state just for the purposes of 15400bbfda8aSnia * the change. 15410bbfda8aSnia * 15420bbfda8aSnia * (if you had released the ctrl before the mouse, the release 15430bbfda8aSnia * event would already be queued up up on the WSM, so would flip 15440bbfda8aSnia * it back after we return) 15450bbfda8aSnia * 15460bbfda8aSnia * XXX Should we be checking DontToggleWorkSpaceManagerState 15470bbfda8aSnia * here? 15480bbfda8aSnia */ 15490bbfda8aSnia control_L_code = XKeysymToKeycode(dpy, XStringToKeysym("Control_L")); 15500bbfda8aSnia control_R_code = XKeysymToKeycode(dpy, XStringToKeysym("Control_R")); 15510bbfda8aSnia XQueryKeymap(dpy, keys); 15520bbfda8aSnia if((keys [control_L_code / 8] & ((char) 0x80 >> (control_L_code % 8))) || 15530bbfda8aSnia keys [control_R_code / 8] & ((char) 0x80 >> (control_R_code % 8))) { 15540bbfda8aSnia WMgrToggleState(vs); 15550bbfda8aSnia } 15560bbfda8aSnia return; 15570bbfda8aSnia } 15580bbfda8aSnia 15590bbfda8aSnia 15600bbfda8aSnia /* Find the workspace we finally found up in */ 15610bbfda8aSnia for(newws = Scr->workSpaceMgr.workSpaceList ; newws != NULL ; 15620bbfda8aSnia newws = newws->next) { 15630bbfda8aSnia MapSubwindow *msw = vs->wsw->mswl[newws->number]; 15640bbfda8aSnia if((newX >= msw->x) && (newX < msw->x + mw->wwidth) && 15650bbfda8aSnia (newY >= msw->y) && (newY < msw->y + mw->wheight)) { 15660bbfda8aSnia break; 15670bbfda8aSnia } 15680bbfda8aSnia } 15690bbfda8aSnia 15700bbfda8aSnia /* And finish off whatever we're supposed to be doing */ 15710bbfda8aSnia switch(button) { 15720bbfda8aSnia case 1 : { /* moving to another workspace */ 15730bbfda8aSnia int occupation; 15740bbfda8aSnia 15750bbfda8aSnia /* If nothing to change, re-map avatar and we're done */ 15760bbfda8aSnia if((newws == NULL) || (newws == oldws) || 15770bbfda8aSnia OCCUPY(wl->twm_win, newws)) { 15780bbfda8aSnia XMapWindow(dpy, sw); 15790bbfda8aSnia break; 15800bbfda8aSnia } 15810bbfda8aSnia 15820bbfda8aSnia /* Out of the old, into the new */ 15830bbfda8aSnia occupation = win->occupation; 15840bbfda8aSnia occupation |= (1 << newws->number); 15850bbfda8aSnia occupation &= ~(1 << oldws->number); 15860bbfda8aSnia ChangeOccupation(win, occupation); 15870bbfda8aSnia 15880bbfda8aSnia /* 15890bbfda8aSnia * Raise it to the top if it's in our current ws, and 15900bbfda8aSnia * properly slot it into the WSM map stack if not. 15910bbfda8aSnia */ 15920bbfda8aSnia if(newws == vs->wsw->currentwspc) { 15930bbfda8aSnia OtpRaise(win, WinWin); 15940bbfda8aSnia WMapRaise(win); 15950bbfda8aSnia } 15960bbfda8aSnia else { 15970bbfda8aSnia WMapRestack(newws); 15980bbfda8aSnia } 15990bbfda8aSnia 16000bbfda8aSnia break; 16010bbfda8aSnia } 16020bbfda8aSnia 16030bbfda8aSnia case 2 : { /* putting in extra workspace */ 16040bbfda8aSnia int occupation; 16050bbfda8aSnia 16060bbfda8aSnia /* Nothing to do if it's going nowhere or places it already is */ 16070bbfda8aSnia if((newws == NULL) || (newws == oldws) || 16080bbfda8aSnia OCCUPY(wl->twm_win, newws)) { 16090bbfda8aSnia break; 16100bbfda8aSnia } 16110bbfda8aSnia 16120bbfda8aSnia /* Move */ 16130bbfda8aSnia occupation = win->occupation | (1 << newws->number); 16140bbfda8aSnia ChangeOccupation(win, occupation); 16150bbfda8aSnia 16160bbfda8aSnia /* Raise/stack */ 16170bbfda8aSnia if(newws == vs->wsw->currentwspc) { 16180bbfda8aSnia OtpRaise(win, WinWin); 16190bbfda8aSnia WMapRaise(win); 16200bbfda8aSnia } 16210bbfda8aSnia else { 16220bbfda8aSnia WMapRestack(newws); 16230bbfda8aSnia } 16240bbfda8aSnia break; 16250bbfda8aSnia } 16260bbfda8aSnia 16270bbfda8aSnia /* 16280bbfda8aSnia * Should actually never hit this state; only 1/2 would have 16290bbfda8aSnia * gotten this far into the code... 16300bbfda8aSnia */ 16310bbfda8aSnia default : 16320bbfda8aSnia return; 16330bbfda8aSnia } 16340bbfda8aSnia 16350bbfda8aSnia /* Clean up our temporary moving-around-in the WSM window */ 16360bbfda8aSnia XDestroyWindow(dpy, w); 16370bbfda8aSnia} 16380bbfda8aSnia 16390bbfda8aSnia 16400bbfda8aSnia 16410bbfda8aSnia 16420bbfda8aSnia/* 16430bbfda8aSnia **************************************************************** 16440bbfda8aSnia * 16450bbfda8aSnia * Functions for doing things with subwindows in the WSM in map state 16460bbfda8aSnia * 16470bbfda8aSnia **************************************************************** 16480bbfda8aSnia */ 16490bbfda8aSnia 16500bbfda8aSnia/* 16510bbfda8aSnia * Backend for mapping up windows in the WSM map. 16520bbfda8aSnia */ 16530bbfda8aSniastatic void 16540bbfda8aSniawmap_mapwin_backend(TwmWindow *win, bool handleraise) 16550bbfda8aSnia{ 16560bbfda8aSnia VirtualScreen *vs; 16570bbfda8aSnia WorkSpace *ws; 16580bbfda8aSnia WinList *wl; 16590bbfda8aSnia 16600bbfda8aSnia for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) { 16610bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 16620bbfda8aSnia for(wl = vs->wsw->mswl[ws->number]->wl; wl != NULL; wl = wl->next) { 16630bbfda8aSnia if(win == wl->twm_win) { 16640bbfda8aSnia /* 16650bbfda8aSnia * When called via deiconify, we might have to do 16660bbfda8aSnia * stuff related to auto-raising the window while we 16670bbfda8aSnia * de-iconify. When called via a map request, the 16680bbfda8aSnia * window is always wherever it previously was in the 16690bbfda8aSnia * stack. 16700bbfda8aSnia */ 16710bbfda8aSnia if(!handleraise || Scr->NoRaiseDeicon) { 16720bbfda8aSnia XMapWindow(dpy, wl->w); 16730bbfda8aSnia } 16740bbfda8aSnia else { 16750bbfda8aSnia XMapRaised(dpy, wl->w); 16760bbfda8aSnia } 16770bbfda8aSnia WMapRedrawName(vs, wl); 16780bbfda8aSnia break; 16790bbfda8aSnia } 16800bbfda8aSnia } 16810bbfda8aSnia } 16820bbfda8aSnia } 16830bbfda8aSnia} 16840bbfda8aSnia 16850bbfda8aSnia/* 16860bbfda8aSnia * Map up a window's subwindow in the map-mode WSM. Happens as a result 16870bbfda8aSnia * of getting (or faking) a Map request event. Notably, _not_ in the 16880bbfda8aSnia * process of de-iconifying a window; mostly as a result of _creating_ 16890bbfda8aSnia * windows, or when a client maps itself without a request from us. 16900bbfda8aSnia * 16910bbfda8aSnia * x-ref comment on WMapDeIconify() for some subtle distinctions between 16920bbfda8aSnia * the two... 16930bbfda8aSnia */ 16940bbfda8aSniavoid 16950bbfda8aSniaWMapMapWindow(TwmWindow *win) 16960bbfda8aSnia{ 16970bbfda8aSnia /* We don't do raise handling */ 16980bbfda8aSnia wmap_mapwin_backend(win, false); 16990bbfda8aSnia} 17000bbfda8aSnia 17010bbfda8aSnia 17020bbfda8aSnia/* 17030bbfda8aSnia * De-iconify a window in the WSM map. The opposite of WMapIconify(), 17040bbfda8aSnia * and different from WMapMapWindow() in complicated ways. This function 17050bbfda8aSnia * winds up getting called when a window is de-iconified via a ctwm 17060bbfda8aSnia * function. 17070bbfda8aSnia */ 17080bbfda8aSniavoid 17090bbfda8aSniaWMapDeIconify(TwmWindow *win) 17100bbfda8aSnia{ 17110bbfda8aSnia /* If it's not showing anywhere, nothing to do. Is this possible? */ 17120bbfda8aSnia if(!win->vs) { 17130bbfda8aSnia return; 17140bbfda8aSnia } 17150bbfda8aSnia 17160bbfda8aSnia /* Loop and map, handling raises if necessary */ 17170bbfda8aSnia wmap_mapwin_backend(win, true); 17180bbfda8aSnia} 17190bbfda8aSnia 17200bbfda8aSnia 17210bbfda8aSnia/* 17220bbfda8aSnia * Hide away a window in the WSM map. Happens when win is iconified; 17230bbfda8aSnia * different from destruction. 17240bbfda8aSnia */ 17250bbfda8aSniavoid 17260bbfda8aSniaWMapIconify(TwmWindow *win) 17270bbfda8aSnia{ 17280bbfda8aSnia VirtualScreen *vs; 17290bbfda8aSnia WorkSpace *ws; 17300bbfda8aSnia WinList *wl; 17310bbfda8aSnia 17320bbfda8aSnia if(!win->vs) { 17330bbfda8aSnia return; 17340bbfda8aSnia } 17350bbfda8aSnia 17360bbfda8aSnia for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) { 17370bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 17380bbfda8aSnia for(wl = vs->wsw->mswl[ws->number]->wl; wl != NULL; wl = wl->next) { 17390bbfda8aSnia if(win == wl->twm_win) { 17400bbfda8aSnia XUnmapWindow(dpy, wl->w); 17410bbfda8aSnia break; 17420bbfda8aSnia } 17430bbfda8aSnia } 17440bbfda8aSnia } 17450bbfda8aSnia } 17460bbfda8aSnia} 17470bbfda8aSnia 17480bbfda8aSnia 17490bbfda8aSnia/* 17500bbfda8aSnia * Position a window in the WSM. Happens as a result of moving things. 17510bbfda8aSnia */ 17520bbfda8aSniavoid 17530bbfda8aSniaWMapSetupWindow(TwmWindow *win, int x, int y, int w, int h) 17540bbfda8aSnia{ 17550bbfda8aSnia VirtualScreen *vs; 17560bbfda8aSnia 17570bbfda8aSnia /* If it's an icon manager, or not on a vscreen, nothing to do */ 17580bbfda8aSnia if(win->isiconmgr || !win->vs) { 17590bbfda8aSnia return; 17600bbfda8aSnia } 17610bbfda8aSnia 17620bbfda8aSnia /* If it's a WSM, we may be resetting size/position, but that's it */ 17630bbfda8aSnia if(win->iswspmgr) { 17640bbfda8aSnia if(w == -1) { 17650bbfda8aSnia return; 17660bbfda8aSnia } 17670bbfda8aSnia ResizeWorkSpaceManager(win->vs, win); 17680bbfda8aSnia return; 17690bbfda8aSnia } 17700bbfda8aSnia 17710bbfda8aSnia /* If it's an occupy window, ditto */ 17720bbfda8aSnia if(win == Scr->workSpaceMgr.occupyWindow->twm_win) { 17730bbfda8aSnia if(w == -1) { 17740bbfda8aSnia return; 17750bbfda8aSnia } 17760bbfda8aSnia ResizeOccupyWindow(win); 17770bbfda8aSnia return; 17780bbfda8aSnia } 17790bbfda8aSnia 17800bbfda8aSnia 17810bbfda8aSnia /* For anything else, we're potentially showing something */ 17820bbfda8aSnia for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) { 17830bbfda8aSnia WorkSpaceWindow *wsw = vs->wsw; 17840bbfda8aSnia WorkSpace *ws; 17850bbfda8aSnia 17860bbfda8aSnia /* Scale factors for windows in the map */ 17870bbfda8aSnia float wf = (float)(wsw->wwidth - 2) / (float) vs->w; 17880bbfda8aSnia float hf = (float)(wsw->wheight - 2) / (float) vs->h; 17890bbfda8aSnia 17900bbfda8aSnia /* 17910bbfda8aSnia * Loop around windows in each WS to find all the places the 17920bbfda8aSnia * requested window should show up. 17930bbfda8aSnia */ 17940bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 17950bbfda8aSnia MapSubwindow *msw = wsw->mswl[ws->number]; 17960bbfda8aSnia 17970bbfda8aSnia for(WinList *wl = msw->wl; wl != NULL; wl = wl->next) { 17980bbfda8aSnia if(win == wl->twm_win) { 17990bbfda8aSnia /* New positions */ 18000bbfda8aSnia wl->x = (int)(x * wf); 18010bbfda8aSnia wl->y = (int)(y * hf); 18020bbfda8aSnia 18030bbfda8aSnia /* Rescale if necessary and move */ 18040bbfda8aSnia if(w == -1) { 18050bbfda8aSnia XMoveWindow(dpy, wl->w, wl->x, wl->y); 18060bbfda8aSnia } 18070bbfda8aSnia else { 18080bbfda8aSnia wl->width = (unsigned int)((w * wf) + 0.5); 18090bbfda8aSnia wl->height = (unsigned int)((h * hf) + 0.5); 18100bbfda8aSnia if(!Scr->use3Dwmap) { 18110bbfda8aSnia wl->width -= 2; 18120bbfda8aSnia wl->height -= 2; 18130bbfda8aSnia } 18140bbfda8aSnia if(wl->width < 1) { 18150bbfda8aSnia wl->width = 1; 18160bbfda8aSnia } 18170bbfda8aSnia if(wl->height < 1) { 18180bbfda8aSnia wl->height = 1; 18190bbfda8aSnia } 18200bbfda8aSnia XMoveResizeWindow(dpy, wl->w, wl->x, wl->y, 18210bbfda8aSnia wl->width, wl->height); 18220bbfda8aSnia } 18230bbfda8aSnia break; 18240bbfda8aSnia } 18250bbfda8aSnia } 18260bbfda8aSnia } 18270bbfda8aSnia } 18280bbfda8aSnia} 18290bbfda8aSnia 18300bbfda8aSnia 18310bbfda8aSnia/* 18320bbfda8aSnia * Frontends for changing the stacking of windows in the WSM. 18330bbfda8aSnia * 18340bbfda8aSnia * Strictly speaker, we have no ability to raise or lower a window in the 18350bbfda8aSnia * map; we only draw the whole stack. And these functions don't actually 18360bbfda8aSnia * change the stacking of a window, they're called as a _result_ of 18370bbfda8aSnia * changing the stacking, to notify the WSM to re-check and update 18380bbfda8aSnia * itself. So while conceptually we maintain a separation for our 18390bbfda8aSnia * callers between various reasons this is being called, the 18400bbfda8aSnia * implementations are identical. 18410bbfda8aSnia */ 18420bbfda8aSniavoid 18430bbfda8aSniaWMapRaiseLower(TwmWindow *win) 18440bbfda8aSnia{ 18450bbfda8aSnia WorkSpace *ws; 18460bbfda8aSnia 18470bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 18480bbfda8aSnia if(OCCUPY(win, ws)) { 18490bbfda8aSnia WMapRestack(ws); 18500bbfda8aSnia } 18510bbfda8aSnia } 18520bbfda8aSnia} 18530bbfda8aSnia 18540bbfda8aSniavoid 18550bbfda8aSniaWMapLower(TwmWindow *win) 18560bbfda8aSnia{ 18570bbfda8aSnia WMapRaiseLower(win); 18580bbfda8aSnia} 18590bbfda8aSnia 18600bbfda8aSniavoid 18610bbfda8aSniaWMapRaise(TwmWindow *win) 18620bbfda8aSnia{ 18630bbfda8aSnia WMapRaiseLower(win); 18640bbfda8aSnia} 18650bbfda8aSnia 18660bbfda8aSnia 18670bbfda8aSnia/* 18680bbfda8aSnia * Backend for redoing the stacking of a window in the WSM. 18690bbfda8aSnia * 18700bbfda8aSnia * XXX Since this tends to get called iteratively, there's probably 18710bbfda8aSnia * something better we can do than doing all this relatively expensive 18720bbfda8aSnia * stuff over and over... 18730bbfda8aSnia */ 18740bbfda8aSniavoid 18750bbfda8aSniaWMapRestack(WorkSpace *ws) 18760bbfda8aSnia{ 18770bbfda8aSnia WinList *wl; 18780bbfda8aSnia Window root, parent; // Dummy 18790bbfda8aSnia Window *children, *smallws; 18800bbfda8aSnia unsigned int nchildren; 18810bbfda8aSnia 18820bbfda8aSnia /* Get a whole list of the windows on the screen */ 18830bbfda8aSnia nchildren = 0; 18840bbfda8aSnia XQueryTree(dpy, Scr->Root, &root, &parent, &children, &nchildren); 18850bbfda8aSnia 18860bbfda8aSnia /* 18870bbfda8aSnia * We're presumably dealing with a [often very small] subset of them, 18880bbfda8aSnia * but just allocate space for the whole list; easier than trying to 18890bbfda8aSnia * shrink down, and really, how big can it possibly be? 18900bbfda8aSnia */ 18910bbfda8aSnia smallws = calloc(nchildren, sizeof(Window)); 18920bbfda8aSnia 18930bbfda8aSnia /* Work it up per vscreen */ 18940bbfda8aSnia for(VirtualScreen *vs = Scr->vScreenList; vs != NULL; vs = vs->next) { 18950bbfda8aSnia int j = 0; 18960bbfda8aSnia const MapSubwindow *msw = vs->wsw->mswl[ws->number]; 18970bbfda8aSnia 18980bbfda8aSnia /* Loop backward (from top to bottom of stack) */ 18990bbfda8aSnia for(int i = nchildren - 1; i >= 0; i--) { 19000bbfda8aSnia TwmWindow *win = GetTwmWindow(children[i]); 19010bbfda8aSnia 19020bbfda8aSnia /* 19030bbfda8aSnia * Only care about certain windows. If it's not a window we 19040bbfda8aSnia * know about, or not a frame (e.g., an icon), or doesn't 19050bbfda8aSnia * occupy this workspace, skip it. 19060bbfda8aSnia */ 19070bbfda8aSnia if(win == NULL || win->frame != children[i] || !OCCUPY(win, ws)) { 19080bbfda8aSnia continue; 19090bbfda8aSnia } 19100bbfda8aSnia 19110bbfda8aSnia /* Debug */ 19120bbfda8aSnia if(tracefile) { 19130bbfda8aSnia fprintf(tracefile, "WMapRestack : w = %lx, win = %p\n", 19140bbfda8aSnia children[i], (void *)win); 19150bbfda8aSnia fflush(tracefile); 19160bbfda8aSnia } 19170bbfda8aSnia 19180bbfda8aSnia /* Find this window in the list for the map of this WS */ 19190bbfda8aSnia for(wl = msw->wl; wl != NULL; wl = wl->next) { 19200bbfda8aSnia /* Debug */ 19210bbfda8aSnia if(tracefile) { 19220bbfda8aSnia fprintf(tracefile, "WMapRestack : wl = %p, twm_win = %p\n", 19230bbfda8aSnia (void *)wl, (void *)wl->twm_win); 19240bbfda8aSnia fflush(tracefile); 19250bbfda8aSnia } 19260bbfda8aSnia 19270bbfda8aSnia if(win == wl->twm_win) { 19280bbfda8aSnia /* There you are. Add into our list to restack. */ 19290bbfda8aSnia smallws[j++] = wl->w; 19300bbfda8aSnia break; 19310bbfda8aSnia } 19320bbfda8aSnia } 19330bbfda8aSnia } 19340bbfda8aSnia 19350bbfda8aSnia /* 19360bbfda8aSnia * Restack the windows in the map. Note that the order is 19370bbfda8aSnia * reversed from earlier; XQueryTree() returns bottom->top, 19380bbfda8aSnia * XRestackWindows() is passed top->bottom. 19390bbfda8aSnia */ 19400bbfda8aSnia XRestackWindows(dpy, smallws, j); 19410bbfda8aSnia } 19420bbfda8aSnia 19430bbfda8aSnia /* Cleanup */ 19440bbfda8aSnia XFree(children); 19450bbfda8aSnia free(smallws); 19460bbfda8aSnia return; 19470bbfda8aSnia} 19480bbfda8aSnia 19490bbfda8aSnia 19500bbfda8aSnia 19510bbfda8aSnia 19520bbfda8aSnia/* 19530bbfda8aSnia **************************************************************** 19540bbfda8aSnia * 19550bbfda8aSnia * Bits related to the actual drawing of the windows in the map. 19560bbfda8aSnia * 19570bbfda8aSnia **************************************************************** 19580bbfda8aSnia */ 19590bbfda8aSnia 19600bbfda8aSnia/* 19610bbfda8aSnia * Update stuff in the WSM when win's icon name changes 19620bbfda8aSnia */ 19630bbfda8aSniavoid 19640bbfda8aSniaWMapUpdateIconName(TwmWindow *win) 19650bbfda8aSnia{ 19660bbfda8aSnia VirtualScreen *vs; 19670bbfda8aSnia WorkSpace *ws; 19680bbfda8aSnia WinList *wl; 19690bbfda8aSnia 19700bbfda8aSnia for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) { 19710bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 19720bbfda8aSnia for(wl = vs->wsw->mswl[ws->number]->wl; wl != NULL; wl = wl->next) { 19730bbfda8aSnia if(win == wl->twm_win) { 19740bbfda8aSnia WMapRedrawName(vs, wl); 19750bbfda8aSnia break; 19760bbfda8aSnia } 19770bbfda8aSnia } 19780bbfda8aSnia } 19790bbfda8aSnia } 19800bbfda8aSnia} 19810bbfda8aSnia 19820bbfda8aSnia 19830bbfda8aSnia/* 19840bbfda8aSnia * Draw a window name into the window's representation in the map-state 19850bbfda8aSnia * WSM. 19860bbfda8aSnia */ 19870bbfda8aSniavoid 19880bbfda8aSniaWMapRedrawName(VirtualScreen *vs, WinList *wl) 19890bbfda8aSnia{ 19900bbfda8aSnia ColorPair cp = wl->cp; 19910bbfda8aSnia 19920bbfda8aSnia if(Scr->ReverseCurrentWorkspace && wl->wlist == vs->wsw->currentwspc) { 19930bbfda8aSnia InvertColorPair(&cp); 19940bbfda8aSnia } 19950bbfda8aSnia WMapRedrawWindow(wl->w, wl->width, wl->height, cp, wl->twm_win->icon_name); 19960bbfda8aSnia} 19970bbfda8aSnia 19980bbfda8aSnia 19990bbfda8aSnia/* 20000bbfda8aSnia * Draw up a window's representation in the map-state WSM, with the 20010bbfda8aSnia * window name. 20020bbfda8aSnia * 20030bbfda8aSnia * The drawing of the window name could probably be done a bit better. 20040bbfda8aSnia * The font size is based on a tiny fraction of the window's height, so 20050bbfda8aSnia * is probably usually too small to be useful, and often appears just as 20060bbfda8aSnia * some odd colored pixels at the top of the window. 20070bbfda8aSnia */ 20080bbfda8aSniastatic void 20090bbfda8aSniaWMapRedrawWindow(Window window, int width, int height, 20100bbfda8aSnia ColorPair cp, const char *label) 20110bbfda8aSnia{ 20120bbfda8aSnia int x, y; 20130bbfda8aSnia const MyFont font = Scr->workSpaceMgr.windowFont; 20140bbfda8aSnia 20150bbfda8aSnia /* Blank out window background color */ 20160bbfda8aSnia XClearWindow(dpy, window); 20170bbfda8aSnia 20180bbfda8aSnia /* Figure out where to position the name */ 20190bbfda8aSnia { 20200bbfda8aSnia XRectangle inc_rect; 20210bbfda8aSnia XRectangle logical_rect; 20220bbfda8aSnia int strhei, strwid; 20230bbfda8aSnia int i, descent; 20240bbfda8aSnia XFontStruct **xfonts; 20250bbfda8aSnia char **font_names; 20260bbfda8aSnia int fnum; 20270bbfda8aSnia 20280bbfda8aSnia XmbTextExtents(font.font_set, label, strlen(label), 20290bbfda8aSnia &inc_rect, &logical_rect); 20300bbfda8aSnia strwid = logical_rect.width; 20310bbfda8aSnia strhei = logical_rect.height; 20320bbfda8aSnia 20330bbfda8aSnia /* 20340bbfda8aSnia * If it's too tall to fit, just give up now. 20350bbfda8aSnia * XXX Probably should still do border stuff below... 20360bbfda8aSnia */ 20370bbfda8aSnia if(strhei > height) { 20380bbfda8aSnia return; 20390bbfda8aSnia } 20400bbfda8aSnia 20410bbfda8aSnia x = (width - strwid) / 2; 20420bbfda8aSnia if(x < 1) { 20430bbfda8aSnia x = 1; 20440bbfda8aSnia } 20450bbfda8aSnia 20460bbfda8aSnia fnum = XFontsOfFontSet(font.font_set, &xfonts, &font_names); 20470bbfda8aSnia for(i = 0, descent = 0; i < fnum; i++) { 20480bbfda8aSnia /* xf = xfonts[i]; */ 20490bbfda8aSnia descent = ((descent < (xfonts[i]->max_bounds.descent)) ? 20500bbfda8aSnia (xfonts[i]->max_bounds.descent) : descent); 20510bbfda8aSnia } 20520bbfda8aSnia 20530bbfda8aSnia y = ((height + strhei) / 2) - descent; 20540bbfda8aSnia } 20550bbfda8aSnia 20560bbfda8aSnia /* Draw up borders around the win */ 20570bbfda8aSnia if(Scr->use3Dwmap) { 20580bbfda8aSnia Draw3DBorder(window, 0, 0, width, height, 1, cp, off, true, false); 20590bbfda8aSnia FB(cp.fore, cp.back); 20600bbfda8aSnia } 20610bbfda8aSnia else { 20620bbfda8aSnia FB(cp.back, cp.fore); 20630bbfda8aSnia XFillRectangle(dpy, window, Scr->NormalGC, 0, 0, width, height); 20640bbfda8aSnia FB(cp.fore, cp.back); 20650bbfda8aSnia } 20660bbfda8aSnia 20670bbfda8aSnia /* Write in the name */ 20680bbfda8aSnia if(Scr->Monochrome != COLOR) { 20690bbfda8aSnia XmbDrawImageString(dpy, window, font.font_set, Scr->NormalGC, x, y, 20700bbfda8aSnia label, strlen(label)); 20710bbfda8aSnia } 20720bbfda8aSnia else { 20730bbfda8aSnia XmbDrawString(dpy, window, font.font_set, Scr->NormalGC, x, y, 20740bbfda8aSnia label, strlen(label)); 20750bbfda8aSnia } 20760bbfda8aSnia} 20770bbfda8aSnia 20780bbfda8aSnia 20790bbfda8aSnia 20800bbfda8aSnia 20810bbfda8aSnia/* 20820bbfda8aSnia * Processes for adding/removing windows from the WSM 20830bbfda8aSnia */ 20840bbfda8aSnia 20850bbfda8aSnia/* 20860bbfda8aSnia * Add a window into any appropriate WSMs' maps. Called during 20870bbfda8aSnia * AddWindow(). 20880bbfda8aSnia */ 20890bbfda8aSniavoid 20900bbfda8aSniaWMapAddWindow(TwmWindow *win) 20910bbfda8aSnia{ 20920bbfda8aSnia WorkSpace *ws; 20930bbfda8aSnia 20940bbfda8aSnia if(!WMapWindowMayBeAdded(win)) { 20950bbfda8aSnia return; 20960bbfda8aSnia } 20970bbfda8aSnia 20980bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 20990bbfda8aSnia if(OCCUPY(win, ws)) { 21000bbfda8aSnia WMapAddWindowToWorkspace(win, ws); 21010bbfda8aSnia } 21020bbfda8aSnia } 21030bbfda8aSnia} 21040bbfda8aSnia 21050bbfda8aSnia 21060bbfda8aSnia/* 21070bbfda8aSnia * Create WSM representation of a given window in a given WS. Called 21080bbfda8aSnia * when windows get added to a workspace, either via WMapAddWindow() 21090bbfda8aSnia * during the AddWindow() process, or via an occupation change. 21100bbfda8aSnia * 21110bbfda8aSnia * (previously: WMapAddToList()) 21120bbfda8aSnia */ 21130bbfda8aSniavoid 21140bbfda8aSniaWMapAddWindowToWorkspace(TwmWindow *win, WorkSpace *ws) 21150bbfda8aSnia{ 21160bbfda8aSnia ColorPair cp; 21170bbfda8aSnia 21180bbfda8aSnia /* Setup coloring for the window */ 21190bbfda8aSnia cp.back = win->title.back; 21200bbfda8aSnia cp.fore = win->title.fore; 21210bbfda8aSnia if(Scr->workSpaceMgr.windowcpgiven) { 21220bbfda8aSnia cp.back = Scr->workSpaceMgr.windowcp.back; 21230bbfda8aSnia GetColorFromList(Scr->workSpaceMgr.windowBackgroundL, 21240bbfda8aSnia win->name, &win->class, &cp.back); 21250bbfda8aSnia cp.fore = Scr->workSpaceMgr.windowcp.fore; 21260bbfda8aSnia GetColorFromList(Scr->workSpaceMgr.windowForegroundL, 21270bbfda8aSnia win->name, &win->class, &cp.fore); 21280bbfda8aSnia } 21290bbfda8aSnia if(Scr->use3Dwmap && !Scr->BeNiceToColormap) { 21300bbfda8aSnia GetShadeColors(&cp); 21310bbfda8aSnia } 21320bbfda8aSnia 21330bbfda8aSnia /* We need a copy in each VS */ 21340bbfda8aSnia for(VirtualScreen *vs = Scr->vScreenList; vs != NULL; vs = vs->next) { 21350bbfda8aSnia unsigned int bw; 21360bbfda8aSnia WinList *wl; 21370bbfda8aSnia const float wf = (float)(vs->wsw->wwidth - 2) / (float) vs->w; 21380bbfda8aSnia const float hf = (float)(vs->wsw->wheight - 2) / (float) vs->h; 21390bbfda8aSnia MapSubwindow *msw = vs->wsw->mswl[ws->number]; 21400bbfda8aSnia 21410bbfda8aSnia /* Put together its winlist entry */ 21420bbfda8aSnia wl = malloc(sizeof(struct winList)); 21430bbfda8aSnia wl->wlist = ws; 21440bbfda8aSnia wl->x = (int)(win->frame_x * wf); 21450bbfda8aSnia wl->y = (int)(win->frame_y * hf); 21460bbfda8aSnia wl->width = (unsigned int)((win->frame_width * wf) + 0.5); 21470bbfda8aSnia wl->height = (unsigned int)((win->frame_height * hf) + 0.5); 21480bbfda8aSnia wl->cp = cp; 21490bbfda8aSnia wl->twm_win = win; 21500bbfda8aSnia 21510bbfda8aSnia /* Size the window bits */ 21520bbfda8aSnia bw = 0; 21530bbfda8aSnia if(!Scr->use3Dwmap) { 21540bbfda8aSnia bw = 1; 21550bbfda8aSnia wl->width -= 2; 21560bbfda8aSnia wl->height -= 2; 21570bbfda8aSnia } 21580bbfda8aSnia if(wl->width < 1) { 21590bbfda8aSnia wl->width = 1; 21600bbfda8aSnia } 21610bbfda8aSnia if(wl->height < 1) { 21620bbfda8aSnia wl->height = 1; 21630bbfda8aSnia } 21640bbfda8aSnia 21650bbfda8aSnia /* Create its little window */ 21660bbfda8aSnia wl->w = XCreateSimpleWindow(dpy, msw->w, wl->x, wl->y, 21670bbfda8aSnia wl->width, wl->height, bw, 21680bbfda8aSnia Scr->Black, cp.back); 21690bbfda8aSnia 21700bbfda8aSnia /* Setup cursor and attributes for it */ 21710bbfda8aSnia { 21720bbfda8aSnia XSetWindowAttributes attr; 21730bbfda8aSnia unsigned long attrmask; 21740bbfda8aSnia 21750bbfda8aSnia attr.cursor = handCursor; 21760bbfda8aSnia attrmask = CWCursor; 21770bbfda8aSnia 21780bbfda8aSnia if(Scr->BackingStore) { 21790bbfda8aSnia attr.backing_store = WhenMapped; 21800bbfda8aSnia attrmask |= CWBackingStore; 21810bbfda8aSnia } 21820bbfda8aSnia 21830bbfda8aSnia XChangeWindowAttributes(dpy, wl->w, attrmask, &attr); 21840bbfda8aSnia } 21850bbfda8aSnia 21860bbfda8aSnia /* Setup events and stash context bits */ 21870bbfda8aSnia XSelectInput(dpy, wl->w, ExposureMask); 21880bbfda8aSnia XSaveContext(dpy, wl->w, TwmContext, (XPointer) vs->wsw->twm_win); 21890bbfda8aSnia XSaveContext(dpy, wl->w, ScreenContext, (XPointer) Scr); 21900bbfda8aSnia XSaveContext(dpy, wl->w, MapWListContext, (XPointer) wl); 21910bbfda8aSnia 21920bbfda8aSnia /* Link it onto the front of the list */ 21930bbfda8aSnia wl->next = msw->wl; 21940bbfda8aSnia msw->wl = wl; 21950bbfda8aSnia 21960bbfda8aSnia /* 21970bbfda8aSnia * And map it, if its window is mapped. That'll kick an expose 21980bbfda8aSnia * event, which will work its way down to WMapRedrawWindow(), and 21990bbfda8aSnia * fill things in. 22000bbfda8aSnia */ 22010bbfda8aSnia if(win->mapped) { 22020bbfda8aSnia XMapWindow(dpy, wl->w); 22030bbfda8aSnia } 22040bbfda8aSnia } // And around to the next vscreen 22050bbfda8aSnia} 22060bbfda8aSnia 22070bbfda8aSnia 22080bbfda8aSnia/* 22090bbfda8aSnia * Remove a window from any WSM maps it's in. Called during window 22100bbfda8aSnia * destruction process. 22110bbfda8aSnia * 22120bbfda8aSnia * (previously: WMapDestroyWindow()) 22130bbfda8aSnia */ 22140bbfda8aSniavoid 22150bbfda8aSniaWMapRemoveWindow(TwmWindow *win) 22160bbfda8aSnia{ 22170bbfda8aSnia WorkSpace *ws; 22180bbfda8aSnia 22190bbfda8aSnia for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 22200bbfda8aSnia if(OCCUPY(win, ws)) { 22210bbfda8aSnia WMapRemoveWindowFromWorkspace(win, ws); 22220bbfda8aSnia } 22230bbfda8aSnia } 22240bbfda8aSnia 22250bbfda8aSnia /* 22260bbfda8aSnia * If it's a mapped occupy window, manually hide aways its bits in 22270bbfda8aSnia * here. 22280bbfda8aSnia * 22290bbfda8aSnia * XXX Better belongs inline in caller or separate func? This is the 22300bbfda8aSnia * only thing exposing occupyWin out of occupation.c. 22310bbfda8aSnia */ 22320bbfda8aSnia if(win == occupyWin) { 22330bbfda8aSnia OccupyWindow *occwin = Scr->workSpaceMgr.occupyWindow; 22340bbfda8aSnia XUnmapWindow(dpy, occwin->twm_win->frame); 22350bbfda8aSnia occwin->twm_win->mapped = false; 22360bbfda8aSnia occwin->twm_win->occupation = 0; 22370bbfda8aSnia occupyWin = NULL; 22380bbfda8aSnia } 22390bbfda8aSnia} 22400bbfda8aSnia 22410bbfda8aSnia 22420bbfda8aSnia/* 22430bbfda8aSnia * Remove window's WSM representation. Happens from WMapRemoveWindow() 22440bbfda8aSnia * as part of the window destruction process, and in the occupation 22450bbfda8aSnia * change process. 22460bbfda8aSnia * 22470bbfda8aSnia * (previously: WMapRemoveFromList()) 22480bbfda8aSnia */ 22490bbfda8aSniavoid 22500bbfda8aSniaWMapRemoveWindowFromWorkspace(TwmWindow *win, WorkSpace *ws) 22510bbfda8aSnia{ 22520bbfda8aSnia VirtualScreen *vs; 22530bbfda8aSnia 22540bbfda8aSnia for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) { 22550bbfda8aSnia WinList **prev = &vs->wsw->mswl[ws->number]->wl; 22560bbfda8aSnia 22570bbfda8aSnia /* Pull it out of the list and destroy it */ 22580bbfda8aSnia for(WinList *wl = *prev ; wl != NULL ; wl = wl->next) { 22590bbfda8aSnia if(win != wl->twm_win) { 22600bbfda8aSnia /* Not it */ 22610bbfda8aSnia prev = &wl->next; 22620bbfda8aSnia continue; 22630bbfda8aSnia } 22640bbfda8aSnia 22650bbfda8aSnia /* There you are. Unlink and kill */ 22660bbfda8aSnia *prev = wl->next; 22670bbfda8aSnia 22680bbfda8aSnia XDeleteContext(dpy, wl->w, TwmContext); 22690bbfda8aSnia XDeleteContext(dpy, wl->w, ScreenContext); 22700bbfda8aSnia XDeleteContext(dpy, wl->w, MapWListContext); 22710bbfda8aSnia XDestroyWindow(dpy, wl->w); 22720bbfda8aSnia free(wl); 22730bbfda8aSnia 22740bbfda8aSnia /* Around to the next vscreen */ 22750bbfda8aSnia break; 22760bbfda8aSnia } 22770bbfda8aSnia } 22780bbfda8aSnia} 22790bbfda8aSnia 22800bbfda8aSnia 22810bbfda8aSnia 22820bbfda8aSnia 22830bbfda8aSnia/* 22840bbfda8aSnia **************************************************************** 22850bbfda8aSnia * 22860bbfda8aSnia * Utils-ish funcs 22870bbfda8aSnia * 22880bbfda8aSnia **************************************************************** 22890bbfda8aSnia */ 22900bbfda8aSnia 22910bbfda8aSnia/* 22920bbfda8aSnia * This is really more util.c fodder, but leaving it here for now because 22930bbfda8aSnia * it's only used once in WMapRedrawName(). If we start finding external 22940bbfda8aSnia * uses for it, it should be moved. 22950bbfda8aSnia */ 22960bbfda8aSniastatic void 22970bbfda8aSniaInvertColorPair(ColorPair *cp) 22980bbfda8aSnia{ 22990bbfda8aSnia Pixel save; 23000bbfda8aSnia 23010bbfda8aSnia save = cp->fore; 23020bbfda8aSnia cp->fore = cp->back; 23030bbfda8aSnia cp->back = save; 23040bbfda8aSnia save = cp->shadc; 23050bbfda8aSnia cp->shadc = cp->shadd; 23060bbfda8aSnia cp->shadd = save; 23070bbfda8aSnia} 23080bbfda8aSnia 23090bbfda8aSnia 23100bbfda8aSnia/* 23110bbfda8aSnia * Verify if a window may be added to the workspace map. 23120bbfda8aSnia * This is not allowed for 23130bbfda8aSnia * - icon managers 23140bbfda8aSnia * - the occupy window 23150bbfda8aSnia * - workspace manager windows 23160bbfda8aSnia * - or, optionally, windows with full occupation. 23170bbfda8aSnia */ 23180bbfda8aSniabool 23190bbfda8aSniaWMapWindowMayBeAdded(TwmWindow *win) 23200bbfda8aSnia{ 23210bbfda8aSnia if(win->isiconmgr) { 23220bbfda8aSnia return false; 23230bbfda8aSnia } 23240bbfda8aSnia if(win == Scr->workSpaceMgr.occupyWindow->twm_win) { 23250bbfda8aSnia return false; 23260bbfda8aSnia } 23270bbfda8aSnia if(win->iswspmgr) { 23280bbfda8aSnia return false; 23290bbfda8aSnia } 23300bbfda8aSnia if(Scr->workSpaceMgr.noshowoccupyall && 23310bbfda8aSnia win->occupation == fullOccupation) { 23320bbfda8aSnia return false; 23330bbfda8aSnia } 23340bbfda8aSnia return true; 23350bbfda8aSnia} 2336