~ctwm/ctwm/trunk

« back to all changes in this revision

Viewing changes to win_utils.c

  • Committer: Matthew Fuller
  • Date: 2016-09-20 20:22:19 UTC
  • mfrom: (523.1.26 cleanups)
  • Revision ID: fullermd@over-yonder.net-20160920202219-ykdjyr1whmip1e5u
Cleanup organization of some window handling code.

Especially move various window-handling bits ouf of menus.c and util.c,
where they have no business being.  Create win_ops and win_util files for
much of it, as well as moving some to other existing locations they
better fit.  Do a little light commenting.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 "decorations.h"
 
15
#include "drawing.h"
 
16
#include "icons.h"
 
17
#include "screen.h"
 
18
#include "util.h"
 
19
#include "win_utils.h"
 
20
 
 
21
 
 
22
/*
 
23
 * Fill in size hints for a window from WM_NORMAL_HINTS prop.
 
24
 *
 
25
 * Formerly in add_window.c
 
26
 */
 
27
void
 
28
GetWindowSizeHints(TwmWindow *tmp)
 
29
{
 
30
        long supplied = 0;
 
31
        XSizeHints *hints = &tmp->hints;
 
32
 
 
33
        if(!XGetWMNormalHints(dpy, tmp->w, hints, &supplied)) {
 
34
                hints->flags = 0;
 
35
        }
 
36
 
 
37
        if(hints->flags & PResizeInc) {
 
38
                if(hints->width_inc == 0) {
 
39
                        hints->width_inc = 1;
 
40
                }
 
41
                if(hints->height_inc == 0) {
 
42
                        hints->height_inc = 1;
 
43
                }
 
44
        }
 
45
 
 
46
        if(!(supplied & PWinGravity) && (hints->flags & USPosition)) {
 
47
                static int gravs[] = { SouthEastGravity, SouthWestGravity,
 
48
                                       NorthEastGravity, NorthWestGravity
 
49
                                     };
 
50
                int right =  tmp->attr.x + tmp->attr.width + 2 * tmp->old_bw;
 
51
                int bottom = tmp->attr.y + tmp->attr.height + 2 * tmp->old_bw;
 
52
                hints->win_gravity =
 
53
                        gravs[((Scr->rooth - bottom <
 
54
                                tmp->title_height + 2 * tmp->frame_bw3D) ? 0 : 2) |
 
55
                              ((Scr->rootw - right   <
 
56
                                tmp->title_height + 2 * tmp->frame_bw3D) ? 0 : 1)];
 
57
                hints->flags |= PWinGravity;
 
58
        }
 
59
 
 
60
        /* Check for min size < max size */
 
61
        if((hints->flags & (PMinSize | PMaxSize)) == (PMinSize | PMaxSize)) {
 
62
                if(hints->max_width < hints->min_width) {
 
63
                        if(hints->max_width > 0) {
 
64
                                hints->min_width = hints->max_width;
 
65
                        }
 
66
                        else if(hints->min_width > 0) {
 
67
                                hints->max_width = hints->min_width;
 
68
                        }
 
69
                        else {
 
70
                                hints->max_width = hints->min_width = 1;
 
71
                        }
 
72
                }
 
73
 
 
74
                if(hints->max_height < hints->min_height) {
 
75
                        if(hints->max_height > 0) {
 
76
                                hints->min_height = hints->max_height;
 
77
                        }
 
78
                        else if(hints->min_height > 0) {
 
79
                                hints->max_height = hints->min_height;
 
80
                        }
 
81
                        else {
 
82
                                hints->max_height = hints->min_height = 1;
 
83
                        }
 
84
                }
 
85
        }
 
86
}
 
87
 
 
88
 
 
89
/*
 
90
 * Fill in info from WM_PROTOCOLS property
 
91
 *
 
92
 * Formerly in add_window.c
 
93
 */
 
94
void
 
