~ctwm/ctwm/trunk

« back to all changes in this revision

Viewing changes to workspace_manager.c

  • Committer: Matthew Fuller
  • Date: 2023-01-28 01:02:55 UTC
  • Revision ID: fullermd@over-yonder.net-20230128010255-7y550i4n37xy9x4k
Bypass BorderedLayout for strut'd windows.

This is a hack, and does the wrong thing.  However, due to the way we
currently handle struts, the previous behavior would force a window to
move outside its own strut, which is nonsense.  A proper implementation
would require evaluating struts individually, not cramming them into
BorderedLayout (which already means something similar but distinct), and
encapsulating those checks in all the places that do window positioning.

That's a major change though; this at least avoids the extra-dumb
behavior, and works no worse than 4.0.3 and pre-r644 code for those
corner cases.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 *  [ ctwm ]
3
 
 *
4
 
 *  Copyright 1992 Claude Lecommandeur.
5
 
 *
6
 
 * Permission to use, copy, modify  and distribute this software  [ctwm] and
7
 
 * its documentation for any purpose is hereby granted without fee, provided
8
 
 * that the above  copyright notice appear  in all copies and that both that
9
 
 * copyright notice and this permission notice appear in supporting documen-
10
 
 * tation, and that the name of  Claude Lecommandeur not be used in adverti-
11
 
 * sing or  publicity  pertaining to  distribution of  the software  without
12
 
 * specific, written prior permission. Claude Lecommandeur make no represen-
13
 
 * tations  about the suitability  of this software  for any purpose.  It is
14
 
 * provided "as is" without express or implied warranty.
15
 
 *
16
 
 * Claude Lecommandeur DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17
 
 * INCLUDING ALL  IMPLIED WARRANTIES OF  MERCHANTABILITY AND FITNESS.  IN NO
18
 
 * EVENT SHALL  Claude Lecommandeur  BE LIABLE FOR ANY SPECIAL,  INDIRECT OR
19
 
 * CONSEQUENTIAL  DAMAGES OR ANY  DAMAGES WHATSOEVER  RESULTING FROM LOSS OF
20
 
 * USE, DATA  OR PROFITS,  WHETHER IN AN ACTION  OF CONTRACT,  NEGLIGENCE OR
21
 
 * OTHER  TORTIOUS ACTION,  ARISING OUT OF OR IN  CONNECTION WITH THE USE OR
22
 
 * PERFORMANCE OF THIS SOFTWARE.
23
 
 *
24
 
 * Author:  Claude Lecommandeur [ lecom@sic.epfl.ch ][ April 1992 ]
 
2
 * Copyright 1992 Claude Lecommandeur.
25
3
 */
26
4
 
27
5
#include "ctwm.h"
35
13
#include "ctwm_atoms.h"
36
14
#include "util.h"
37
15
#include "animate.h"
38
 
#include "parse.h"
39
16
#include "screen.h"
40
 
#include "icons.h"
41
 
#include "decorations.h"
42
 
#include "resize.h"
43
17
#include "add_window.h"
44
18
#include "events.h"
45
19
#include "otp.h"
46
 
#include "clicktofocus.h"
47
20
#include "cursor.h"
48
 
#include "list.h"
49
21
#include "image.h"
50
 
#include "functions.h"
51
22
#include "drawing.h"
52
 
#ifdef EWMH
53
 
#  include "ewmh_atoms.h"
54
 
#endif
 
23
#include "list.h"
 
24
#include "occupation.h"
 
25
#include "vscreen.h"
 
26
#include "win_decorations.h"
 
27
#include "win_iconify.h"
 
28
#include "win_ops.h"
 
29
#include "win_utils.h"
 
30
#include "workspace_manager.h"
 
31
#include "workspace_utils.h"
 
32
#include "xparsegeometry.h"
 
33
 
55
34
 
56
35
#include "gram.tab.h"
57
36
 
58
 
// Gotten via screen.h
59
 
//#include "workmgr.h"
60
 
 
61
 
 
62
 
static void DisplayWinUnchecked(VirtualScreen *vs,
63
 
                                TwmWindow *tmp_win);
 
37
 
 
38
// Temp; x-ref desc in workspace_utils
 
39
extern bool useBackgroundInfo;
 
40
 
 
41
 
64
42
static void CreateWorkSpaceManagerWindow(VirtualScreen *vs);
 
43
static void ResizeWorkSpaceManager(VirtualScreen *vs, TwmWindow *win);
65
44
static void PaintWorkSpaceManagerBorder(VirtualScreen *vs);
66
 
static void ResizeWorkSpaceManager(VirtualScreen *vs, TwmWindow *win);
 
45
 
 
46
static void wmap_mapwin_backend(TwmWindow *win, bool handleraise);
 
47
 
 
48
static void WMapRedrawWindow(Window window, int width, int height,
 
49
                             ColorPair cp, const char *label);
 
50
 
67
51
static void InvertColorPair(ColorPair *cp);
68
 
static void WMapRedrawWindow(Window window, int width, int height,
69
 
                             ColorPair cp, char *label);
70
 
 
71
 
static bool useBackgroundInfo = false;
72
 
static XContext MapWListContext = (XContext) 0;
73
 
static Cursor handCursor  = (Cursor) 0;
74
 
 
75
 
void InitWorkSpaceManager(void)
 
52
 
 
53
 
 
54
static XContext MapWListContext = None;
 
55
static Cursor handCursor = None;
 
56
 
 
57
 
 
58
 
 
59
/*
 
60
 ****************************************************************
 
61
 *
 
62
 * First, functions related to general creation and drawing of the WSM
 
63
 * window and its backing structs
 
64
 *
 
65
 ****************************************************************
 
66
 */
 
67
 
 
68
/*
 
69
 * Allocate an X Context for WSM stuff.
 
70
 */
 
71
void
 
