CTWM
Loading...
Searching...
No Matches
/usr/src/RPM/BUILD/ctwm-4.1.0/win_utils.c
Go to the documentation of this file.
1/*
2 * Window-handling utility funcs
3 */
4
5#include "ctwm.h"
6
7#include <stdio.h>
8#include <stdlib.h>
9
10#include <X11/Xatom.h>
11
12#include "add_window.h" // NoName
13#include "ctwm_atoms.h"
14#include "drawing.h"
15#include "events.h"
16#include "event_internal.h" // Temp?
17#ifdef EWMH
18# include "ewmh_atoms.h"
19#endif
20#include "icons.h"
21#include "list.h"
22#include "occupation.h"
23#include "otp.h"
24#include "r_area.h"
25#include "r_area_list.h"
26#include "r_layout.h"
27#include "screen.h"
28#include "util.h"
29#include "win_decorations.h"
30#include "win_ops.h"
31#include "win_utils.h"
32#include "workspace_utils.h"
33
34
35/*
36 * Fill in size hints for a window from WM_NORMAL_HINTS prop.
37 *
38 * Formerly in add_window.c
39 */
40void
42{
43 long supplied = 0;
44 XSizeHints *hints = &tmp->hints;
45
46 if(!XGetWMNormalHints(dpy, tmp->w, hints, &supplied)) {
47 hints->flags = 0;
48 }
49
50 if(hints->flags & PResizeInc) {
51 if(hints->width_inc == 0) {
52 hints->width_inc = 1;
53 }
54 if(hints->height_inc == 0) {
55 hints->height_inc = 1;
56 }
57 }
58
59 if(!(supplied & PWinGravity) && (hints->flags & USPosition)) {
60 static int gravs[] = { SouthEastGravity, SouthWestGravity,
62 };
63 int right = tmp->attr.x + tmp->attr.width + 2 * tmp->old_bw;
64 int bottom = tmp->attr.y + tmp->attr.height + 2 * tmp->old_bw;
65 hints->win_gravity =
66 gravs[((Scr->rooth - bottom <
67 tmp->title_height + 2 * tmp->frame_bw3D) ? 0 : 2) |
68 ((Scr->rootw - right <
69 tmp->title_height + 2 * tmp->frame_bw3D) ? 0 : 1)];
70 hints->flags |= PWinGravity;
71 }
72
73 /* Check for min size < max size */
74 if((hints->flags & (PMinSize | PMaxSize)) == (PMinSize | PMaxSize)) {
75 if(hints->max_width < hints->min_width) {
76 if(hints->max_width > 0) {
77 hints->min_width = hints->max_width;
78 }
79 else if(hints->min_width > 0) {
80 hints->max_width = hints->min_width;
81 }
82 else {
83 hints->max_width = hints->min_width = 1;
84 }
85 }
86
87 if(hints->max_height < hints->min_height) {
88 if(hints->max_height > 0) {
89 hints->min_height = hints->max_height;
90 }
91 else if(hints->min_height > 0) {
92 hints->max_height = hints->min_height;
93 }
94 else {
95 hints->max_height = hints->min_height = 1;
96 }
97 }
98 }
99}
100
101
102/*
103 * Fill in info from WM_PROTOCOLS property
104 *
105 * Formerly in add_window.c
106 */
107void
109{
110 unsigned long flags = 0L;
111 Atom *protocols = NULL;
112 int n;
113
114 if(XGetWMProtocols(dpy, tmp->w, &protocols, &n)) {
115 int i;
116 Atom *ap;
117
118 for(i = 0, ap = protocols; i < n; i++, ap++) {
119 if(*ap == XA_WM_TAKE_FOCUS) {
120 flags |= DoesWmTakeFocus;
121 }
122 if(*ap == XA_WM_SAVE_YOURSELF) {
123 flags |= DoesWmSaveYourself;
124 }
125 if(*ap == XA_WM_DELETE_WINDOW) {
126 flags |= DoesWmDeleteWindow;
127 }
128 }
129 if(protocols) {
130 XFree(protocols);
131 }
132 }
133 tmp->protocols = flags;
134}
135
136
137/*
138 * Figure signs for calculating location offsets for a window dependent
139 * on its gravity.
140 *
141 * Depending on how its gravity is set, offsets to window coordinates for
142 * e.g. border widths may need to move either down (right) or up (left).
143 * Or possibly not at all. So we write multipliers into passed vars for
144 * callers.
145 *
146 * Formerly in add_window.c
147 */
148void
150{
151 static struct _gravity_offset {
152 int x, y;
153 } gravity_offsets[] = {
154 [ForgetGravity] = { 0, 0 },
155 [NorthWestGravity] = { -1, -1 },
156 [NorthGravity] = { 0, -1 },
157 [NorthEastGravity] = { 1, -1 },
158 [WestGravity] = { -1, 0 },
159 [CenterGravity] = { 0, 0 },
160 [EastGravity] = { 1, 0 },
161 [SouthWestGravity] = { -1, 1 },
162 [SouthGravity] = { 0, 1 },
163 [SouthEastGravity] = { 1, 1 },
164 [StaticGravity] = { 0, 0 },
165 };
166 int g = ((tmp->hints.flags & PWinGravity)
167 ? tmp->hints.win_gravity : NorthWestGravity);
168
170 *xp = *yp = 0;
171 }
172 else {
173 *xp = gravity_offsets[g].x;
174 *yp = gravity_offsets[g].y;
175 }
176}
177
178
179/*
180 * Finds the TwmWindow structure associated with a Window (if any), or
181 * NULL.
182 *
183 * This is a relatively cheap function since it does not involve
184 * communication with the server. Probably faster than walking the list
185 * of TwmWindows, since the lookup is by a hash table.
186 *
187 * Formerly in add_window.c
188 */
189TwmWindow *
191{
193 int stat;
194
196 if(stat == XCNOENT) {
197 twmwin = NULL;
198 }
199
200 return twmwin;
201}
202
203
204/***********************************************************************
205 *
206 * Procedure:
207 * GetWMPropertyString - Get Window Manager text property and
208 * convert it to a string.
209 *
210 * Returned Value:
211 * (char *) - pointer to the malloc'd string or NULL
212 *
213 * Inputs:
214 * w - the id of the window whose property is to be retrieved
215 * prop - property atom (typically WM_NAME or WM_ICON_NAME)
216 *
217 ***********************************************************************
218 *
219 * Formerly in util.c
220 */
221char *
223{
225 char *stringptr;
226
228 if(text_prop.value == NULL) {
229 return NULL;
230 }
231
232 if(text_prop.encoding == XA_STRING
233 || text_prop.encoding == XA_UTF8_STRING
234 || text_prop.encoding == XA_COMPOUND_TEXT) {
235 /* property is encoded as compound text - convert to locale string */
236 char **text_list;
237 int text_list_count;
238 int status;
239
240 /* Check historical strictness */
241 if(Scr->StrictWinNameEncoding) {
242 bool fail = false;
243
244 if((prop == XA_WM_NAME || prop == XA_WM_ICON_NAME)
245 && text_prop.encoding != XA_STRING
246 && text_prop.encoding != XA_COMPOUND_TEXT) {
247 fail = true;
248 }
249
250#ifdef EWMH
252 && text_prop.encoding != XA_UTF8_STRING) {
253 fail = true;
254 }
255#endif // EWMH
256
257 if(fail) {
258 fprintf(stderr, "%s: Invalid encoding for property %s "
259 "of window 0x%lx\n", ProgramName,
260 XGetAtomName(dpy, prop), w);
261 XFree(text_prop.value);
262 return NULL;
263 }
264 }
265
266
269 if(text_list_count == 0
270 || text_list == NULL
271 || text_list[0] == NULL) {
272 // Got nothing
273 XFree(text_prop.value);
274 return NULL;
275 }
276 else if(status < 0 || text_list_count < 0) {
277 // Got an error statuf
278 switch(status) {
281 "%s: Converter not found; unable to convert property %s of window ID %lx.\n",
283 break;
284 case XNoMemory:
286 "%s: Insufficient memory; unable to convert property %s of window ID %lx.\n",
288 break;
291 "%s: Locale not supported; unable to convert property %s of window ID %lx.\n",
293 break;
294 }
295 stringptr = NULL;
296 /*
297 don't call XFreeStringList - text_list appears to have
298 invalid address if status is bad
299 XFreeStringList(text_list);
300 */
301 }
302 else {
303 // Actually got the data!
306 }
307 }
308 else {
309 /* property is encoded in a format we don't understand */
311 "%s: Encoding not STRING or COMPOUND_TEXT; unable to decode property %s of window ID %lx.\n",
313 stringptr = NULL;
314 }
315 XFree(text_prop.value);
316
317 return stringptr;
318}
319
320
321/*
322 * Cleanup something stored that we got from the above originally.
323 *
324 * Formerly in util.c
325 */
326void
328{
329 if(prop && prop != NoName) {
330 free(prop);
331 }
332}
333
334
335/*
336 * Window mapped on some virtual screen?
337 *
338 * Formerly in util.c
339 */
340bool
342{
343 return (tmp_win->vs != NULL);
344}
345
346
347/*
348 * Various code paths do a dance of "mask off notifications of event type
349 * ; do something that triggers that event (but we're doing it, so we
350 * don't need the notification) ; restore previous mask". So have some
351 * util funcs to make it more visually obvious.
352 *
353 * e.g.:
354 * long prev_mask = mask_out_event(w, PropertyChangeMask);
355 * do_something_that_changes_properties();
356 * restore_mask(prev_mask);
357 *
358 * We're cheating a little with the -1 return on mask_out_event(), as
359 * that's theoretically valid for the data type. It's not as far as I
360 * can tell for X or us though; having all the bits set (well, I guess
361 * I'm assuming 2s-complement too) is pretty absurd, and there are only
362 * 25 defined bits in Xlib, so even on 32-bit systems, it shouldn't fill
363 * up long.
364 */
365long
367{
369
370 /* Get current mask */
371 if(XGetWindowAttributes(dpy, w, &wattr) == 0) {
372 return -1;
373 }
374
375 /*
376 * If we're ignoring nothing, nothing to do. This is probably not
377 * strictly speaking a useful thing to ask for in general, but it's
378 * the right thing for us to do if we're asked to do nothing.
379 */
380 if(ignore_event == 0) {
381 return wattr.your_event_mask;
382 }
383
384 /* Delegate */
385 return mask_out_event_mask(w, ignore_event, wattr.your_event_mask);
386}
387
388long
390{
391 /* Set to the current, minus what we're wanting to ignore */
393
394 /* Return what it was */
395 return curmask;
396}
397
398int
400{
401 return XSelectInput(dpy, w, restore);
402}
403
404
405/*
406 * Setting and getting WM_STATE property.
407 *
408 * x-ref ICCCM section 4.1.3.1
409 * https://tronche.com/gui/x/icccm/sec-4.html#s-4.1.3.1
410 *
411 * XXX These should probably be named more alike, as they're
412 * complementary ops.
413 */
414void
416{
417 unsigned long data[2]; /* "suggested" by ICCCM version 1 */
418
419 data[0] = (unsigned long) state;
420 data[1] = (unsigned long)(tmp_win->iconify_by_unmapping ? None :
421 (tmp_win->icon ? tmp_win->icon->w : None));
422
424 PropModeReplace, (unsigned char *) data, 2);
425}
426
427
428bool
430{
432 int actual_format;
433 unsigned long nitems, bytesafter;
434 unsigned long *datap = NULL;
435 bool retval = false;
436
439 (unsigned char **) &datap) != Success || !datap) {
440 return false;
441 }
442
443 if(nitems <= 2) { /* "suggested" by ICCCM version 1 */
444 *statep = (int) datap[0];
445 *iwp = (Window) datap[1];
446 retval = true;
447 }
448
449 XFree(datap);
450 return retval;
451}
452
453
454/*
455 * Display a window's position in the dimensions window. This is used
456 * during various window positioning (during new window popups, moves,
457 * etc).
458 *
459 * This reuses the same window for the position as is used during
460 * resizing for the dimesions of the window in DisplaySize(). The
461 * innards of the funcs can probably be collapsed together a little, and
462 * the higher-level knowledge of Scr->SizeWindow (e.g., for unmapping
463 * after ths op is done) should probably be encapsulated a bit better.
464 */
465void
467{
468 char str [100];
469 char signx = '+';
470 char signy = '+';
471
472 if(x < 0) {
473 x = -x;
474 signx = '-';
475 }
476 if(y < 0) {
477 y = -y;
478 signy = '-';
479 }
480 sprintf(str, " %c%-4d %c%-4d ", signx, x, signy, y);
481 XRaiseWindow(dpy, Scr->SizeWindow);
482
483 Draw3DBorder(Scr->SizeWindow, 0, 0,
484 Scr->SizeStringOffset + Scr->SizeStringWidth + SIZE_HINDENT,
485 Scr->SizeFont.height + SIZE_VINDENT * 2,
486 2, Scr->DefaultC, off, false, false);
487
488 FB(Scr->DefaultC.fore, Scr->DefaultC.back);
489 XmbDrawImageString(dpy, Scr->SizeWindow, Scr->SizeFont.font_set,
490 Scr->NormalGC, Scr->SizeStringOffset,
491 Scr->SizeFont.ascent + SIZE_VINDENT, str, 13);
492}
493
494void
495MoveResizeSizeWindow(int x, int y, unsigned int width, unsigned int height)
496{
497 XResizeWindow(dpy, Scr->SizeWindow, width, height);
498
499 if(Scr->CenterFeedbackWindow) {
500 RArea monitor = RLayoutGetAreaAtXY(Scr->BorderedLayout, x, y);
501
502 XMoveWindow(dpy, Scr->SizeWindow,
503 monitor.x + monitor.width / 2 - width / 2,
504 monitor.y + monitor.height / 2 - height / 2);
505 }
506}
507
508
509/*
510 * Various funcs for adjusting coordinates for windows based on
511 * resistances etc.
512 *
513 * XXX In desperate need of better commenting.
514 */
515static void
517{
518 if(final->x >= cur_win->x + cur_win->width) {
519 return;
520 }
521 if(final->y >= cur_win->y + cur_win->height) {
522 return;
523 }
524 if(final->x + final->width <= cur_win->x) {
525 return;
526 }
527 if(final->y + final->height <= cur_win->y) {
528 return;
529 }
530
531 if(final->x + Scr->MovePackResistance > cur_win->x +
532 cur_win->width) { /* left */
533 final->x = MAX(final->x, cur_win->x + cur_win->width);
534 return;
535 }
536 if(final->x + final->width < cur_win->x +
537 Scr->MovePackResistance) { /* right */
538 final->x = MIN(final->x, cur_win->x - final->width);
539 return;
540 }
541 if(final->y + Scr->MovePackResistance > cur_win->y +
542 cur_win->height) { /* top */
543 final->y = MAX(final->y, cur_win->y + cur_win->height);
544 return;
545 }
546 if(final->y + final->height < cur_win->y +
547 Scr->MovePackResistance) { /* bottom */
548 final->y = MIN(final->y, cur_win->y - final->height);
549 }
550}
551
552static bool
554{
556 return false;
557}
558
559void
561{
562 TwmWindow *t;
564 RArea final = RAreaNew(*x, *y,
565 tmp_win->frame_width + 2 * tmp_win->frame_bw,
566 tmp_win->frame_height + 2 * tmp_win->frame_bw);
567
568 /* Global layout is not a single rectangle, check against the
569 * monitor borders */
570 if(Scr->BorderedLayout->horiz->len > 1) {
572 Scr->BorderedLayout->monitors, _tryToPackVsEachMonitor, &final);
573 }
574
575 for(t = Scr->FirstWindow; t != NULL; t = t->next) {
576 if(t == tmp_win) {
577 continue;
578 }
579#ifdef WINBOX
580 if(t->winbox != tmp_win->winbox) {
581 continue;
582 }
583#endif
584 if(t->vs != tmp_win->vs) {
585 continue;
586 }
587 if(!t->mapped) {
588 continue;
589 }
590
591 cur_win = RAreaNew(t->frame_x, t->frame_y,
592 t->frame_width + 2 * t->frame_bw,
593 t->frame_height + 2 * t->frame_bw);
594
595 _tryToPack(&final, &cur_win);
596 }
597
598 *x = final.x;
599 *y = final.y;
600}
601
602
603/*
604 * Directionals for TryToPush_be(). These differ from the specs for
605 * jump/pack/fill in functions. because there's an indeterminate option.
606 */
614static void TryToPush_be(TwmWindow *tmp_win, int x, int y, PushDirection dir);
615
616void
618{
620}
621
622static void
624{
625 TwmWindow *t;
626 int newx, newy, ndir;
627 bool move;
628 int w, h;
629 int winw = tmp_win->frame_width + 2 * tmp_win->frame_bw;
630 int winh = tmp_win->frame_height + 2 * tmp_win->frame_bw;
631
632 for(t = Scr->FirstWindow; t != NULL; t = t->next) {
633 if(t == tmp_win) {
634 continue;
635 }
636#ifdef WINBOX
637 if(t->winbox != tmp_win->winbox) {
638 continue;
639 }
640#endif
641 if(t->vs != tmp_win->vs) {
642 continue;
643 }
644 if(!t->mapped) {
645 continue;
646 }
647
648 w = t->frame_width + 2 * t->frame_bw;
649 h = t->frame_height + 2 * t->frame_bw;
650 if(x >= t->frame_x + w) {
651 continue;
652 }
653 if(y >= t->frame_y + h) {
654 continue;
655 }
656 if(x + winw <= t->frame_x) {
657 continue;
658 }
659 if(y + winh <= t->frame_y) {
660 continue;
661 }
662
663 move = false;
664 if((dir == PD_ANY || dir == PD_LEFT) &&
665 (x + Scr->MovePackResistance > t->frame_x + w)) {
666 newx = x - w;
667 newy = t->frame_y;
668 ndir = PD_LEFT;
669 move = true;
670 }
671 else if((dir == PD_ANY || dir == PD_RIGHT) &&
672 (x + winw < t->frame_x + Scr->MovePackResistance)) {
673 newx = x + winw;
674 newy = t->frame_y;
675 ndir = PD_RIGHT;
676 move = true;
677 }
678 else if((dir == PD_ANY || dir == PD_TOP) &&
679 (y + Scr->MovePackResistance > t->frame_y + h)) {
680 newx = t->frame_x;
681 newy = y - h;
682 ndir = PD_TOP;
683 move = true;
684 }
685 else if((dir == PD_ANY || dir == PD_BOTTOM) &&
686 (y + winh < t->frame_y + Scr->MovePackResistance)) {
687 newx = t->frame_x;
688 newy = y + winh;
689 ndir = PD_BOTTOM;
690 move = true;
691 }
692 if(move) {
694 TryToPack(t, &newx, &newy);
696 &newx, t->frame_width + 2 * t->frame_bw,
697 &newy, t->frame_height + 2 * t->frame_bw);
698 SetupWindow(t, newx, newy, t->frame_width, t->frame_height, -1);
699 }
700 }
701}
702
703
704void
706{
707 int w = tmp_win->frame_width + 2 * tmp_win->frame_bw;
708 int h = tmp_win->frame_height + 2 * tmp_win->frame_bw;
709 int grav = ((tmp_win->hints.flags & PWinGravity)
710 ? tmp_win->hints.win_gravity : NorthWestGravity);
711
712 switch(grav) {
713 case ForgetGravity :
714 case StaticGravity :
715 case NorthWestGravity :
716 case NorthGravity :
717 case WestGravity :
718 case CenterGravity :
719 *x = ((*x - Scr->BorderLeft) / Scr->XMoveGrid) * Scr->XMoveGrid
720 + Scr->BorderLeft;
721 *y = ((*y - Scr->BorderTop) / Scr->YMoveGrid) * Scr->YMoveGrid
722 + Scr->BorderTop;
723 break;
724 case NorthEastGravity :
725 case EastGravity :
726 *x = (((*x + w - Scr->BorderLeft) / Scr->XMoveGrid) *
727 Scr->XMoveGrid) - w + Scr->BorderLeft;
728 *y = ((*y - Scr->BorderTop) / Scr->YMoveGrid) *
729 Scr->YMoveGrid + Scr->BorderTop;
730 break;
731 case SouthWestGravity :
732 case SouthGravity :
733 *x = ((*x - Scr->BorderLeft) / Scr->XMoveGrid) * Scr->XMoveGrid
734 + Scr->BorderLeft;
735 *y = (((*y + h - Scr->BorderTop) / Scr->YMoveGrid) * Scr->YMoveGrid)
736 - h + Scr->BorderTop;
737 break;
738 case SouthEastGravity :
739 *x = (((*x + w - Scr->BorderLeft) / Scr->XMoveGrid) *
740 Scr->XMoveGrid) - w + Scr->BorderLeft;
741 *y = (((*y + h - Scr->BorderTop) / Scr->YMoveGrid) *
742 Scr->YMoveGrid) - h + Scr->BorderTop;
743 break;
744 }
745}
746
747
748
749#ifdef WINBOX
750/*
751 * Functions related to keeping windows from being placed off-screen (or
752 * off-screen too far). Involved in handling of params like DontMoveOff
753 * and MoveOffResistance, etc.
754 */
755static void ConstrainLeftTop(int *value, int border);
756static void ConstrainRightBottom(int *value, int size1, int border, int size2);
757#endif
758
759bool
760ConstrainByLayout(RLayout *layout, int move_off_res, int *left, int width,
761 int *top, int height)
762{
763 RArea area = RAreaNew(*left, *top, width, height);
764 int limit;
765 bool clipped = false;
766
767 limit = RLayoutFindBottomEdge(layout, &area) - height + 1;
768 if(area.y > limit) {
769 if(move_off_res >= 0 && area.y >= limit + move_off_res) {
770 area.y -= move_off_res;
771 }
772 else {
773 area.y = limit;
774 clipped = true;
775 }
776 }
777
778 limit = RLayoutFindRightEdge(layout, &area) - width + 1;
779 if(area.x > limit) {
780 if(move_off_res >= 0 && area.x >= limit + move_off_res) {
781 area.x -= move_off_res;
782 }
783 else {
784 area.x = limit;
785 clipped = true;
786 }
787 }
788
790 if(area.x < limit) {
791 if(move_off_res >= 0 && area.x <= limit - move_off_res) {
792 area.x += move_off_res;
793 }
794 else {
795 area.x = limit;
796 clipped = true;
797 }
798 }
799
801 if(area.y < limit) {
802 if(move_off_res >= 0 && area.y <= limit - move_off_res) {
803 area.y += move_off_res;
804 }
805 else {
806 area.y = limit;
807 clipped = true;
808 }
809 }
810
811 *left = area.x;
812 *top = area.y;
813
814 return clipped;
815}
816
817void
818ConstrainByBorders1(int *left, int width, int *top, int height)
819{
820 ConstrainByLayout(Scr->BorderedLayout, Scr->MoveOffResistance,
821 left, width, top, height);
822}
823
824void
825ConstrainByBorders(TwmWindow *twmwin, int *left, int width,
826 int *top, int height)
827{
828 if(false) {
829 // Dummy
830 }
831#ifdef WINBOX
832 else if(twmwin->winbox) {
834 XGetWindowAttributes(dpy, twmwin->winbox->window, &attr);
835 ConstrainRightBottom(left, width, 0, attr.width);
836 ConstrainLeftTop(left, 0);
837 ConstrainRightBottom(top, height, 0, attr.height);
838 ConstrainLeftTop(top, 0);
839 }
840#endif
841 else {
842 ConstrainByBorders1(left, width, top, height);
843 }
844}
845
846#ifdef WINBOX
847static void
848ConstrainLeftTop(int *value, int border)
849{
850 if(*value < border) {
851 if(Scr->MoveOffResistance < 0 ||
852 *value > border - Scr->MoveOffResistance) {
853 *value = border;
854 }
855 else if(Scr->MoveOffResistance > 0 &&
856 *value <= border - Scr->MoveOffResistance) {
857 *value = *value + Scr->MoveOffResistance;
858 }
859 }
860}
861
862static void
863ConstrainRightBottom(int *value, int size1, int border, int size2)
864{
865 if(*value + size1 > size2 - border) {
866 if(Scr->MoveOffResistance < 0 ||
867 *value + size1 < size2 - border + Scr->MoveOffResistance) {
868 *value = size2 - size1 - border;
869 }
870 else if(Scr->MoveOffResistance > 0 &&
871 *value + size1 >= size2 - border + Scr->MoveOffResistance) {
872 *value = *value - Scr->MoveOffResistance;
873 }
874 }
875}
876#endif
877
878
879/*
880 * Zoom over to a particular window.
881 */
882void
884{
885 int x, y;
886
887 if(t->ring.cursor_valid) {
888 x = t->ring.curs_x;
889 y = t->ring.curs_y;
890#ifdef DEBUG
891 fprintf(stderr, "WarpToWindow: cursor_valid; x == %d, y == %d\n", x, y);
892#endif
893
894 /*
895 * XXX is this correct with 3D borders? Easier check possible?
896 * frame_bw is for the left border.
897 */
898 if(x < t->frame_bw) {
899 x = t->frame_bw;
900 }
901 if(x >= t->frame_width + t->frame_bw) {
902 x = t->frame_width + t->frame_bw - 1;
903 }
904 if(y < t->title_height + t->frame_bw) {
905 y = t->title_height + t->frame_bw;
906 }
907 if(y >= t->frame_height + t->frame_bw) {
908 y = t->frame_height + t->frame_bw - 1;
909 }
910#ifdef DEBUG
911 fprintf(stderr, "WarpToWindow: adjusted ; x := %d, y := %d\n", x, y);
912#endif
913 }
914 else {
915 x = t->frame_width / 2;
916 y = t->frame_height / 2;
917#ifdef DEBUG
918 fprintf(stderr, "WarpToWindow: middle; x := %d, y := %d\n", x, y);
919#endif
920 }
921#if 0
922 int dest_x, dest_y;
924
925 /*
926 * Check if the proposed position actually is visible. If not, raise the window.
927 * "If the coordinates are contained in a mapped
928 * child of dest_w, that child is returned to child_return."
929 * We'll need to check for the right child window; the frame probably.
930 * (What about XXX window boxes?)
931 *
932 * Alternatively, use XQueryPointer() which returns the root window
933 * the pointer is in, but XXX that won't work for VirtualScreens.
934 */
935 if(XTranslateCoordinates(dpy, t->frame, Scr->Root, x, y, &dest_x, &dest_y,
936 &child)) {
937 if(child != t->frame) {
938 must_raise = true;
939 }
940 }
941#endif
942 if(t->auto_raise || must_raise) {
944 }
945 if(! visible(t)) {
946 WorkSpace *wlist;
947
948 for(wlist = Scr->workSpaceMgr.workSpaceList; wlist != NULL;
949 wlist = wlist->next) {
950 if(OCCUPY(t, wlist)) {
951 break;
952 }
953 }
954 if(wlist != NULL) {
955 GotoWorkSpace(Scr->currentvs, wlist);
956 }
957 }
958
959 XWarpPointer(dpy, None, Scr->Root, 0, 0, 0, 0, x + t->frame_x, y + t->frame_y);
961
962#ifdef DEBUG
963 {
966 int root_x_return;
967 int root_y_return;
968 int win_x_return;
969 int win_y_return;
970 unsigned int mask_return;
971
975 "XQueryPointer: root_return=%x, child_return=%x, root_x_return=%d, root_y_return=%d, win_x_return=%d, win_y_return=%d\n",
978 }
979 }
980#endif
981}
982
983
984/*
985 * ICCCM Client Messages - Section 4.2.8 of the ICCCM dictates that all
986 * client messages will have the following form:
987 *
988 * event type ClientMessage
989 * message type XA_WM_PROTOCOLS
990 * window tmp->w
991 * format 32
992 * data[0] message atom
993 * data[1] time stamp
994 */
995void
997{
999
1000 ev.type = ClientMessage;
1001 ev.window = w;
1002 ev.message_type = XA_WM_PROTOCOLS;
1003 ev.format = 32;
1004 ev.data.l[0] = a;
1005 ev.data.l[1] = timestamp;
1006 XSendEvent(dpy, w, False, 0L, (XEvent *) &ev);
1007}
1008
1009
1010/*
1011 * Create synthetic WM_HINTS info for windows. When a window specifies
1012 * stuff, we should probably pay attention to it (though we don't
1013 * always; x-ref comments in AddWindow() especially about focus).
1014 * However, when it doesn't tell us anything at all, we should assume
1015 * something useful. "Window managers are free to assume convenient
1016 * values for all fields of the WM_HINTS property if a window is mapped
1017 * without one." (ICCCM Ch. 4,
1018 * <https://www.x.org/releases/X11R7.7/doc/xorg-docs/icccm/icccm.html#Client_Properties>).
1019 *
1020 * Specifically, we assume it wants us to give it focus. It's fairly
1021 * bogus for a window not to tell us anything, but e.g current versions
1022 * of Chrome do (don't do) just that. So we better make up something
1023 * useful.
1024 *
1025 * Should probably be some configurability for this, so make the func
1026 * take the window, even though we don't currently do anything useful
1027 * with it...
1028 */
1029XWMHints *
1031{
1032 XWMHints *hints;
1033
1034 hints = XAllocWMHints();
1035 if(!hints) {
1036 return NULL;
1037 }
1038
1039 /*
1040 * Reasonable defaults. Takes input, in normal state.
1041 *
1042 * XXX Make configurable?
1043 */
1044 hints->flags = InputHint | StateHint;
1045 hints->input = True;
1046 hints->initial_state = NormalState;
1047
1048 return hints;
1049}
1050
1051
1052/**
1053 * Perform whatever adaptations of WM_HINTS info we do.
1054 *
1055 * Most of these relate to focus, but we also fiddle with group
1056 * membership.
1057 */
1058XWMHints *
1060{
1061 /*
1062 * If we have WM_HINTS, but they don't tell us anything about focus,
1063 * force it to true for our purposes.
1064 *
1065 * CL: Having with not willing focus cause problems with AutoSqueeze
1066 * and a few others things. So I suppress it. And the whole focus
1067 * thing is buggy anyway.
1068 */
1069 if(!(hints->flags & InputHint)) {
1070 hints->input = True;
1071 }
1072
1073 /*
1074 * Now we're expecting to give the window focus if it asked for it
1075 * via WM_HINTS, if it didn't say anything one way or the other in
1076 * WM_HINTS, or if it didn't give us any WM_HINTS at all. But if it
1077 * explicitly asked not to, we don't give it unless overridden by
1078 * config.
1079 */
1080 if(Scr->ForceFocus || IsInList(Scr->ForceFocusL, win)) {
1081 hints->input = True;
1082 }
1083
1084
1085 /* Setup group bits */
1086 if(hints->flags & WindowGroupHint) {
1087 win->group = hints->window_group;
1088 if(win->group) {
1089 /*
1090 * GTK windows often have a spurious "group leader" window which is
1091 * never reported to us and therefore does not really exist. This
1092 * is annoying because we treat group members a lot like transient
1093 * windows. Look for that here. It is in fact a duplicate of the
1094 * WM_CLIENT_LEADER property.
1095 */
1096 if(win->group != win->w && !GetTwmWindow(win->group)) {
1097 win->group = 0;
1098 }
1099 }
1100 }
1101 else {
1102 win->group = 0;
1103 }
1104
1105 return hints;
1106}
1107
1108
1109/**
1110 * [Re]set a window's name. This goes over the available naming sources
1111 * for the window and points the TwmWindow::name at the appropriate one.
1112 * It may also set a property to signal other EWMH-aware clients when
1113 * we're naming it a way they can't see themselves.
1114 *
1115 * \note This should rarely be called directly; apply_window_name()
1116 * should be used instead. It's split out because we need to do this
1117 * step individually in AddWindow().
1118 *
1119 * \note Note also that we never need to worry about freeing the
1120 * TwmWindow::name; it always points to one of the TwmWindow::names
1121 * values (which are free'd by the event handler when they change) or to
1122 * NoName (which is static). So we can just casually flip it around at
1123 * will.
1124 */
1125bool
1127{
1128 char *newname = NULL;
1129#define TRY(fld) { \
1130 if(newname == NULL && win->names.fld != NULL) { \
1131 newname = win->names.fld; \
1132 } \
1133 }
1134 TRY(ctwm_wm_name)
1135#ifdef EWMH
1137#endif
1138 TRY(wm_name)
1139#undef TRY
1140
1141 if(newname == NULL) {
1142 newname = NoName;
1143 }
1144 if(win->name == newname) {
1145 return false; // Nothing to do
1146 }
1147
1148 // Now we know what to call it
1149 win->name = newname;
1150
1151#ifdef EWMH
1152 // EWMH says we set an additional property on any windows where what
1153 // we consider the name isn't what's in _NET_WM_NAME, so pagers etc
1154 // can call it the same as we do.
1155 //
1156 // The parts of the text describing it conflict a little; at one
1157 // place, it implies this should be set unless we're using
1158 // _NET_WM_NAME, in another it seems to suggest WM_NAME should be
1159 // considered applicable too. I choose to implement it excluding
1160 // both, so this only gets set if we're overriding either standard
1161 // naming (probably rare).
1162 if(win->name != win->names.net_wm_name && win->name != win->names.wm_name) {
1163 // XXX We're not doing any checking of the encoding here... I
1164 // don't see that Xlib helps us any, so we probably have to fall
1165 // back to iconv? That came into the base in POSIX 2008, but was
1166 // in XSI back into the 90's I believe?
1168 8, PropModeReplace, (unsigned char *)win->name,
1169 strlen(win->name));
1170 }
1171 else {
1173 }
1174#endif // EWMH
1175
1176 // We set a name
1177 return true;
1178}
1179
1180
1181/**
1182 * [Re]set and apply changes to a window's name. This is called after
1183 * we've received a new WM_NAME (or other name-setting) property, to
1184 * update our titlebars, icon managers, etc.
1185 */
1186void
1188{
1189 /* [Re]set ->name */
1190 if(set_window_name(win) == false) {
1191 // No change
1192 return;
1193 }
1194 win->nameChanged = true;
1195
1196
1197 /* Update the active name */
1198 {
1201
1202 XmbTextExtents(Scr->TitleBarFont.font_set,
1203 win->name, strlen(win->name),
1205 win->name_width = logical_rect.width;
1206 }
1207
1208 /* recompute the priority if necessary */
1209 if(Scr->AutoPriority) {
1210 OtpRecomputePrefs(win);
1211 }
1212
1213 SetupWindow(win, win->frame_x, win->frame_y,
1214 win->frame_width, win->frame_height, -1);
1215
1216 if(win->title_w) {
1217 XClearArea(dpy, win->title_w, 0, 0, 0, 0, True);
1218 }
1219 if(Scr->AutoOccupy) {
1220 WmgrRedoOccupation(win);
1221 }
1222
1223#if 0
1224 /* Experimental, not yet working. */
1225 {
1226 ColorPair cp;
1227 int f, b;
1228
1229 f = GetColorFromList(Scr->TitleForegroundL, win->name,
1230 &win->class, &cp.fore);
1231 b = GetColorFromList(Scr->TitleBackgroundL, win->name,
1232 &win->class, &cp.back);
1233 if(f || b) {
1234 if(Scr->use3Dtitles && !Scr->BeNiceToColormap) {
1235 GetShadeColors(&cp);
1236 }
1237 win->title = cp;
1238 }
1239 f = GetColorFromList(Scr->BorderColorL, win->name,
1240 &win->class, &cp.fore);
1241 b = GetColorFromList(Scr->BorderColorL, win->name,
1242 &win->class, &cp.back);
1243 if(f || b) {
1244 if(Scr->use3Dborders && !Scr->BeNiceToColormap) {
1245 GetShadeColors(&cp);
1246 }
1247 win->borderC = cp;
1248 }
1249
1250 f = GetColorFromList(Scr->BorderTileForegroundL, win->name,
1251 &win->class, &cp.fore);
1252 b = GetColorFromList(Scr->BorderTileBackgroundL, win->name,
1253 &win->class, &cp.back);
1254 if(f || b) {
1255 if(Scr->use3Dborders && !Scr->BeNiceToColormap) {
1256 GetShadeColors(&cp);
1257 }
1258 win->border_tile = cp;
1259 }
1260 }
1261#endif
1262
1263 /*
1264 * If we haven't set a separate icon name, we use the window name, so
1265 * we need to update it.
1266 */
1267 if(win->names.icon_set == false) {
1269 }
1270 AutoPopupMaybe(win);
1271
1272 return;
1273}
1274
1275
1276/**
1277 * [Re]set a window's icon name. As with the window name version in
1278 * set_window_name(), this is mostly separate so the AddWindow() process
1279 * can call it.
1280 *
1281 * \note As with TwmWindow::name, we never want to try free()'ing or the
1282 * like TwmWindow::icon_name.
1283 *
1284 * \sa set_window_name() for details; this is just the icon name
1285 * equivalent of it.
1286 */
1287bool
1289{
1290 char *newname = NULL;
1291#define TRY(fld) { \
1292 if(newname == NULL && win->names.fld != NULL) { \
1293 newname = win->names.fld; \
1294 win->names.icon_set = true; \
1295 } \
1296 }
1297 TRY(ctwm_wm_icon_name)
1298#ifdef EWMH
1300#endif
1301 TRY(wm_icon_name)
1302#undef TRY
1303
1304 // Our fallback for icon names is the window name. Flag when we're
1305 // doing that, so the window name handler can know when it needs to
1306 // call us.
1307 if(newname == NULL) {
1308 newname = win->name;
1309 win->names.icon_set = false;
1310 }
1311 if(win->icon_name == newname) {
1312 return false; // Nothing to do
1313 }
1314
1315 // A name is chosen
1316 win->icon_name = newname;
1317
1318#ifdef EWMH
1319 // EWMH asks for _NET_WM_VISIBLE_ICON_NAME in various cases where
1320 // we're not using 'standard' properties' values. x-ref comments above in
1321 // set_window_name() about the parallel property for the window name
1322 // for various caveats.
1323 if(win->icon_name != win->names.net_wm_icon_name
1324 && win->icon_name != win->names.wm_icon_name) {
1325 // XXX Still encoding questionable; x-ref above.
1328 8, PropModeReplace, (unsigned char *)win->icon_name,
1329 strlen(win->icon_name));
1330 }
1331 else {
1333 }
1334#endif // EWMH
1335
1336 // Did it
1337 return true;
1338}
1339
1340
1341/**
1342 * [Re]set and apply changes to a window's icon name. This is called
1343 * after we've received a new WM_ICON_NAME (or other name-setting)
1344 * property, to update our titlebars, icon managers, etc.
1345 *
1346 * \sa apply_window_name() which does the same for the window title.
1347 */
1348void
1350{
1351 /* [Re]set ->icon_name */
1352 if(set_window_icon_name(win) == false) {
1353 // No change
1354 return;
1355 }
1356
1357
1358 /* Lot less to do for icons... */
1361
1362 return;
1363}
static int PlaceX
Definition add_window.c:82
char NoName[]
Definition add_window.c:89
char * ProgramName
Definition ctwm_main.c:146
#define OCCUPY(w, b)
Definition ctwm.h:369
#define DoesWmDeleteWindow
Definition ctwm.h:324
#define DoesWmSaveYourself
Definition ctwm.h:323
Display * dpy
Definition ctwm_main.c:84
XContext TwmContext
Definition ctwm_main.c:119
#define FB(fix_fore, fix_back)
Definition ctwm.h:119
#define DoesWmTakeFocus
Definition ctwm.h:322
#define Scr
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
@ off
Definition drawing.h:8
Time EventTime
Definition event_core.c:79
TwmWindow * Tmp_win
Definition event_core.c:91
void AutoPopupMaybe(TwmWindow *tmp)
Definition event_utils.c:54
void AutoRaiseWindow(TwmWindow *tmp)
Definition event_utils.c:27
int frame_x
X position on screen of frame.
int frame_y
Y position on screen of frame.
unsigned int name_width
width of name text
Window title_w
The title bar Window.
unsigned int frame_width
Width of frame.
unsigned int frame_height
Height of frame.
void RedoIcon(TwmWindow *win)
Definition icons.c:1160
bool GetColorFromList(name_list *list_head, char *name, XClassHint *class, Pixel *ptr)
Definition list.c:194
bool IsInList(name_list *list_head, TwmWindow *twin)
Definition list.c:140
int y
Definition menus.c:70
int x
Definition menus.c:69
void WmgrRedoOccupation(TwmWindow *win)
Definition occupation.c:442
void OtpRecomputePrefs(TwmWindow *twm_win)
Definition otp.c:1073
RArea RAreaNew(int x, int y, int width, int height)
Construct an RArea from given components.
Definition r_area.c:19
void RAreaListForeach(const RAreaList *self, bool(*func)(const RArea *cur_area, void *data), void *data)
Run a function over each RArea in an RAreaList until one returns true, allowing them a place to stash...
int RLayoutFindBottomEdge(const RLayout *self, const RArea *area)
Find the bottom of the top stripe of self that area fits into.
Definition r_layout.c:424
RArea RLayoutGetAreaAtXY(const RLayout *self, int x, int y)
Find the RArea in a RLayout that a given coordinate falls into.
Definition r_layout.c:544
int RLayoutFindRightEdge(const RLayout *self, const RArea *area)
Find the right edge of the left-most stripe of self that area fits into.
Definition r_layout.c:503
int RLayoutFindLeftEdge(const RLayout *self, const RArea *area)
Find the left edge of the right-most stripe of self that area fits into.
Definition r_layout.c:489
int RLayoutFindTopEdge(const RLayout *self, const RArea *area)
Find the top of the bottom stripe of self that area fits into.
Definition r_layout.c:438
#define SIZE_VINDENT
Internal padding in the size window.
Definition screen.h:59
#define SIZE_HINDENT
Internal padding in the size window.
Definition screen.h:58
Pixel back
Definition ctwm.h:141
Pixel fore
Definition ctwm.h:141
A particular extent of space.
Definition r_structs.h:16
int y
Y position.
Definition r_structs.h:18
int x
X position.
Definition r_structs.h:17
The layout of our display.
Definition r_structs.h:45
bool icon_set
Whether an icon name property has been set.
char * wm_name
Name from ICCCM WM_NAME property.
char * wm_icon_name
Icon name from WM_ICON_NAME property.
Info and control for every X Window we take over.
ColorPair border_tile
ColorPair for non-focused window borders.
Window w
The actual X Window handle.
bool nameChanged
Has TwmWindow::name ever changed? Used only in session saving.
char * name
Current window name. Points into TwmWindow::names.
char * icon_name
Current icon name. Points into TwmWindow::names.
XClassHint class
Window class info. From XGetClassHint().
ColorPair borderC
ColorPair for focused window borders.
ColorPair title
ColorPair for various other titlebar bits.
struct TwmWindow::_names names
Various sources of window/icon names. "
Window group
Window group, from WM hints.
struct WorkSpace * next
void GetShadeColors(ColorPair *cp)
Try and create a 'shaded' version of a color for prettier UI.
Definition util.c:245
#define MIN(x, y)
Definition util.h:39
#define MAX(x, y)
Definition util.h:36
void SetupWindow(TwmWindow *tmp_win, int x, int y, int w, int h, int bw)
void SetFocus(TwmWindow *tmp_win, Time tim)
Definition win_ops.c:128
void apply_window_icon_name(TwmWindow *win)
[Re]set and apply changes to a window's icon name.
Definition win_utils.c:1349
void GetWindowSizeHints(TwmWindow *tmp)
Definition win_utils.c:41
void send_clientmessage(Window w, Atom a, Time timestamp)
Definition win_utils.c:996
bool set_window_name(TwmWindow *win)
[Re]set a window's name.
Definition win_utils.c:1126
XWMHints * munge_wmhints(TwmWindow *win, XWMHints *hints)
Perform whatever adaptations of WM_HINTS info we do.
Definition win_utils.c:1059
void DisplayPosition(const TwmWindow *_unused_tmp_win, int x, int y)
Definition win_utils.c:466
void FreeWMPropertyString(char *prop)
Definition win_utils.c:327
bool visible(const TwmWindow *tmp_win)
Definition win_utils.c:341
void MoveResizeSizeWindow(int x, int y, unsigned int width, unsigned int height)
Definition win_utils.c:495
bool GetWMState(Window w, int *statep, Window *iwp)
Definition win_utils.c:429
static void _tryToPack(RArea *final, const RArea *cur_win)
Definition win_utils.c:516
#define TRY(fld)
static bool _tryToPackVsEachMonitor(const RArea *monitor_area, void *vfinal)
Definition win_utils.c:553
TwmWindow * GetTwmWindow(Window w)
Definition win_utils.c:190
void ConstrainByBorders(TwmWindow *twmwin, int *left, int width, int *top, int height)
Definition win_utils.c:825
XWMHints * gen_synthetic_wmhints(TwmWindow *win)
Definition win_utils.c:1030
int restore_mask(Window w, long restore)
Definition win_utils.c:399
bool ConstrainByLayout(RLayout *layout, int move_off_res, int *left, int width, int *top, int height)
Definition win_utils.c:760
PushDirection
Definition win_utils.c:607
@ PD_RIGHT
Definition win_utils.c:611
@ PD_BOTTOM
Definition win_utils.c:609
@ PD_LEFT
Definition win_utils.c:610
@ PD_TOP
Definition win_utils.c:612
@ PD_ANY
Definition win_utils.c:608
void ConstrainByBorders1(int *left, int width, int *top, int height)
Definition win_utils.c:818
long mask_out_event_mask(Window w, long ignore_event, long curmask)
Definition win_utils.c:389
void FetchWmProtocols(TwmWindow *tmp)
Definition win_utils.c:108
long mask_out_event(Window w, long ignore_event)
Definition win_utils.c:366
void SetMapStateProp(TwmWindow *tmp_win, int state)
Definition win_utils.c:415
void TryToPush(TwmWindow *tmp_win, int x, int y)
Definition win_utils.c:617
void WarpToWindow(TwmWindow *t, bool must_raise)
Definition win_utils.c:883
void apply_window_name(TwmWindow *win)
[Re]set and apply changes to a window's name.
Definition win_utils.c:1187
void TryToGrid(TwmWindow *tmp_win, int *x, int *y)
Definition win_utils.c:705
void TryToPack(TwmWindow *tmp_win, int *x, int *y)
Definition win_utils.c:560
char * GetWMPropertyString(Window w, Atom prop)
Definition win_utils.c:222
static void TryToPush_be(TwmWindow *tmp_win, int x, int y, PushDirection dir)
Definition win_utils.c:623
void GetGravityOffsets(TwmWindow *tmp, int *xp, int *yp)
Definition win_utils.c:149
bool set_window_icon_name(TwmWindow *win)
[Re]set a window's icon name.
Definition win_utils.c:1288
void GotoWorkSpace(VirtualScreen *vs, WorkSpace *ws)