95
FetchWmProtocols(TwmWindow *tmp)
 
96
{
 
97
        unsigned long flags = 0L;
 
98
        Atom *protocols = NULL;
 
99
        int n;
 
100
 
 
101
        if(XGetWMProtocols(dpy, tmp->w, &protocols, &n)) {
 
102
                int i;
 
103
                Atom *ap;
 
104
 
 
105
                for(i = 0, ap = protocols; i < n; i++, ap++) {
 
106
                        if(*ap == XA_WM_TAKE_FOCUS) {
 
107
                                flags |= DoesWmTakeFocus;
 
108
                        }
 
109
                        if(*ap == XA_WM_SAVE_YOURSELF) {
 
110
                                flags |= DoesWmSaveYourself;
 
111
                        }
 
112
                        if(*ap == XA_WM_DELETE_WINDOW) {
 
113
                                flags |= DoesWmDeleteWindow;
 
114
                        }
 
115
                }
 
116
                if(protocols) {
 
117
                        XFree(protocols);
 
118
                }
 
119
        }
 
120
        tmp->protocols = flags;
 
121
}
 
122
 
 
123
 
 
124
/*
 
125
 * Figure signs for calculating location offsets for a window dependent
 
126
 * on its gravity.
 
127
 *
 
128
 * Depending on how its gravity is set, offsets to window coordinates for
 
129
 * e.g. border widths may need to move either down (right) or up (left).
 
130
 * Or possibly not at all.  So we write multipliers into passed vars for
 
131
 * callers.
 
132
 *
 
133
 * Formerly in add_window.c
 
134
 */
 
135
void
 
136
GetGravityOffsets(TwmWindow *tmp, int *xp, int *yp)
 
137
{
 
138
        static struct _gravity_offset {
 
139
                int x, y;
 
140
        } gravity_offsets[] = {
 
141
                [ForgetGravity]    = {  0,  0 },
 
142
                [NorthWestGravity] = { -1, -1 },
 
143
                [NorthGravity]     = {  0, -1 },
 
144
                [NorthEastGravity] = {  1, -1 },
 
145
                [WestGravity]      = { -1,  0 },
 
146
                [CenterGravity]    = {  0,  0 },
 
147
                [EastGravity]      = {  1,  0 },
 
148
                [SouthWestGravity] = { -1,  1 },
 
149
                [SouthGravity]     = {  0,  1 },
 
150
                [SouthEastGravity] = {  1,  1 },
 
151
                [StaticGravity]    = {  0,  0 },
 
152
        };
 
153
        int g = ((tmp->hints.flags & PWinGravity)
 
154
                 ? tmp->hints.win_gravity : NorthWestGravity);
 
155
 
 
156
        if(g < ForgetGravity || g > StaticGravity) {
 
157
                *xp = *yp = 0;
 
158
        }
 
159
        else {
 
160
                *xp = gravity_offsets[g].x;
 
161
                *yp = gravity_offsets[g].y;
 
162
        }
 
163
}
 
164
 
 
165
 
 
166
/*
 
167
 * Finds the TwmWindow structure associated with a Window (if any), or
 
168
 * NULL.
 
169
 *
 
170
 * This is a relatively cheap function since it does not involve
 
171
 * communication with the server. Probably faster than walking the list
 
172
 * of TwmWindows, since the lookup is by a hash table.
 
173
 *
 
174
 * Formerly in add_window.c
 
175
 */
 
176
TwmWindow *
 
177
GetTwmWindow(Window w)
 
178
{
 
179
        TwmWindow *twmwin;
 
180
        int stat;
 
181
 
 
182
        stat = XFindContext(dpy, w, TwmContext, (XPointer *)&twmwin);
 
183
        if(stat == XCNOENT) {
 
184
                twmwin = NULL;
 
185
        }
 
186
 
 
187
        return twmwin;
 
188
}
 