72
InitWorkSpaceManagerContext(void)
76
73
{
77
 
        Scr->workSpaceMgr.count         = 0;
78
 
        Scr->workSpaceMgr.workSpaceList = NULL;
79
 
        Scr->workSpaceMgr.initialstate  = WMS_buttons;
80
 
        Scr->workSpaceMgr.geometry      = NULL;
81
 
        Scr->workSpaceMgr.buttonStyle   = STYLE_NORMAL;
82
 
        Scr->workSpaceMgr.windowcp.back = Scr->White;
83
 
        Scr->workSpaceMgr.windowcp.fore = Scr->Black;
84
 
        Scr->workSpaceMgr.windowcpgiven = false;
85
 
 
86
 
        Scr->workSpaceMgr.occupyWindow = calloc(1, sizeof(OccupyWindow));
87
 
        Scr->workSpaceMgr.occupyWindow->name      = "Occupy Window";
88
 
        Scr->workSpaceMgr.occupyWindow->icon_name = "Occupy Window Icon";
89
 
        Scr->workSpaceMgr.occupyWindow->geometry  = NULL;
90
 
        Scr->workSpaceMgr.occupyWindow->columns   = 0;
91
 
        Scr->workSpaceMgr.occupyWindow->twm_win   = NULL;
92
 
        Scr->workSpaceMgr.occupyWindow->vspace    = Scr->WMgrVertButtonIndent;
93
 
        Scr->workSpaceMgr.occupyWindow->hspace    = Scr->WMgrHorizButtonIndent;
94
 
 
95
 
        Scr->workSpaceMgr.curColors.back  = Scr->Black;
96
 
        Scr->workSpaceMgr.curColors.fore  = Scr->White;
97
 
        Scr->workSpaceMgr.defColors.back  = Scr->White;
98
 
        Scr->workSpaceMgr.defColors.fore  = Scr->Black;
99
 
        Scr->workSpaceMgr.curImage        = NULL;
100
 
        Scr->workSpaceMgr.curPaint        = false;
101
 
        Scr->workSpaceMgr.defImage        = NULL;
102
 
        Scr->workSpaceMgr.vspace          = Scr->WMgrVertButtonIndent;
103
 
        Scr->workSpaceMgr.hspace          = Scr->WMgrHorizButtonIndent;
104
 
        Scr->workSpaceMgr.name            = "WorkSpaceManager";
105
 
        Scr->workSpaceMgr.icon_name       = "WorkSpaceManager Icon";
106
 
 
107
 
        Scr->workSpaceMgr.windowFont.basename =
108
 
                "-adobe-courier-medium-r-normal--10-100-75-75-m-60-iso8859-1";
109
 
        /*"-adobe-courier-bold-r-normal--8-80-75-75-m-50-iso8859-1";*/
110
 
 
111
 
        XrmInitialize();
112
 
        if(MapWListContext == (XContext) 0) {
 
74
        if(MapWListContext == None) {
113
75
                MapWListContext = XUniqueContext();
114
76
        }
115
77
}
116
78
 
117
 
void ConfigureWorkSpaceManager(void)
 
79
 
 
80
/**
 
81
 * Prep up structures for WSM windows in each VS.  Called (for each
 
82
 * Screen) in startup after InitVirtualScreens() has setup the VS stuff
 
83
 * (and after config file processing).  This also retrieves info for each
 
84
 * vs about which workspace is active, if available (from restarting
 
85
 * ourself, etc).
 
86
 *
 
87
 * XXX Passed param isn't quite complete, as we call some funcs that use
 
88
 * global Scr...
 
89
 */
 
90
void
 
91
ConfigureWorkSpaceManager(ScreenInfo *scr)
118
92
{
119
 
        VirtualScreen *vs;
120
 
 
121
 
        for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
 
93
        WorkSpace *ws = Scr->workSpaceMgr.workSpaceList;
 
94
        char *vsmapbuf, *vsmap;
 
95
 
 
96
        // Get the workspace name that's up on this vscreen.  This is
 
97
        // where the startup process actually sets what workspace we're
 
98
        // [re]starting in.
 
99
        vsmapbuf = CtwmGetVScreenMap(dpy, Scr->Root);
 
100
        if(vsmapbuf != NULL) {
 
101
                // Property is a comma-separate list of the workspaces for
 
102
                // each vscreen, in magic order.  So we start by chopping off
 
103
                // the first and then re-chop in the loop below.
 
104
                vsmap = strtok(vsmapbuf, ",");
 
105
        }
 
106
        else {
 
107
                vsmap = NULL;
 
108
        }
 
109
 
 
110
 
 
111
        // Setup each vs
 
112
        for(VirtualScreen *vs = scr->vScreenList; vs != NULL; vs = vs->next) {
 
113
                WorkSpace *fws;
 
114
 
122
115
                /*
123
116
                 * Make sure this is all properly initialized to nothing.  Otherwise
124
117
                 * bad and undefined behavior can show up in certain cases (e.g.,
127
120
                 * e.g.  f.menu "TwmWindows".)
128
121
                 */
129
122
                WorkSpaceWindow *wsw = calloc(1, sizeof(WorkSpaceWindow));
130
 
                wsw->state = Scr->workSpaceMgr.initialstate;
 
123
                wsw->state = scr->workSpaceMgr.initialstate;
 
124
 
 
125
                // If we have a current ws for this vs, assign it in, and
 
126
                // loop onward to the ws for the next vs.  For any we don't
 
127
                // have a default for, the default ws is the first one we haven't
 
128
                // used yet.
 
129
                if((fws = GetWorkspace(vsmap)) != NULL) {
 
130
                        wsw->currentwspc = fws;
 
131
                        vsmap = strtok(NULL, ",");
 
132
                }
 
133
                else {
 
134
                        wsw->currentwspc = ws;
 
135
                        if(ws) {
 
136
                                ws = ws->next;
 
137
                        }
 
138
                }
 
139
 
131
140
                vs->wsw = wsw;
132
141
        }
 
142
 
 
143
        free(vsmapbuf);
133
144
}
134
145
 
135
 
/***********************************************************************
136
 
 *
137
 
 *  Procedure:
138
 
 *      CreateWorkSpaceManager - create the workspace manager window
139
 
 *              for this screen.
140
 
 *
141
 
 *  Returned Value:
142
 
 *      none
143
 
 *
144
 
 *  Inputs:
145
 
 *      none
146
 
 *
147
 
 ***********************************************************************
 
146
 
 
147
 
 
148
 
 
149
/*
 
150
 * Create workspace manager windows for each vscreen.  Called (for each
 
151
 * screen) late in startup, after the preceeding funcs have run their
 
152
 * course.
148
153
 */
149
 
void CreateWorkSpaceManager(void)
 
154
void
 
155
CreateWorkSpaceManager(void)
150
156
{
151
 
        char vsmapbuf    [1024], *vsmap;
152
 
        VirtualScreen    *vs;
153
 
        WorkSpace        *ws, *fws;
154
 
        int              vsmaplen;
155
 
 
156
157
        if(! Scr->workSpaceManagerActive) {
157
158
                return;
158
159
        }
159
160
 
 
161
        /* Setup basic fonts/colors/cursors */
160
162
        Scr->workSpaceMgr.windowFont.basename =
161
163
                "-adobe-courier-medium-r-normal--10-100-75-75-m-60-iso8859-1";
162
164
        Scr->workSpaceMgr.buttonFont = Scr->IconManagerFont;
164
166
        if(!Scr->BeNiceToColormap) {
165
167
                GetShadeColors(&Scr->workSpaceMgr.cp);
166
168
        }
167
 
 
168
 
        NewFontCursor(&handCursor, "top_left_arrow");
169
 
 
170
 
        vsmaplen = sizeof(vsmapbuf);
171
 
        if(CtwmGetVScreenMap(dpy, Scr->Root, vsmapbuf, &vsmaplen)) {
172
 
                vsmap = strtok(vsmapbuf, ",");
173
 
        }
174
 
        else {
175
 
                vsmap = NULL;
176
 
        }
 
169
        if(handCursor == None) {
 
170
                NewFontCursor(&handCursor, "top_left_arrow");
 
171
        }
 
172
 
177
173
 
178
174
        /*
179
 
         * weird things can happen if the config file is changed or the atom
180
 
         * returned above is messed with.  Sometimes windows may disappear in
181
 
         * that case depending on what's changed.  (depending on where they were
182
 
         * on the actual screen.
 
175
         * Create a WSM window for each vscreen.  We don't need one for each
 
176
         * workspace (we just reuse the same one), but we do need one for
 
177
         * each vscreen (since they have to be displayed simultaneously).
183
178
         */
184
 
        ws = Scr->workSpaceMgr.workSpaceList;
185
 
        for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
186
 
                WorkSpaceWindow *wsw = vs->wsw;
187
 
                if(vsmap) {
188
 
                        fws = GetWorkspace(vsmap);
189
 
                }
190
 
                else {
191
 
                        fws = NULL;
192
 
                }
193
 
                if(fws) {
194
 
                        wsw->currentwspc = fws;
195
 
                        vsmap = strtok(NULL, ",");
196
 
                }
197
 
                else {
198
 
                        wsw->currentwspc = ws;
199
 
                        ws = ws->next;
200
 
                }
 
179
        for(VirtualScreen *vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
201
180
                CreateWorkSpaceManagerWindow(vs);
202
181
        }
203
 
        CreateOccupyWindow();
204
 
 
205
 
        for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
206
 
                WorkSpaceWindow *wsw = vs->wsw;
207
 
                WorkSpace *ws2 = wsw->currentwspc;
208
 
                MapSubwindow *msw = wsw->mswl [ws2->number];
 
182
 
 
183
 
 
184
        /*
 
185
         * Init background in the WSM workspace subwindow and potentially the
 
186
         * root window to the settings for the active workspace
 
187
         *
 
188
         * XXX CTAG_BGDRAW This process is also done in similar fashion
 
189
         * during CreateWorkSpaceManagerWindow(), and the two parts are done
 
190
         * split well apart during GotoWorkSpace().  The details of the
 
191
         * process should be factored out into helper functions instead of
 
192
         * being reimplemented in each place.  That will require a little
 
193
         * shuffling of code, and careful thinking on the apparent
 
194
         * differences (which seem like they may be cosmetic).  Todo.
 
195
         */
 
196
        for(VirtualScreen *vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
 
197
                WorkSpaceWindow *wsw = vs->wsw;    // Our WSW
 
198
                WorkSpace *ws2 = wsw->currentwspc; // Active WS
 
199
                MapSubwindow *msw = wsw->mswl[ws2->number]; // Active WS's subwin
 
200
 
 
201
                /* Setup the background/border on the active workspace */
209
202
                if(Scr->workSpaceMgr.curImage == NULL) {
210
203
                        if(Scr->workSpaceMgr.curPaint) {
211
204
                                XSetWindowBackground(dpy, msw->w, Scr->workSpaceMgr.curColors.back);
217
210
                XSetWindowBorder(dpy, msw->w, Scr->workSpaceMgr.curBorderColor);
218
211
                XClearWindow(dpy, msw->w);
219
212
 
 
213
                /* Set the root window to the color/image of that WS if we should */
220
214
                if(useBackgroundInfo && ! Scr->DontPaintRootWindow) {
221
215
                        if(ws2->image == NULL) {
222
216
                                XSetWindowBackground(dpy, vs->window, ws2->backcp.back);
228
222
                }
229
223
        }
230
224
 
 
225
 
 
226
        /*
 
227
         * Set the property we use to store the full list of workspaces.
 
228
         *
 
229
         * XXX This isn't really part of creating the WSM windows, so doesn't
 
230
         * strictly belong here.  It does need to happen after the config
 
231
         * file parsing setup the workspaces, so couldn't go into
 
232
         * InitWorkSpaceManager().  It could probably move into
 
233
         * ConfigureWorkSpaceManager() though, or could move into a separate
 
234
         * hypotehtical ConfigureWorkSpaces() sort of thing...
 
235
         */
231
236
        {
232
237
                char *wrkSpcList;
233
238
                int  len;
239
244
        }
240
245
}
241
246
 
242
 
void GotoWorkSpaceByName(VirtualScreen *vs, char *wname)
243
 
{
244
 
        WorkSpace *ws;
245
 
 
246
 
        if(! Scr->workSpaceManagerActive) {
247
 
                return;
248
 
        }
249
 
        if(!vs) {
250
 
                return;
251
 
        }
252
 
        ws = GetWorkspace(wname);
253
 
        if(ws == NULL) {
254
 
                return;
255
 
        }
256
 
        GotoWorkSpace(vs, ws);
257
 
}
258
 
 
259
 
void GotoWorkSpaceByNumber(VirtualScreen *vs, int workspacenum)
260
 
{
261
 
        WorkSpace *ws;
262
 
        if(! Scr->workSpaceManagerActive) {
263
 
                return;
264
 
        }
265
 
        if(!vs) {
266
 
                return;
267
 
        }
268
 
        for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
269
 
                if(ws->number == workspacenum) {
270
 
                        break;
271
 
                }
272
 
        }
273
 
        if(ws == NULL) {
274
 
                return;
275
 
        }
276
 
        GotoWorkSpace(vs, ws);
277
 
}
278
 
/* */
279
 
 
280
 
void GotoPrevWorkSpace(VirtualScreen *vs)
281
 
{
282
 
        WorkSpace *ws1, *ws2;
283
 
 
284
 
        if(! Scr->workSpaceManagerActive) {
285
 
                return;
286
 
        }
287
 
        if(!vs) {
288
 
                return;
289
 
        }
290
 
        ws1 = Scr->workSpaceMgr.workSpaceList;
291
 
        if(ws1 == NULL) {
292
 
                return;
293
 
        }
294
 
        ws2 = ws1->next;
295
 
 
296
 
        while((ws2 != vs->wsw->currentwspc) && (ws2 != NULL)) {
297
 
                ws1 = ws2;
298
 
                ws2 = ws2->next;
299
 
        }
300
 
        GotoWorkSpace(vs, ws1);
301
 
}
302
 
 
303
 
void GotoNextWorkSpace(VirtualScreen *vs)
304
 
{
305
 
        WorkSpace *ws;
306
 
        if(! Scr->workSpaceManagerActive) {
307
 
                return;
308
 
        }
309
 
        if(!vs) {
310
 
                return;
311
 
        }
312
 
 
313
 
        ws = vs->wsw->currentwspc;
314
 
        ws = (ws->next != NULL) ? ws->next : Scr->workSpaceMgr.workSpaceList;
315
 
        GotoWorkSpace(vs, ws);
316
 
}
317
 
 
318
 
void GotoRightWorkSpace(VirtualScreen *vs)
319
 
{
320
 
        WorkSpace *ws;
321
 
        int number, columns, count;
322
 
 
323
 
        if(!Scr->workSpaceManagerActive) {
324
 
                return;
325
 
        }
326
 
        if(!vs) {
327
 
                return;
328
 
        }
329
 
 
330
 
        ws      = vs->wsw->currentwspc;
331
 
        number  = ws->number;
332
 
        columns = Scr->workSpaceMgr.columns;
333
 
        count   = Scr->workSpaceMgr.count;
334
 
        number++;
335
 
        if((number % columns) == 0) {
336
 
                number -= columns;
337
 
        }
338
 
        else if(number >= count) {
339
 
                number = (number / columns) * columns;
340
 
        }
341
 
 
342
 
        GotoWorkSpaceByNumber(vs, number);
343
 
}
344
 
 
345
 
void GotoLeftWorkSpace(VirtualScreen *vs)
346
 
{
347
 
        WorkSpace *ws;
348
 
        int number, columns, count;
349
 
 
350
 
        if(!Scr->workSpaceManagerActive) {
351
 
                return;
352
 
        }
353
 
        if(!vs) {
354
 
                return;
355
 
        }
356
 
 
357
 
        ws      = vs->wsw->currentwspc;
358
 
        number  = ws->number;
359
 
        columns = Scr->workSpaceMgr.columns;
360
 
        count   = Scr->workSpaceMgr.count;
361
 
        number += (number % columns) ? -1 : (columns - 1);
362
 
        if(number >= count) {
363
 
                number = count - 1;
364
 
        }
365
 
        GotoWorkSpaceByNumber(vs, number);
366
 
}
367
 
 
368
 
void GotoUpWorkSpace(VirtualScreen *vs)
369
 
{
370
 
        WorkSpace *ws;
371
 
        int number, lines, columns, count;
372
 
 
373
 
        if(!Scr->workSpaceManagerActive) {
374
 
                return;
375
 
        }
376
 
        if(!vs) {
377
 
                return;
378
 
        }
379
 
 
380
 
        ws      = vs->wsw->currentwspc;
381
 
        number  = ws->number;
382
 
        lines   = Scr->workSpaceMgr.lines;
383
 
        columns = Scr->workSpaceMgr.columns;
384
 
        count   = Scr->workSpaceMgr.count;
385
 
        number -=  columns;
386
 
        if(number < 0) {
387
 
                number += lines * columns;
388
 
                /* If the number of workspaces is not a multiple of nr of columns */
389
 
                if(number >= count) {
390
 
                        number -= columns;
391
 
                }
392
 
        }
393
 
        GotoWorkSpaceByNumber(vs, number);
394
 
}
395
 
 
396
 
void GotoDownWorkSpace(VirtualScreen *vs)
397
 
{
398
 
        WorkSpace *ws;
399
 
        int number, columns, count;
400
 
 
401
 
        if(!Scr->workSpaceManagerActive) {
402
 
                return;
403
 
        }
404
 
        if(!vs) {
405
 
                return;
406
 
        }
407
 
 
408
 
        ws      = vs->wsw->currentwspc;
409
 
        number  = ws->number;
410
 
        columns = Scr->workSpaceMgr.columns;
411
 
        count   = Scr->workSpaceMgr.count;
412
 
        number +=  columns;
413
 
        if(number >= count) {
414
 
                number %= columns;
415
 
        }
416
 
        GotoWorkSpaceByNumber(vs, number);
417
 
}
418
 
 
419
 
/*
420
 
 * Show the background (by hiding all windows) or undo it.
421
 
 * f.showbackground, also can be called via EWMH bits.
422
 
 *
423
 
 * newstate is the desired showing state.
424
 
 * Pass -1 to toggle, 1 to show the background,
425
 
 * or 0 to re-show the windows.
426
 
 *
427
 
 * XXX Doesn't really belong here; more of a functions.c-ish thing
428
 
 * probably.  But left here for the moment.
429
 
 */
430
 
void ShowBackground(VirtualScreen *vs, int newstate)
431
 
{
432
 
        static int state = 0;
433
 
        TwmWindow *twmWin;
434
 
 
435
 
        if(newstate == state) {
436
 
                return;
437
 
        }
438
 
 
439
 
        if(state) {
440
 
                for(twmWin = Scr->FirstWindow; twmWin != NULL; twmWin = twmWin->next) {
441
 
                        if(twmWin->savevs == vs) {
442
 
                                DisplayWin(vs, twmWin);
443
 
                        }
444
 
                        twmWin->savevs = NULL;
445
 
                }
446
 
                state = 0;
447
 
        }
448
 
        else {
449
 
                for(twmWin = Scr->FirstWindow; twmWin != NULL; twmWin = twmWin->next) {
450
 
                        if(twmWin->vs == vs
451
 
#ifdef EWMH
452
 
                                        /* leave wt_Desktop and wt_Dock visible */
453
 
                                        && twmWin->ewmhWindowType == wt_Normal
454
 
#endif /* EWMH */
455
 
                          ) {
456
 
                                twmWin->savevs = twmWin->vs;
457
 
                                Vanish(vs, twmWin);
458
 
                        }
459
 
                }
460
 
                state = 1;
461
 
        }
462
 
#ifdef EWMH
463
 
        EwmhSet_NET_SHOWING_DESKTOP(state);
464
 
#endif /* EWMH */
465
 
}
466
 
 
467
 
void GotoWorkSpace(VirtualScreen *vs, WorkSpace *ws)
468
 
{
469
 
        TwmWindow            *twmWin;
470
 
        WorkSpace            *oldws, *newws;
471
 
        WList                *wl, *wl1;
472
 
        WinList              winl;
473
 
        XSetWindowAttributes attr;
474
 
        XWindowAttributes    winattrs;
475
 
        unsigned long        eventMask;
476
 
        IconMgr              *iconmgr;
477
 
        Window               oldw;
478
 
        Window               neww;
479
 
        TwmWindow            *focuswindow;
480
 
        VirtualScreen        *tmpvs;
481
 
 
482
 
        if(! Scr->workSpaceManagerActive) {
483
 
                return;
484
 
        }
485
 
        for(tmpvs = Scr->vScreenList; tmpvs != NULL; tmpvs = tmpvs->next) {
486
 
                if(ws == tmpvs->wsw->currentwspc) {
487
 
                        XBell(dpy, 0);
488
 
                        return;
489
 
                }
490
 
        }
491
 
        oldws = vs->wsw->currentwspc;
492
 
        newws = ws;
493
 
        if(oldws == newws) {
494
 
                return;
495
 
        }
496
 
 
497
 
        attr.backing_store = NotUseful;
498
 
        attr.save_under    = False;
499
 
 
500
 
        if(useBackgroundInfo && ! Scr->DontPaintRootWindow) {
501
 
                if(newws->image == NULL) {
502
 
                        XSetWindowBackground(dpy, vs->window, newws->backcp.back);
503
 
                }
504
 
                else {
505
 
                        XSetWindowBackgroundPixmap(dpy, vs->window, newws->image->pixmap);
506
 
                }
507
 
                XClearWindow(dpy, vs->window);
508
 
        }
509
 
 
510
 
        /* If SaveWorkspaceFocus is on, save the focus of the last window. */
511
 
        if(Scr->SaveWorkspaceFocus) {
512
 
                oldws->save_focus = Scr->Focus;
513
 
        }
514
 
 
515
 
        focuswindow = NULL;
516
 
        /* For better visual effect, the order or map/unmap is important:
517
 
           - map from top to bottom.
518
 
           - unmap from bottom to top.
519
 
           - unmap after mapping.
520
 
           The guiding factor: at any point during the transition, something
521
 
           should be visible only if it was visible before the transition or if
522
 
           it will be visible at the end.  */
523
 
        OtpCheckConsistency();
524
 
 
525
 
        for(twmWin = OtpTopWin(); twmWin != NULL;
526
 
                        twmWin = OtpNextWinDown(twmWin)) {
527
 
 
528
 
                if(OCCUPY(twmWin, newws)) {
529
 
                        if(!twmWin->vs) {
530
 
                                DisplayWin(vs, twmWin);
531
 
                        }
532
 
#ifdef EWMH
533
 
                        if(OCCUPY(twmWin, oldws)) {
534
 
                                /*
535
 
                                 * If the window remains visible, re-order the workspace
536
 
                                 * numbers in NET_WM_DESKTOP.
537
 
                                 */
538
 
                                EwmhSet_NET_WM_DESKTOP_ws(twmWin, newws);
539
 
                        }
540
 
#endif
541
 
                }
542
 
        }
543
 
 
544
 
        for(twmWin = OtpBottomWin(); twmWin != NULL;
545
 
                        twmWin = OtpNextWinUp(twmWin)) {
546
 
                if(twmWin->vs == vs) {
547
 
                        if(!OCCUPY(twmWin, newws)) {
548
 
                                VirtualScreen *tvs;
549
 
 
550
 
                                Vanish(vs, twmWin);
551
 
                                /*
552
 
                                 * Now that the window has Vanished from one virtual screen,
553
 
                                 * check to see if it is wanted on another one.
554
 
                                 * This is relatively rare, so don't bother with the
555
 
                                 * top-to-bottom order here.
556
 
                                 */
557
 
                                if(Scr->numVscreens > 1) {
558
 
                                        for(tvs = Scr->vScreenList; tvs != NULL; tvs = tvs->next) {
559
 
                                                if(tvs == vs) { /* no, not back on the old one */
560
 
                                                        continue;
561
 
                                                }
562
 
                                                if(OCCUPY(twmWin, tvs->wsw->currentwspc)) {
563
 
                                                        DisplayWin(tvs, twmWin);
564
 
                                                        break;
565
 
                                                }
566
 
                                        }
567
 
                                }
568
 
                        }
569
 
                        else if(twmWin->hasfocusvisible) {
570
 
                                focuswindow = twmWin;
571
 
                                SetFocusVisualAttributes(focuswindow, false);
572
 
                        }
573
 
                }
574
 
        }
575
 
        OtpCheckConsistency();
576
 
 
577
 
        /*
578
 
           Reorganize icon manager window lists
579
 
        */
580
 
        for(twmWin = Scr->FirstWindow; twmWin != NULL; twmWin = twmWin->next) {
581
 
                wl = twmWin->iconmanagerlist;
582
 
                if(wl == NULL) {
583
 
                        continue;
584
 
                }
585
 
                if(OCCUPY(wl->iconmgr->twm_win, newws)) {
586
 
                        continue;
587
 
                }
588
 
                wl1 = wl;
589
 
                wl  = wl->nextv;
590
 
                while(wl != NULL) {
591
 
                        if(OCCUPY(wl->iconmgr->twm_win, newws)) {
592
 
                                break;
593
 
                        }
594
 
                        wl1 = wl;
595
 
                        wl  = wl->nextv;
596
 
                }
597
 
                if(wl != NULL) {
598
 
                        wl1->nextv = wl->nextv;
599
 
                        wl->nextv  = twmWin->iconmanagerlist;
600
 
                        twmWin->iconmanagerlist = wl;
601
 
                }
602
 
        }
603
 
        wl = NULL;
604
 
        for(iconmgr = newws->iconmgr; iconmgr; iconmgr = iconmgr->next) {
605
 
                if(iconmgr->first) {
606
 
                        wl = iconmgr->first;
607
 
                        break;
608
 
                }
609
 
        }
610
 
        CurrentIconManagerEntry(wl);
611
 
        if(focuswindow) {
612
 
                SetFocusVisualAttributes(focuswindow, true);
613
 
        }
614
 
        vs->wsw->currentwspc = newws;
615
 
        if(Scr->ReverseCurrentWorkspace && vs->wsw->state == WMS_map) {
616
 
                MapSubwindow *msw = vs->wsw->mswl [oldws->number];
617
 
                for(winl = msw->wl; winl != NULL; winl = winl->next) {
618
 
                        WMapRedrawName(vs, winl);
619
 
                }
620
 
                msw = vs->wsw->mswl [newws->number];
621
 
                for(winl = msw->wl; winl != NULL; winl = winl->next) {
622
 
                        WMapRedrawName(vs, winl);
623
 
                }
624
 
        }
625
 
        else if(vs->wsw->state == WMS_buttons) {
626
 
                ButtonSubwindow *bsw = vs->wsw->bswl [oldws->number];
627
 
                PaintWsButton(WSPCWINDOW, vs, bsw->w, oldws->label, oldws->cp, off);
628
 
                bsw = vs->wsw->bswl [newws->number];
629
 
                PaintWsButton(WSPCWINDOW, vs, bsw->w, newws->label, newws->cp,  on);
630
 
        }
631
 
        oldws->iconmgr = Scr->iconmgr;
632
 
        Scr->iconmgr = newws->iconmgr;
633
 
 
634
 
        oldw = vs->wsw->mswl [oldws->number]->w;
635
 
        neww = vs->wsw->mswl [newws->number]->w;
636
 
        if(useBackgroundInfo) {
637
 
                if(oldws->image == NULL || Scr->NoImagesInWorkSpaceManager) {
638
 
                        XSetWindowBackground(dpy, oldw, oldws->backcp.back);
639
 
                }
640
 
                else {
641
 
                        XSetWindowBackgroundPixmap(dpy, oldw, oldws->image->pixmap);
642
 
                }
643
 
        }
644
 
        else {
645
 
                if(Scr->workSpaceMgr.defImage == NULL || Scr->NoImagesInWorkSpaceManager) {
646
 
                        XSetWindowBackground(dpy, oldw, Scr->workSpaceMgr.defColors.back);
647
 
                }
648
 
                else {
649
 
                        XSetWindowBackgroundPixmap(dpy, oldw, Scr->workSpaceMgr.defImage->pixmap);
650
 
                }
651
 
        }
652
 
        attr.border_pixel = Scr->workSpaceMgr.defBorderColor;
653
 
        XChangeWindowAttributes(dpy, oldw, CWBorderPixel, &attr);
654
 
 
655
 
        if(Scr->workSpaceMgr.curImage == NULL) {
656
 
                if(Scr->workSpaceMgr.curPaint) {
657
 
                        XSetWindowBackground(dpy, neww, Scr->workSpaceMgr.curColors.back);
658
 
                }
659
 
        }
660
 
        else {
661
 
                XSetWindowBackgroundPixmap(dpy, neww, Scr->workSpaceMgr.curImage->pixmap);
662
 
        }
663
 
        attr.border_pixel =  Scr->workSpaceMgr.curBorderColor;
664
 
        XChangeWindowAttributes(dpy, neww, CWBorderPixel, &attr);
665
 
 
666
 
        XClearWindow(dpy, oldw);
667
 
        XClearWindow(dpy, neww);
668
 
 
669
 
        XGetWindowAttributes(dpy, Scr->Root, &winattrs);
670
 
        eventMask = winattrs.your_event_mask;
671
 
        XSelectInput(dpy, Scr->Root, eventMask & ~PropertyChangeMask);
672
 
 
673
 
        XChangeProperty(dpy, Scr->Root, XA_WM_CURRENTWORKSPACE, XA_STRING, 8,
674
 
                        PropModeReplace, (unsigned char *) newws->name, strlen(newws->name));
675
 
#ifdef EWMH
676
 
        {
677
 
                long number = newws->number;
678
 
                /*
679
 
                 * TODO: this should probably not use Scr->Root but ->XineramaRoot.
680
 
                 * That is the real root window if we're using virtual screens.
681
 
                 * Also, on the real root it would need values for each of the
682
 
                 * virtual roots, but that doesn't fit in the EWMH ideas.
683
 
                 */
684
 
                XChangeProperty(dpy, Scr->Root, XA__NET_CURRENT_DESKTOP,
685
 
                                XA_CARDINAL, 32,
686
 
                                PropModeReplace, (unsigned char *) &number, 1);
687
 
        }
688
 
#endif /* EWMH */
689
 
        XSelectInput(dpy, Scr->Root, eventMask);
690
 
 
691
 
        /*    XDestroyWindow (dpy, cachew);*/
692
 
        if(Scr->ChangeWorkspaceFunction.func != 0) {
693
 
                char *action;
694
 
                XEvent event;
695
 
 
696
 
                action = Scr->ChangeWorkspaceFunction.item ?
697
 
                         Scr->ChangeWorkspaceFunction.item->action : NULL;
698
 
                ExecuteFunction(Scr->ChangeWorkspaceFunction.func, action,
699
 
                                (Window) 0, NULL, &event, C_ROOT, false);
700
 
        }
701
 
 
702
 
        /* If SaveWorkspaceFocus is on, try to restore the focus to the last
703
 
           window which was focused when we left this workspace. */
704
 
        if(Scr->SaveWorkspaceFocus && newws->save_focus) {
705
 
                twmWin = newws->save_focus;
706
 
                if(OCCUPY(twmWin, newws)) {     /* check should not even be needed anymore */
707
 
                        WarpToWindow(twmWin, false);
708
 
                }
709
 
                else {
710
 
                        newws->save_focus = NULL;
711
 
                }
712
 
        }
713
 
 
714
 
        /* keep track of the order of the workspaces across restarts */
715
 
        CtwmSetVScreenMap(dpy, Scr->Root, Scr->vScreenList);
716
 
 
717
 
        XSync(dpy, 0);
718
 
        if(Scr->ClickToFocus || Scr->SloppyFocus) {
719
 
                set_last_window(newws);
720
 
        }
721
 
        MaybeAnimate = true;
722
 
}
723
 
 
724
 
char *GetCurrentWorkSpaceName(VirtualScreen *vs)
725
 
{
726
 
        if(! Scr->workSpaceManagerActive) {
727
 
                return (NULL);
728
 
        }
729
 
        if(!vs) {
730
 
                vs = Scr->vScreenList;
731
 
        }
732
 
        return vs->wsw->currentwspc->name;
733
 
}
734
 
 
735
 
 
736
 
/*
737
 
 * Create a workspace.  This is what gets called when parsing
738
 
 * WorkSpaces {} config file entries.
739
 
 *
740
 
 * WorkSpaces {
741
 
 *  "One" { name background foreground backback backfore "backpix.jpg" }
742
 
 *  #         |      |           |        |       |            |
743
 
 *  #     WS name    |      Button Text   |   Map/Root FG      |
744
 
 *  #            Button BG             Map BG            Map/Root BG img
745
 
 * }
746
 
 */
747
 
void
748
 
AddWorkSpace(const char *name, const char *background, const char *foreground,
749
 
             const char *backback, const char *backfore, const char *backpix)
750
 
{
751
 
        WorkSpace *ws;
752
 
 
753
 
        /* XXX Shouldn't just silently return if we're already at max...  */
754
 
        if(Scr->workSpaceMgr.count == MAXWORKSPACE) {
755
 
                return;
756
 
        }
757
 
 
758
 
        /* Init.  Label can change over time, but starts the same a name. */
759
 
        ws = calloc(1, sizeof(WorkSpace));
760
 
        ws->name  = strdup(name);
761
 
        ws->label = strdup(name);
762
 
        ws->number = Scr->workSpaceMgr.count++;
763
 
 
764
 
        /* We're a new entry on the "everything" list */
765
 
        fullOccupation |= (1 << ws->number);
766
 
 
767
 
 
768
 
        /*
769
 
         * FB/BG colors for the button state may be specified, or fallback to
770
 
         * the icon manager's if not.
771
 
         */
772
 
        if(background == NULL) {
773
 
                ws->cp.back = Scr->IconManagerC.back;
774
 
        }
775
 
        else {
776
 
                GetColor(Scr->Monochrome, &(ws->cp.back), background);
777
 
        }
778
 
 
779
 
        if(foreground == NULL) {
780
 
                ws->cp.fore = Scr->IconManagerC.fore;
781
 
        }
782
 
        else {
783
 
                GetColor(Scr->Monochrome, &(ws->cp.fore), foreground);
784
 
        }
785
 
 
786
 
        /* Shadows for 3d buttons derived from that */
787
 
#ifdef COLOR_BLIND_USER
788
 
        ws->cp.shadc = Scr->White;
789
 
        ws->cp.shadd = Scr->Black;
790
 
#else
791
 
        if(!Scr->BeNiceToColormap) {
792
 
                GetShadeColors(&ws->cp);
793
 
        }
794
 
#endif
795
 
 
796
 
 
797
 
        /*
798
 
         * Map-state fb/bg color, as well as root win background.
799
 
         */
800
 
        if(backback == NULL) {
801
 
                GetColor(Scr->Monochrome, &(ws->backcp.back), "Black");
802
 
        }
803
 
        else {
804
 
                GetColor(Scr->Monochrome, &(ws->backcp.back), backback);
805
 
                useBackgroundInfo = true;
806
 
        }
807
 
 
808
 
        if(backfore == NULL) {
809
 
                GetColor(Scr->Monochrome, &(ws->backcp.fore), "White");
810
 
        }
811
 
        else {
812
 
                GetColor(Scr->Monochrome, &(ws->backcp.fore), backfore);
813
 
                useBackgroundInfo = true;
814
 
        }
815
 
 
816
 
 
817
 
        /* Maybe there's an image to stick on the root as well */
818
 
        ws->image = GetImage(backpix, ws->backcp);
819
 
        if(ws->image != NULL) {
820
 
                useBackgroundInfo = true;
821
 
        }
822
 
 
823
 
 
824
 
        /* Put ourselves on the end of the workspace list */
825
 
        if(Scr->workSpaceMgr.workSpaceList == NULL) {
826
 
                Scr->workSpaceMgr.workSpaceList = ws;
827
 
        }
828
 
        else {
829
 
                WorkSpace *wstmp = Scr->workSpaceMgr.workSpaceList;
830
 
                while(wstmp->next != NULL) {
831
 
                        wstmp = wstmp->next;
832
 
                }
833
 
                wstmp->next = ws;
834
 
        }
835
 
 
836
 
        /* There's at least one defined WS now */
837
 
        Scr->workSpaceManagerActive = true;
838
 
 
839
 
        return;
840
 
}
841
 
 
842
 
 
843
 
WorkSpace *
844
 
GetWorkspace(char *wname)
845
 
{
846
 
        WorkSpace *ws;
847
 
 
848
 
        /* Guard */
849
 
        if(!wname) {
850
 
                return (NULL);
851
 
        }
852
 
 
853
 
        /* Check by label */
854
 
        for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
855
 
                if(strcmp(ws->label, wname) == 0) {
856
 
                        return ws;
857
 
                }
858
 
        }
859
 
 
860
 
        /* Check by name */
861
 
        for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
862
 
                if(strcmp(ws->name, wname) == 0) {
863
 
                        return ws;
864
 
                }
865
 
        }
866
 
 
867
 
        /* Nope */
868
 
        return NULL;
869
 
}
870
 
 
871
 
 
872
 
void
873
 
ReparentFrameAndIcon(TwmWindow *tmp_win)
874
 
{
875
 
        VirtualScreen *vs = tmp_win->vs; /* which virtual screen we want it in */
876
 
 
877
 
        /* parent_vs is the current real parent of the window */
878
 
        if(vs != tmp_win->parent_vs) {
879
 
                struct Icon *icon = tmp_win->icon;
880
 
 
881
 
                tmp_win->parent_vs = vs;
882
 
 
883
 
                if(icon && icon->w) {
884
 
                        ReparentWindowAndIcon(dpy, tmp_win, vs->window,
885
 
                                              tmp_win->frame_x, tmp_win->frame_y,
886
 
                                              icon->w_x, icon->w_y);
887
 
                }
888
 
                else {
889
 
                        ReparentWindow(dpy, tmp_win,  WinWin, vs->window,
890
 
                                       tmp_win->frame_x, tmp_win->frame_y);
891
 
                }
892
 
        }
893
 
}
894
 
 
895
 
 
896
 
/*
897
 
 * Get this window outta here.  Note that despite naming, this is
898
 
 * unrelated to f.vanish.
899
 
 */
900
 
void
901
 
Vanish(VirtualScreen *vs, TwmWindow *tmp_win)
902
 
{
903
 
        if(vs && tmp_win->vs && tmp_win->vs != vs) {
904
 
                return;
905
 
        }
906
 
        if(tmp_win->UnmapByMovingFarAway) {
907
 
                XMoveWindow(dpy, tmp_win->frame, Scr->rootw + 1, Scr->rooth + 1);
908
 
        }
909
 
        else if(tmp_win->mapped) {
910
 
                XWindowAttributes winattrs;
911
 
                unsigned long     eventMask;
912
 
 
913
 
                XGetWindowAttributes(dpy, tmp_win->w, &winattrs);
914
 
                eventMask = winattrs.your_event_mask;
915
 
                XSelectInput(dpy, tmp_win->w, eventMask & ~StructureNotifyMask);
916
 
                XUnmapWindow(dpy, tmp_win->w);
917
 
                XUnmapWindow(dpy, tmp_win->frame);
918
 
                XSelectInput(dpy, tmp_win->w, eventMask);
919
 
 
920
 
                if(!tmp_win->DontSetInactive) {
921
 
                        SetMapStateProp(tmp_win, InactiveState);
922
 
                }
923
 
        }
924
 
        else if(tmp_win->icon_on && tmp_win->icon && tmp_win->icon->w) {
925
 
                XUnmapWindow(dpy, tmp_win->icon->w);
926
 
                IconDown(tmp_win);
927
 
        }
928
 
 
929
 
#if 0
930
 
        /*
931
 
         * The purpose of this is in the event of a ctwm death/restart,
932
 
         * geometries of windows that were on unmapped workspaces will show
933
 
         * up where they belong.
934
 
         * XXX - I doubt its usefulness, since still-mapped windows won't
935
 
         * enjoy this "protection", making it suboptimal at best.
936
 
         * XXX - XReparentWindow() messes up the stacking order of windows.
937
 
         * It should be avoided as much as possible. This already affects
938
 
         * switching away from and back to a workspace. Therefore do this only
939
 
         * if there are at least 2 virtual screens AND the new one (firstvs)
940
 
         * differs from where the window currently is. (Olaf Seibert).
941
 
         */
942
 
 
943
 
        if(Scr->numVscreens > 1) {
944
 
                int x, y;
945
 
                unsigned int junk;
946
 
                Window junkW, w = tmp_win->frame;
947
 
                VirtualScreen *firstvs = NULL;
948
 
 
949
 
                for(firstvs = Scr->vScreenList; firstvs; firstvs = firstvs->next)
950
 
                        if(firstvs->x == 0 && firstvs->y == 0) {
951
 
                                break;
952
 
                        }
953
 
                if(firstvs && firstvs != vs) {
954
 
                        tmp_win->vs = firstvs;
955
 
                        ReparentFrameAndIcon(tmp_win);
956
 
                }
957
 
        }
958
 
#endif
959
 
 
960
 
        tmp_win->vs = NULL;
961
 
}
962
 
 
963
 
void
964
 
DisplayWin(VirtualScreen *vs, TwmWindow *tmp_win)
965
 
{
966
 
        OtpCheckConsistency();
967
 
        DisplayWinUnchecked(vs, tmp_win);
968
 
        OtpCheckConsistency();
969
 
}
970
 
 
971
 
static void DisplayWinUnchecked(VirtualScreen *vs, TwmWindow *tmp_win)
972
 
{
973
 
        XWindowAttributes   winattrs;
974
 
        unsigned long       eventMask;
975
 
 
976
 
        /*
977
 
         * A window cannot be shown in multiple virtual screens, even if
978
 
         * it occupies both corresponding workspaces.
979
 
         */
980
 
        if(vs && tmp_win->vs) {
981
 
                return;
982
 
        }
983
 
 
984
 
        tmp_win->vs = vs;
985
 
 
986
 
        if(!tmp_win->mapped) {
987
 
                ReparentFrameAndIcon(tmp_win);
988
 
 
989
 
                if(tmp_win->isicon) {
990
 
                        if(tmp_win->icon_on) {
991
 
                                if(tmp_win->icon && tmp_win->icon->w) {
992
 
 
993
 
                                        IconUp(tmp_win);
994
 
                                        XMapWindow(dpy, tmp_win->icon->w);
995
 
                                }
996
 
                        }
997
 
                }
998
 
 
999
 
                return;
1000
 
        }
1001
 
        if(tmp_win->UnmapByMovingFarAway) {
1002
 
                if(vs) {        /* XXX I don't believe the handling of UnmapByMovingFarAway is quite correct */
1003
 
                        XReparentWindow(dpy, tmp_win->frame, vs->window,
1004
 
                                        tmp_win->frame_x, tmp_win->frame_y);
1005
 
                }
1006
 
                else {
1007
 
                        XMoveWindow(dpy, tmp_win->frame, tmp_win->frame_x, tmp_win->frame_y);
1008
 
                }
1009
 
        }
1010
 
        else {
1011
 
                if(!tmp_win->squeezed) {
1012
 
                        XGetWindowAttributes(dpy, tmp_win->w, &winattrs);
1013
 
                        eventMask = winattrs.your_event_mask;
1014
 
                        XSelectInput(dpy, tmp_win->w, eventMask & ~StructureNotifyMask);
1015
 
                        XMapWindow(dpy, tmp_win->w);
1016
 
                        XSelectInput(dpy, tmp_win->w, eventMask);
1017
 
                }
1018
 
 
1019
 
                ReparentFrameAndIcon(tmp_win);
1020
 
 
1021
 
                XMapWindow(dpy, tmp_win->frame);
1022
 
                SetMapStateProp(tmp_win, NormalState);
1023
 
        }
1024
 
}
1025
 
 
1026
 
 
1027
 
static void CreateWorkSpaceManagerWindow(VirtualScreen *vs)
1028
 
{
1029
 
        int           mask;
1030
 
        int           lines, vspace, hspace, count, columns;
1031
 
        unsigned int  width, height, bwidth, bheight;
1032
 
        char          *name, *icon_name, *geometry;
1033
 
        int           i, j;
1034
 
        ColorPair     cp;
1035
 
        MyFont        font;
1036
 
        WorkSpace     *ws;
1037
 
        int           x, y, strWid, wid;
1038
 
        unsigned long border;
1039
 
        TwmWindow     *tmp_win;
1040
 
        XSetWindowAttributes        attr;
1041
 
        XWindowAttributes           wattr;
1042
 
        unsigned long               attrmask;
1043
 
        XSizeHints    sizehints;
1044
 
        XWMHints      wmhints;
1045
 
        int           gravity;
1046
 
        XRectangle inc_rect;
1047
 
        XRectangle logical_rect;
1048
 
 
1049
 
        name      = Scr->workSpaceMgr.name;
1050
 
        icon_name = Scr->workSpaceMgr.icon_name;
1051
 
        geometry  = Scr->workSpaceMgr.geometry;
1052
 
        columns   = Scr->workSpaceMgr.columns;
1053
 
        vspace    = Scr->workSpaceMgr.vspace;
1054
 
        hspace    = Scr->workSpaceMgr.hspace;
1055
 
        font      = Scr->workSpaceMgr.buttonFont;
1056
 
        cp        = Scr->workSpaceMgr.cp;
1057
 
        border    = Scr->workSpaceMgr.defBorderColor;
1058
 
 
1059
 
        count = 0;
1060
 
        for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1061
 
                count++;
1062
 
        }
1063
 
        Scr->workSpaceMgr.count = count;
 
247
 
 
248
/*
 
249
 * Put together the actual window for the workspace manager.  Called as
 
250
 * part of CreateWorkSpaceManager() during startup, once per vscreen
 
251
 * (since there's a separate window for each).
 
252
 */
 
253
static void
 
254
CreateWorkSpaceManagerWindow(VirtualScreen *vs)
 
255
{
 
256
        unsigned int width, height;
 
257
        TwmWindow *tmp_win;
 
258
        int x, y, gravity;
 
259
        /* Shortcuts */
 
260
        const int vspace = Scr->workSpaceMgr.vspace;
 
261
        const int hspace = Scr->workSpaceMgr.hspace;
 
262
        const long count = Scr->workSpaceMgr.count;
 
263
 
 
264
        /* No workspaces?  Nothing to do. */
1064
265
        if(count == 0) {
1065
266
                return;
1066
267
        }
1067
268
 
1068
 
        if(columns == 0) {
1069
 
                lines   = 2;
1070
 
                columns = ((count - 1) / lines) + 1;
1071
 
        }
1072
 
        else {
1073
 
                lines   = ((count - 1) / columns) + 1;
1074
 
        }
1075
 
        Scr->workSpaceMgr.lines   = lines;
1076
 
        Scr->workSpaceMgr.columns = columns;
1077
 
 
1078
 
        strWid = 0;
1079
 
        for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1080
 
                XmbTextExtents(font.font_set, ws->label, strlen(ws->label),
1081
 
                               &inc_rect, &logical_rect);
1082
 
                wid = logical_rect.width;
1083
 
                if(wid > strWid) {
1084
 
                        strWid = wid;
1085
 
                }
1086
 
        }
1087
 
        if(geometry != NULL) {
1088
 
                mask = XParseGeometry(geometry, &x, &y, &width, &height);
1089
 
                bwidth  = (mask & WidthValue)  ? ((width - (columns * hspace)) / columns) :
1090
 
                          strWid + 10;
1091
 
                bheight = (mask & HeightValue) ? ((height - (lines  * vspace)) / lines) : 22;
1092
 
                width   = columns * (bwidth  + hspace);
1093
 
                height  = lines   * (bheight + vspace);
1094
 
 
1095
 
                if(!(mask & YValue)) {
1096
 
                        y = 0;
1097
 
                        mask |= YNegative;
1098
 
                }
1099
 
                if(mask & XValue) {
1100
 
                        if(mask & XNegative) {
1101
 
                                x += vs->w - width;
1102
 
                                gravity = (mask & YNegative) ? SouthEastGravity : NorthEastGravity;
 
269
        /*
 
270
         * Work out grid.  wSM.columns will be filled if specified in
 
271
         * WorkSpaceManageGeometry, or uninitialized (0) if not.
 
272
         */
 
273
        {
 
274
                int lines, columns;
 
275
                columns = Scr->workSpaceMgr.columns;
 
276
                if(columns == 0) {
 
277
                        lines = 2;
 
278
                        columns = ((count - 1) / lines) + 1;
 
279
                }
 
280
                else {
 
281
                        lines = ((count - 1) / columns) + 1;
 
282
                }
 
283
                Scr->workSpaceMgr.lines   = lines;
 
284
                Scr->workSpaceMgr.columns = columns;
 
285
        }
 
286
 
 
287
 
 
288
        /* Work out dimensions of stuff */
 
289
        {
 
290
                unsigned int bwidth, bheight;
 
291
                unsigned short strWid;
 
292
                WorkSpace *ws;
 
293
                const char *geometry = Scr->workSpaceMgr.geometry;
 
294
                const int lines      = Scr->workSpaceMgr.lines;
 
295
                const int columns    = Scr->workSpaceMgr.columns;
 
296
 
 
297
                /* Figure longest label */
 
298
                strWid = 0;
 
299
                for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
 
300
                        XRectangle inc_rect;
 
301
                        XRectangle logical_rect;
 
302
                        unsigned short wid;
 
303
                        const MyFont font = Scr->workSpaceMgr.buttonFont;
 
304
 
 
305
                        XmbTextExtents(font.font_set, ws->label, strlen(ws->label),
 
306
                                       &inc_rect, &logical_rect);
 
307
                        wid = logical_rect.width;
 
308
                        if(wid > strWid) {
 
309
                                strWid = wid;
 
310
                        }
 
311
                }
 
312
 
 
313
                /*
 
314
                 * If WorkSpaceManagerGeometry is given, work from that.  Else,
 
315
                 * create a workable minimum ourselves.
 
316
                 * */
 
317
                if(geometry != NULL) {
 
318
                        int mask;
 
319
 
 
320
                        /* Base button/subwindow sizes */
 
321
                        bwidth = strWid + 10;
 
322
                        bheight = 22;
 
323
 
 
324
                        /* Adjust to WSMGeometry if specified */
 
325
                        mask = RLayoutXParseGeometry(Scr->Layout, geometry, &x, &y, &width, &height);
 
326
                        if(mask & WidthValue) {
 
327
                                bwidth = (width - (columns * hspace)) / columns;
 
328
                        }
 
329
                        if(mask & HeightValue) {
 
330
                                bheight = (height - (lines * vspace)) / lines;
 
331
                        }
 
332
 
 
333
                        /* Size of the whole thing is based off those */
 
334
                        width  = columns * (bwidth  + hspace);
 
335
                        height = lines   * (bheight + vspace);
 
336
 
 
337
                        /*
 
338
                         * If no Y given, put it at the bottom of the screen.  If one
 
339
                         * is, just accept it.  If it's a negative, we have to figure
 
340
                         * out where that actually is on this vscreen.
 
341
                         */
 
342
                        if(!(mask & YValue)) {
 
343
                                y = 0;
 
344
                                mask |= YNegative;
 
345
                        }
 
346
                        if(mask & YNegative) {
 
347
                                y += vs->h - height;
 
348
                        }
 
349
 
 
350
                        /*
 
351
                         * If X is given, tweak as necessary for the vscreen
 
352
                         * location.  Otherwise, put it in in something like the
 
353
                         * middle.
 
354
                         */
 
355
                        if(mask & XValue) {
 
356
                                if(mask & XNegative) {
 
357
                                        x += vs->w - width;
 
358
                                        gravity = (mask & YNegative) ? SouthEastGravity : NorthEastGravity;
 
359
                                }
 
360
                                else {
 
361
                                        gravity = (mask & YNegative) ? SouthWestGravity : NorthWestGravity;
 
362
                                }
1103
363
                        }
1104
364
                        else {
1105
 
                                gravity = (mask & YNegative) ? SouthWestGravity : NorthWestGravity;
 
365
                                x = (vs->w - width) / 2;
 
366
                                gravity = (mask & YValue) ? ((mask & YNegative) ?
 
367
                                                             SouthGravity : NorthGravity) : SouthGravity;
1106
368
                        }
1107
369
                }
1108
370
                else {
1109
 
                        x = (vs->w - width) / 2;
1110
 
                        gravity = (mask & YValue) ? ((mask & YNegative) ?
1111
 
                                                     SouthGravity : NorthGravity) : SouthGravity;
1112
 
                }
1113
 
                if(mask & YNegative) {
1114
 
                        y += vs->h - height;
1115
 
                }
1116
 
        }
1117
 
        else {
1118
 
                bwidth  = strWid + 2 * Scr->WMgrButtonShadowDepth + 6;
1119
 
                bheight = 22;
1120
 
                width   = columns * (bwidth  + hspace);
1121
 
                height  = lines   * (bheight + vspace);
1122
 
                x       = (vs->w - width) / 2;
1123
 
                y       = vs->h - height;
1124
 
                gravity = NorthWestGravity;
1125
 
        }
1126
 
 
1127
 
#define Dummy   1
1128
 
 
1129
 
        vs->wsw->width   = Dummy;
1130
 
        vs->wsw->height  = Dummy;
1131
 
        vs->wsw->bswl = calloc(Scr->workSpaceMgr.count, sizeof(ButtonSubwindow *));
1132
 
        vs->wsw->mswl = calloc(Scr->workSpaceMgr.count, sizeof(MapSubwindow *));
1133
 
 
 
371
                        /* No geom specified, come up with one */
 
372
                        bwidth  = strWid + 2 * Scr->WMgrButtonShadowDepth + 6;
 
373
                        bheight = 22;
 
374
                        width   = columns * (bwidth  + hspace);
 
375
                        height  = lines   * (bheight + vspace);
 
376
                        x       = (vs->w - width) / 2;
 
377
                        y       = vs->h - height;
 
378
                        gravity = NorthWestGravity;
 
379
                }
 
380
        }
 
381
 
 
382
        /* Set w/h to dummy values; ResizeWorkSpaceManager() writes real ones */
 
383
        vs->wsw->width  = 1;
 
384
        vs->wsw->height = 1;
 
385
 
 
386
        /* Allocate structs for map/button subwindows */
 
387
        vs->wsw->bswl = calloc(count, sizeof(ButtonSubwindow *));
 
388
        vs->wsw->mswl = calloc(count, sizeof(MapSubwindow *));
 
389
 
 
390
        /* Create main window */
1134
391
        vs->wsw->w = XCreateSimpleWindow(dpy, Scr->Root, x, y, width, height, 0,
1135
 
                                         Scr->Black, cp.back);
1136
 
        i = 0;
1137
 
        j = 0;
1138
 
        for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1139
 
                Window mapsw, butsw;
1140
 
                MapSubwindow *msw;
1141
 
                ButtonSubwindow *bsw;
1142
 
 
1143
 
                vs->wsw->bswl [ws->number] = bsw = malloc(sizeof(ButtonSubwindow));
1144
 
                vs->wsw->mswl [ws->number] = msw = malloc(sizeof(MapSubwindow));
1145
 
 
1146
 
                butsw = bsw->w =
1147
 
                                XCreateSimpleWindow(dpy, vs->wsw->w,
1148
 
                                                    Dummy /* x */, Dummy /* y */,
1149
 
                                                    Dummy /* width */, Dummy /* height */,
1150
 
                                                    0, Scr->Black, ws->cp.back);
1151
 
 
1152
 
                mapsw = msw->w =
1153
 
                                XCreateSimpleWindow(dpy, vs->wsw->w,
1154
 
                                                    Dummy /* x */, Dummy /* y */,
1155
 
                                                    Dummy /* width */, Dummy /* height */,
1156
 
                                                    1, border, ws->cp.back);
1157
 
 
1158
 
                if(vs->wsw->state == WMS_buttons) {
1159
 
                        XMapWindow(dpy, butsw);
1160
 
                }
1161
 
                else {
1162
 
                        XMapWindow(dpy, mapsw);
1163
 
                }
1164
 
 
1165
 
                vs->wsw->mswl [ws->number]->wl = NULL;
1166
 
                if(useBackgroundInfo) {
1167
 
                        if(ws->image == NULL || Scr->NoImagesInWorkSpaceManager) {
1168
 
                                XSetWindowBackground(dpy, mapsw, ws->backcp.back);
1169
 
                        }
1170
 
                        else {
1171
 
                                XSetWindowBackgroundPixmap(dpy, mapsw, ws->image->pixmap);
1172
 
                        }
1173
 
                }
1174
 
                else {
1175
 
                        if(Scr->workSpaceMgr.defImage == NULL || Scr->NoImagesInWorkSpaceManager) {
1176
 
                                XSetWindowBackground(dpy, mapsw, Scr->workSpaceMgr.defColors.back);
1177
 
                        }
1178
 
                        else {
1179
 
                                XSetWindowBackgroundPixmap(dpy, mapsw, Scr->workSpaceMgr.defImage->pixmap);
1180
 
                        }
1181
 
                }
1182
 
                XClearWindow(dpy, butsw);
1183
 
                i++;
1184
 
                if(i == columns) {
1185
 
                        i = 0;
1186
 
                        j++;
1187
 
                };
1188
 
        }
