CTWM
Loading...
Searching...
No Matches
/usr/src/RPM/BUILD/ctwm-4.1.0/workspace_manager.c
Go to the documentation of this file.
1/*
2 * Copyright 1992 Claude Lecommandeur.
3 */
4
5#include "ctwm.h"
6
7#include <stdio.h>
8#include <string.h>
9#include <stdlib.h>
10
11#include <X11/Xatom.h>
12
13#include "ctwm_atoms.h"
14#include "util.h"
15#include "animate.h"
16#include "screen.h"
17#include "add_window.h"
18#include "events.h"
19#include "otp.h"
20#include "cursor.h"
21#include "image.h"
22#include "drawing.h"
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
34
35#include "gram.tab.h"
36
37
38// Temp; x-ref desc in workspace_utils
39extern bool useBackgroundInfo;
40
41
45
46static void wmap_mapwin_backend(TwmWindow *win, bool handleraise);
47
48static void WMapRedrawWindow(Window window, int width, int height,
49 ColorPair cp, const char *label);
50
51static void InvertColorPair(ColorPair *cp);
52
53
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 */
71void
78
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 */
90void
92{
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.
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
115 /*
116 * Make sure this is all properly initialized to nothing. Otherwise
117 * bad and undefined behavior can show up in certain cases (e.g.,
118 * with no Workspaces {} defined in .ctwmrc, the only defined
119 * workspace will be random memory bytes, which can causes crashes on
120 * e.g. f.menu "TwmWindows".)
121 */
122 WorkSpaceWindow *wsw = calloc(1, sizeof(WorkSpaceWindow));
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
140 vs->wsw = wsw;
141 }
142
143 free(vsmapbuf);
144}
145
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.
153 */
154void
156{
157 if(! Scr->workSpaceManagerActive) {
158 return;
159 }
160
161 /* Setup basic fonts/colors/cursors */
162 Scr->workSpaceMgr.windowFont.basename =
163 "-adobe-courier-medium-r-normal--10-100-75-75-m-60-iso8859-1";
164 Scr->workSpaceMgr.buttonFont = Scr->IconManagerFont;
165 Scr->workSpaceMgr.cp = Scr->IconManagerC;
166 if(!Scr->BeNiceToColormap) {
167 GetShadeColors(&Scr->workSpaceMgr.cp);
168 }
169 if(handCursor == None) {
170 NewFontCursor(&handCursor, "top_left_arrow");
171 }
172
173
174 /*
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).
178 */
179 for(VirtualScreen *vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
181 }
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 */
202 if(Scr->workSpaceMgr.curImage == NULL) {
203 if(Scr->workSpaceMgr.curPaint) {
204 XSetWindowBackground(dpy, msw->w, Scr->workSpaceMgr.curColors.back);
205 }
206 }
207 else {
208 XSetWindowBackgroundPixmap(dpy, msw->w, Scr->workSpaceMgr.curImage->pixmap);
209 }
210 XSetWindowBorder(dpy, msw->w, Scr->workSpaceMgr.curBorderColor);
211 XClearWindow(dpy, msw->w);
212
213 /* Set the root window to the color/image of that WS if we should */
214 if(useBackgroundInfo && ! Scr->DontPaintRootWindow) {
215 if(ws2->image == NULL) {
216 XSetWindowBackground(dpy, vs->window, ws2->backcp.back);
217 }
218 else {
219 XSetWindowBackgroundPixmap(dpy, vs->window, ws2->image->pixmap);
220 }
221 XClearWindow(dpy, vs->window);
222 }
223 }
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 */
236 {
237 char *wrkSpcList;
238 int len;
239
240 len = GetPropertyFromMask(0xFFFFFFFFu, &wrkSpcList);
242 PropModeReplace, (unsigned char *) wrkSpcList, len);
244 }
245}
246
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 */
253static void
255{
256 unsigned int width, height;
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. */
265 if(count == 0) {
266 return;
267 }
268
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) {
302 unsigned short wid;
303 const MyFont font = Scr->workSpaceMgr.buttonFont;
304
305 XmbTextExtents(font.font_set, ws->label, strlen(ws->label),
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;
359 }
360 else {
362 }
363 }
364 else {
365 x = (vs->w - width) / 2;
366 gravity = (mask & YValue) ? ((mask & YNegative) ?
368 }
369 }
370 else {
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;
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 */
391 vs->wsw->w = XCreateSimpleWindow(dpy, Scr->Root, x, y, width, height, 0,
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) {
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,
418 0, Scr->Black, ws->cp.back);
419
420 msw->w = XCreateSimpleWindow(dpy, vs->wsw->w,
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() */
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 {
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
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 */
492 Scr->iconmgr, vs);
493 if(! tmp_win) {
494 fprintf(stderr, "cannot create workspace manager window, exiting...\n");
495 exit(1);
496 }
497 tmp_win->occupation = fullOccupation;
498 tmp_win->attr.width = width;
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 */
505
506
507 /* Setup cursor/gravity and listen for events */
508 {
511 unsigned long attrmask;
512
513 attr.cursor = Scr->ButtonCursor;
514 attr.win_gravity = gravity;
517
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
549 | ExposureMask);
552
556 }
557
558
559 /* Set WM_STATE prop */
561
562
563 /* Setup root window if necessary */
564 /* XXX X-ref CTAG_BGDRAW in CreateWorkSpaceManager() */
565 if(useBackgroundInfo && ! Scr->DontPaintRootWindow) {
566 WorkSpace *ws = Scr->workSpaceMgr.workSpaceList;
567 if(ws->image == NULL) {
568 XSetWindowBackground(dpy, Scr->Root, ws->backcp.back);
569 }
570 else {
571 XSetWindowBackgroundPixmap(dpy, Scr->Root, ws->image->pixmap);
572 }
573 XClearWindow(dpy, Scr->Root);
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 */
588static void
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 */
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 */
662}
663
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 */
677void
679{
680 WorkSpace *ws;
681
682 /* x-ref header comment */
683 return;
684
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 */
699static void
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 */
715void
717{
718 if(vs->wsw->state == WMS_buttons) {
720 WorkSpace *ws;
721
722 /* Find the button we're exposing */
723 for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
724 buttonw = vs->wsw->bswl[ws->number]->w;
725 if(event->xexpose.window == buttonw) {
726 break;
727 }
728 }
729
730 /* If none, just paint the border. Else paint the button. */
731 if(ws == NULL) {
733 }
734 else {
735 ButtonState bs = (ws == vs->wsw->currentwspc) ? on : off;
736 PaintWsButton(WSPCWINDOW, vs, buttonw, ws->label, ws->cp, bs);
737 }
738 }
739 else {
740 WinList *wl;
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 */
747 if(XFindContext(dpy, event->xexpose.window, MapWListContext,
748 (XPointer *) &wl) == XCNOENT) {
749 return;
750 }
751 if(wl && wl->twm_win && wl->twm_win->mapped) {
752 WMapRedrawName(vs, wl);
753 }
754 }
755}
756
757
758
759/*
760 * Moving the WSM between button and map state
761 */
762void
764{
765 if(vs->wsw->state == WMS_buttons) {
766 WMgrSetMapState(vs);
767 }
768 else {
770 }
771}
772
773void
775{
776 WorkSpace *ws;
777
778 if(vs->wsw->state == WMS_map) {
779 return;
780 }
781 for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
782 XUnmapWindow(dpy, vs->wsw->bswl [ws->number]->w);
783 XMapWindow(dpy, vs->wsw->mswl [ws->number]->w);
784 }
785 vs->wsw->state = WMS_map;
786 MaybeAnimate = true;
787}
788
789void
791{
792 WorkSpace *ws;
793
794 if(vs->wsw->state == WMS_buttons) {
795 return;
796 }
797 for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
798 XUnmapWindow(dpy, vs->wsw->mswl [ws->number]->w);
799 XMapWindow(dpy, vs->wsw->bswl [ws->number]->w);
800 }
801 vs->wsw->state = WMS_buttons;
802}
803
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 */
821void
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
839void
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 */
860 if(vs->wsw->state == WMS_map) {
861 return;
862 }
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 */
868 for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
869 if(vs->wsw->bswl[ws->number]->w == event->xkey.subwindow) {
870 break;
871 }
872 }
873 if(ws == NULL) {
874 /* Not on a button, nothing to do */
875 return;
876 }
877
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);
936 }
937}
938
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 */
948void
950{
952 WinList *wl;
953 TwmWindow *win;
954 unsigned int W0, H0;
956 Window w = 0;
957 Position newX = 0, newY = 0, winX = 0, winY = 0;
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 */
970 if(vs->wsw->state == WMS_buttons) {
971 WorkSpace *ws;
972 for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
973 if(vs->wsw->bswl[ws->number]->w == parent) {
974 GotoWorkSpace(vs, ws);
975 break;
976 }
977 }
978 return;
979 }
980
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) {
992 break;
993 }
994 }
995 if(oldws == NULL) {
996 /* None? We're done here. */
997 return;
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 */
1004 if(sw == (Window) 0) {
1005 GotoWorkSpace(vs, oldws);
1006 return;
1007 }
1008
1009 /* Use the context to find the winlist entry for this window */
1010 if(XFindContext(dpy, sw, MapWListContext, (XPointer *) &wl) == XCNOENT) {
1011 return;
1012 }
1013 win = wl->twm_win;
1014
1015 /*
1016 * Sometimes we skip transients, so do so. XXX Should this
1017 * GotoWorkSpace()?
1018 */
1019 if((! Scr->TransientHasOccupation) && win->istransient) {
1020 return;
1021 }
1022
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 */
1046 if(win->OpaqueMove) {
1047 if(Scr->OpaqueMoveThreshold >= 200) {
1048 Scr->OpaqueMove = true;
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 }
1061 }
1062 else {
1063 Scr->OpaqueMove = false;
1064 }
1065
1066 /*
1067 * Buttons inside the workspace manager, when clicking on the
1068 * representation of a window:
1069 * 1: drag window to a different workspace
1070 * 2: drag a copy of the window to a different workspace
1071 * (show it in both workspaces)
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.
1076 */
1077 switch(button) {
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 */
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;
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,
1112 mw->w, X0, Y0, &X1, &Y1, &junkW);
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 */
1119 attrs.event_mask = ExposureMask;
1120 attrs.background_pixel = wl->cp.back;
1121 attrs.border_pixel = wl->cp.back;
1122 w = XCreateWindow(dpy, mw->w, X1, Y1, W0, H0, bw,
1125 &attrs);
1126 XMapRaised(dpy, w);
1127
1128 /* Do our dance on it to draw the name/color/etc */
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 */
1137 if(realmovemode && Scr->ShowWinWhenMovingInWmgr) {
1138 if(Scr->OpaqueMove) {
1139 DisplayWin(vs, win);
1140 }
1141 else {
1142 MoveOutline(Scr->Root,
1143 win->frame_x - win->frame_bw,
1144 win->frame_y - win->frame_bw,
1145 win->frame_width + 2 * win->frame_bw,
1146 win->frame_height + 2 * win->frame_bw,
1147 win->frame_bw,
1148 win->title_height + win->frame_bw3D);
1149 }
1150 }
1151
1152 /* Move onward */
1153 break;
1154 }
1155
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) {
1164 }
1165 return;
1166 }
1167
1168 default :
1169 return;
1170 }
1171
1172 /*
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...
1177 */
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,
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 */
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();
1226 break;
1227 }
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;
1251 }
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;
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. */
1284 break;
1285 }
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 */
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) {
1365 goto movewin;
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
1433movewin:
1434 /*
1435 * However we get here, the real window is
1436 * visible and needs to be moved. So move it.
1437 */
1438 if(Scr->OpaqueMove) {
1439 XMoveWindow(dpy, win->frame, winX, winY);
1440 }
1441 else {
1442 MoveOutline(Scr->Root,
1443 winX - win->frame_bw,
1444 winY - win->frame_bw,
1445 win->frame_width + 2 * win->frame_bw,
1446 win->frame_height + 2 * win->frame_bw,
1447 win->frame_bw,
1448 win->title_height + win->frame_bw3D);
1449 }
1450 }
1451
1452move:
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! */
1460 break;
1461 }
1462 }
1463 }
1464 }
1465
1466 /*
1467 * Finished with dragging (button released).
1468 */
1469 if(realmovemode) {
1470 /* Moving the real window? Move the real window. */
1471 if(Scr->ShowWinWhenMovingInWmgr || alreadyvivible) {
1472 if(Scr->OpaqueMove && !OCCUPY(win, vs->wsw->currentwspc)) {
1473 Vanish(vs, win);
1474 }
1475 if(!Scr->OpaqueMove) {
1476 MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
1477 WMapRedrawName(vs, wl);
1478 }
1479 }
1480 SetupWindow(win, winX, winY, win->frame_width, win->frame_height, -1);
1481 }
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;
1490
1491 /* End our grab */
1493
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) {
1513 char keys [32];
1514
1515 /* Re-show old miniwindow, destroy the temp, and warp to WS */
1516 XMapWindow(dpy, sw);
1517 XDestroyWindow(dpy, w);
1518 GotoWorkSpace(vs, oldws);
1519 if(!Scr->DontWarpCursorInWMap) {
1520 WarpToWindow(win, Scr->RaiseOnWarp);
1521 }
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 */
1561 if((keys [control_L_code / 8] & ((char) 0x80 >> (control_L_code % 8))) ||
1562 keys [control_R_code / 8] & ((char) 0x80 >> (control_R_code % 8))) {
1563 WMgrToggleState(vs);
1564 }
1565 return;
1566 }
1567
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];
1573 if((newX >= msw->x) && (newX < msw->x + mw->wwidth) &&
1574 (newY >= msw->y) && (newY < msw->y + mw->wheight)) {
1575 break;
1576 }
1577 }
1578
1579 /* And finish off whatever we're supposed to be doing */
1580 switch(button) {
1581 case 1 : { /* moving to another workspace */
1582 int occupation;
1583
1584 /* If nothing to change, re-map avatar and we're done */
1585 if((newws == NULL) || (newws == oldws) ||
1586 OCCUPY(wl->twm_win, newws)) {
1587 XMapWindow(dpy, sw);
1588 break;
1589 }
1590
1591 /* Out of the old, into the new */
1592 occupation = win->occupation;
1593 occupation |= (1 << newws->number);
1594 occupation &= ~(1 << oldws->number);
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 */
1601 if(newws == vs->wsw->currentwspc) {
1602 OtpRaise(win, WinWin);
1603 WMapRaise(win);
1604 }
1605 else {
1607 }
1608
1609 break;
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 */
1616 if((newws == NULL) || (newws == oldws) ||
1617 OCCUPY(wl->twm_win, newws)) {
1618 break;
1619 }
1620
1621 /* Move */
1622 occupation = win->occupation | (1 << newws->number);
1623 ChangeOccupation(win, occupation);
1624
1625 /* Raise/stack */
1626 if(newws == vs->wsw->currentwspc) {
1627 OtpRaise(win, WinWin);
1628 WMapRaise(win);
1629 }
1630 else {
1632 }
1633 break;
1634 }
1635
1636 /*
1637 * Should actually never hit this state; only 1/2 would have
1638 * gotten this far into the code...
1639 */
1640 default :
1641 return;
1642 }
1643
1644 /* Clean up our temporary moving-around-in the WSM window */
1645 XDestroyWindow(dpy, w);
1646}
1647
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.
1661 */
1662static void
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 */
1703void
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 */
1717void
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 */
1734void
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 */
1761void
1762WMapSetupWindow(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 */
1851void
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
1863void
1865{
1866 WMapRaiseLower(win);
1867}
1868
1869void
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 */
1883void
1885{
1886 WinList *wl;
1887 Window root, parent; // Dummy
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);
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);
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 */
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 */
1972void
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 */
1996void
1998{
1999 ColorPair cp = wl->cp;
2000
2001 if(Scr->ReverseCurrentWorkspace && wl->wlist == vs->wsw->currentwspc) {
2002 InvertColorPair(&cp);
2003 }
2004 WMapRedrawWindow(wl->w, wl->width, wl->height, cp, wl->twm_win->icon_name);
2005}
2006
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 */
2017static void
2018WMapRedrawWindow(Window window, int width, int height,
2019 ColorPair cp, const char *label)
2020{
2021 int x, y;
2022 const MyFont font = Scr->workSpaceMgr.windowFont;
2023
2024 /* Blank out window background color */
2025 XClearWindow(dpy, window);
2026
2027 /* Figure out where to position the name */
2028 {
2031 int strhei, strwid;
2032 int i, descent;
2034 char **font_names;
2035 int fnum;
2036
2037 XmbTextExtents(font.font_set, label, strlen(label),
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
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 */
2066 if(Scr->use3Dwmap) {
2067 Draw3DBorder(window, 0, 0, width, height, 1, cp, off, true, false);
2068 FB(cp.fore, cp.back);
2069 }
2070 else {
2071 FB(cp.back, cp.fore);
2072 XFillRectangle(dpy, window, Scr->NormalGC, 0, 0, width, height);
2073 FB(cp.fore, cp.back);
2074 }
2075
2076 /* Write in the name */
2077 if(Scr->Monochrome != COLOR) {
2078 XmbDrawImageString(dpy, window, font.font_set, Scr->NormalGC, x, y,
2079 label, strlen(label));
2080 }
2081 else {
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 */
2098void
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)) {
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 */
2122void
2124{
2125 ColorPair cp;
2126
2127 /* Setup coloring for the window */
2128 cp.back = win->title.back;
2129 cp.fore = win->title.fore;
2130 if(Scr->workSpaceMgr.windowcpgiven) {
2131 cp.back = Scr->workSpaceMgr.windowcp.back;
2132 GetColorFromList(Scr->workSpaceMgr.windowBackgroundL,
2133 win->name, &win->class, &cp.back);
2134 cp.fore = Scr->workSpaceMgr.windowcp.fore;
2135 GetColorFromList(Scr->workSpaceMgr.windowForegroundL,
2136 win->name, &win->class, &cp.fore);
2137 }
2138 if(Scr->use3Dwmap && !Scr->BeNiceToColormap) {
2139 GetShadeColors(&cp);
2140 }
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 */
2151 wl = malloc(sizeof(struct winList));
2152 wl->wlist = ws;
2153 wl->x = (int)(win->frame_x * wf);
2154 wl->y = (int)(win->frame_y * hf);
2155 wl->width = (unsigned int)((win->frame_width * wf) + 0.5);
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 */
2161 bw = 0;
2162 if(!Scr->use3Dwmap) {
2163 bw = 1;
2164 wl->width -= 2;
2165 wl->height -= 2;
2166 }
2167 if(wl->width < 1) {
2168 wl->width = 1;
2169 }
2170 if(wl->height < 1) {
2171 wl->height = 1;
2172 }
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 {
2182 unsigned long attrmask;
2183
2184 attr.cursor = handCursor;
2186
2187 if(Scr->BackingStore) {
2188 attr.backing_store = WhenMapped;
2190 }
2191
2192 XChangeWindowAttributes(dpy, wl->w, attrmask, &attr);
2193 }
2194
2195 /* Setup events and stash context bits */
2197 XSaveContext(dpy, wl->w, TwmContext, (XPointer) vs->wsw->twm_win);
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 */
2210 if(win->mapped) {
2211 XMapWindow(dpy, wl->w);
2212 }
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 */
2223void
2225{
2226 WorkSpace *ws;
2227
2228 for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
2229 if(OCCUPY(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 */
2258void
2260{
2261 VirtualScreen *vs;
2262
2263 for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
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;
2272 }
2273
2274 /* There you are. Unlink and kill */
2275 *prev = wl->next;
2276
2277 XDeleteContext(dpy, wl->w, TwmContext);
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 */
2305static void
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 */
2327bool
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;
2344}
static int PlaceX
Definition add_window.c:82
TwmWindow * AddWindow(Window w, AWType wtype, IconMgr *iconp, VirtualScreen *vs)
Definition add_window.c:113
@ AWT_WORKSPACE_MANAGER
Definition add_window.h:27
bool MaybeAnimate
Definition animate.c:33
#define OCCUPY(w, b)
Definition ctwm.h:369
XContext ScreenContext
Definition ctwm_main.c:121
Display * dpy
Definition ctwm_main.c:84
XContext TwmContext
Definition ctwm_main.c:119
#define FB(fix_fore, fix_back)
Definition ctwm.h:119
unsigned int JunkDepth
Definition ctwm.h:359
#define Scr
void NewFontCursor(Cursor *cp, const char *str)
Definition cursor.c:117
void Draw3DBorder(Window w, int x, int y, int width, int height, int bw, ColorPair cp, ButtonState state, bool fill, bool forcebw)
Definition drawing.c:34
void PaintWsButton(PWBType which, VirtualScreen *vs, Window w, char *label, ColorPair cp, ButtonState state)
Definition drawing.c:153
ButtonState
Definition drawing.h:8
@ off
Definition drawing.h:8
@ on
Definition drawing.h:8
@ WSPCWINDOW
Definition drawing.h:16
bool DispatchEvent(void)
Definition event_core.c:305
XEvent Event
Definition event_core.c:66
VirtualScreen * vScreenList
Linked list of per-VS info.
Definition screen.h:513
int frame_x
X position on screen of frame.
int frame_y
Y position on screen of frame.
Window frame
The X window for the overall frame.
int frame_bw
2d border width.
unsigned int title_height
Height of the full title bar.
unsigned int frame_width
Width of frame.
unsigned int frame_height
Height of frame.
int frame_bw3D
3d border width.
bool GetColorFromList(name_list *list_head, char *name, XClassHint *class, Pixel *ptr)
Definition list.c:194
int y
Definition menus.c:70
int x
Definition menus.c:69
TwmWindow * occupyWin
Definition occupation.c:51
int fullOccupation
Definition occupation.c:43
void ChangeOccupation(TwmWindow *tmp_win, int newoccupation)
int GetPropertyFromMask(unsigned int mask, char **prop)
void ResizeOccupyWindow(TwmWindow *win)
Definition occupation.c:874
void OtpRaise(TwmWindow *twm_win, WinType wintype)
Definition otp.c:763
@ WinWin
Definition otp.h:14
static int len
Definition parse.c:75
MenuRoot * root
Definition parse_yacc.c:26
int cont
Definition parse_yacc.c:28
Pixel back
Definition ctwm.h:141
Pixel shadd
Definition ctwm.h:141
Pixel fore
Definition ctwm.h:141
Pixel shadc
Definition ctwm.h:141
Definition ctwm.h:127
XFontSet font_set
Definition ctwm.h:129
Info and control for each X Screen we control.
Definition screen.h:96
WorkSpaceMgr workSpaceMgr
Info about the WorkSpaceManager (and Occupy window) for the screen.
Definition screen.h:508
Info and control for every X Window we take over.
bool iswspmgr
This is a workspace manager window.
bool OpaqueMove
Move opaquely.
bool isiconmgr
This is an icon manager window.
bool istransient
This is a transient window.
char * name
Current window name. Points into TwmWindow::names.
char * icon_name
Current icon name. Points into TwmWindow::names.
int occupation
Workspaces the window is in (bitmap)
struct VirtualScreen * vs
Where the window is currently mapped (may be NULL)
bool mapped
Is the window mapped ?
XClassHint class
Window class info. From XGetClassHint().
ColorPair title
ColorPair for various other titlebar bits.
XWindowAttributes attr
Window attributes from XGetWindowAttributes()
struct VirtualScreen * next
Definition vscreen.h:12
struct WorkSpaceWindow * wsw
Definition vscreen.h:11
WMgrState initialstate
WorkSpace * currentwspc
ButtonSubwindow ** bswl
MapSubwindow ** mswl
struct WorkSpace * next
struct WorkSpace * wlist
ColorPair cp
TwmWindow * twm_win
struct winList * next
FILE * tracefile
Definition util.c:59
void GetShadeColors(ColorPair *cp)
Try and create a 'shaded' version of a color for prettier UI.
Definition util.c:245
char * CtwmGetVScreenMap(Display *display, Window rootw)
Definition vscreen.c:166
void Vanish(VirtualScreen *vs, TwmWindow *tmp_win)
Definition vscreen.c:344
void DisplayWin(VirtualScreen *vs, TwmWindow *tmp_win)
Definition vscreen.c:232
void SetupWindow(TwmWindow *tmp_win, int x, int y, int w, int h, int bw)
void MoveOutline(Window root, int x, int y, int width, int height, int bw, int th)
Definition win_ops.c:317
TwmWindow * GetTwmWindow(Window w)
Definition win_utils.c:190
void SetMapStateProp(TwmWindow *tmp_win, int state)
Definition win_utils.c:415
void WarpToWindow(TwmWindow *t, bool must_raise)
Definition win_utils.c:883
void WMapLower(TwmWindow *win)
void WMapRedrawName(VirtualScreen *vs, WinList *wl)
static Cursor handCursor
void WMapAddWindowToWorkspace(TwmWindow *win, WorkSpace *ws)
void WMapDeIconify(TwmWindow *win)
void WMapIconify(TwmWindow *win)
void WMgrToggleState(VirtualScreen *vs)
void WMapRemoveWindow(TwmWindow *win)
static void WMapRedrawWindow(Window window, int width, int height, ColorPair cp, const char *label)
static void wmap_mapwin_backend(TwmWindow *win, bool handleraise)
void WMapRestack(WorkSpace *ws)
void WMapSetupWindow(TwmWindow *win, int x, int y, int w, int h)
bool useBackgroundInfo
void InitWorkSpaceManagerContext(void)
void WMapRaiseLower(TwmWindow *win)
void WMgrHandleKeyPressEvent(VirtualScreen *vs, XEvent *event)
static void CreateWorkSpaceManagerWindow(VirtualScreen *vs)
static XContext MapWListContext
void WMapUpdateIconName(TwmWindow *win)
void WMapMapWindow(TwmWindow *win)
void CreateWorkSpaceManager(void)
void WMgrSetButtonsState(VirtualScreen *vs)
bool WMapWindowMayBeAdded(TwmWindow *win)
static void PaintWorkSpaceManagerBorder(VirtualScreen *vs)
void ConfigureWorkSpaceManager(ScreenInfo *scr)
Prep up structures for WSM windows in each VS.
void WMapAddWindow(TwmWindow *win)
void WMapRemoveWindowFromWorkspace(TwmWindow *win, WorkSpace *ws)
void WMgrSetMapState(VirtualScreen *vs)
void WMapRaise(TwmWindow *win)
void PaintWorkSpaceManager(VirtualScreen *vs)
void WMgrHandleExposeEvent(VirtualScreen *vs, XEvent *event)
void WMgrHandleKeyReleaseEvent(VirtualScreen *vs, XEvent *event)
static void InvertColorPair(ColorPair *cp)
static void ResizeWorkSpaceManager(VirtualScreen *vs, TwmWindow *win)
void WMgrHandleButtonEvent(VirtualScreen *vs, XEvent *event)
@ WMS_buttons
@ WMS_map
void GotoWorkSpace(VirtualScreen *vs, WorkSpace *ws)
WorkSpace * GetWorkspace(const char *wname)
int RLayoutXParseGeometry(RLayout *layout, const char *geometry, int *x, int *y, unsigned int *width, unsigned int *height)
Parse an X Geometry out to get the positions and sizes.