189
 
 
190
 
 
191
/***********************************************************************
 
192
 *
 
193
 *  Procedure:
 
194
 *      GetWMPropertyString - Get Window Manager text property and
 
195
 *                              convert it to a string.
 
196
 *
 
197
 *  Returned Value:
 
198
 *      (char *) - pointer to the malloc'd string or NULL
 
199
 *
 
200
 *  Inputs:
 
201
 *      w       - the id of the window whose property is to be retrieved
 
202
 *      prop    - property atom (typically WM_NAME or WM_ICON_NAME)
 
203
 *
 
204
 ***********************************************************************
 
205
 *
 
206
 * Formerly in util.c
 
207
 */
 
208
unsigned char *
 
209
GetWMPropertyString(Window w, Atom prop)
 
210
{
 
211
        XTextProperty       text_prop;
 
212
        char                **text_list;
 
213
        int                 text_list_count;
 
214
        unsigned char       *stringptr;
 
215
        int                 status, len = -1;
 
216
 
 
217
        (void)XGetTextProperty(dpy, w, &text_prop, prop);
 
218
        if(text_prop.value != NULL) {
 
219
                if(text_prop.encoding == XA_STRING
 
220
                                || text_prop.encoding == XA_COMPOUND_TEXT) {
 
221
                        /* property is encoded as compound text - convert to locale string */
 
222
                        status = XmbTextPropertyToTextList(dpy, &text_prop,
 
223
                                                           &text_list, &text_list_count);
 
224
                        if(text_list_count == 0) {
 
225
                                stringptr = NULL;
 
226
                        }
 
227
                        else if(text_list == NULL) {
 
228
                                stringptr = NULL;
 
229
                        }
 
230
                        else if(text_list [0] == NULL) {
 
231
                                stringptr = NULL;
 
232
                        }
 
233
                        else if(status < 0 || text_list_count < 0) {
 
234
                                switch(status) {
 
235
                                        case XConverterNotFound:
 
236
                                                fprintf(stderr,
 
237
                                                        "%s: Converter not found; unable to convert property %s of window ID %lx.\n",
 
238
                                                        ProgramName, XGetAtomName(dpy, prop), w);
 
239
                                                break;
 
240
                                        case XNoMemory:
 
241
                                                fprintf(stderr,
 
242
                                                        "%s: Insufficient memory; unable to convert property %s of window ID %lx.\n",
 
243
                                                        ProgramName, XGetAtomName(dpy, prop), w);
 
244
                                                break;
 
245
                                        case XLocaleNotSupported:
 
246
                                                fprintf(stderr,
 
247
                                                        "%s: Locale not supported; unable to convert property %s of window ID %lx.\n",
 
248
                                                        ProgramName, XGetAtomName(dpy, prop), w);
 
249
                                                break;
 
250
                                }
 
251
                                stringptr = NULL;
 
252
                                /*
 
253
                                   don't call XFreeStringList - text_list appears to have
 
254
                                   invalid address if status is bad
 
255
                                   XFreeStringList(text_list);
 
256
                                */
 
257
                        }
 
258
                        else {
 
259
                                len = strlen(text_list[0]);
 
260
                                stringptr = memcpy(malloc(len + 1), text_list[0], len + 1);
 
261
                                XFreeStringList(text_list);
 
262
                        }
 
263
                }
 
264
                else {
 
265
                        /* property is encoded in a format we don't understand */
 
266
                        fprintf(stderr,
 
267
                                "%s: Encoding not STRING or COMPOUND_TEXT; unable to decode property %s of window ID %lx.\n",
 
268
                                ProgramName, XGetAtomName(dpy, prop), w);
 
269
                        stringptr = NULL;
 
270
                }
 
271
                XFree(text_prop.value);
 
272
        }
 
273
        else {
 
274
                stringptr = NULL;
 
275
        }
 
276
 
 
277
        return stringptr;
 
278
}
 