1189
 
 
1190
 
        sizehints.flags       = USPosition | PBaseSize | PMinSize | PResizeInc |
1191
 
                                PWinGravity;
1192
 
        sizehints.x           = x;
1193
 
        sizehints.y           = y;
1194
 
        sizehints.base_width  = columns * hspace;
1195
 
        sizehints.base_height = lines   * vspace;
1196
 
        sizehints.width_inc   = columns;
1197
 
        sizehints.height_inc  = lines;
1198
 
        sizehints.min_width   = columns  * (hspace + 2);
1199
 
        sizehints.min_height  = lines    * (vspace + 2);
1200
 
        sizehints.win_gravity = gravity;
1201
 
 
1202
 
        wmhints.flags         = InputHint | StateHint;
1203
 
        wmhints.input         = True;
1204
 
        wmhints.initial_state = NormalState;
1205
 
 
1206
 
        XmbSetWMProperties(dpy, vs->wsw->w, name, icon_name, NULL, 0,
1207
 
                           &sizehints, &wmhints, NULL);
1208
 
 
 
392
                                         Scr->Black, Scr->workSpaceMgr.cp.back);
 
393
 
 
394
 
 
395
        /*
 
396
         * Create the map and button subwindows for each workspace
 
397
         */
 
398
        {
 
399
                WorkSpace *ws;
 
400
 
 
401
                for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
 
402
                        MapSubwindow *msw;
 
403
                        ButtonSubwindow *bsw;
 
404
                        const int Dummy = 1;
 
405
                        const unsigned long border = Scr->workSpaceMgr.defBorderColor;
 
406
 
 
407
                        /* Alloc structs */
 
408
                        vs->wsw->bswl[ws->number] = bsw
 
409
                                                    = calloc(1, sizeof(ButtonSubwindow));
 
410
                        vs->wsw->mswl[ws->number] = msw = calloc(1, sizeof(MapSubwindow));
 
411
 
 
412
                        /*
 
413
                         * Create windows for button/map.  ResizeWorkSpaceManager()
 
414
                         * sets the real sizes and positions, so we dummy 'em.
 
415
                         */
 
416
                        bsw->w = XCreateSimpleWindow(dpy, vs->wsw->w,
 
417
                                                     Dummy, Dummy, Dummy, Dummy,
 
418
                                                     0, Scr->Black, ws->cp.back);
 
419
 
 
420
                        msw->w = XCreateSimpleWindow(dpy, vs->wsw->w,
 
421
                                                     Dummy, Dummy, Dummy, Dummy,
 
422
                                                     1, border, ws->cp.back);
 
423
 
 
424
                        /* Map whichever is up by default */
 
425
                        if(vs->wsw->state == WMS_buttons) {
 
426
                                XMapWindow(dpy, bsw->w);
 
427
                        }
 
428
                        else {
 
429
                                XMapWindow(dpy, msw->w);
 
430
                        }
 
431
 
 
432
                        /* Setup background on map-state window */
 
433
                        /* XXX X-ref CTAG_BGDRAW in CreateWorkSpaceManager() */
 
434
                        if(useBackgroundInfo) {
 
435
                                if(ws->image == NULL || Scr->NoImagesInWorkSpaceManager) {
 
436
                                        XSetWindowBackground(dpy, msw->w, ws->backcp.back);
 
437
                                }
 
438
                                else {
 
439
                                        XSetWindowBackgroundPixmap(dpy, msw->w, ws->image->pixmap);
 
440
                                }
 
441
                        }
 
442
                        else {
 
443
                                if(Scr->workSpaceMgr.defImage == NULL || Scr->NoImagesInWorkSpaceManager) {
 
444
                                        XSetWindowBackground(dpy, msw->w, Scr->workSpaceMgr.defColors.back);
 
445
                                }
 
446
                                else {
 
447
                                        XSetWindowBackgroundPixmap(dpy, msw->w, Scr->workSpaceMgr.defImage->pixmap);
 
448
                                }
 
449
                        }
 
450
 
 
451
                        /*
 
452
                         * Clear out button subwin; PaintWorkSpaceManager() fills it
 
453
                         * in.  Is this really necessary?
 
454
                         */
 
455
                        XClearWindow(dpy, bsw->w);
 
456
                }
 
457
        }
 
458
 
 
459
 
 
460
        /* Set WM properties */
 
461
        {
 
462
                XSizeHints sizehints;
 
463
                XWMHints   wmhints;
 
464
                const int lines   = Scr->workSpaceMgr.lines;
 
465
                const int columns = Scr->workSpaceMgr.columns;
 
466
                const char *name      = Scr->workSpaceMgr.name;
 
467
                const char *icon_name = Scr->workSpaceMgr.icon_name;
 
468
 
 
469
                sizehints.flags       = USPosition | PBaseSize | PMinSize | PResizeInc
 
470
                                        | PWinGravity;
 
471
                sizehints.x           = x;
 
472
                sizehints.y           = y;
 
473
                sizehints.base_width  = columns * hspace;
 
474
                sizehints.base_height = lines   * vspace;
 
475
                sizehints.width_inc   = columns;
 
476
                sizehints.height_inc  = lines;
 
477
                sizehints.min_width   = columns  * (hspace + 2);
 
478
                sizehints.min_height  = lines    * (vspace + 2);
 
479
                sizehints.win_gravity = gravity;
 
480
 
 
481
                wmhints.flags         = InputHint | StateHint;
 
482
                wmhints.input         = True;
 
483
                wmhints.initial_state = NormalState;
 
484
 
 
485
                XmbSetWMProperties(dpy, vs->wsw->w, name, icon_name, NULL, 0,
 
486
                                   &sizehints, &wmhints, NULL);
 
487
        }
 
488
 
 
489
 
 
490
        /* Create our TwmWindow wrapping around it */
1209
491
        tmp_win = AddWindow(vs->wsw->w, AWT_WORKSPACE_MANAGER,
1210
492
                            Scr->iconmgr, vs);
