~ctwm/ctwm/trunk

« back to all changes in this revision

Viewing changes to win_utils.c

  • Committer: Matthew Fuller
  • Date: 2016-09-11 15:41:36 UTC
  • mto: This revision was merged to the branch mainline in revision 522.
  • Revision ID: fullermd@over-yonder.net-20160911154136-mrh2qth2nh2pxcqq
tracefile is used broadly across the code for debug output.  Move it
to util.[ch]; it's maybe a little wrong there, but it's _very_ wrong
having it as part of the event code.

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
 
}