279
 
 
280
 
 
281
/*
 
282
 * Cleanup something stored that we got from the above originally.
 
283
 *
 
284
 * Formerly in util.c
 
285
 */
 
286
void
 
287
FreeWMPropertyString(char *prop)
 
288
{
 
289
        if(prop && (char *)prop != NoName) {
 
290
                free(prop);
 
291
        }
 
292
}
 
293
 
 
294
 
 
295
/*
 
296
 * Window mapped on some virtual screen?
 
297
 *
 
298
 * Formerly in util.c
 
299
 */
 
300
bool
 
301
visible(const TwmWindow *tmp_win)
 
302
{
 
303
        return (tmp_win->vs != NULL);
 
304
}
 
305
 
 
306
 
 
307
/*
 
308
 * Various code paths do a dance of "mask off notifications of event type
 
309
 * ; do something that triggers that event (but we're doing it, so we
 
310
 * don't need the notification) ; restore previous mask".  So have some
 
311
 * util funcs to make it more visually obvious.
 
312
 *
 
313
 * e.g.:
 
314
 *     long prev_mask = mask_out_event(w, PropertyChangeMask);
 
315
 *     do_something_that_changes_properties();
 
316
 *     restore_mask(prev_mask);
 
317
 *
 
318
 * We're cheating a little with the -1 return on mask_out_event(), as
 
319
 * that's theoretically valid for the data type.  It's not as far as I
 
320
 * can tell for X or us though; having all the bits set (well, I guess
 
321
 * I'm assuming 2s-complement too) is pretty absurd, and there are only
 
322
 * 25 defined bits in Xlib, so even on 32-bit systems, it shouldn't fill
 
323
 * up long.
 
324
 */
 
325
long
 
326
mask_out_event(Window w, long ignore_event)
 
327
{
 
328
        XWindowAttributes wattr;
 
329
 
 
330
        /* Get current mask */
 
331
        if(XGetWindowAttributes(dpy, w, &wattr) == 0) {
 
332
                return -1;
 
333
        }
 
334
 
 
335
        /*
 
336
         * If we're ignoring nothing, nothing to do.  This is probably not
 
337
         * strictly speaking a useful thing to ask for in general, but it's
 
338
         * the right thing for us to do if we're asked to do nothing.
 
339
         */
 
340
        if(ignore_event == 0) {
 
341
                return wattr.your_event_mask;
 
342
        }
 
343
 
 
344
        /* Delegate */
 
345
        return mask_out_event_mask(w, ignore_event, wattr.your_event_mask);
 
346
}
 
347
 
 
348
long
 
349
mask_out_event_mask(Window w, long ignore_event, long curmask)
 
350
{
 
351
        /* Set to the current, minus what we're wanting to ignore */
 
352
        XSelectInput(dpy, w, (curmask & ~ignore_event));
 
353
 
 
354
        /* Return what it was */
 
355
        return curmask;
 
356
}
 
357
 
 
358
int
 
359
restore_mask(Window w, long restore)
 
360
{
 
361
        return XSelectInput(dpy, w, restore);
 
362
}
 
363
 
 
364
 
 
365
/*
 
366
 * Setting and getting WM_STATE property.
 
367
 *
 
368
 * x-ref ICCCM section 4.1.3.1
 
369
 * https://tronche.com/gui/x/icccm/sec-4.html#s-4.1.3.1
 
370
 *
 
371
 * XXX These should probably be named more alike, as they're
 
372
 * complementary ops.
 
373
 */
 
374
void
 
375
SetMapStateProp(TwmWindow *tmp_win, int state)
 
376
{
 
377
        unsigned long data[2];              /* "suggested" by ICCCM version 1 */
 
378
 
 
379
        data[0] = (unsigned long) state;
 
380
        data[1] = (unsigned long)(tmp_win->iconify_by_unmapping ? None :
 
381
                                  (tmp_win->icon ? tmp_win->icon->w : None));
 
382
 
 
383
        XChangeProperty(dpy, tmp_win->w, XA_WM_STATE, XA_WM_STATE, 32,
 
384
                        PropModeReplace, (unsigned char *) data, 2);
 
385
}
 