1211
493
        if(! tmp_win) {
1215
497
        tmp_win->occupation = fullOccupation;
1216
498
        tmp_win->attr.width = width;
1217
499
        tmp_win->attr.height = height;
 
500
        vs->wsw->twm_win = tmp_win;
 
501
 
 
502
 
 
503
        /* Do the figuring to size and internal-layout it */
1218
504
        ResizeWorkSpaceManager(vs, tmp_win);
1219
505
 
1220
 
        attrmask = 0;
1221
 
        attr.cursor = Scr->ButtonCursor;
1222
 
        attrmask |= CWCursor;
1223
 
        attr.win_gravity = gravity;
1224
 
        attrmask |= CWWinGravity;
1225
 
        XChangeWindowAttributes(dpy, vs->wsw->w, attrmask, &attr);
1226
 
 
1227
 
        XGetWindowAttributes(dpy, vs->wsw->w, &wattr);
1228
 
        attrmask = wattr.your_event_mask | KeyPressMask | KeyReleaseMask | ExposureMask;
1229
 
        XSelectInput(dpy, vs->wsw->w, attrmask);
1230
 
 
1231
 
        for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1232
 
                Window buttonw = vs->wsw->bswl [ws->number]->w;
1233
 
                Window mapsubw = vs->wsw->mswl [ws->number]->w;
1234
 
                XSelectInput(dpy, buttonw, ButtonPressMask | ButtonReleaseMask | ExposureMask);
 
506
 
 
507
        /* Setup cursor/gravity and listen for events */
 
508
        {
 
509
                XWindowAttributes wattr;
 
510
                XSetWindowAttributes attr;
 
511
                unsigned long attrmask;
 
512
 
 
513
                attr.cursor = Scr->ButtonCursor;
 
514
                attr.win_gravity = gravity;
 
515
                attrmask = CWCursor | CWWinGravity;
 
516
                XChangeWindowAttributes(dpy, vs->wsw->w, attrmask, &attr);
 
517
 
 
518
                XGetWindowAttributes(dpy, vs->wsw->w, &wattr);
 
519
                attrmask = wattr.your_event_mask | KeyPressMask | KeyReleaseMask
 
520
                           | ExposureMask;
 
521
                XSelectInput(dpy, vs->wsw->w, attrmask);
 
522
        }
 
523
 
 
524
 
 
525
        /*
 
526
         * Mark the buttons as listening to click and exposure events, and
 
527
         * stash away some pointers in contexts.  We stash the overall WSM
 
528
         * window in TwmContext, which means that when an event looks up the
 
529
         * window, it finds the WSM rather than the subwindow, and then falls
 
530
         * into the WMgrHandle*Event()'s, which then dig down into the event
 
531
         * to find where it happened in there.
 
532
         *
 
533
         * The map window doesn't listen to expose events; it's just empty
 
534
         * and background colored.  The individual subwindows in the map
 
535
         * listen for exposes for drawing themselves.
 
536
         *
 
537
         * Dragging windows around to move or re-occupy in the map window
 
538
         * does rely on motion events, but we don't listen for them here.
 
539
         * That happens in WMgrHandleButtonEvent() after getting the initial
 
540
         * click.  It changes the listen and runs through the action
 
541
         * internally; those motions never run through our main event loop.
 
542
         */
 
543
        for(WorkSpace *ws = Scr->workSpaceMgr.workSpaceList; ws != NULL;
 
544
                        ws = ws->next) {
 
545
                Window buttonw = vs->wsw->bswl[ws->number]->w;
 
546
                Window mapsubw = vs->wsw->mswl[ws->number]->w;
 
547
 
 
548
                XSelectInput(dpy, buttonw, ButtonPressMask | ButtonReleaseMask
 
549
                             | ExposureMask);
1235
550
                XSaveContext(dpy, buttonw, TwmContext, (XPointer) tmp_win);
1236
551
                XSaveContext(dpy, buttonw, ScreenContext, (XPointer) Scr);
1237
552
 
1239
554
                XSaveContext(dpy, mapsubw, TwmContext, (XPointer) tmp_win);
1240
555
                XSaveContext(dpy, mapsubw, ScreenContext, (XPointer) Scr);
1241
556
        }
 
557
 
 
558
 
 
559
        /* Set WM_STATE prop */
1242
560
        SetMapStateProp(tmp_win, WithdrawnState);
1243
 
        vs->wsw->twm_win = tmp_win;
1244
 
 
1245
 
        ws = Scr->workSpaceMgr.workSpaceList;
 
561
 
 
562
 
 
563
        /* Setup root window if necessary */
 
564
        /* XXX X-ref CTAG_BGDRAW in CreateWorkSpaceManager() */
1246
565
        if(useBackgroundInfo && ! Scr->DontPaintRootWindow) {
 
566
                WorkSpace *ws = Scr->workSpaceMgr.workSpaceList;
1247
567
                if(ws->image == NULL) {
1248
568
                        XSetWindowBackground(dpy, Scr->Root, ws->backcp.back);
1249
569
                }
1252
572
                }
1253
573
                XClearWindow(dpy, Scr->Root);
1254
574
        }
 
575
 
 
576
 
 
577
        /*
 
578
         * Don't have to PaintWorkSpaceManager(vs) here, because
 
579
         * ResizeWorkSpaceManager() already called it for us.
 
580
         */
 
581
}
 
582
 
 
583
 
 
584
/*
 
585
 * Size and layout a WSM.  Mostly an internal bit in the process of
 
586
 * setting it up.
 
587
 */
 
588
static void
 
589
ResizeWorkSpaceManager(VirtualScreen *vs, TwmWindow *win)
 
590
{
 
591
        WorkSpace *ws;
 
592
        int       i, j;
 
593
        /* Lots of shortcuts to ease reading */
 
594
        const int neww    = win->attr.width;
 
595
        const int newh    = win->attr.height;
 
596
        const int hspace  = Scr->workSpaceMgr.hspace;
 
597
        const int vspace  = Scr->workSpaceMgr.vspace;
 
598
        const int lines   = Scr->workSpaceMgr.lines;
 
599
        const int columns = Scr->workSpaceMgr.columns;
 
600
        const int bwidth  = (neww - (columns * hspace)) / columns;
 
601
        const int bheight = (newh - (lines   * vspace)) / lines;
 
602
        const int wwidth  = neww / columns;
 
603
        const int wheight = newh / lines;
 
604
        const float wf    = (float)(wwidth  - 2) / (float) vs->w;
 
605
        const float hf    = (float)(wheight - 2) / (float) vs->h;
 
606
 
 
607
        /* If nothing's changed since our last run, there's nothing to change */
 
608
        if(neww == vs->wsw->width && newh == vs->wsw->height) {
 
609
                return;
 
610
        }
 
611
 
 
612
        /* Set the new overall vals */
 
613
        vs->wsw->bwidth  = bwidth;
 
614
        vs->wsw->bheight = bheight;
 
615
        vs->wsw->width   = neww;
 
616
        vs->wsw->height  = newh;
 
617
        vs->wsw->wwidth  = wwidth;
 
618
        vs->wsw->wheight = wheight;
 
619
 
 
620
        /* Iterate over the WS's */
 
621
        i = 0;
 
622
        j = 0;
 
623
        for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
 
624
                MapSubwindow    *msw = vs->wsw->mswl[ws->number];
 
625
                ButtonSubwindow *bsw = vs->wsw->bswl[ws->number];
 
626
 
 
627
                /* Move button window to its place in the grid and size appropriately */
 
628
                XMoveResizeWindow(dpy, bsw->w,
 
629
                                  i * (bwidth  + hspace) + (hspace / 2),
 
630
                                  j * (bheight + vspace) + (vspace / 2),
 
631
                                  bwidth, bheight);
 
632
 
 
633
                /* Move the map window as well */
 
634
                msw->x = i * wwidth;
 
635
                msw->y = j * wheight;
 
636
                XMoveResizeWindow(dpy, msw->w, msw->x, msw->y, wwidth - 2, wheight - 2);
 
637
 
 
638
                /*
 
639
                 * Redo interior sizing and placement of all the windows in the
 
640
                 * WS in the map window
 
641
                 */
 
642
                for(WinList *wl = msw->wl; wl != NULL; wl = wl->next) {
 
643
                        TwmWindow *tmp_win = wl->twm_win;
 
644
                        wl->x      = (int)(tmp_win->frame_x * wf);
 
645
                        wl->y      = (int)(tmp_win->frame_y * hf);
 
646
                        wl->width  = (unsigned int)((tmp_win->frame_width  * wf) + 0.5);
 
647
                        wl->height = (unsigned int)((tmp_win->frame_height * hf) + 0.5);
 
648
                        XMoveResizeWindow(dpy, wl->w, wl->x, wl->y, wl->width, wl->height);
 
649
                }
 
650
 
 
651
                /* And around to the next WS */
 
652
                i++;
 
653
                if(i == columns) {
 
654
                        i = 0;
 
655
                        j++;
 
656
                };
 
657
        }
 
658
 
 
659
 
 
660
        /* Draw it */
1255
661
        PaintWorkSpaceManager(vs);
1256
662
}
1257
663
 
1258
 
void WMgrHandleExposeEvent(VirtualScreen *vs, XEvent *event)
 
664
 
 
665
/*
 
666
 * Draw up the button-state pieces of a WSM window.
 
667
 *
 
668
 * Note: this is currently stubbed out and does nothing.  Historically
 
669
 * it's been called during startup when the WSM window is put together,
 
670
 * and when the screen is unmasked.  However, the only apparent result is
 
671
 * that the border and buttons get drawn a little earlier; they already
 
672
 * get expose events that get picked up when we start the event loop.
 
673
 *
 
674
 * If we don't find any reason to reinstate it, we should remove this in
 
675
 * the future.
 
676
 */
 
677
void
 
678
PaintWorkSpaceManager(VirtualScreen *vs)
1259
679
{
1260
680
        WorkSpace *ws;
1261
 
        Window buttonw;
1262
 
 
 
681
 
 
682
        /* x-ref header comment */
 
683
        return;
 
684
 
 
685
        PaintWorkSpaceManagerBorder(vs);
 
686
 
 
687
        for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
 
688
                Window buttonw = vs->wsw->bswl[ws->number]->w;
 
689
                ButtonState bs = (ws == vs->wsw->currentwspc) ? on : off;
 
690
 
 
691
                PaintWsButton(WSPCWINDOW, vs, buttonw, ws->label, ws->cp, bs);
 
692
        }
 
693
}
 
694
 
 
695
 
 
696
/*
 
697
 * Border around the WSM
 
698
 */
 
699
static void
 
700
PaintWorkSpaceManagerBorder(VirtualScreen *vs)
 
701
{
 
702
        int width, height;
 
703
 
 
704
        width  = vs->wsw->width;
 
705
        height = vs->wsw->height;
 
706
        Draw3DBorder(vs->wsw->w, 0, 0, width, height, 2, Scr->workSpaceMgr.cp, off,
 
707
                     true, false);
 
708
}
 
709
 
 
710
 
 
711
/*
 
712
 * Draw a workspace manager window on expose.  X-ref comment on
 
713
 * PaintWorkSpaceManager().
 
714
 */
 
715
void
 
716
WMgrHandleExposeEvent(VirtualScreen *vs, XEvent *event)
 
717
{
1263
718
        if(vs->wsw->state == WMS_buttons) {
 
719
                Window buttonw;
 
720
                WorkSpace *ws;
 
721
 
 
722
                /* Find the button we're exposing */
1264
723
                for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1265
 
                        buttonw = vs->wsw->bswl [ws->number]->w;
 
724
                        buttonw = vs->wsw->bswl[ws->number]->w;
1266
725
                        if(event->xexpose.window == buttonw) {
1267
726
                                break;
1268
727
                        }
1269
728
                }
 
729
 
 
730
                /* If none, just paint the border.  Else paint the button. */
1270
731
                if(ws == NULL) {
1271
732
                        PaintWorkSpaceManagerBorder(vs);
1272
733
                }
1273
 
                else if(ws == vs->wsw->currentwspc) {
1274
 
                        PaintWsButton(WSPCWINDOW, vs, buttonw, ws->label, ws->cp, on);
1275
 
                }
1276
734
                else {
1277
 
                        PaintWsButton(WSPCWINDOW, vs, buttonw, ws->label, ws->cp, off);
 
735
                        ButtonState bs = (ws == vs->wsw->currentwspc) ? on : off;
 
736
                        PaintWsButton(WSPCWINDOW, vs, buttonw, ws->label, ws->cp, bs);
1278
737
                }
1279
738
        }
1280
739
        else {
1281
 
                WinList   wl;
 
740
                WinList *wl;
1282
741
 
 
742
                /*
 
743
                 * This is presumably exposing some individual window in the WS
 
744
                 * subwindow; find it from the stashed context on the window, and
 
745
                 * redraw it.
 
746
                 */
1283
747
                if(XFindContext(dpy, event->xexpose.window, MapWListContext,
1284
748
                                (XPointer *) &wl) == XCNOENT) {
1285
749
                        return;
1290
754
        }
1291
755
}
1292
756
 
1293
 
void PaintWorkSpaceManager(VirtualScreen *vs)
1294
 
{
1295
 
        WorkSpace *ws;
1296
 
 
1297
 
        PaintWorkSpaceManagerBorder(vs);
1298
 
        for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1299
 
                Window buttonw = vs->wsw->bswl [ws->number]->w;
1300
 
                if(ws == vs->wsw->currentwspc) {
1301
 
                        PaintWsButton(WSPCWINDOW, vs, buttonw, ws->label, ws->cp, on);
1302
 
                }
1303
 
                else {
1304
 
                        PaintWsButton(WSPCWINDOW, vs, buttonw, ws->label, ws->cp, off);
1305
 
                }
1306
 
        }
1307
 
}
1308
 
 
1309
 
static void PaintWorkSpaceManagerBorder(VirtualScreen *vs)
1310
 
{
1311
 
        int width, height;
1312
 
 
1313
 
        width  = vs->wsw->width;
1314
 
        height = vs->wsw->height;
1315
 
        Draw3DBorder(vs->wsw->w, 0, 0, width, height, 2, Scr->workSpaceMgr.cp, off,
1316
 
                     true, false);
1317
 
}
1318
 
 
1319
 
 
1320
 
void WMapToggleState(VirtualScreen *vs)
 
757
 
 
758
 
 
759
/*
 
760
 * Moving the WSM between button and map state
 
761
 */
 
762
void
 
763
WMgrToggleState(VirtualScreen *vs)
1321
764
{
1322
765
        if(vs->wsw->state == WMS_buttons) {
1323
 
                WMapSetMapState(vs);
 
766
                WMgrSetMapState(vs);
1324
767
        }
1325
768
        else {
1326
 
                WMapSetButtonsState(vs);
 
769
                WMgrSetButtonsState(vs);
1327
770
        }
1328
771
}
1329
772
 
1330
 
void WMapSetMapState(VirtualScreen *vs)
 
773
void
 
774
WMgrSetMapState(VirtualScreen *vs)
1331
775
{
1332
 
        WorkSpace     *ws;
 
776
        WorkSpace *ws;
1333
777
 
1334
778
        if(vs->wsw->state == WMS_map) {
1335
779
                return;
1342
786
        MaybeAnimate = true;
1343
787
}
1344
788
 
1345
 
void WMapSetButtonsState(VirtualScreen *vs)
 
789
void
 
790
WMgrSetButtonsState(VirtualScreen *vs)
1346
791
{
1347
 
        WorkSpace     *ws;
 
792
        WorkSpace *ws;
1348
793
 
1349
794
        if(vs->wsw->state == WMS_buttons) {
1350
795
                return;
1356
801
        vs->wsw->state = WMS_buttons;
1357
802
}
1358
803
 
1359
 
/*
1360
 
 * Verify if a window may be added to the workspace map.
1361
 
 * This is not allowed for
1362
 
 * - icon managers
1363
 
 * - the occupy window
1364
 
 * - workspace manager windows
1365
 
 * - or, optionally, windows with full occupation.
1366
 
 */
1367
 
int
1368
 
WMapWindowMayBeAdded(TwmWindow *win)
1369
 
{
1370
 
        if(win->isiconmgr) {
1371
 
                return 0;
1372
 
        }
1373
 
        if(win == Scr->workSpaceMgr.occupyWindow->twm_win) {
1374
 
                return 0;
1375
 
        }
1376
 
        if(win->iswspmgr) {
1377
 
                return 0;
1378
 
        }
1379
 
        if(Scr->workSpaceMgr.noshowoccupyall &&
1380
 
                        win->occupation == fullOccupation) {
1381
 
                return 0;
1382
 
        }
1383
 
        return 1;
1384
 
}
1385
 
 
1386
 
void WMapAddWindow(TwmWindow *win)
1387
 
{
1388
 
        WorkSpace     *ws;
1389
 
 
1390
 
        if(!WMapWindowMayBeAdded(win)) {
1391
 
                return;
1392
 
        }
1393
 
 
1394
 
        for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1395
 
                if(OCCUPY(win, ws)) {
1396
 
                        WMapAddToList(win, ws);
1397
 
                }
1398
 
        }
1399
 
}
1400
 
 
1401
 
void WMapDestroyWindow(TwmWindow *win)
1402
 
{
1403
 
        WorkSpace *ws;
1404
 
 
1405
 
        for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1406
 
                if(OCCUPY(win, ws)) {
1407
 
                        WMapRemoveFromList(win, ws);
1408
 
                }
1409
 
        }
1410
 
        /* XXX Better belongs inline in caller or separate func? */
1411
 
        if(win == occupyWin) {
1412
 
                OccupyWindow *occwin = Scr->workSpaceMgr.occupyWindow;
1413
 
                XUnmapWindow(dpy, occwin->twm_win->frame);
1414
 
                occwin->twm_win->mapped = false;
1415
 
                occwin->twm_win->occupation = 0;
1416
 
                occupyWin = NULL;
1417
 
        }
1418
 
}
1419
 
 
1420
 
void WMapMapWindow(TwmWindow *win)
1421
 
{
1422
 
        VirtualScreen *vs;
1423
 
        WorkSpace *ws;
1424
 
        WinList   wl;
1425
 
 
1426
 
        for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
1427
 
                for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1428
 
                        for(wl = vs->wsw->mswl [ws->number]->wl; wl != NULL; wl = wl->next) {
1429
 
                                if(wl->twm_win == win) {
1430
 
                                        XMapWindow(dpy, wl->w);
1431
 
                                        WMapRedrawName(vs, wl);
1432
 
                                        break;
1433
 
                                }
1434
 
                        }
1435
 
                }
1436
 
        }
1437
 
}
1438
 
 
1439
 
void WMapSetupWindow(TwmWindow *win, int x, int y, int w, int h)
1440
 
{
1441
 
        VirtualScreen *vs;
1442
 
        WorkSpace     *ws;
1443
 
        WinList       wl;
1444
 
 
1445
 
        if(win->isiconmgr) {
1446
 
                return;
1447
 
        }
1448
 
        if(!win->vs) {
1449
 
                return;
1450
 
        }
1451
 
 
1452
 
        if(win->iswspmgr) {
1453
 
                if(w == -1) {
1454
 
                        return;
1455
 
                }
1456
 
                ResizeWorkSpaceManager(win->vs, win);
1457
 
                return;
1458
 
        }
1459
 
        if(win == Scr->workSpaceMgr.occupyWindow->twm_win) {
1460
 
                if(w == -1) {
1461
 
                        return;
1462
 
                }
1463
 
                ResizeOccupyWindow(win);
1464
 
                return;
1465
 
        }
1466
 
        for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
1467
 
                WorkSpaceWindow *wsw = vs->wsw;
1468
 
                float wf = (float)(wsw->wwidth  - 2) / (float) vs->w;
1469
 
                float hf = (float)(wsw->wheight - 2) / (float) vs->h;
1470
 
 
1471
 
                for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1472
 
                        for(wl = wsw->mswl [ws->number]->wl; wl != NULL; wl = wl->next) {
1473
 
                                if(win == wl->twm_win) {
1474
 
                                        wl->x = (int)(x * wf);
1475
 
                                        wl->y = (int)(y * hf);
1476
 
                                        if(w == -1) {
1477
 
                                                XMoveWindow(dpy, wl->w, wl->x, wl->y);
1478
 
                                        }
1479
 
                                        else {
1480
 
                                                wl->width  = (unsigned int)((w * wf) + 0.5);
1481
 
                                                wl->height = (unsigned int)((h * hf) + 0.5);
1482
 
                                                if(!Scr->use3Dwmap) {
1483
 
                                                        wl->width  -= 2;
1484
 
                                                        wl->height -= 2;
1485
 
                                                }
1486
 
                                                if(wl->width  < 1) {
1487
 
                                                        wl->width  = 1;
1488
 
                                                }
1489
 
                                                if(wl->height < 1) {
1490
 
                                                        wl->height = 1;
1491
 
                                                }
1492
 
                                                XMoveResizeWindow(dpy, wl->w, wl->x, wl->y, wl->width, wl->height);
1493
 
                                        }
1494
 
                                        break;
1495
 
                                }
1496
 
                        }
1497
 
                }
1498
 
        }
1499
 
}
1500
 
 
1501
 
void WMapIconify(TwmWindow *win)
1502
 
{
1503
 
        VirtualScreen *vs;
1504
 
        WorkSpace *ws;
1505
 
        WinList    wl;
1506
 
 
1507
 
        if(!win->vs) {
1508
 
                return;
1509
 
        }
1510
 
 
1511
 
        for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
1512
 
                for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1513
 
                        for(wl = vs->wsw->mswl [ws->number]->wl; wl != NULL; wl = wl->next) {
1514
 
                                if(win == wl->twm_win) {
1515
 
                                        XUnmapWindow(dpy, wl->w);
1516
 
                                        break;
1517
 
                                }
1518
 
                        }
1519
 
                }
1520
 
        }
1521
 
}
1522
 
 
1523
 
void WMapDeIconify(TwmWindow *win)
1524
 
{
1525
 
        VirtualScreen *vs;
1526
 
        WorkSpace *ws;
1527
 
        WinList    wl;
1528
 
 
1529
 
        if(!win->vs) {
1530
 
                return;
1531
 
        }
1532
 
 
1533
 
        for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
1534
 
                for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1535
 
                        for(wl = vs->wsw->mswl [ws->number]->wl; wl != NULL; wl = wl->next) {
1536
 
                                if(win == wl->twm_win) {
1537
 
                                        if(Scr->NoRaiseDeicon) {
1538
 
                                                XMapWindow(dpy, wl->w);
1539
 
                                        }
1540
 
                                        else {
1541
 
                                                XMapRaised(dpy, wl->w);
1542
 
                                        }
1543
 
                                        WMapRedrawName(win->vs, wl);
1544
 
                                        break;
1545
 
                                }
1546
 
                        }
1547
 
                }
1548
 
        }
1549
 
}
1550
 
 
1551
 
void WMapRaiseLower(TwmWindow *win)
1552
 
{
1553
 
        WorkSpace *ws;
1554
 
 
1555
 
        for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1556
 
                if(OCCUPY(win, ws)) {
1557
 
                        WMapRestack(ws);
1558
 
                }
1559
 
        }
1560
 
}
1561
 
 
1562
 
void WMapLower(TwmWindow *win)
1563
 
{
1564
 
        WorkSpace *ws;
1565
 
 
1566
 
        for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1567
 
                if(OCCUPY(win, ws)) {
1568
 
                        WMapRestack(ws);
1569
 
                }
1570
 
        }
1571
 
}
1572
 
 
1573
 
void WMapRaise(TwmWindow *win)
1574
 
{
1575
 
        WorkSpace *ws;
1576
 
 
1577
 
        for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1578
 
                if(OCCUPY(win, ws)) {
1579
 
                        WMapRestack(ws);
1580
 
                }
1581
 
        }
1582
 
}
1583
 
 
1584
 
void WMapRestack(WorkSpace *ws)
1585
 
