2
* Copyright © 2005 Novell, Inc.
4
* Permission to use, copy, modify, distribute, and sell this software
5
* and its documentation for any purpose is hereby granted without
6
* fee, provided that the above copyright notice appear in all copies
7
* and that both that copyright notice and this permission notice
8
* appear in supporting documentation, and that the name of
9
* Novell, Inc. not be used in advertising or publicity pertaining to
10
* distribution of the software without specific, written prior permission.
11
* Novell, Inc. makes no representations about the suitability of this
12
* software for any purpose. It is provided "as is" without express or
15
* NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
17
* NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
19
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
20
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
21
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23
* Author: David Reveman <davidr@novell.com>
30
#include <X11/cursorfont.h>
34
#define ResizeUpMask (1L << 0)
35
#define ResizeDownMask (1L << 1)
36
#define ResizeLeftMask (1L << 2)
37
#define ResizeRightMask (1L << 3)
39
#define RESIZE_INITIATE_BUTTON_DEFAULT Button3
40
#define RESIZE_INITIATE_MODIFIERS_DEFAULT (CompPressMask | CompAltMask)
42
#define RESIZE_TERMINATE_BUTTON_DEFAULT Button3
43
#define RESIZE_TERMINATE_MODIFIERS_DEFAULT CompReleaseMask
56
#define NUM_KEYS (sizeof (rKeys) / sizeof (rKeys[0]))
58
#define MIN_KEY_WIDTH_INC 24
59
#define MIN_KEY_HEIGHT_INC 24
61
static int displayPrivateIndex;
63
typedef struct _ResizeDisplay {
64
int screenPrivateIndex;
65
HandleEventProc handleEvent;
72
KeyCode key[NUM_KEYS];
75
#define RESIZE_SCREEN_OPTION_INITIATE 0
76
#define RESIZE_SCREEN_OPTION_TERMINATE 1
77
#define RESIZE_SCREEN_OPTION_NUM 2
79
typedef struct _ResizeScreen {
80
CompOption opt[RESIZE_SCREEN_OPTION_NUM];
90
Cursor downLeftCursor;
91
Cursor downRightCursor;
97
#define GET_RESIZE_DISPLAY(d) \
98
((ResizeDisplay *) (d)->privates[displayPrivateIndex].ptr)
100
#define RESIZE_DISPLAY(d) \
101
ResizeDisplay *rd = GET_RESIZE_DISPLAY (d)
103
#define GET_RESIZE_SCREEN(s, rd) \
104
((ResizeScreen *) (s)->privates[(rd)->screenPrivateIndex].ptr)
106
#define RESIZE_SCREEN(s) \
107
ResizeScreen *rs = GET_RESIZE_SCREEN (s, GET_RESIZE_DISPLAY (s->display))
109
#define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))
112
resizeGetScreenOptions (CompScreen *screen,
115
RESIZE_SCREEN (screen);
117
*count = NUM_OPTIONS (rs);
122
resizeSetScreenOption (CompScreen *screen,
124
CompOptionValue *value)
129
RESIZE_SCREEN (screen);
131
o = compFindOption (rs->opt, NUM_OPTIONS (rs), name, &index);
136
case RESIZE_SCREEN_OPTION_INITIATE:
137
if (addScreenBinding (screen, &value->bind))
139
removeScreenBinding (screen, &o->value.bind);
141
if (compSetBindingOption (o, value))
145
case RESIZE_SCREEN_OPTION_TERMINATE:
146
if (compSetBindingOption (o, value))
157
resizeScreenInitOptions (ResizeScreen *rs,
162
o = &rs->opt[RESIZE_SCREEN_OPTION_INITIATE];
163
o->name = "initiate";
164
o->shortDesc = "Initiate Window Resize";
165
o->longDesc = "Start moving window";
166
o->type = CompOptionTypeBinding;
167
o->value.bind.type = CompBindingTypeButton;
168
o->value.bind.u.button.modifiers = RESIZE_INITIATE_MODIFIERS_DEFAULT;
169
o->value.bind.u.button.button = RESIZE_INITIATE_BUTTON_DEFAULT;
171
o = &rs->opt[RESIZE_SCREEN_OPTION_TERMINATE];
172
o->name = "terminate";
173
o->shortDesc = "Terminate Window Resize";
174
o->longDesc = "Stop moving window";
175
o->type = CompOptionTypeBinding;
176
o->value.bind.type = CompBindingTypeButton;
177
o->value.bind.u.button.modifiers = RESIZE_TERMINATE_MODIFIERS_DEFAULT;
178
o->value.bind.u.button.button = RESIZE_TERMINATE_BUTTON_DEFAULT;
182
resizeInitiate (CompScreen *s,
192
RESIZE_DISPLAY (s->display);
194
/* some plugin has already grabbed the screen */
201
w = findTopLevelWindowAtScreen (s, window);
206
if (w->type & (CompWindowTypeDesktopMask |
207
CompWindowTypeDockMask |
208
CompWindowTypeFullscreenMask))
211
if (w->attrib.override_redirect)
216
rd->width = w->attrib.width;
217
rd->height = w->attrib.height;
219
rs->prevPointerX = x;
220
rs->prevPointerY = y;
226
if (mask & ResizeLeftMask)
228
if (mask & ResizeDownMask)
229
cursor = rs->downLeftCursor;
230
else if (mask & ResizeUpMask)
231
cursor = rs->upLeftCursor;
233
cursor = rs->leftCursor;
235
else if (mask & ResizeRightMask)
237
if (mask & ResizeDownMask)
238
cursor = rs->downRightCursor;
239
else if (mask & ResizeUpMask)
240
cursor = rs->upRightCursor;
242
cursor = rs->rightCursor;
244
else if (mask & ResizeUpMask)
246
cursor = rs->upCursor;
250
cursor = rs->downCursor;
253
rs->grabIndex = pushScreenGrab (s, cursor);
258
rd->releaseButton = releaseButton;
260
(s->windowGrabNotify) (w, x, y, state,
261
CompWindowGrabResizeMask |
262
CompWindowGrabButtonMask);
268
resizeTerminate (CompDisplay *d)
274
RESIZE_SCREEN (rd->w->screen);
278
removeScreenGrab (rd->w->screen, rs->grabIndex, NULL);
282
(rd->w->screen->windowUngrabNotify) (rd->w);
284
syncWindowPosition (rd->w);
287
rd->releaseButton = 0;
292
resizeUpdateWindowSize (CompDisplay *d)
301
if (rd->w->state & CompWindowStateMaximizedVertMask)
302
rd->height = rd->w->attrib.height;
304
if (rd->w->state & CompWindowStateMaximizedHorzMask)
305
rd->width = rd->w->attrib.width;
307
if (rd->width == rd->w->attrib.width &&
308
rd->height == rd->w->attrib.height)
314
if (constrainNewWindowSize (rd->w,
315
rd->width, rd->height,
320
xwc.x = rd->w->attrib.x;
321
if (rd->mask & ResizeLeftMask)
322
xwc.x -= width - rd->w->attrib.width;
324
xwc.y = rd->w->attrib.y;
325
if (rd->mask & ResizeUpMask)
326
xwc.y -= height - rd->w->attrib.height;
331
sendSyncRequest (rd->w);
333
XConfigureWindow (d->display, rd->w->id,
334
CWX | CWY | CWWidth | CWHeight,
340
resizeHandleMotionEvent (CompScreen *s,
348
int pointerDx, pointerDy;
350
RESIZE_DISPLAY (s->display);
352
pointerDx = xRoot - rs->prevPointerX;
353
pointerDy = yRoot - rs->prevPointerY;
354
rs->prevPointerX = xRoot;
355
rs->prevPointerY = yRoot;
357
if (pointerDx || pointerDy)
359
if (rd->mask & ResizeLeftMask)
360
rd->width -= pointerDx;
361
else if (rd->mask & ResizeRightMask)
362
rd->width += pointerDx;
364
if (rd->mask & ResizeUpMask)
365
rd->height -= pointerDy;
366
else if (rd->mask & ResizeDownMask)
367
rd->height += pointerDy;
369
resizeUpdateWindowSize (s->display);
375
resizeHandleEvent (CompDisplay *d,
382
switch (event->type) {
385
s = findScreenAtDisplay (d, event->xkey.root);
390
if (EV_KEY (&rs->opt[RESIZE_SCREEN_OPTION_INITIATE], event))
396
ResizeDownMask | ResizeRightMask,
399
if (EV_KEY (&rs->opt[RESIZE_SCREEN_OPTION_TERMINATE], event) ||
400
(event->type == KeyPress &&
401
event->xkey.keycode == s->escapeKeyCode))
404
if (rs->grabIndex && rd->w && event->type == KeyPress)
406
int i, widthInc, heightInc;
408
widthInc = rd->w->sizeHints.width_inc;
409
heightInc = rd->w->sizeHints.height_inc;
411
if (widthInc < MIN_KEY_WIDTH_INC)
412
widthInc = MIN_KEY_WIDTH_INC;
414
if (heightInc < MIN_KEY_HEIGHT_INC)
415
heightInc = MIN_KEY_HEIGHT_INC;
417
for (i = 0; i < NUM_KEYS; i++)
419
if (event->xkey.keycode == rd->key[i])
421
XWarpPointer (d->display, None, None, 0, 0, 0, 0,
422
rKeys[i].dx * widthInc,
423
rKeys[i].dy * heightInc);
432
s = findScreenAtDisplay (d, event->xbutton.root);
437
if (EV_BUTTON (&rs->opt[RESIZE_SCREEN_OPTION_INITIATE], event))
439
event->xbutton.window,
440
event->xbutton.x_root,
441
event->xbutton.y_root,
442
event->xbutton.state,
443
ResizeDownMask | ResizeRightMask,
446
if (EV_BUTTON (&rs->opt[RESIZE_SCREEN_OPTION_TERMINATE], event))
449
if (event->type == ButtonRelease &&
450
(rd->releaseButton == -1 ||
451
event->xbutton.button == rd->releaseButton))
456
s = findScreenAtDisplay (d, event->xmotion.root);
458
resizeHandleMotionEvent (s,
459
event->xmotion.x_root,
460
event->xmotion.y_root);
463
if (event->xclient.message_type == d->wmMoveResizeAtom)
467
if (event->xclient.data.l[2] <= WmMoveResizeSizeLeft ||
468
event->xclient.data.l[2] == WmMoveResizeSizeKeyboard)
470
w = findWindowAtDisplay (d, event->xclient.window);
473
if (event->xclient.data.l[2] == WmMoveResizeSizeKeyboard)
477
x = w->attrib.x + w->width / 2;
478
y = w->attrib.y + w->height / 2;
480
XWarpPointer (d->display, None, w->screen->root,
483
resizeInitiate (w->screen, event->xclient.window,
485
ResizeDownMask | ResizeRightMask,
490
static unsigned int mask[] = {
491
ResizeUpMask | ResizeLeftMask,
493
ResizeUpMask | ResizeRightMask,
495
ResizeDownMask | ResizeRightMask,
497
ResizeDownMask | ResizeLeftMask,
504
XQueryPointer (d->display, w->screen->root,
505
&root, &child, &xRoot, &yRoot,
508
/* TODO: not only button 1 */
509
if (state & Button1Mask)
511
resizeInitiate (w->screen, event->xclient.window,
512
event->xclient.data.l[0],
513
event->xclient.data.l[1],
514
state | CompPressMask,
515
mask[event->xclient.data.l[2]],
516
event->xclient.data.l[3] ?
517
event->xclient.data.l[3] : -1);
519
resizeHandleMotionEvent (w->screen, xRoot, yRoot);
527
if (rd->w && rd->w->id == event->xdestroywindow.window)
531
if (rd->w && rd->w->id == event->xunmap.window)
534
if (event->type == d->syncEvent + XSyncAlarmNotify)
538
XSyncAlarmNotifyEvent *sa;
540
sa = (XSyncAlarmNotifyEvent *) event;
542
if (rd->w->syncAlarm == sa->alarm)
543
resizeUpdateWindowSize (d);
549
UNWRAP (rd, d, handleEvent);
550
(*d->handleEvent) (d, event);
551
WRAP (rd, d, handleEvent, resizeHandleEvent);
555
resizeInitDisplay (CompPlugin *p,
561
rd = malloc (sizeof (ResizeDisplay));
565
rd->screenPrivateIndex = allocateScreenPrivateIndex (d);
566
if (rd->screenPrivateIndex < 0)
574
rd->releaseButton = 0;
576
for (i = 0; i < NUM_KEYS; i++)
577
rd->key[i] = XKeysymToKeycode (d->display,
578
XStringToKeysym (rKeys[i].name));
580
WRAP (rd, d, handleEvent, resizeHandleEvent);
582
d->privates[displayPrivateIndex].ptr = rd;
588
resizeFiniDisplay (CompPlugin *p,
593
freeScreenPrivateIndex (d, rd->screenPrivateIndex);
595
UNWRAP (rd, d, handleEvent);
601
resizeInitScreen (CompPlugin *p,
606
RESIZE_DISPLAY (s->display);
608
rs = malloc (sizeof (ResizeScreen));
614
rs->prevPointerX = 0;
615
rs->prevPointerY = 0;
617
resizeScreenInitOptions (rs, s->display->display);
619
rs->leftCursor = XCreateFontCursor (s->display->display, XC_left_side);
620
rs->rightCursor = XCreateFontCursor (s->display->display, XC_right_side);
621
rs->upCursor = XCreateFontCursor (s->display->display,
623
rs->upLeftCursor = XCreateFontCursor (s->display->display,
625
rs->upRightCursor = XCreateFontCursor (s->display->display,
626
XC_top_right_corner);
627
rs->downCursor = XCreateFontCursor (s->display->display,
629
rs->downLeftCursor = XCreateFontCursor (s->display->display,
630
XC_bottom_left_corner);
631
rs->downRightCursor = XCreateFontCursor (s->display->display,
632
XC_bottom_right_corner);
634
addScreenBinding (s, &rs->opt[RESIZE_SCREEN_OPTION_INITIATE].value.bind);
636
s->privates[rd->screenPrivateIndex].ptr = rs;
642
resizeFiniScreen (CompPlugin *p,
651
resizeInit (CompPlugin *p)
653
displayPrivateIndex = allocateDisplayPrivateIndex ();
654
if (displayPrivateIndex < 0)
661
resizeFini (CompPlugin *p)
663
if (displayPrivateIndex >= 0)
664
freeDisplayPrivateIndex (displayPrivateIndex);
667
CompPluginVTable resizeVTable = {
679
0, /* GetDisplayOptions */
680
0, /* SetDisplayOption */
681
resizeGetScreenOptions,
682
resizeSetScreenOption,
688
getCompPluginInfo (void)
690
return &resizeVTable;