386
 
 
387
 
 
388
bool
 
389
GetWMState(Window w, int *statep, Window *iwp)
 
390
{
 
391
        Atom actual_type;
 
392
        int actual_format;
 
393
        unsigned long nitems, bytesafter;
 
394
        unsigned long *datap = NULL;
 
395
        bool retval = false;
 
396
 
 
397
        if(XGetWindowProperty(dpy, w, XA_WM_STATE, 0L, 2L, False, XA_WM_STATE,
 
398
                              &actual_type, &actual_format, &nitems, &bytesafter,
 
399
                              (unsigned char **) &datap) != Success || !datap) {
 
400
                return false;
 
401
        }
 
402
 
 
403
        if(nitems <= 2) {                   /* "suggested" by ICCCM version 1 */
 
404
                *statep = (int) datap[0];
 
405
                *iwp = (Window) datap[1];
 
406
                retval = true;
 
407
        }
 
408
 
 
409
        XFree(datap);
 
410
        return retval;
 
411
}
 
412
 
 
413
 
 
414
/*
 
415
 * Display a window's position in the dimensions window.  This is used
 
416
 * during various window positioning (during new window popups, moves,
 
417
 * etc).
 
418
 *
 
419
 * This reuses the same window for the position as is used during
 
420
 * resizing for the dimesions of the window in DisplaySize().  The
 
421
 * innards of the funcs can probably be collapsed together a little, and
 
422
 * the higher-level knowledge of Scr->SizeWindow (e.g., for unmapping
 
423
 * after ths op is done) should probably be encapsulated a bit better.
 
424
 */
 
425
void
 
426
DisplayPosition(const TwmWindow *_unused_tmp_win, int x, int y)
 
427
{
 
428
        char str [100];
 
429
        char signx = '+';
 
430
        char signy = '+';
 
431
 
 
432
        if(x < 0) {
 
433
                x = -x;
 
434
                signx = '-';
 
435
        }
 
436
        if(y < 0) {
 
437
                y = -y;
 
438
                signy = '-';
 
439
        }
 
440
        sprintf(str, " %c%-4d %c%-4d ", signx, x, signy, y);
 
441
        XRaiseWindow(dpy, Scr->SizeWindow);
 
442
 
 
443
        Draw3DBorder(Scr->SizeWindow, 0, 0,
 
444
                     Scr->SizeStringOffset + Scr->SizeStringWidth + SIZE_HINDENT,
 
445
                     Scr->SizeFont.height + SIZE_VINDENT * 2,
 
446
                     2, Scr->DefaultC, off, false, false);
 
447
 
 
448
        FB(Scr->DefaultC.fore, Scr->DefaultC.back);
 
449
        XmbDrawImageString(dpy, Scr->SizeWindow, Scr->SizeFont.font_set,
 
450
                           Scr->NormalGC, Scr->SizeStringOffset,
 
451
                           Scr->SizeFont.ascent + SIZE_VINDENT , str, 13);
 
452
}
 
453
 
 
454
 
 
455
/*
 
456
 * Various funcs for adjusting coordinates for windows based on
 
457
 * resistances etc.
 
458
 *
 
459
 * XXX In desperate need of better commenting.
 
460
 */
 
461
void
 
462
TryToPack(TwmWindow *tmp_win, int *x, int *y)
 