{
1586
 
        VirtualScreen *vs;
1587
 
        TwmWindow   *win;
1588
 
        WinList     wl;
1589
 
        Window      root;
1590
 
        Window      parent;
1591
 
        Window      *children, *smallws;
1592
 
        unsigned int number;
1593
 
        int         i, j;
1594
 
 
1595
 
        number = 0;
1596
 
        XQueryTree(dpy, Scr->Root, &root, &parent, &children, &number);
1597
 
        smallws = calloc(number, sizeof(Window));
1598
 
 
1599
 
        for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
1600
 
                j = 0;
1601
 
                for(i = number - 1; i >= 0; i--) {
1602
 
                        if(!(win = GetTwmWindow(children [i]))) {
1603
 
                                continue;
1604
 
                        }
1605
 
                        if(win->frame != children [i]) {
1606
 
                                continue;        /* skip icons */
1607
 
                        }
1608
 
                        if(! OCCUPY(win, ws)) {
1609
 
                                continue;
1610
 
                        }
1611
 
                        if(tracefile) {
1612
 
                                fprintf(tracefile, "WMapRestack : w = %lx, win = %p\n", children [i],
1613
 
                                        (void *)win);
1614
 
                                fflush(tracefile);
1615
 
                        }
1616
 
                        for(wl = vs->wsw->mswl [ws->number]->wl; wl != NULL; wl = wl->next) {
1617
 
                                if(tracefile) {
1618
 
                                        fprintf(tracefile, "WMapRestack : wl = %p, twm_win = %p\n", (void *)wl,
1619
 
                                                (void *)wl->twm_win);
1620
 
                                        fflush(tracefile);
1621
 
                                }
1622
 
                                if(win == wl->twm_win) {
1623
 
                                        smallws [j++] = wl->w;
1624
 
                                        break;
1625
 
                                }
1626
 
                        }
1627
 
                }
1628
 
                XRestackWindows(dpy, smallws, j);
1629
 
        }
1630
 
        XFree(children);
1631
 
        free(smallws);
1632
 
        return;
1633
 
}
1634
 
 
1635
 
void WMapUpdateIconName(TwmWindow *win)
1636
 
{
1637
 
        VirtualScreen *vs;
1638
 
        WorkSpace *ws;
1639
 
        WinList   wl;
1640
 
 
1641
 
        for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
1642
 
                for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1643
 
                        for(wl = vs->wsw->mswl [ws->number]->wl; wl != NULL; wl = wl->next) {
1644
 
                                if(win == wl->twm_win) {
1645
 
                                        WMapRedrawName(vs, wl);
1646
 
                                        break;
1647
 
                                }
1648
 
                        }
1649
 
                }
1650
 
        }
1651
 
}
1652
 
 
1653
 
void WMgrHandleKeyReleaseEvent(VirtualScreen *vs, XEvent *event)
1654
 
{
1655
 
        KeySym      keysym;
1656
 
 
1657
 
        keysym  = XLookupKeysym((XKeyEvent *) event, 0);
1658
 
        if(! keysym) {
1659
 
                return;
1660
 
        }
1661
 
        if(keysym == XK_Control_L || keysym == XK_Control_R) {
1662
 
                /* DontToggleWorkSpaceManagerState added 20040607 by dl*/
1663
 
                if(!Scr->DontToggleWorkspaceManagerState) {
1664
 
                        WMapToggleState(vs);
1665
 
                }
1666
 
                return;
1667
 
        }
1668
 
}
1669
 
 
1670
 
void WMgrHandleKeyPressEvent(VirtualScreen *vs, XEvent *event)
1671
 
{
1672
 
        WorkSpace *ws;
1673
 
        int       len, i, lname;
1674
 
        char      key [16];
1675
 
        unsigned char k;
1676
 
        char      name [128];
1677
 
        KeySym    keysym;
1678
 
 
1679
 
        keysym  = XLookupKeysym((XKeyEvent *) event, 0);
1680
 
        if(! keysym) {
1681
 
                return;
1682
 
        }
1683
 
        if(keysym == XK_Control_L || keysym == XK_Control_R) {
1684
 
                /* DontToggleWorkSpaceManagerState added 20040607 by dl*/
1685
 
                if(!Scr->DontToggleWorkspaceManagerState) {
1686
 
                        WMapToggleState(vs);
1687
 
                }
1688
 
                return;
1689
 
        }
 
804
 
 
805
 
 
806
 
 
807
/*
 
808
 ****************************************************************
 
809
 *
 
810
 * Handlers for mouse/key actions in the WSM
 
811
 *
 
812
 ****************************************************************
 
813
 */
 
814
 
 
815
/*
 
816
 * Key press/release events in the WSM.  A major use (and only for
 
817
 * release) is the Ctrl-key switching between map and button state.  The
 
818
 * other use is on-the-fly renaming of workspaces by typing in the
 
819
 * button-state WSM.
 
820
 */
 
821
void
 
822
WMgrHandleKeyReleaseEvent(VirtualScreen *vs, XEvent *event)
 
823
{
 
824
        KeySym keysym;
 
825
 
 
826
        keysym = XLookupKeysym((XKeyEvent *) event, 0);
 
827
        if(! keysym) {
 
828
                return;
 
829
        }
 
830
        if(keysym == XK_Control_L || keysym == XK_Control_R) {
 
831
                /* DontToggleWorkSpaceManagerState added 20040607 by dl*/
 
832
                if(!Scr->DontToggleWorkspaceManagerState) {
 
833
                        WMgrToggleState(vs);
 
834
                }
 
835
                return;
 
836
        }
 
837
}
 
838
 
 
839
void
 
840
WMgrHandleKeyPressEvent(VirtualScreen *vs, XEvent *event)
 
841
{
 
842
        WorkSpace *ws;
 
843
 
 
844
        /* Check if we're using Control to toggle the state */
 
845
        {
 
846
                KeySym keysym = XLookupKeysym((XKeyEvent *) event, 0);
 
847
                if(! keysym) {
 
848
                        return;
 
849
                }
 
850
                if(keysym == XK_Control_L || keysym == XK_Control_R) {
 
851
                        /* DontToggleWorkSpaceManagerState added 20040607 by dl*/
 
852
                        if(!Scr->DontToggleWorkspaceManagerState) {
 
853
                                WMgrToggleState(vs);
 
854
                        }
 
855
                        return;
 
856
                }
 
857
        }
 
858
 
 
859
        /* Otherwise, key presses do nothing in map state */
1690
860
        if(vs->wsw->state == WMS_map) {
1691
861
                return;
1692
862
        }
1693
863
 
 
864
        /*
 
865
         * If we're typing in a button-state WSM, and the mouse is on one of
 
866
         * the buttons, that means we're changing the name, so do that dance.
 
867
         */
1694
868
        for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1695
 
                if(vs->wsw->bswl [ws->number]->w == event->xkey.subwindow) {
 
869
                if(vs->wsw->bswl[ws->number]->w == event->xkey.subwindow) {
1696
870
                        break;
1697
871
                }
1698
872
        }
1699
873
        if(ws == NULL) {
 
874
                /* Not on a button, nothing to do */
1700
875
                return;
1701
876
        }
1702
877
 
1703
 
        strcpy(name, ws->label);
1704
 
        lname = strlen(name);
1705
 
        len   = XLookupString(&(event->xkey), key, 16, NULL, NULL);
1706
 
        for(i = 0; i < len; i++) {
1707
 
                k = key [i];
1708
 
                if(isprint(k)) {
1709
 
                        name [lname++] = k;
1710
 
                }
1711
 
                else if((k == 127) || (k == 8)) {
1712
 
                        if(lname != 0) {
1713
 
                                lname--;
1714
 
                        }
1715
 
                }
1716
 
                else {
1717
 
                        break;
1718
 
                }
1719
 
        }
1720
 
        name [lname] = '\0';
1721
 
        ws->label = realloc(ws->label, (strlen(name) + 1));
1722
 
        strcpy(ws->label, name);
1723
 
        if(ws == vs->wsw->currentwspc) {
1724
 
                PaintWsButton(WSPCWINDOW, vs, vs->wsw->bswl [ws->number]->w, ws->label, ws->cp,
1725
 
                              on);
1726
 
        }
1727
 
        else {
1728
 
                PaintWsButton(WSPCWINDOW, vs, vs->wsw->bswl [ws->number]->w, ws->label, ws->cp,
1729
 
                              off);
 
878
 
 
879
        /*
 
880
         * Edit the label.
 
881
         */
 
882
        {
 
883
                int    nkeys;
 
884
                char   keys[16];
 
885
                size_t nlen;
 
886
                char   *newname;
 
887
 
 
888
                /* Look up what keystrokes are queued.  Arbitrary buf size */
 
889
                nkeys = XLookupString(&(event->xkey), keys, 16, NULL, NULL);
 
890
 
 
891
                /* Label length can't grow to more than cur+nkeys */
 
892
                nlen = strlen(ws->label);
 
893
                newname = malloc(nlen + nkeys + 1);
 
894
                strcpy(newname, ws->label);
 
895
 
 
896
                /* Iterate over the passed keystrokes */
 
897
                for(int i = 0 ; i < nkeys ; i++) {
 
898
                        unsigned char k = keys[i];
 
899
 
 
900
                        if(isprint(k)) {
 
901
                                /* Printable chars append to the string */
 
902
                                newname[nlen++] = k;
 
903
                        }
 
904
                        else if((k == 127) || (k == 8)) {
 
905
                                /*
 
906
                                 * DEL or BS back up a char.
 
907
                                 *
 
908
                                 * XXX Would it be more generally correct to do this via
 
909
                                 * keysyms, in the face of changed keyboard mappings or
 
910
                                 * significantly differing locales?
 
911
                                 */
 
912
                                if(nlen != 0) {
 
913
                                        nlen--;
 
914
                                }
 
915
                        }
 
916
                        else {
 
917
                                /* Any other char stops the process dead */
 
918
                                break;
 
919
                        }
 
920
                }
 
921
                /* Now ends where it ends */
 
922
                newname[nlen] = '\0';
 
923
 
 
924
                /* Swap it in */
 
925
                free(ws->label);
 
926
                ws->label = newname;
 
927
        }
 
928
 
 
929
 
 
930
        /* Redraw the button with the new label */
 
931
        {
 
932
                ButtonState bs = (ws == vs->wsw->currentwspc) ? on : off;
 
933
 
 
934
                PaintWsButton(WSPCWINDOW, vs, vs->wsw->bswl[ws->number]->w, ws->label,
 
935
                              ws->cp, bs);
1730
936
        }
1731
937
}
1732
938
 
1733
 
void WMgrHandleButtonEvent(VirtualScreen *vs, XEvent *event)
 
939
 
 
940
/*
 
941
 * Mouse clicking in WSM.  Gets called on button press (not release).  In
 
942
 * the simple case, that's just switching workspaces.  In the more
 
943
 * complex, it's changing window occupation in various different ways, or
 
944
 * even moving windows.  When that's happening, it internally hijacks
 
945
 * button/motion/exposure events and implements them for the moving, with
 
946
 * magic escapes if it gets them for something else.  Ew.
 
947
 */
 
948
void
 
949
WMgrHandleButtonEvent(VirtualScreen *vs, XEvent *event)
1734
950
{
1735
 
        WorkSpaceWindow     *mw;
1736
 
        WorkSpace           *ws, *oldws, *newws, *cws;
1737
 
        WinList             wl;
1738
 
        TwmWindow           *win;
1739
 
        int                 occupation;
1740
 
        unsigned int        W0, H0, bw;
1741
 
        bool                cont;
1742
 
        XEvent              ev;
1743
 
        Window              w = 0, sw, parent;
1744
 
        int                 X0, Y0, X1, Y1, XW, YW, XSW, YSW;
1745
 
        Position            newX = 0, newY = 0, winX = 0, winY = 0;
1746
 
        Window              junkW;
1747
 
        unsigned int        junk;
1748
 
        unsigned int        button;
1749
 
        unsigned int        modifier;
1750
 
        XSetWindowAttributes attrs;
1751
 
        float               wf, hf;
1752
 
        bool                alreadyvivible, realmovemode, startincurrent;
1753
 
        Time                etime;
1754
 
 
1755
 
        parent   = event->xbutton.window;
1756
 
        sw       = event->xbutton.subwindow;        /* mini-window in ws manager */
1757
 
        mw       = vs->wsw;
1758
 
        button   = event->xbutton.button;
1759
 
        modifier = event->xbutton.state;
1760
 
        etime    = event->xbutton.time;
1761
 
 
 
951
        WorkSpace    *oldws, *newws;
 
952
        WinList      *wl;
 
953
        TwmWindow    *win;
 
954
        unsigned int W0, H0;
 
955
        XEvent       lastev;
 
956
        Window       w = 0;
 
957
        Position     newX = 0, newY = 0, winX = 0, winY = 0;
 
958
        bool         alreadyvivible, realmovemode;
 
959
        const WorkSpaceWindow *mw = vs->wsw;
 
960
 
 
961
        /* Shortcuts into the event */
 
962
        const Window parent = event->xbutton.window;    // Map/button for WS
 
963
        const Window sw     = event->xbutton.subwindow; // Map mini-win
 
964
        const Time etime    = event->xbutton.time;
 
965
        const unsigned int button   = event->xbutton.button;
 
966
        const unsigned int modifier = event->xbutton.state;
 
967
 
 
968
 
 
969
        /* If we're in button state, we're just clicking to change */
1762
970
        if(vs->wsw->state == WMS_buttons) {
 
971
                WorkSpace *ws;
1763
972
                for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1764
 
                        if(vs->wsw->bswl [ws->number]->w == parent) {
 
973
                        if(vs->wsw->bswl[ws->number]->w == parent) {
 
974
                                GotoWorkSpace(vs, ws);
1765
975
                                break;
1766
976
                        }
1767
977
                }
1768
 
                if(ws == NULL) {
1769
 
                        return;
1770
 
                }
1771
 
                GotoWorkSpace(vs, ws);
1772
978
                return;
1773
979
        }
1774
980
 
1775
 
        for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1776
 
                if(vs->wsw->mswl [ws->number]->w == parent) {
 
981
        /*
 
982
         * If we get this far, we're in map state, where things are more
 
983
         * complicated.  A simple click/release means change here too, but
 
984
         * there's also the possibility of dragging a subwindow around to
 
985
         * change its window's occupation.
 
986
         */
 
987
 
 
988
        /* Find what workspace we're clicking in */
 
989
        for(oldws = Scr->workSpaceMgr.workSpaceList ; oldws != NULL ;
 
990
                        oldws = oldws->next) {
 
991
                if(vs->wsw->mswl[oldws->number]->w == parent) {
1777
992
                        break;
1778
993
                }
1779
994
        }
1780
 
        if(ws == NULL) {
 
995
        if(oldws == NULL) {
 
996
                /* None?  We're done here. */
1781
997
                return;
1782
998
        }
 
999
 
 
1000
        /*
 
1001
         * If clicked in the workspace but outside a window, we can only be
 
1002
         * switching workspaces.  So just do that, and we're done.
 
1003
         */
1783
1004
        if(sw == (Window) 0) {
1784
 
                /*
1785
 
                 * If clicked in the workspace but outside a window,
1786
 
                 * only switch workspaces.
1787
 
                 */
1788
 
                GotoWorkSpace(vs, ws);
 
1005
                GotoWorkSpace(vs, oldws);
1789
1006
                return;
1790
1007
        }
1791
 
        oldws = ws;
1792
1008
 
 
1009
        /* Use the context to find the winlist entry for this window */
1793
1010
        if(XFindContext(dpy, sw, MapWListContext, (XPointer *) &wl) == XCNOENT) {
1794
1011
                return;
1795
1012
        }
1796
1013
        win = wl->twm_win;
 
1014
 
 
1015
        /*
 
1016
         * Sometimes we skip transients, so do so.  XXX Should this
 
1017
         * GotoWorkSpace()?
 
1018
         */
1797
1019
        if((! Scr->TransientHasOccupation) && win->istransient) {
1798
1020
                return;
1799
1021
        }
1800
1022
 
1801
 
        XTranslateCoordinates(dpy, Scr->Root, sw, event->xbutton.x_root,
1802
 
                              event->xbutton.y_root,
1803
 
                              &XW, &YW, &junkW);
1804
 
        realmovemode = (Scr->ReallyMoveInWorkspaceManager && !(modifier & ShiftMask)) ||
1805
 
                       (!Scr->ReallyMoveInWorkspaceManager && (modifier & ShiftMask));
1806
 
        startincurrent = (oldws == vs->wsw->currentwspc);
 
1023
        /*
 
1024
         * Are we trying to actually move the window, by moving its avatar in
 
1025
         * the WSM?  If ReallyMoveInWorkspaceManager is set, we're moving on
 
1026
         * click, but not in shift-click.  If it's not, it's the reverse.
 
1027
         *
 
1028
         * XXX This interacts really oddly and badly when you're also moving
 
1029
         * the window from WS to WS.
 
1030
         */
 
1031
        realmovemode = false;
 
1032
        if(Scr->ReallyMoveInWorkspaceManager) {
 
1033
                if(!(modifier & ShiftMask)) {
 
1034
                        realmovemode = true;
 
1035
                }
 
1036
        }
 
1037
        else if(modifier & ShiftMask) {
 
1038
                realmovemode = true;
 
1039
        }
 
1040
 
 
1041
        /*
 
1042
         * Frob screen-wide OpaqueMove as necessary for this window's
 
1043
         * details.
 
1044
         * XXX Really?
 
1045
         */
1807
1046
        if(win->OpaqueMove) {
1808
 
                int sw2, ss;
1809
 
 
1810
 
                sw2 = win->frame_width * win->frame_height;
1811
 
                ss = vs->w * vs->h;
1812
 
                if(sw2 > ((ss * Scr->OpaqueMoveThreshold) / 100)) {
1813
 
                        Scr->OpaqueMove = false;
1814
 
                }
1815
 
                else {
 
1047
                if(Scr->OpaqueMoveThreshold >= 200) {
1816
1048
                        Scr->OpaqueMove = true;
1817
1049
                }
 
1050
                else {
 
1051
                        const unsigned long winsz = win->frame_width * win->frame_height;
 
1052
                        const unsigned long scrsz = vs->w * vs->h;
 
1053
                        const float sf = Scr->OpaqueMoveThreshold / 100.0;
 
1054
                        if(winsz > (scrsz * sf)) {
 
1055
                                Scr->OpaqueMove = false;
 
1056
                        }
 
1057
                        else {
 
1058
                                Scr->OpaqueMove = true;
 
1059
                        }
 
1060
                }
1818
1061
        }
1819
1062
        else {
1820
1063
                Scr->OpaqueMove = false;
1821
1064
        }
 
1065
 
1822
1066
        /*
1823
1067
         * Buttons inside the workspace manager, when clicking on the
1824
1068
         * representation of a window:
1826
1070
         * 2: drag a copy of the window to a different workspace
1827
1071
         *    (show it in both workspaces)
1828
1072
         * 3: remove the window from this workspace (if it isn't the last).
 
1073
         *
 
1074
         * XXX If you move between workspaces while also doing realmovemode,
 
1075
         * really messed up things happen.
1829
1076
         */
1830
1077
        switch(button) {
1831
 
                case 1 :
 
1078
                case 1 : {
 
1079
                        /*
 
1080
                         * Moving from one to another; get rid of the old location,
 
1081
                         * then fall through to the "duplicating" case below.
 
1082
                         */
1832
1083
                        XUnmapWindow(dpy, sw);
1833
 
 
1834
 
                case 2 :
1835
 
                        XGetGeometry(dpy, sw, &junkW, &X0, &Y0, &W0, &H0, &bw, &junk);
1836
 
                        XTranslateCoordinates(dpy, vs->wsw->mswl [oldws->number]->w,
 
1084
                        /* FALLTHRU */
 
1085
                }
 
1086
 
 
1087
                case 2 : {
 
1088
                        /*
 
1089
                         * Duplicating window to another WS.  We create a copy of the
 
1090
                         * window, and start moving that.  The 'moving' case above
 
1091
                         * falls through to us after unmapping that old window,
 
1092
                         * leaving just our copy, which is good enough.  This is
 
1093
                         * really just setting up the visual stuff for the move; the
 
1094
                         * actual occupation changes etc. come at the end of the
 
1095
                         * motion, much lower down.
 
1096
                         */
 
1097
                        int X0, Y0, X1, Y1;
 
1098
                        unsigned int bw;
 
1099
                        XSetWindowAttributes attrs;
 
1100
                        Window junkW;
 
1101
 
 
1102
                        /* [XYWH]0 = size/location of the avatar in the map */
 
1103
                        XGetGeometry(dpy, sw, &junkW, &X0, &Y0, &W0, &H0, &bw, &JunkDepth);
 
1104
 
 
1105
                        /*
 
1106
                         * [XY]0 are the coordinates of the avatar subwindow inside
 
1107
                         * the individual workspace window in the map.  Turn those
 
1108
                         * into [XY]1 as the coordinates of it relative to the whole
 
1109
                         * WSM window.
 
1110
                         */
 
1111
                        XTranslateCoordinates(dpy, vs->wsw->mswl[oldws->number]->w,
1837
1112
                                              mw->w, X0, Y0, &X1, &Y1, &junkW);
1838
1113
 
 
1114
                        /*
 
1115
                         * Create the copy window to drag around, as a child of the
 
1116
                         * whole WSM (so we can move it between workspaces), and map
 
1117
                         * it.
 
1118
                         */
1839
1119
                        attrs.event_mask       = ExposureMask;
1840
1120
                        attrs.background_pixel = wl->cp.back;
1841
1121
                        attrs.border_pixel     = wl->cp.back;
1842
 
                        /* Create a draggable mini-window */
1843
1122
                        w = XCreateWindow(dpy, mw->w, X1, Y1, W0, H0, bw,
1844
 
                                          CopyFromParent,
1845
 
                                          CopyFromParent,
1846
 
                                          CopyFromParent,
1847
 
                                          CWEventMask | CWBackPixel | CWBorderPixel, &attrs);
1848
 
 
 
1123
                                          CopyFromParent, CopyFromParent, CopyFromParent,
 
1124
                                          CWEventMask | CWBackPixel | CWBorderPixel,
 
1125
                                          &attrs);
1849
1126
                        XMapRaised(dpy, w);
 
1127
 
 
1128
                        /* Do our dance on it to draw the name/color/etc */
1850
1129
                        WMapRedrawWindow(w, W0, H0, wl->cp, wl->twm_win->icon_name);
 
1130
 
 
1131
                        /*
 
1132
                         * If we're moving the real window and
 
1133
                         * AlwaysShowWindowWhenMovingFromWorkspaceManager is set in
 
1134
                         * config, we need to be sure the real window is visible
 
1135
                         * while we move it.
 
1136
                         */
1851
1137
                        if(realmovemode && Scr->ShowWinWhenMovingInWmgr) {
1852
1138
                                if(Scr->OpaqueMove) {
1853
1139
                                        DisplayWin(vs, win);
1862
1148
                                                    win->title_height + win->frame_bw3D);
1863
1149
                                }
1864
1150
                        }
 
1151
 
 
1152
                        /* Move onward */
1865
1153
                        break;
 
1154
                }
1866
1155
 
1867
 
                case 3 :
1868
 
                        occupation = win->occupation & ~(1 << oldws->number);
1869
 
                        if(occupation != 0) {
1870
 
                                ChangeOccupation(win, occupation);
 
1156
                /*
 
1157
                 * For the button 3 or anything else case, there's no dragging or
 
1158
                 * anything, so they do their thing and just immediately return.
 
1159
                 */
 
1160
                case 3 : {
 
1161
                        int newocc = win->occupation & ~(1 << oldws->number);
 
1162
                        if(newocc != 0) {
 
1163
                                ChangeOccupation(win, newocc);
1871
1164
                        }
1872
1165
                        return;
 
1166
                }
 
1167
 
1873
1168
                default :
1874
1169
                        return;
1875
1170
        }
1876
1171
 
1877
1172
        /*
1878
1173
         * Keep dragging the representation of the window
 
1174
         *
 
1175
         * XXX Look back at this and see if we can move it to an inner
 
1176
         * function for readability...
1879
1177
         */
1880
 
        wf = (float)(mw->wwidth  - 1) / (float) vs->w;
1881
 
        hf = (float)(mw->wheight - 1) / (float) vs->h;
1882
 
        XGrabPointer(dpy, mw->w, False,
1883
 
                     ButtonPressMask | ButtonMotionMask | ButtonReleaseMask,
1884
 
                     GrabModeAsync, GrabModeAsync, mw->w, Scr->MoveCursor, CurrentTime);
1885
 
 
1886
 
        alreadyvivible = false;
1887
 
        cont = true;
1888
 
        while(cont) {
1889
 
                MapSubwindow *msw;
1890
 
                XMaskEvent(dpy, ButtonPressMask | ButtonMotionMask |
1891
 
                           ButtonReleaseMask | ExposureMask, &ev);
1892
 
                switch(ev.xany.type) {
1893
 
                        case ButtonPress :
1894
 
                        case ButtonRelease :
1895
 
                                if(ev.xbutton.button != button) {
 
1178
        {
 
1179
                const float wf = (float)(mw->wwidth  - 1) / (float) vs->w;
 
1180
                const float hf = (float)(mw->wheight - 1) / (float) vs->h;
 
1181
                int XW, YW;
 
1182
                bool cont;
 
1183
                Window junkW;
 
1184
 
 
1185
                /* Figure where in the subwindow the click was, and stash in XW/YW */
 
1186
                XTranslateCoordinates(dpy, Scr->Root, sw, event->xbutton.x_root,
 
1187
                                      event->xbutton.y_root,
 
1188
                                      &XW, &YW, &junkW);
 
1189
 
 
1190
                /*
 
1191
                 * Grab the pointer, lock it into the WSM, and get the events
 
1192
                 * related to buttons and movement.  We don't need
 
1193
                 * PointerMotionMask, since that would only happen after buttons
 
1194
                 * are released, and we'll be done by then.
 
1195
                 */
 
1196
                XGrabPointer(dpy, mw->w, False,
 
1197
                             ButtonPressMask | ButtonMotionMask | ButtonReleaseMask,
 
1198
                             GrabModeAsync, GrabModeAsync, mw->w, Scr->MoveCursor,
 
1199
                             CurrentTime);
 
1200
 
 
1201
                /* Start handling events until we're done */
 
1202
                alreadyvivible = false;
 
1203
                cont = true;
 
1204
                while(cont) {
 
1205
                        XEvent ev;
 
1206
 
 
1207
                        /* Grab the next event and handle */
 
1208
                        XMaskEvent(dpy, ButtonPressMask | ButtonMotionMask |
 
1209
                                   ButtonReleaseMask | ExposureMask, &ev);
 
1210
                        switch(ev.xany.type) {
 
1211
                                case Expose : {
 
1212
                                        /* Something got exposed */
 
1213
                                        if(ev.xexpose.window == w) {
 
1214
                                                /*
 
1215
                                                 * The win we're working with?  We know how to do
 
1216
                                                 * that.
 
1217
                                                 */
 
1218
                                                WMapRedrawWindow(w, W0, H0, wl->cp,
 
1219
                                                                 wl->twm_win->icon_name);
 
1220
                                                break;
 
1221
                                        }
 
1222
 
 
1223
                                        /* Else, delegate to our global dispatcher */
 
1224
                                        Event = ev;
 
1225
                                        DispatchEvent();
1896
1226
                                        break;
1897
1227
                                }
1898
 
                                cont = false;
1899
 
                                newX = ev.xbutton.x;
1900
 
                                newY = ev.xbutton.y;
1901
 
 
1902
 
                        case MotionNotify :
1903
 
                                if(cont) {
1904
 
                                        newX = ev.xmotion.x;
1905
 
                                        newY = ev.xmotion.y;
 
1228
 
 
1229
                                case ButtonPress :
 
1230
                                case ButtonRelease : {
 
1231
                                        /*
 
1232
                                         * Events for buttons other than the one whose press
 
1233
                                         * started this activity are totally ignored.
 
1234
                                         */
 
1235
                                        if(ev.xbutton.button != button) {
 
1236
                                                break;
 
1237
                                        }
 
1238
 
 
1239
                                        /*
 
1240
                                         * Otherwise, this is a press/release of the button
 
1241
                                         * that started things.  Though I'm not sure how it
 
1242
                                         * could be a press, since it was already pressed.
 
1243
                                         * Regardless, this is our exit condition.  Fall
 
1244
                                         * through into the Motion case to handle any
 
1245
                                         * remaining movement.
 
1246
                                         */
 
1247
                                        lastev = ev;
 
1248
                                        cont = false;
 
1249
                                        newX = ev.xbutton.x;
 
1250
                                        newY = ev.xbutton.y;
1906
1251
                                }
1907
 
                                if(realmovemode) {
1908
 
                                        for(cws = Scr->workSpaceMgr.workSpaceList;
1909
 
                                                        cws != NULL;
1910
 
                                                        cws = cws->next) {
1911
 
                                                msw = vs->wsw->mswl [cws->number];
1912
 
                                                if((newX >= msw->x) && (newX <  msw->x + mw->wwidth) &&
1913
 
                                                                (newY >= msw->y) && (newY <  msw->y + mw->wheight)) {
 
1252
 
 
1253
                                /* Everything remaining is motion handling */
 
1254
                                case MotionNotify : {
 
1255
                                        /* If we fell through from above, no new movement */
 
1256
                                        if(cont) {
 
1257
                                                newX = ev.xmotion.x;
 
1258
                                                newY = ev.xmotion.y;
 
1259
                                        }
 
1260
 
 
1261
                                        /* Lots to do if we're moving the window for real */
 
1262
                                        if(realmovemode) {
 
1263
                                                int XSW, YSW;
 
1264
                                                WorkSpace *cws;
 
1265
                                                MapSubwindow *msw;
 
1266
 
 
1267
                                                /* Did the move start in the currently visible WS? */
 
1268
                                                bool startincurrent = (oldws == vs->wsw->currentwspc);
 
1269
 
 
1270
                                                /* Find the workspace we wound up in */
 
1271
                                                for(cws = Scr->workSpaceMgr.workSpaceList ;
 
1272
                                                                cws != NULL ;
 
1273
                                                                cws = cws->next) {
 
1274
                                                        msw = vs->wsw->mswl [cws->number];
 
1275
                                                        if((newX >= msw->x)
 
1276
                                                                        && (newX <  msw->x + mw->wwidth)
 
1277
                                                                        && (newY >= msw->y)
 
1278
                                                                        && (newY <  msw->y + mw->wheight)) {
 
1279
                                                                break;
 
1280
                                                        }
 
1281
                                                }
 
1282
                                                if(!cws) {
 
1283
                                                        /* None?  Ignore. */
1914
1284
                                                        break;
1915
1285
                                                }
1916
 
                                        }
1917
 
                                        if(!cws) {
1918
 
                                                break;
1919
 
                                        }
1920
 
                                        winX = newX - XW;
1921
 
                                        winY = newY - YW;
1922
 
                                        msw = vs->wsw->mswl [cws->number];
1923
 
                                        XTranslateCoordinates(dpy, mw->w, msw->w,
1924
 
                                                              winX, winY, &XSW, &YSW, &junkW);
1925
 
                                        winX = (int)(XSW / wf);
1926
 
                                        winY = (int)(YSW / hf);
1927
 
                                        if(Scr->DontMoveOff) {
1928
 
                                                int width = win->frame_width;
1929
 
                                                int height = win->frame_height;
1930
 
 
1931
 
                                                if((winX < Scr->BorderLeft) && ((Scr->MoveOffResistance < 0) ||
1932
 
                                                                                (winX > Scr->BorderLeft - Scr->MoveOffResistance))) {
1933
 
                                                        winX = Scr->BorderLeft;
1934
 
                                                        newX = msw->x + XW + Scr->BorderLeft * mw->wwidth / vs->w;
1935
 
                                                }
1936
 
                                                if(((winX + width) > vs->w - Scr->BorderRight) &&
1937
 
                                                                ((Scr->MoveOffResistance < 0) ||
1938
 
                                                                 ((winX + width) < vs->w - Scr->BorderRight + Scr->MoveOffResistance))) {
1939
 
                                                        winX = vs->w - Scr->BorderRight - width;
1940
 
                                                        newX = msw->x + mw->wwidth *
1941
 
                                                               (1 - Scr->BorderRight / (double) vs->w) - wl->width + XW - 2;
1942
 
                                                }
1943
 
                                                if((winY < Scr->BorderTop) && ((Scr->MoveOffResistance < 0) ||
1944
 
                                                                               (winY > Scr->BorderTop - Scr->MoveOffResistance))) {
1945
 
                                                        winY = Scr->BorderTop;
1946
 
                                                        newY = msw->y + YW + Scr->BorderTop * mw->height / vs->h;
1947
 
                                                }
1948
 
                                                if(((winY + height) > vs->h - Scr->BorderBottom) &&
1949
 
                                                                ((Scr->MoveOffResistance < 0) ||
1950
 
                                                                 ((winY + height) < vs->h - Scr->BorderBottom + Scr->MoveOffResistance))) {
1951
 
                                                        winY = vs->h - Scr->BorderBottom - height;
1952
 
                                                        newY = msw->y + mw->wheight *
1953
 
                                                               (1 - Scr->BorderBottom / (double) vs->h) - wl->height + YW - 2;
1954
 
                                                }
1955
 
                                        }
1956
 
                                        WMapSetupWindow(win, winX, winY, -1, -1);
1957
 
                                        if(Scr->ShowWinWhenMovingInWmgr) {
1958
 
                                                goto movewin;
1959
 
                                        }
1960
 
                                        if(cws == vs->wsw->currentwspc) {
1961
 
                                                if(alreadyvivible) {
 
1286
 
 
1287
                                                /*
 
1288
                                                 * Mouse is wherever it started inside the
 
1289
                                                 * subwindow, so figure the X/Y of the top left
 
1290
                                                 * of the subwindow from there.  (coords relative
 
1291
                                                 * to the whole WSM because of grab)
 
1292
                                                 */
 
1293
                                                winX = newX - XW;
 
1294
                                                winY = newY - YW;
 
1295
 
 
1296
                                                /* XXX redundant w/previous? */
 
1297
                                                msw = vs->wsw->mswl[cws->number];
 
1298
 
 
1299
                                                /*
 
1300
                                                 * Figure where those coords are relative to the
 
1301
                                                 * per-workspace window.
 
1302
                                                 */
 
1303
                                                XTranslateCoordinates(dpy, mw->w, msw->w,
 
1304
                                                                      winX, winY, &XSW, &YSW, &junkW);
 
1305
 
 
1306
                                                /*
 
1307
                                                 * Now rework the win[XY] to be the coordinates
 
1308
                                                 * the window would be in the whole screen, based
 
1309
                                                 * on the [XY]SW inside the map, using our scale
 
1310
                                                 * factors.
 
1311
                                                 */
 
1312
                                                winX = (int)(XSW / wf);
 
1313
                                                winY = (int)(YSW / hf);
 
1314
 
 
1315
                                                /*
 
1316
                                                 * Clip to the screen if DontMoveOff is set.
 
1317
                                                 *
 
1318
                                                 * XXX Can we use the Constrain*() functions for
 
1319
                                                 * this, instead of implementing icky magic
 
1320
                                                 * internally?
 
1321
                                                 */
 
1322
                                                if(Scr->DontMoveOff) {
 
1323
                                                        const int width = win->frame_width;
 
1324
                                                        const int height = win->frame_height;
 
1325
 
 
1326
                                                        if((winX < Scr->BorderLeft) && ((Scr->MoveOffResistance < 0) ||
 
1327
                                                                                        (winX > Scr->BorderLeft - Scr->MoveOffResistance))) {
 
1328
                                                                winX = Scr->BorderLeft;
 
1329
                                                                newX = msw->x + XW + Scr->BorderLeft * mw->wwidth / vs->w;
 
1330
                                                        }
 
1331
                                                        if(((winX + width) > vs->w - Scr->BorderRight) &&
 
1332
                                                                        ((Scr->MoveOffResistance < 0) ||
 
1333
                                                                         ((winX + width) < vs->w - Scr->BorderRight + Scr->MoveOffResistance))) {
 
1334
                                                                winX = vs->w - Scr->BorderRight - width;
 
1335
                                                                newX = msw->x + mw->wwidth *
 
1336
                                                                       (1 - Scr->BorderRight / (double) vs->w) - wl->width + XW - 2;
 
1337
                                                        }
 
1338
                                                        if((winY < Scr->BorderTop) && ((Scr->MoveOffResistance < 0) ||
 
1339
                                                                                       (winY > Scr->BorderTop - Scr->MoveOffResistance))) {
 
1340
                                                                winY = Scr->BorderTop;
 
1341
                                                                newY = msw->y + YW + Scr->BorderTop * mw->height / vs->h;
 
1342
                                                        }
 
1343
                                                        if(((winY + height) > vs->h - Scr->BorderBottom) &&
 
1344
                                                                        ((Scr->MoveOffResistance < 0) ||
 
1345
                                                                         ((winY + height) < vs->h - Scr->BorderBottom + Scr->MoveOffResistance))) {
 
1346
                                                                winY = vs->h - Scr->BorderBottom - height;
 
1347
                                                                newY = msw->y + mw->wheight
 
1348
                                                                       * (1 - Scr->BorderBottom / (double) vs->h)
 
1349
                                                                       * - wl->height + YW - 2;
 
1350
                                                        }
 
1351
                                                }
 
1352
 
 
1353
 
 
1354
                                                /* Setup the avatar for the new position of win */
 
1355
                                                WMapSetupWindow(win, winX, winY, -1, -1);
 
1356
 
 
1357
                                                /*
 
1358
                                                 * If SWWMIW, we already made sure above the
 
1359
                                                 * window is always visible on the screen.  So we
 
1360
                                                 * don't need to do any of the following steps to
 
1361
                                                 * maybe show it or maybe un-show it, since we
 
1362
                                                 * know it's already always shown.
 
1363
                                                 */
 
1364
                                                if(Scr->ShowWinWhenMovingInWmgr) {
1962
1365
                                                        goto movewin;
1963
1366
                                                }
 
1367
 
 
1368
                                                /*
 
1369
                                                 * If we wound up in the same workspace as is
 
1370
                                                 * being displayed on the screen, we need to make
 
1371
                                                 * sure that window is showing up on the screen
 
1372
                                                 * as a "about to be occupied here if you release
 
1373
                                                 * the button" indication.
 
1374
                                                 */
 
1375
                                                if(cws == vs->wsw->currentwspc) {
 
1376
                                                        if(alreadyvivible) {
 
1377
                                                                /* Unless it's already there */
 
1378
                                                                goto movewin;
 
1379
                                                        }
 
1380
                                                        if(Scr->OpaqueMove) {
 
1381
                                                                XMoveWindow(dpy, win->frame, winX, winY);
 
1382
                                                                DisplayWin(vs, win);
 
1383
                                                        }
 
1384
                                                        else {
 
1385
                                                                MoveOutline(Scr->Root,
 
1386
                                                                            winX - win->frame_bw,
 
1387
                                                                            winY - win->frame_bw,
 
1388
                                                                            win->frame_width  + 2 * win->frame_bw,
 
1389
                                                                            win->frame_height + 2 * win->frame_bw,
 
1390
                                                                            win->frame_bw,
 
1391
                                                                            win->title_height + win->frame_bw3D);
 
1392
                                                        }
 
1393
                                                        alreadyvivible = true;
 
1394
 
 
1395
                                                        /*
 
1396
                                                         * We already moved it, skip past the other
 
1397
                                                         * code trying to move it in other cases.
 
1398
                                                         */
 
1399
                                                        goto move;
 
1400
                                                }
 
1401
 
 
1402
                                                /*
 
1403
                                                 * If it's for whatever reason not being shown on
 
1404
                                                 * the screen, then we don't need to move it; hop
 
1405
                                                 * straight to moving the avatar.
 
1406
                                                 */
 
1407
                                                if(!alreadyvivible) {
 
1408
                                                        goto move;
 
1409
                                                }
 
1410
 
 
1411
                                                /*
 
1412
                                                 * So it _is_ being shown.  If it's not supposed
 
1413
                                                 * to be here, hide it away (don't need to worry
 
1414
                                                 * about AlwaysShow, it would have skipped past
 
1415
                                                 * us from ab0ve).  Also, if we started moving
 
1416
                                                 * the window out of the visible workspace with
 
1417
                                                 * button 1, it's gonna not be here if you
 
1418
                                                 * release, so hide it away.
 
1419
                                                 */
 
1420
                                                if(!OCCUPY(win, vs->wsw->currentwspc) ||
 
1421
                                                                (startincurrent && (button == 1))) {
 
1422
                                                        if(Scr->OpaqueMove) {
 
1423
                                                                Vanish(vs, win);
 
1424
                                                                XMoveWindow(dpy, win->frame, winX, winY);
 
1425
                                                        }
 
1426
                                                        else {
 
1427
                                                                MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
 
1428
                                                        }
 
1429
                                                        alreadyvivible = false;
 
1430
                                                        goto move;
 
1431
                                                }
 
1432
 
 
1433
movewin:
 
1434
                                                /*
 
1435
                                                 * However we get here, the real window is
 
1436
                                                 * visible and needs to be moved.  So move it.
 
1437
                                                 */
1964
1438
                                                if(Scr->OpaqueMove) {
1965
1439
                                                        XMoveWindow(dpy, win->frame, winX, winY);
1966
 
                                                        DisplayWin(vs, win);
1967
1440
                                                }
1968
1441
                                                else {
1969
1442
                                                        MoveOutline(Scr->Root,
1970
 
                                                                    winX - win->frame_bw, winY - win->frame_bw,
 
1443
                                                                    winX - win->frame_bw,
 
1444
                                                                    winY - win->frame_bw,
1971
1445
                                                                    win->frame_width  + 2 * win->frame_bw,
1972
1446
                                                                    win->frame_height + 2 * win->frame_bw,
1973
1447
                                                                    win->frame_bw,
1974
1448
                                                                    win->title_height + win->frame_bw3D);
1975
1449
                                                }
1976
 
                                                alreadyvivible = true;
1977
 
                                                goto move;
1978
 
                                        }
1979
 
                                        if(!alreadyvivible) {
1980
 
                                                goto move;
1981
 
                                        }
1982
 
                                        if(!OCCUPY(win, vs->wsw->currentwspc) ||
1983
 
                                                        (startincurrent && (button == 1))) {
1984
 
                                                if(Scr->OpaqueMove) {
1985
 
                                                        Vanish(vs, win);
1986
 
                                                        XMoveWindow(dpy, win->frame, winX, winY);
1987
 
                                                }
1988
 
                                                else {
1989
 
                                                        MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
1990
 
                                                }
1991
 
                                                alreadyvivible = false;
1992
 
                                                goto move;
1993
 
                                        }
1994
 
movewin:
1995
 
                                        if(Scr->OpaqueMove) {
1996
 
                                                XMoveWindow(dpy, win->frame, winX, winY);
1997
 
                                        }
1998
 
                                        else {
1999
 
                                                MoveOutline(Scr->Root,
2000
 
                                                            winX - win->frame_bw, winY - win->frame_bw,
2001
 
                                                            win->frame_width  + 2 * win->frame_bw,
2002
 
                                                            win->frame_height + 2 * win->frame_bw,
2003
 
                                                            win->frame_bw,
2004
 
                                                            win->title_height + win->frame_bw3D);
2005
 
                                        }
2006
 
                                }
 
1450
                                        }
 
1451
 
2007
1452
move:
2008
 
                                XMoveWindow(dpy, w, newX - XW, newY - YW);
2009
 
                                break;
2010
 
                        case Expose :
2011
 
                                if(ev.xexpose.window == w) {
2012
 
                                        WMapRedrawWindow(w, W0, H0, wl->cp, wl->twm_win->icon_name);
 
1453
                                        /*
 
1454
                                         * Just move the subwindow in the map to the new
 
1455
                                         * location.
 
1456
                                         */
 
1457
                                        XMoveWindow(dpy, w, newX - XW, newY - YW);
 
1458
 
 
1459
                                        /* And we're done.  Next event! */
2013
1460
                                        break;
2014
1461
                                }
2015
 
                                Event = ev;
2016
 
                                DispatchEvent();
2017
 
                                break;
 
1462
                        }
2018
1463
                }
2019
1464
        }
 
1465
 
2020
1466
        /*
2021
1467
         * Finished with dragging (button released).
2022
1468
         */
2023
1469
        if(realmovemode) {
 
1470
                /* Moving the real window?  Move the real window. */
2024
1471
                if(Scr->ShowWinWhenMovingInWmgr || alreadyvivible) {
2025
1472
                        if(Scr->OpaqueMove && !OCCUPY(win, vs->wsw->currentwspc)) {
2026
1473
                                Vanish(vs, win);
2032
1479
                }
2033
1480
                SetupWindow(win, winX, winY, win->frame_width, win->frame_height, -1);
2034
1481
        }
2035
 
        ev.xbutton.subwindow = (Window) 0;
2036
 
        ev.xbutton.window = parent;
2037
 
        XPutBackEvent(dpy, &ev);
 
1482
 
 
1483
        /*
 
1484
         * Last event that caused us to escape is other code's
 
1485
         * responsibility, put it back in the queue.
 
1486
         */
 
1487
        lastev.xbutton.subwindow = (Window) 0;
 
1488
        lastev.xbutton.window = parent;
 
1489
        XPutBackEvent(dpy, &lastev);
 
1490
 
 
1491
        /* End our grab */
2038
1492
        XUngrabPointer(dpy, CurrentTime);
2039
1493
 
2040
 
        if((ev.xbutton.time - etime) < 250) {
2041
 
                /* Just a quick click or drag */
 
1494
        /*
 
1495
         * If you wanted to change workspaces, and clicked _outside_ a
 
1496
         * window, it would have just switched way up near the top of the
 
1497
         * function.  But if you clicked _in_ a window [in the WSM map], it
 
1498
         * would have to go through the whole fun to find out whether you
 
1499
         * wanted to move/reoccupy the window, or were just wanting to change
 
1500
         * WSen.
 
1501
         *
 
1502
         * So if it's been <250ms (completely arbitrary and non-configgable,
 
1503
         * probably should be rethought) since you started, assume you just
 
1504
         * wanted to switch workspaces.  Don't do any occupation change, And
 
1505
         * just switch.  Also do some magic related to the map/button
 
1506
         * toggling.
 
1507
         *
 
1508
         * XXX This still leaves any window _moves_ done.  It seems like it
 
1509
         * should probably revert those too?
 
1510
         */
 
1511
        if((lastev.xbutton.time - etime) < 250) {
2042
1512
                KeyCode control_L_code, control_R_code;
2043
 
                KeySym  control_L_sym,  control_R_sym;
2044
1513
                char keys [32];
2045
1514
 
 
1515
                /* Re-show old miniwindow, destroy the temp, and warp to WS */
2046
1516
                XMapWindow(dpy, sw);
2047
1517
                XDestroyWindow(dpy, w);
2048
 
                GotoWorkSpace(vs, ws);
 
1518
                GotoWorkSpace(vs, oldws);
2049
1519
                if(!Scr->DontWarpCursorInWMap) {
2050
1520
                        WarpToWindow(win, Scr->RaiseOnWarp);
2051
1521
                }
2052
 
                control_L_sym  = XStringToKeysym("Control_L");
2053
 
                control_R_sym  = XStringToKeysym("Control_R");
2054
 
                control_L_code = XKeysymToKeycode(dpy, control_L_sym);
2055
 
                control_R_code = XKeysymToKeycode(dpy, control_R_sym);
 
1522
 
 
1523
                /*
 
1524
                 * The control keys toggle between map and button state.  If we
 
1525
                 * did a short move, and ctrl is being held at the end, flip the
 
1526
                 * state.  This has several possible causes and effects.
 
1527
                 *
 
1528
                 * One is that _during_ a move, we don't do look through KeyPress
 
1529
                 * events, so we wouldn't see it happen yet.  But after we're
 
1530
                 * done and return back into the event loop, that press will come
 
1531
                 * in and cause the state to change.  It may be weird to the user
 
1532
                 * to see that happen, not when they hit ctrl, but _later_, after
 
1533
                 * they release the mouse button.  The "best" solution may be to
 
1534
                 * find that press in the event queue and empty it out, but a
 
1535
                 * cheap solution is just to pre-flip it and then let the event
 
1536
                 * code flip it back.  Flickery maybe, but easy.  Now, _should_ we be
 
1537
                 * doing that?  I'm a little doubtful...
 
1538
                 *
 
1539
                 * A second is that if the WSM is "naturally" in button mode, and
 
1540
                 * you temporarily ctrl-flip it into map mode and then click in a
 
1541
                 * window.  This code will cause it to automatically flip back
 
1542
                 * after you release the mouse if you haven't released ctrl yet.
 
1543
                 * This is apparently needed because, unless you have
 
1544
                 * DontWarpCursorInWMap set, the previous few lines of code would
 
1545
                 * have shifted the cursor to the window you clicked, which means
 
1546
                 * you don't get a chance to release it in the WSM and flip the
 
1547
                 * state back.  It seems a reasonable assumption that the user
 
1548
                 * wanted a temporary change of state just for the purposes of
 
1549
                 * the change.
 
1550
                 *
 
1551
                 * (if you had released the ctrl before the mouse, the release
 
1552
                 * event would already be queued up up on the WSM, so would flip
 
1553
                 * it back after we return)
 
1554
                 *
 
1555
                 * XXX Should we be checking DontToggleWorkSpaceManagerState
 
1556
                 * here?
 
1557
                 */
 
1558
                control_L_code = XKeysymToKeycode(dpy, XStringToKeysym("Control_L"));
 
1559
                control_R_code = XKeysymToKeycode(dpy, XStringToKeysym("Control_R"));
2056
1560
                XQueryKeymap(dpy, keys);
2057
1561
                if((keys [control_L_code / 8] & ((char) 0x80 >> (control_L_code % 8))) ||
2058
1562
                                keys [control_R_code / 8] & ((char) 0x80 >> (control_R_code % 8))) {
2059
 
                        WMapToggleState(vs);
 
1563
                        WMgrToggleState(vs);
2060
1564
                }
2061
1565
                return;
2062
1566
        }
2063
1567
 
2064
 
        for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
2065
 
                MapSubwindow *msw = vs->wsw->mswl [ws->number];
 
1568
 
 
1569
        /* Find the workspace we finally found up in */
 
1570
        for(newws = Scr->workSpaceMgr.workSpaceList ; newws != NULL ;
 
1571
                        newws = newws->next) {
 
1572
                MapSubwindow *msw = vs->wsw->mswl[newws->number];
2066
1573
                if((newX >= msw->x) && (newX < msw->x + mw->wwidth) &&
2067
1574
                                (newY >= msw->y) && (newY < msw->y + mw->wheight)) {
2068
1575
                        break;
2069
1576
                }
2070
1577
        }
2071
 
        newws = ws;
 
1578
 
 
1579
        /* And finish off whatever we're supposed to be doing */
2072
1580
        switch(button) {
2073
 
                case 1 : /* moving to another workspace */
 
1581
                case 1 : { /* moving to another workspace */
 
1582
                        int occupation;
 
1583
 
 
1584
                        /* If nothing to change, re-map avatar and we're done */
2074
1585
                        if((newws == NULL) || (newws == oldws) ||
2075
1586
                                        OCCUPY(wl->twm_win, newws)) {
2076
1587
                                XMapWindow(dpy, sw);
2077
1588
                                break;
2078
1589
                        }
2079
 
                        occupation = (win->occupation | (1 << newws->number)) & ~(1 << oldws->number);
 
1590
 
 
1591
                        /* Out of the old, into the new */
 
1592
                        occupation = win->occupation;
 
1593
                        occupation |= (1 << newws->number);
 
1594
                        occupation &= ~(1 << oldws->number);
2080
1595
                        ChangeOccupation(win, occupation);
 
1596
 
 
1597
                        /*
 
1598
                         * Raise it to the top if it's in our current ws, and
 
1599
                         * properly slot it into the WSM map stack if not.
 
1600
                         */
2081
1601
                        if(newws == vs->wsw->currentwspc) {
2082
1602
                                OtpRaise(win, WinWin);
2083
1603
                                WMapRaise(win);
2085
1605
                        else {
2086
1606
                                WMapRestack(newws);
2087
1607
                        }
 
1608
 
2088
1609
                        break;
2089
 
 
2090
 
                case 2 : /* putting in extra workspace */
 
1610
                }
 
1611
 
 
1612
                case 2 : { /* putting in extra workspace */
 
1613
                        int occupation;
 
1614
 
 
1615
                        /* Nothing to do if it's going nowhere or places it already is */
2091
1616
                        if((newws == NULL) || (newws == oldws) ||
2092
1617
                                        OCCUPY(wl->twm_win, newws)) {
2093
1618
                                break;
2094
1619
                        }
2095
1620
 
 
1621
                        /* Move */
2096
1622
                        occupation = win->occupation | (1 << newws->number);
2097
1623
                        ChangeOccupation(win, occupation);
 
1624
 
 
1625
                        /* Raise/stack */
2098
1626
                        if(newws == vs->wsw->currentwspc) {
2099
1627
                                OtpRaise(win, WinWin);
2100
1628
                                WMapRaise(win);
2103
1631
                                WMapRestack(newws);
2104
1632
                        }
2105
1633
                        break;
 
1634
                }
2106
1635
 
 
1636
                /*
 
1637
                 * Should actually never hit this state; only 1/2 would have
 
1638
                 * gotten this far into the code...
 
1639
                 */
2107
1640
                default :
2108
1641
                        return;
2109
1642
        }
 
1643
 
 
1644
        /* Clean up our temporary moving-around-in the WSM window */
2110
1645
        XDestroyWindow(dpy, w);
2111
1646
}
2112
1647
 
2113
 
/*
2114
 
 * This is really more util.c fodder, but leaving it here for now because
2115
 
 * it's only used once in the below func.  If we start finding external
2116
 
 * uses for it, it should be moved.
 
1648
 
 
1649
 
 
1650
 
 
1651
/*
 
1652
 ****************************************************************
 
1653
 *
 
1654
 * Functions for doing things with subwindows in the WSM in map state
 
1655
 *
 
1656
 ****************************************************************
 
1657
 */
 
1658
 
 
1659
/*
 
1660
 * Backend for mapping up windows in the WSM map.
2117
1661
 */
2118
1662
static void
2119
 
InvertColorPair(ColorPair *cp)
2120
 
{
2121
 
        Pixel save;
2122
 
 
2123
 
        save = cp->fore;
2124
 
        cp->fore = cp->back;
2125
 
        cp->back = save;
2126
 
        save = cp->shadc;
2127
 
        cp->shadc = cp->shadd;
2128
 
        cp->shadd = save;
2129
 
}
2130
 
 
2131
 
void WMapRedrawName(VirtualScreen *vs, WinList wl)
2132
 
{
2133
 
        int       w = wl->width;
2134
 
        int       h = wl->height;
2135
 
        ColorPair cp;
2136
 
        char      *label;
2137
 
 
2138
 
        label  = wl->twm_win->icon_name;
2139
 
        cp     = wl->cp;
 
1663
wmap_mapwin_backend(TwmWindow *win, bool handleraise)
 
1664
{
 
1665
        VirtualScreen *vs;
 
1666
        WorkSpace *ws;
 
1667
        WinList *wl;
 
1668
 
 
1669
        for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
 
1670
                for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
 
1671
                        for(wl = vs->wsw->mswl[ws->number]->wl; wl != NULL; wl = wl->next) {
 
1672
                                if(win == wl->twm_win) {
 
1673
                                        /*
 
1674
                                         * When called via deiconify, we might have to do
 
1675
                                         * stuff related to auto-raising the window while we
 
1676
                                         * de-iconify.  When called via a map request, the
 
1677
                                         * window is always wherever it previously was in the
 
1678
                                         * stack.
 
1679
                                         */
 
1680
                                        if(!handleraise || Scr->NoRaiseDeicon) {
 
1681
                                                XMapWindow(dpy, wl->w);
 
1682
                                        }
 
1683
                                        else {
 
1684
                                                XMapRaised(dpy, wl->w);
 
1685
                                        }
 
1686
                                        WMapRedrawName(vs, wl);
 
1687
                                        break;
 
1688
                                }
 
1689
                        }
 
1690
                }
 
1691
        }
 
1692
}
 
1693
 
 
1694
/*
 
1695
 * Map up a window's subwindow in the map-mode WSM.  Happens as a result
 
1696
 * of getting (or faking) a Map request event.  Notably, _not_ in the
 
1697
 * process of de-iconifying a window; mostly as a result of _creating_
 
1698
 * windows, or when a client maps itself without a request from us.
 
1699
 *
 
1700
 * x-ref comment on WMapDeIconify() for some subtle distinctions between
 
1701
 * the two...
 
1702
 */
 
1703
void
 
1704
WMapMapWindow(TwmWindow *win)
 
1705
{
 
1706
        /* We don't do raise handling */
 
1707
        wmap_mapwin_backend(win, false);
 
1708
}
 
1709
 
 
1710
 
 
1711
/*
 
1712
 * De-iconify a window in the WSM map.  The opposite of WMapIconify(),
 
1713
 * and different from WMapMapWindow() in complicated ways.  This function
 
1714
 * winds up getting called when a window is de-iconified via a ctwm
 
1715
 * function.
 
1716
 */
 
1717
void
 
1718
WMapDeIconify(TwmWindow *win)
 
1719
{
 
1720
        /* If it's not showing anywhere, nothing to do.  Is this possible? */
 
1721
        if(!win->vs) {
 
1722
                return;
 
1723
        }
 
1724
 
 
1725
        /* Loop and map, handling raises if necessary */
 
1726
        wmap_mapwin_backend(win, true);
 
1727
}
 
1728
 
 
1729
 
 
1730
/*
 
1731
 * Hide away a window in the WSM map.  Happens when win is iconified;
 
1732
 * different from destruction.
 
1733
 */
 
1734
void
 
1735
WMapIconify(TwmWindow *win)
 
1736
{
 
1737
        VirtualScreen *vs;
 
1738
        WorkSpace *ws;
 
1739
        WinList *wl;
 
1740
 
 
1741
        if(!win->vs) {
 
1742
                return;
 
1743
        }
 
1744
 
 
1745
        for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
 
1746
                for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
 
1747
                        for(wl = vs->wsw->mswl[ws->number]->wl; wl != NULL; wl = wl->next) {
 
1748
                                if(win == wl->twm_win) {
 
1749
                                        XUnmapWindow(dpy, wl->w);
 
1750
                                        break;
 
1751
                                }
 
1752
                        }
 
1753
                }
 
1754
        }
 
1755
}
 
1756
 
 
1757
 
 
1758
/*
 
1759
 * Position a window in the WSM.  Happens as a result of moving things.
 
1760
 */
 
1761
void
 
1762
WMapSetupWindow(TwmWindow *win, int x, int y, int w, int h)
 
1763
{
 
1764
        VirtualScreen *vs;
 
1765
 
 
1766
        /* If it's an icon manager, or not on a vscreen, nothing to do */
 
1767
        if(win->isiconmgr || !win->vs) {
 
1768
                return;
 
1769
        }
 
1770
 
 
1771
        /* If it's a WSM, we may be resetting size/position, but that's it */
 
1772
        if(win->iswspmgr) {
 
1773
                if(w == -1) {
 
1774
                        return;
 
1775
                }
 
1776
                ResizeWorkSpaceManager(win->vs, win);
 
1777
                return;
 
1778
        }
 
1779
 
 
1780
        /* If it's an occupy window, ditto */
 
1781
        if(win == Scr->workSpaceMgr.occupyWindow->twm_win) {
 
1782
                if(w == -1) {
 
1783
                        return;
 
1784
                }
 
1785
                ResizeOccupyWindow(win);
 
1786
                return;
 
1787
        }
 
1788
 
 
1789
 
 
1790
        /* For anything else, we're potentially showing something */
 
1791
        for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
 
1792
                WorkSpaceWindow *wsw = vs->wsw;
 
1793
                WorkSpace *ws;
 
1794
 
 
1795
                /* Scale factors for windows in the map */
 
1796
                float wf = (float)(wsw->wwidth  - 2) / (float) vs->w;
 
1797
                float hf = (float)(wsw->wheight - 2) / (float) vs->h;
 
1798
 
 
1799
                /*
 
1800
                 * Loop around windows in each WS to find all the places the
 
1801
                 * requested window should show up.
 
1802
                 */
 
1803
                for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
 
1804
                        MapSubwindow *msw = wsw->mswl[ws->number];
 
1805
 
 
1806
                        for(WinList *wl = msw->wl; wl != NULL; wl = wl->next) {
 
1807
                                if(win == wl->twm_win) {
 
1808
                                        /* New positions */
 
1809
                                        wl->x = (int)(x * wf);
 
1810
                                        wl->y = (int)(y * hf);
 
1811
 
 
1812
                                        /* Rescale if necessary and move */
 
1813
                                        if(w == -1) {
 
1814
                                                XMoveWindow(dpy, wl->w, wl->x, wl->y);
 
1815
                                        }
 
1816
                                        else {
 
1817
                                                wl->width  = (unsigned int)((w * wf) + 0.5);
 
1818
                                                wl->height = (unsigned int)((h * hf) + 0.5);
 
1819
                                                if(!Scr->use3Dwmap) {
 
1820
                                                        wl->width  -= 2;
 
1821
                                                        wl->height -= 2;
 
1822
                                                }
 
1823
                                                if(wl->width < 1) {
 
1824
                                                        wl->width = 1;
 
1825
                                                }
 
1826
                                                if(wl->height < 1) {
 
1827
                                                        wl->height = 1;
 
1828
                                                }
 
1829
                                                XMoveResizeWindow(dpy, wl->w, wl->x, wl->y,
 
1830
                                                                  wl->width, wl->height);
 
1831
                                        }
 
1832
                                        break;
 
1833
                                }
 
1834
                        }
 
1835
                }
 
1836
        }
 
1837
}
 
1838
 
 
1839
 
 
1840
/*
 
1841
 * Frontends for changing the stacking of windows in the WSM.
 
1842
 *
 
1843
 * Strictly speaker, we have no ability to raise or lower a window in the
 
1844
 * map; we only draw the whole stack.  And these functions don't actually
 
1845
 * change the stacking of a window, they're called as a _result_ of
 
1846
 * changing the stacking, to notify the WSM to re-check and update
 
1847
 * itself.  So while conceptually we maintain a separation for our
 
1848
 * callers between various reasons this is being called, the
 
1849
 * implementations are identical.
 
1850
 */
 
1851
void
 
1852
WMapRaiseLower(TwmWindow *win)
 
1853
{
 
1854
        WorkSpace *ws;
 
1855
 
 
1856
        for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
 
1857
                if(OCCUPY(win, ws)) {
 
1858
                        WMapRestack(ws);
 
1859
                }
 
1860
        }
 
1861
}
 
1862
 
 
1863
void
 
1864
WMapLower(TwmWindow *win)
 
1865
{
 
1866
        WMapRaiseLower(win);
 
1867
}
 
1868
 
 
1869
void
 
1870
WMapRaise(TwmWindow *win)
 
1871
{
 
1872
        WMapRaiseLower(win);
 
1873
}
 
1874
 
 
1875
 
 
1876
/*
 
1877
 * Backend for redoing the stacking of a window in the WSM.
 
1878
 *
 
1879
 * XXX Since this tends to get called iteratively, there's probably
 
1880
 * something better we can do than doing all this relatively expensive
 
1881
 * stuff over and over...
 
1882
 */
 
1883
void
 
1884
WMapRestack(WorkSpace *ws)
 
1885
{
 
1886
        WinList *wl;
 
1887
        Window  root, parent; // Dummy
 
1888
        Window  *children, *smallws;
 
1889
        unsigned int nchildren;
 
1890
 
 
1891
        /* Get a whole list of the windows on the screen */
 
1892
        nchildren = 0;
 
1893
        XQueryTree(dpy, Scr->Root, &root, &parent, &children, &nchildren);
 
1894
 
 
1895
        /*
 
1896
         * We're presumably dealing with a [often very small] subset of them,
 
1897
         * but just allocate space for the whole list; easier than trying to
 
1898
         * shrink down, and really, how big can it possibly be?
 
1899
         */
 
1900
        smallws = calloc(nchildren, sizeof(Window));
 
1901
 
 
1902
        /* Work it up per vscreen */
 
1903
        for(VirtualScreen *vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
 
1904
                int j = 0;
 
1905
                const MapSubwindow *msw = vs->wsw->mswl[ws->number];
 
1906
 
 
1907
                /* Loop backward (from top to bottom of stack) */
 
1908
                for(int i = nchildren - 1; i >= 0; i--) {
 
1909
                        TwmWindow *win = GetTwmWindow(children[i]);
 
1910
 
 
1911
                        /*
 
1912
                         * Only care about certain windows.  If it's not a window we
 
1913
                         * know about, or not a frame (e.g., an icon), or doesn't
 
1914
                         * occupy this workspace, skip it.
 
1915
                         */
 
1916
                        if(win == NULL || win->frame != children[i] || !OCCUPY(win, ws)) {
 
1917
                                continue;
 
1918
                        }
 
1919
 
 
1920
                        /* Debug */
 
1921
                        if(tracefile) {
 
1922
                                fprintf(tracefile, "WMapRestack : w = %lx, win = %p\n",
 
1923
                                        children[i], (void *)win);
 
1924
                                fflush(tracefile);
 
1925
                        }
 
1926
 
 
1927
                        /* Find this window in the list for the map of this WS */
 
1928
                        for(wl = msw->wl; wl != NULL; wl = wl->next) {
 
1929
                                /* Debug */
 
1930
                                if(tracefile) {
 
1931
                                        fprintf(tracefile, "WMapRestack : wl = %p, twm_win = %p\n",
 
1932
                                                (void *)wl, (void *)wl->twm_win);
 
1933
                                        fflush(tracefile);
 
1934
                                }
 
1935
 
 
1936
                                if(win == wl->twm_win) {
 
1937
                                        /* There you are.  Add into our list to restack. */
 
1938
                                        smallws[j++] = wl->w;
 
1939
                                        break;
 
1940
                                }
 
1941
                        }
 
1942
                }
 
1943
 
 
1944
                /*
 
1945
                 * Restack the windows in the map.  Note that the order is
 
1946
                 * reversed from earlier; XQueryTree() returns bottom->top,
 
1947
                 * XRestackWindows() is passed top->bottom.
 
1948
                 */
 
1949
                XRestackWindows(dpy, smallws, j);
 
1950
        }
 
1951
 
 
1952
        /* Cleanup */
 
1953
        XFree(children);
 
1954
        free(smallws);
 
1955
        return;
 
1956
}
 
1957
 
 
1958
 
 
1959
 
 
1960
 
 
1961
/*
 
1962
 ****************************************************************
 
1963
 *
 
1964
 * Bits related to the actual drawing of the windows in the map.
 
1965
 *
 
1966
 ****************************************************************
 
1967
 */
 
1968
 
 
1969
/*
 
1970
 * Update stuff in the WSM when win's icon name changes
 
1971
 */
 
1972
void
 
1973
WMapUpdateIconName(TwmWindow *win)
 
1974
{
 
1975
        VirtualScreen *vs;
 
1976
        WorkSpace *ws;
 
1977
        WinList *wl;
 
1978
 
 
1979
        for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
 
1980
                for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
 
1981
                        for(wl = vs->wsw->mswl[ws->number]->wl; wl != NULL; wl = wl->next) {
 
1982
                                if(win == wl->twm_win) {
 
1983
                                        WMapRedrawName(vs, wl);
 
1984
                                        break;
 
1985
                                }
 
1986
                        }
 
1987
                }
 
1988
        }
 
1989
}
 
1990
 
 
1991
 
 
1992
/*
 
1993
 * Draw a window name into the window's representation in the map-state
 
1994
 * WSM.
 
1995
 */
 
1996
void
 
1997
WMapRedrawName(VirtualScreen *vs, WinList *wl)
 
1998
{
 
1999
        ColorPair cp = wl->cp;
2140
2000
 
2141
2001
        if(Scr->ReverseCurrentWorkspace && wl->wlist == vs->wsw->currentwspc) {
2142
2002
                InvertColorPair(&cp);
2143
2003
        }
2144
 
        WMapRedrawWindow(wl->w, w, h, cp, label);
 
2004
        WMapRedrawWindow(wl->w, wl->width, wl->height, cp, wl->twm_win->icon_name);
2145
2005
}
2146
2006
 
2147
 
static void WMapRedrawWindow(Window window, int width, int height,
2148
 
                             ColorPair cp, char *label)
 
2007
 
 
2008
/*
 
2009
 * Draw up a window's representation in the map-state WSM, with the
 
2010
 * window name.
 
2011
 *
 
2012
 * The drawing of the window name could probably be done a bit better.
 
2013
 * The font size is based on a tiny fraction of the window's height, so
 
2014
 * is probably usually too small to be useful, and often appears just as
 
2015
 * some odd colored pixels at the top of the window.
 
2016
 */
 
2017
static void
 
2018
WMapRedrawWindow(Window window, int width, int height,
 
2019
                 ColorPair cp, const char *label)
2149
2020
{
2150
 
        int         x, y, strhei, strwid;
2151
 
        MyFont      font;
2152
 
        XRectangle inc_rect;
2153
 
        XRectangle logical_rect;
2154
 
        XFontStruct **xfonts;
2155
 
        char **font_names;
2156
 
        int i;
2157
 
        int descent;
2158
 
        int fnum;
 
2021
        int x, y;
 
2022
        const MyFont font = Scr->workSpaceMgr.windowFont;
2159
2023
 
 
2024
        /* Blank out window background color */
2160
2025
        XClearWindow(dpy, window);
2161
 
        font = Scr->workSpaceMgr.windowFont;
2162
 
 
2163
 
        XmbTextExtents(font.font_set, label, strlen(label),
2164
 
                       &inc_rect, &logical_rect);
2165
 
        strwid = logical_rect.width;
2166
 
        strhei = logical_rect.height;
2167
 
        if(strhei > height) {
2168
 
                return;
2169
 
        }
2170
 
 
2171
 
        x = (width  - strwid) / 2;
2172
 
        if(x < 1) {
2173
 
                x = 1;
2174
 
        }
2175
 
 
2176
 
        fnum = XFontsOfFontSet(font.font_set, &xfonts, &font_names);
2177
 
        for(i = 0, descent = 0; i < fnum; i++) {
2178
 
                /* xf = xfonts[i]; */
2179
 
                descent = ((descent < (xfonts[i]->max_bounds.descent)) ?
2180
 
                           (xfonts[i]->max_bounds.descent) : descent);
2181
 
        }
2182
 
 
2183
 
        y = ((height + strhei) / 2) - descent;
2184
 
 
 
2026
 
 
2027
        /* Figure out where to position the name */
 
2028
        {
 
2029
                XRectangle inc_rect;
 
2030
                XRectangle logical_rect;
 
2031
                int strhei, strwid;
 
2032
                int i, descent;
 
2033
                XFontStruct **xfonts;
 
2034
                char **font_names;
 
2035
                int fnum;
 
2036
 
 
2037
                XmbTextExtents(font.font_set, label, strlen(label),
 
2038
                               &inc_rect, &logical_rect);
 
2039
                strwid = logical_rect.width;
 
2040
                strhei = logical_rect.height;
 
2041
 
 
2042
                /*
 
2043
                 * If it's too tall to fit, just give up now.
 
2044
                 * XXX Probably should still do border stuff below...
 
2045
                 */
 
2046
                if(strhei > height) {
 
2047
                        return;
 
2048
                }
 
2049
 
 
2050
                x = (width - strwid) / 2;
 
2051
                if(x < 1) {
 
2052
                        x = 1;
 
2053
                }
 
2054
 
 
2055
                fnum = XFontsOfFontSet(font.font_set, &xfonts, &font_names);
 
2056
                for(i = 0, descent = 0; i < fnum; i++) {
 
2057
                        /* xf = xfonts[i]; */
 
2058
                        descent = ((descent < (xfonts[i]->max_bounds.descent)) ?
 
2059
                                   (xfonts[i]->max_bounds.descent) : descent);
 
2060
                }
 
2061
 
 
2062
                y = ((height + strhei) / 2) - descent;
 
2063
        }
 
2064
 
 
2065
        /* Draw up borders around the win */
2185
2066
        if(Scr->use3Dwmap) {
2186
2067
                Draw3DBorder(window, 0, 0, width, height, 1, cp, off, true, false);
2187
2068
                FB(cp.fore, cp.back);
2191
2072
                XFillRectangle(dpy, window, Scr->NormalGC, 0, 0, width, height);
2192
2073
                FB(cp.fore, cp.back);
2193
2074
        }
 
2075
 
 
2076
        /* Write in the name */
2194
2077
        if(Scr->Monochrome != COLOR) {
2195
 
                XmbDrawImageString(dpy, window, font.font_set, Scr->NormalGC, x, y, label,
2196
 
                                   strlen(label));
 
2078
                XmbDrawImageString(dpy, window, font.font_set, Scr->NormalGC, x, y,
 
2079
                                   label, strlen(label));
2197
2080
        }
2198
2081
        else {
2199
 
                XmbDrawString(dpy, window, font.font_set, Scr->NormalGC, x, y, label,
2200
 
                              strlen(label));
2201
 
        }
2202
 
}
2203
 
 
2204
 
void
2205
 
WMapAddToList(TwmWindow *win, WorkSpace *ws)
2206
 
{
2207
 
        VirtualScreen *vs;
2208
 
        WinList wl;
2209
 
        float   wf, hf;
 
2082
                XmbDrawString(dpy, window, font.font_set, Scr->NormalGC, x, y,
 
2083
                              label, strlen(label));
 
2084
        }
 
2085
}
 
2086
 
 
2087
 
 
2088
 
 
2089
 
 
2090
/*
 
2091
 * Processes for adding/removing windows from the WSM
 
2092
 */
 
2093
 
 
2094
/*
 
2095
 * Add a window into any appropriate WSMs' maps.  Called during
 
2096
 * AddWindow().
 
2097
 */
 
2098
void
 
2099
WMapAddWindow(TwmWindow *win)
 
2100
{
 
2101
        WorkSpace *ws;
 
2102
 
 
2103
        if(!WMapWindowMayBeAdded(win)) {
 
2104
                return;
 
2105
        }
 
2106
 
 
2107
        for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
 
2108
                if(OCCUPY(win, ws)) {
 
2109
                        WMapAddWindowToWorkspace(win, ws);
 
2110
                }
 
2111
        }
 
2112
}
 
2113
 
 
2114
 
 
2115
/*
 
2116
 * Create WSM representation of a given window in a given WS.  Called
 
2117
 * when windows get added to a workspace, either via WMapAddWindow()
 
2118
 * during the AddWindow() process, or via an occupation change.
 
2119
 *
 
2120
 * (previously: WMapAddToList())
 
2121
 */
 
2122
void
 
2123
WMapAddWindowToWorkspace(TwmWindow *win, WorkSpace *ws)
 
2124
{
2210
2125
        ColorPair cp;
2211
 
        XSetWindowAttributes attr;
2212
 
        unsigned long attrmask;
2213
 
        unsigned int bw;
2214
2126
 
 
2127
        /* Setup coloring for the window */
2215
2128
        cp.back = win->title.back;
2216
2129
        cp.fore = win->title.fore;
2217
2130
        if(Scr->workSpaceMgr.windowcpgiven) {
2218
2131
                cp.back = Scr->workSpaceMgr.windowcp.back;
2219
2132
                GetColorFromList(Scr->workSpaceMgr.windowBackgroundL,
2220
 
                                 win->full_name, &win->class, &cp.back);
 
2133
                                 win->name, &win->class, &cp.back);
2221
2134
                cp.fore = Scr->workSpaceMgr.windowcp.fore;
2222
2135
                GetColorFromList(Scr->workSpaceMgr.windowForegroundL,
2223
 
                                 win->full_name, &win->class, &cp.fore);
 
2136
                                 win->name, &win->class, &cp.fore);
2224
2137
        }
2225
2138
        if(Scr->use3Dwmap && !Scr->BeNiceToColormap) {
2226
2139
                GetShadeColors(&cp);
2227
2140
        }
2228
 
        for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
2229
 
                wf = (float)(vs->wsw->wwidth  - 2) / (float) vs->w;
2230
 
                hf = (float)(vs->wsw->wheight - 2) / (float) vs->h;
 
2141
 
 
2142
        /* We need a copy in each VS */
 
2143
        for(VirtualScreen *vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
 
2144
                unsigned int bw;
 
2145
                WinList *wl;
 
2146
                const float wf = (float)(vs->wsw->wwidth  - 2) / (float) vs->w;
 
2147
                const float hf = (float)(vs->wsw->wheight - 2) / (float) vs->h;
 
2148
                MapSubwindow *msw = vs->wsw->mswl[ws->number];
 
2149
 
 
2150
                /* Put together its winlist entry */
2231
2151
                wl = malloc(sizeof(struct winList));
2232
2152
                wl->wlist  = ws;
2233
2153
                wl->x      = (int)(win->frame_x * wf);
2234
2154
                wl->y      = (int)(win->frame_y * hf);
2235
2155
                wl->width  = (unsigned int)((win->frame_width  * wf) + 0.5);
2236
2156
                wl->height = (unsigned int)((win->frame_height * hf) + 0.5);
 
2157
                wl->cp     = cp;
 
2158
                wl->twm_win = win;
 
2159
 
 
2160
                /* Size the window bits */
2237
2161
                bw = 0;
2238
2162
                if(!Scr->use3Dwmap) {
2239
2163
                        bw = 1;
2240
2164
                        wl->width  -= 2;
2241
2165
                        wl->height -= 2;
2242
2166
                }
2243
 
                if(wl->width  < 1) {
 
2167
                if(wl->width < 1) {
2244
2168
                        wl->width  = 1;
2245
2169
                }
2246
2170
                if(wl->height < 1) {
2247
2171
                        wl->height = 1;
2248
2172
                }
2249
 
                wl->w = XCreateSimpleWindow(dpy, vs->wsw->mswl [ws->number]->w, wl->x, wl->y,
2250
 
                                            wl->width, wl->height, bw, Scr->Black, cp.back);
2251
 
                attrmask = 0;
2252
 
                if(Scr->BackingStore) {
2253
 
                        attr.backing_store = WhenMapped;
2254
 
                        attrmask |= CWBackingStore;
 
2173
 
 
2174
                /* Create its little window */
 
2175
                wl->w = XCreateSimpleWindow(dpy, msw->w, wl->x, wl->y,
 
2176
                                            wl->width, wl->height, bw,
 
2177
                                            Scr->Black, cp.back);
 
2178
 
 
2179
                /* Setup cursor and attributes for it */
 
2180
                {
 
2181
                        XSetWindowAttributes attr;
 
2182
                        unsigned long attrmask;
 
2183
 
 
2184
                        attr.cursor = handCursor;
 
2185
                        attrmask = CWCursor;
 
2186
 
 
2187
                        if(Scr->BackingStore) {
 
2188
                                attr.backing_store = WhenMapped;
 
2189
                                attrmask |= CWBackingStore;
 
2190
                        }
 
2191
 
 
2192
                        XChangeWindowAttributes(dpy, wl->w, attrmask, &attr);
2255
2193
                }
2256
 
                attr.cursor = handCursor;
2257
 
                attrmask |= CWCursor;
2258
 
                XChangeWindowAttributes(dpy, wl->w, attrmask, &attr);
 
2194
 
 
2195
                /* Setup events and stash context bits */
2259
2196
                XSelectInput(dpy, wl->w, ExposureMask);
2260
2197
                XSaveContext(dpy, wl->w, TwmContext, (XPointer) vs->wsw->twm_win);
2261
2198
                XSaveContext(dpy, wl->w, ScreenContext, (XPointer) Scr);
2262
2199
                XSaveContext(dpy, wl->w, MapWListContext, (XPointer) wl);
2263
 
                wl->twm_win = win;
2264
 
                wl->cp      = cp;
2265
 
                wl->next    = vs->wsw->mswl [ws->number]->wl;
2266
 
                vs->wsw->mswl [ws->number]->wl = wl;
 
2200
 
 
2201
                /* Link it onto the front of the list */
 
2202
                wl->next = msw->wl;
 
2203
                msw->wl  = wl;
 
2204
 
 
2205
                /*
 
2206
                 * And map it, if its window is mapped.  That'll kick an expose
 
2207
                 * event, which will work its way down to WMapRedrawWindow(), and
 
2208
                 * fill things in.
 
2209
                 */
2267
2210
                if(win->mapped) {
2268
2211
                        XMapWindow(dpy, wl->w);
2269
2212
                }
2270
 
        }
2271
 
}
2272
 
 
2273
 
void
2274
 
WMapRemoveFromList(TwmWindow *win, WorkSpace *ws)
 
2213
        } // And around to the next vscreen
 
2214
}
 
2215
 
 
2216
 
 
2217
/*
 
2218
 * Remove a window from any WSM maps it's in.  Called during window
 
2219
 * destruction process.
 
2220
 *
 
2221
 * (previously: WMapDestroyWindow())
 
2222
 */
 
2223
void
 
2224
WMapRemoveWindow(TwmWindow *win)
 
2225
{
 
2226
        WorkSpace *ws;
 
2227
 
 
2228
        for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
 
2229
                if(OCCUPY(win, ws)) {
 
2230
                        WMapRemoveWindowFromWorkspace(win, ws);
 
2231
                }
 
2232
        }
 
2233
 
 
2234
        /*
 
2235
         * If it's a mapped occupy window, manually hide aways its bits in
 
2236
         * here.
 
2237
         *
 
2238
         * XXX Better belongs inline in caller or separate func?  This is the
 
2239
         * only thing exposing occupyWin out of occupation.c.
 
2240
         */
 
2241
        if(win == occupyWin) {
 
2242
                OccupyWindow *occwin = Scr->workSpaceMgr.occupyWindow;
 
2243
                XUnmapWindow(dpy, occwin->twm_win->frame);
 
2244
                occwin->twm_win->mapped = false;
 
2245
                occwin->twm_win->occupation = 0;
 
2246
                occupyWin = NULL;
 
2247
        }
 
2248
}
 
2249
 
 
2250
 
 
2251
/*
 
2252
 * Remove window's WSM representation.  Happens from WMapRemoveWindow()
 
2253
 * as part of the window destruction process, and in the occupation
 
2254
 * change process.
 
2255
 *
 
2256
 * (previously: WMapRemoveFromList())
 
2257
 */
 
2258
void
 
2259
WMapRemoveWindowFromWorkspace(TwmWindow *win, WorkSpace *ws)
2275
2260
{
2276
2261
        VirtualScreen *vs;
2277
 
        WinList wl, *prev;
2278
2262
 
2279
2263
        for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
2280
 
                prev = &vs->wsw->mswl [ws->number]->wl;
2281
 
                wl = *prev;
2282
 
                while(wl != NULL) {
2283
 
                        if(win == wl->twm_win) {
2284
 
                                *prev = wl->next;
2285
 
                                XDeleteContext(dpy, wl->w, TwmContext);
2286
 
                                XDeleteContext(dpy, wl->w, ScreenContext);
2287
 
                                XDeleteContext(dpy, wl->w, MapWListContext);
2288
 
                                XDestroyWindow(dpy, wl->w);
2289
 
                                free(wl);
2290
 
                                break;
 
2264
                WinList **prev = &vs->wsw->mswl[ws->number]->wl;
 
2265
 
 
2266
                /* Pull it out of the list and destroy it */
 
2267
                for(WinList *wl = *prev ; wl != NULL ; wl = wl->next) {
 
2268
                        if(win != wl->twm_win) {
 
2269
                                /* Not it */
 
2270
                                prev = &wl->next;
 
2271
                                continue;
2291
2272
                        }
2292
 
                        prev = &wl->next;
2293
 
                        wl   = *prev;
2294
 
                }
2295
 
        }
2296
 
}
2297
 
 
2298
 
static void ResizeWorkSpaceManager(VirtualScreen *vs, TwmWindow *win)
2299
 
{
2300
 
        int           bwidth, bheight;
2301
 
        int           wwidth, wheight;
2302
 
        int           hspace, vspace;
2303
 
        int           lines, columns;
2304
 
        int           neww, newh;
2305
 
        WorkSpace     *ws;
2306
 
        TwmWindow     *tmp_win;
2307
 
        WinList       wl;
2308
 
        int           i, j;
2309
 
        float         wf, hf;
2310
 
 
2311
 
        neww = win->attr.width;
2312
 
        newh = win->attr.height;
2313
 
        if(neww == vs->wsw->width && newh == vs->wsw->height) {
2314
 
                return;
2315
 
        }
2316
 
 
2317
 
        hspace  = Scr->workSpaceMgr.hspace;
2318
 
        vspace  = Scr->workSpaceMgr.vspace;
2319
 
        lines   = Scr->workSpaceMgr.lines;
2320
 
        columns = Scr->workSpaceMgr.columns;
2321
 
        bwidth  = (neww - (columns * hspace)) / columns;
2322
 
        bheight = (newh - (lines   * vspace)) / lines;
2323
 
        wwidth  = neww / columns;
2324
 
        wheight = newh / lines;
2325
 
        wf = (float)(wwidth  - 2) / (float) vs->w;
2326
 
        hf = (float)(wheight - 2) / (float) vs->h;
2327
 
 
2328
 
        i = 0;
2329
 
        j = 0;
2330
 
        for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
2331
 
                MapSubwindow *msw = vs->wsw->mswl [ws->number];
2332
 
                XMoveResizeWindow(dpy, vs->wsw->bswl [ws->number]->w,
2333
 
                                  i * (bwidth  + hspace) + (hspace / 2),
2334
 
                                  j * (bheight + vspace) + (vspace / 2),
2335
 
                                  bwidth, bheight);
2336
 
                msw->x = i * wwidth;
2337
 
                msw->y = j * wheight;
2338
 
                XMoveResizeWindow(dpy, msw->w, msw->x, msw->y, wwidth - 2, wheight - 2);
2339
 
                for(wl = msw->wl; wl != NULL; wl = wl->next) {
2340
 
                        tmp_win    = wl->twm_win;
2341
 
                        wl->x      = (int)(tmp_win->frame_x * wf);
2342
 
                        wl->y      = (int)(tmp_win->frame_y * hf);
2343
 
                        wl->width  = (unsigned int)((tmp_win->frame_width  * wf) + 0.5);
2344
 
                        wl->height = (unsigned int)((tmp_win->frame_height * hf) + 0.5);
2345
 
                        XMoveResizeWindow(dpy, wl->w, wl->x, wl->y, wl->width, wl->height);
2346
 
                }
2347
 
                i++;
2348
 
                if(i == columns) {
2349
 
                        i = 0;
2350
 
                        j++;
2351
 
                };
2352
 
        }
2353
 
        vs->wsw->bwidth    = bwidth;
2354
 
        vs->wsw->bheight   = bheight;
2355
 
        vs->wsw->width     = neww;
2356
 
        vs->wsw->height    = newh;
2357
 
        vs->wsw->wwidth     = wwidth;
2358
 
        vs->wsw->wheight    = wheight;
2359
 
        PaintWorkSpaceManager(vs);
2360
 
}
2361
 
 
2362
 
 
2363
 
void WMapCreateCurrentBackGround(char *border,
2364
 
                                 char *background, char *foreground,
2365
 
                                 char *pixmap)
2366
 
{
2367
 
        Image *image;
2368
 
        WorkSpaceMgr *ws = &Scr->workSpaceMgr;
2369
 
 
2370
 
        ws->curBorderColor = Scr->Black;
2371
 
        ws->curColors.back = Scr->White;
2372
 
        ws->curColors.fore = Scr->Black;
2373
 
        ws->curImage       = NULL;
2374
 
 
2375
 
        if(border == NULL) {
2376
 
                return;
2377
 
        }
2378
 
        GetColor(Scr->Monochrome, &ws->curBorderColor, border);
2379
 
        if(background == NULL) {
2380
 
                return;
2381
 
        }
2382
 
        ws->curPaint = true;
2383
 
        GetColor(Scr->Monochrome, &ws->curColors.back, background);
2384
 
        if(foreground == NULL) {
2385
 
                return;
2386
 
        }
2387
 
        GetColor(Scr->Monochrome, &ws->curColors.fore, foreground);
2388
 
 
2389
 
        if(pixmap == NULL) {
2390
 
                return;
2391
 
        }
2392
 
        if((image = GetImage(pixmap, Scr->workSpaceMgr.curColors)) == NULL) {
2393
 
                fprintf(stderr, "Can't find pixmap %s\n", pixmap);
2394
 
                return;
2395
 
        }
2396
 
        ws->curImage = image;
2397
 
}
2398
 
 
2399
 
void WMapCreateDefaultBackGround(char *border,
2400
 
                                 char *background, char *foreground,
2401
 
                                 char *pixmap)
2402
 
{
2403
 
        Image *image;
2404
 
        WorkSpaceMgr *ws = &Scr->workSpaceMgr;
2405
 
 
2406
 
        ws->defBorderColor = Scr->Black;
2407
 
        ws->defColors.back = Scr->White;
2408
 
        ws->defColors.fore = Scr->Black;
2409
 
        ws->defImage       = NULL;
2410
 
 
2411
 
        if(border == NULL) {
2412
 
                return;
2413
 
        }
2414
 
        GetColor(Scr->Monochrome, &ws->defBorderColor, border);
2415
 
        if(background == NULL) {
2416
 
                return;
2417
 
        }
2418
 
        GetColor(Scr->Monochrome, &ws->defColors.back, background);
2419
 
        if(foreground == NULL) {
2420
 
                return;
2421
 
        }
2422
 
        GetColor(Scr->Monochrome, &ws->defColors.fore, foreground);
2423
 
        if(pixmap == NULL) {
2424
 
                return;
2425
 
        }
2426
 
        if((image = GetImage(pixmap, ws->defColors)) == NULL) {
2427
 
                return;
2428
 
        }
2429
 
        ws->defImage = image;
 
2273
 
 
2274
                        /* There you are.  Unlink and kill */
 
2275
                        *prev = wl->next;
 
2276
 
 
2277
                        XDeleteContext(dpy, wl->w, TwmContext);
 
2278
                        XDeleteContext(dpy, wl->w, ScreenContext);
 
2279
                        XDeleteContext(dpy, wl->w, MapWListContext);
 
2280
                        XDestroyWindow(dpy, wl->w);
 
2281
                        free(wl);
 
2282
 
 
2283
                        /* Around to the next vscreen */
 
2284
                        break;
 
2285
                }
 
2286
        }
 
2287
}
 