463
{
 
464
        TwmWindow   *t;
 
465
        int         newx, newy;
 
466
        int         w, h;
 
467
        int         winw = tmp_win->frame_width  + 2 * tmp_win->frame_bw;
 
468
        int         winh = tmp_win->frame_height + 2 * tmp_win->frame_bw;
 
469
 
 
470
        newx = *x;
 
471
        newy = *y;
 
472
        for(t = Scr->FirstWindow; t != NULL; t = t->next) {
 
473
                if(t == tmp_win) {
 
474
                        continue;
 
475
                }
 
476
                if(t->winbox != tmp_win->winbox) {
 
477
                        continue;
 
478
                }
 
479
                if(t->vs != tmp_win->vs) {
 
480
                        continue;
 
481
                }
 
482
                if(!t->mapped) {
 
483
                        continue;
 
484
                }
 
485
 
 
486
                w = t->frame_width  + 2 * t->frame_bw;
 
487
                h = t->frame_height + 2 * t->frame_bw;
 
488
                if(newx >= t->frame_x + w) {
 
489
                        continue;
 
490
                }
 
491
                if(newy >= t->frame_y + h) {
 
492
                        continue;
 
493
                }
 
494
                if(newx + winw <= t->frame_x) {
 
495
                        continue;
 
496
                }
 
497
                if(newy + winh <= t->frame_y) {
 
498
                        continue;
 
499
                }
 
500
 
 
501
                if(newx + Scr->MovePackResistance > t->frame_x + w) {  /* left */
 
502
                        newx = MAX(newx, t->frame_x + w);
 
503
                        continue;
 
504
                }
 
505
                if(newx + winw < t->frame_x + Scr->MovePackResistance) {  /* right */
 
506
                        newx = MIN(newx, t->frame_x - winw);
 
507
                        continue;
 
508
                }
 
509
                if(newy + Scr->MovePackResistance > t->frame_y + h) {  /* top */
 
510
                        newy = MAX(newy, t->frame_y + h);
 
511
                        continue;
 
512
                }
 
513
                if(newy + winh < t->frame_y + Scr->MovePackResistance) {  /* bottom */
 
514
                        newy = MIN(newy, t->frame_y - winh);
 
515
                        continue;
 
516
                }
 
517
        }
 
518
        *x = newx;
 
519
        *y = newy;
 
520
}
 
521
 
 
522
 
 
523
/*
 
524
 * Directionals for TryToPush_be().  These differ from the specs for
 
525
 * jump/pack/fill in functions. because there's an indeterminate option.
 
526
 */
 
527
typedef enum {
 
528
        PD_ANY,
 
529
        PD_BOTTOM,
 
530
        PD_LEFT,
 
531
        PD_RIGHT,
 
532
        PD_TOP,
 
533
} PushDirection;
 
534
static void TryToPush_be(TwmWindow *tmp_win, int x, int y, PushDirection dir);
 
535
 
 
536
void
 
537
TryToPush(TwmWindow *tmp_win, int x, int y)
 
538
{
 
539
        TryToPush_be(tmp_win, x, y, PD_ANY);
 
540
}
 
541
 
 
542
static void
 
543
TryToPush_be(TwmWindow *tmp_win, int x, int y, PushDirection dir)
 