2288
 
 
2289
 
 
2290
 
 
2291
 
 
2292
/*
 
2293
 ****************************************************************
 
2294
 *
 
2295
 * Utils-ish funcs
 
2296
 *
 
2297
 ****************************************************************
 
2298
 */
 
2299
 
 
2300
/*
 
2301
 * This is really more util.c fodder, but leaving it here for now because
 
2302
 * it's only used once in WMapRedrawName().  If we start finding external
 
2303
 * uses for it, it should be moved.
 
2304
 */
 
2305
static void
 
2306
InvertColorPair(ColorPair *cp)
 
2307
{
 
2308
        Pixel save;
 
2309
 
 
2310
        save = cp->fore;
 
2311
        cp->fore = cp->back;
 
2312
        cp->back = save;
 
2313
        save = cp->shadc;
 
2314
        cp->shadc = cp->shadd;
 
2315
        cp->shadd = save;
 
2316
}
 
2317
 
 
2318
 
 
2319
/*
 
2320
 * Verify if a window may be added to the workspace map.
 
2321
 * This is not allowed for
 
2322
 * - icon managers
 
2323
 * - the occupy window
 
2324
 * - workspace manager windows
 
2325
 * - or, optionally, windows with full occupation.
 
2326
 */
 
2327
bool
 
2328
WMapWindowMayBeAdded(TwmWindow *win)
 
2329
{
 
2330
        if(win->isiconmgr) {
 
2331
                return false;
 
2332
        }
 
2333
        if(win == Scr->workSpaceMgr.occupyWindow->twm_win) {
 
2334
                return false;
 
2335
        }
 
2336
        if(win->iswspmgr) {
 
2337
                return false;
 
2338
        }
 
2339
        if(Scr->workSpaceMgr.noshowoccupyall &&
 
2340
                        win->occupation == fullOccupation) {
 
2341
                return false;
 
2342
        }
 
2343
        return true;
2430
2344
}