544
{
 
545
        TwmWindow   *t;
 
546
        int         newx, newy, ndir;
 
547
        bool        move;
 
548
        int         w, h;
 
549
        int         winw = tmp_win->frame_width  + 2 * tmp_win->frame_bw;
 
550
        int         winh = tmp_win->frame_height + 2 * tmp_win->frame_bw;
 
551
 
 
552
        for(t = Scr->FirstWindow; t != NULL; t = t->next) {
 
553
                if(t == tmp_win) {
 
554
                        continue;
 
555
                }
 
556
                if(t->winbox != tmp_win->winbox) {
 
557
                        continue;
 
558
                }
 
559
                if(t->vs != tmp_win->vs) {
 
560
                        continue;
 
561
                }
 
562
                if(!t->mapped) {
 
563
                        continue;
 
564
                }
 
565
 
 
566
                w = t->frame_width  + 2 * t->frame_bw;
 
567
                h = t->frame_height + 2 * t->frame_bw;
 
568
                if(x >= t->frame_x + w) {
 
569
                        continue;
 
570
                }
 
571
                if(y >= t->frame_y + h) {
 
572
                        continue;
 
573
                }
 
574
                if(x + winw <= t->frame_x) {
 
575
                        continue;
 
576
                }
 
577
                if(y + winh <= t->frame_y) {
 
578
                        continue;
 
579
                }
 
580
 
 
581
                move = false;
 
582
                if((dir == PD_ANY || dir == PD_LEFT) &&
 
583
                                (x + Scr->MovePackResistance > t->frame_x + w)) {
 
584
                        newx = x - w;
 
585
                        newy = t->frame_y;
 
586
                        ndir = PD_LEFT;
 
587
                        move = true;
 
588
                }
 
589
                else if((dir == PD_ANY || dir == PD_RIGHT) &&
 
590
                                (x + winw < t->frame_x + Scr->MovePackResistance)) {
 
591
                        newx = x + winw;
 
592
                        newy = t->frame_y;
 
593
                        ndir = PD_RIGHT;
 
594
                        move = true;
 
595
                }
 
596
                else if((dir == PD_ANY || dir == PD_TOP) &&
 
597
                                (y + Scr->MovePackResistance > t->frame_y + h)) {
 
598
                        newx = t->frame_x;
 
599
                        newy = y - h;
 
600
                        ndir = PD_TOP;
 
601
                        move = true;
 
602
                }
 
603
                else if((dir == PD_ANY || dir == PD_BOTTOM) &&
 
604
                                (y + winh < t->frame_y + Scr->MovePackResistance)) {
 
605
                        newx = t->frame_x;
 
606
                        newy = y + winh;
 
607
                        ndir = PD_BOTTOM;
 
608
                        move = true;
 
609
                }
 
610
                if(move) {
 
611
                        TryToPush_be(t, newx, newy, ndir);
 
612
                        TryToPack(t, &newx, &newy);
 
613
                        ConstrainByBorders(tmp_win,
 
614
                                           &newx, t->frame_width  + 2 * t->frame_bw,
 
615
                                           &newy, t->frame_height + 2 * t->frame_bw);
 
616
                        SetupWindow(t, newx, newy, t->frame_width, t->frame_height, -1);
 
617
                }
 
618
        }
 
619
}
 
620
 
 
621
 
 
622
void
 
623
TryToGrid(TwmWindow *tmp_win, int *x, int *y)
 
624
{
 
625
        int w    = tmp_win->frame_width  + 2 * tmp_win->frame_bw;
 
626
        int h    = tmp_win->frame_height + 2 * tmp_win->frame_bw;
 
627
        int grav = ((tmp_win->hints.flags & PWinGravity)
 
628
                    ? tmp_win->hints.win_gravity : NorthWestGravity);
 
629
 
 
630
        switch(grav) {
 
631
                case ForgetGravity :
 
632
                case StaticGravity :
 
633
                case NorthWestGravity :
 
634
                case NorthGravity :
 
635
                case WestGravity :
 
636
                case CenterGravity :
 
637
                        *x = ((*x - Scr->BorderLeft) / Scr->XMoveGrid) * Scr->XMoveGrid
 
638
                             + Scr->BorderLeft;
 
639
                        *y = ((*y - Scr->BorderTop) / Scr->YMoveGrid) * Scr->YMoveGrid
 
640
                             + Scr->BorderTop;
 
641
                        break;
 
642
                case NorthEastGravity :
 
643
                case EastGravity :
 
644
                        *x = (((*x + w - Scr->BorderLeft) / Scr->XMoveGrid) *
 
645
                              Scr->XMoveGrid) - w + Scr->BorderLeft;
 
646
                        *y = ((*y - Scr->BorderTop) / Scr->YMoveGrid) *
 
647
                             Scr->YMoveGrid + Scr->BorderTop;
 
648
                        break;
 
649
                case SouthWestGravity :
 
650
                case SouthGravity :
 
651
                        *x = ((*x - Scr->BorderLeft) / Scr->XMoveGrid) * Scr->XMoveGrid
 
652
                             + Scr->BorderLeft;
 
653
                        *y = (((*y + h - Scr->BorderTop) / Scr->YMoveGrid) * Scr->YMoveGrid)
 
654
                             - h + Scr->BorderTop;
 
655
                        break;
 
656
                case SouthEastGravity :
 
657
                        *x = (((*x + w - Scr->BorderLeft) / Scr->XMoveGrid) *
 
658
                              Scr->XMoveGrid) - w + Scr->BorderLeft;
 
659
                        *y = (((*y + h - Scr->BorderTop) / Scr->YMoveGrid) *
 
660
                              Scr->YMoveGrid) - h + Scr->BorderTop;
 
661
                        break;
 
662
        }
 
663
}
 
664
 
 
665
 
 
666
 
 
667
/*
 
668
 * Functions related to keeping windows from being placed off-screen (or
 
669
 * off-screen too far).  Involved in handling of params like DontMoveOff
 
670
 * and MoveOffResistance, etc.
 
671
 */
 
672
static void ConstrainLeftTop(int *value, int border);
 
673
static void ConstrainRightBottom(int *value, int size1, int border, int size2);
 
674
 
 
675
void
 
676
ConstrainByBorders1(int *left, int width, int *top, int height)
 
677
{
 
678
        ConstrainRightBottom(left, width, Scr->BorderRight, Scr->rootw);
 
679
        ConstrainLeftTop(left, Scr->BorderLeft);
 
680
        ConstrainRightBottom(top, height, Scr->BorderBottom, Scr->rooth);
 
681
        ConstrainLeftTop(top, Scr->BorderTop);
 
682
}
 
683
 
 
684
void
 
685
ConstrainByBorders(TwmWindow *twmwin, int *left, int width,
 
686
                   int *top, int height)
 
687
{
 
688
        if(twmwin->winbox) {
 
689
                XWindowAttributes attr;
 
690
                XGetWindowAttributes(dpy, twmwin->winbox->window, &attr);
 
691
                ConstrainRightBottom(left, width, 0, attr.width);
 
692
                ConstrainLeftTop(left, 0);
 
693
                ConstrainRightBottom(top, height, 0, attr.height);
 
694
                ConstrainLeftTop(top, 0);
 
695
        }
 
696
        else {
 
697
                ConstrainByBorders1(left, width, top, height);
 
698
        }
 
699
}
 
700
 
 
701
static void
 
702
ConstrainLeftTop(int *value, int border)
 
703
{
 
704
        if(*value < border) {
 
705
                if(Scr->MoveOffResistance < 0 ||
 
706
                                *value > border - Scr->MoveOffResistance) {
 
707
                        *value = border;
 
708
                }
 
709
                else if(Scr->MoveOffResistance > 0 &&
 
710
                                *value <= border - Scr->MoveOffResistance) {
 
711
                        *value = *value + Scr->MoveOffResistance;
 
712
                }
 
713
        }
 
714
}
 
715
 
 
716
static void
 
717
ConstrainRightBottom(int *value, int size1, int border, int size2)
 
718
{
 
719
        if(*value + size1 > size2 - border) {
 
720
                if(Scr->MoveOffResistance < 0 ||
 
721
                                *value + size1 < size2 - border + Scr->MoveOffResistance) {
 
722
                        *value = size2 - size1 - border;
 
723
                }
 
724
                else if(Scr->MoveOffResistance > 0 &&
 
725
                                *value + size1 >= size2 - border + Scr->MoveOffResistance) {
 
726
                        *value = *value - Scr->MoveOffResistance;
 
727
                }
 
728
        }
 
729
}