~mc-return/compiz/compiz.merge-src-screen.cpp-improvements

« back to all changes in this revision

Viewing changes to plugins/resize.cpp

  • Committer: Dennis kasprzyk
  • Author(s): Dennis Kasprzyk
  • Date: 2009-03-15 05:09:18 UTC
  • Revision ID: git-v1:163f6b6f3c3b7764987cbdf8e03cc355edeaa499
New generalized build system.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright © 2005 Novell, Inc.
3
 
 *
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
13
 
 * implied warranty.
14
 
 *
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.
22
 
 *
23
 
 * Author: David Reveman <davidr@novell.com>
24
 
 */
25
 
 
26
 
#include <stdio.h>
27
 
#include <stdlib.h>
28
 
#include <string.h>
29
 
#include <math.h>
30
 
 
31
 
#include <X11/Xatom.h>
32
 
#include <X11/cursorfont.h>
33
 
 
34
 
#include <core/core.h>
35
 
#include <core/atoms.h>
36
 
#include "resize.h"
37
 
 
38
 
COMPIZ_PLUGIN_20081216 (resize, ResizePluginVTable)
39
 
 
40
 
void
41
 
ResizeScreen::getPaintRectangle (BoxPtr pBox)
42
 
{
43
 
    pBox->x1 = geometry.x - w->input ().left;
44
 
    pBox->y1 = geometry.y - w->input ().top;
45
 
    pBox->x2 = geometry.x +
46
 
        geometry.width + w->serverGeometry ().border () * 2 +
47
 
        w->input ().right;
48
 
 
49
 
    if (w->shaded ())
50
 
    {
51
 
        pBox->y2 = geometry.y + w->size ().height () + w->input ().bottom;
52
 
    }
53
 
    else
54
 
    {
55
 
        pBox->y2 = geometry.y +
56
 
            geometry.height + w->serverGeometry ().border () * 2 +
57
 
            w->input ().bottom;
58
 
    }
59
 
}
60
 
 
61
 
void
62
 
ResizeWindow::getStretchScale (BoxPtr pBox, float *xScale, float *yScale)
63
 
{
64
 
    int width, height;
65
 
 
66
 
    width  = window->size ().width () + window->input ().left +
67
 
             window->input ().right;
68
 
    height = window->size ().height () + window->input ().top +
69
 
             window->input ().bottom;
70
 
 
71
 
    *xScale = (width)  ? (pBox->x2 - pBox->x1) / (float) width  : 1.0f;
72
 
    *yScale = (height) ? (pBox->y2 - pBox->y1) / (float) height : 1.0f;
73
 
}
74
 
 
75
 
void
76
 
ResizeScreen::getStretchRectangle (BoxPtr pBox)
77
 
{
78
 
    BoxRec box;
79
 
    float  xScale, yScale;
80
 
 
81
 
    getPaintRectangle (&box);
82
 
    ResizeWindow::get (w)->getStretchScale (&box, &xScale, &yScale);
83
 
 
84
 
    pBox->x1 = (int)(box.x1 - (w->output ().left - w->input ().left) * xScale);
85
 
    pBox->y1 = (int)(box.y1 - (w->output ().top - w->input ().top) * yScale);
86
 
    pBox->x2 = (int)(box.x2 + w->output ().right * xScale);
87
 
    pBox->y2 = (int)(box.y2 + w->output ().bottom * yScale);
88
 
}
89
 
 
90
 
void
91
 
ResizeScreen::damageRectangle (BoxPtr pBox)
92
 
{
93
 
    int x1, x2, y1, y2;
94
 
 
95
 
    x1 = pBox->x1 - 1;
96
 
    y1 = pBox->y1 - 1;
97
 
    x2 = pBox->x2 + 1;
98
 
    y2 = pBox->y2 + 1;
99
 
 
100
 
    if (cScreen)
101
 
        cScreen->damageRegion (CompRegion (CompRect (x1, y1, x2 - x1, y2 - y1)));
102
 
}
103
 
 
104
 
Cursor
105
 
ResizeScreen::cursorFromResizeMask (unsigned int mask)
106
 
{
107
 
    Cursor cursor;
108
 
 
109
 
    if (mask & ResizeLeftMask)
110
 
    {
111
 
        if (mask & ResizeDownMask)
112
 
            cursor = downLeftCursor;
113
 
        else if (mask & ResizeUpMask)
114
 
            cursor = upLeftCursor;
115
 
        else
116
 
            cursor = leftCursor;
117
 
    }
118
 
    else if (mask & ResizeRightMask)
119
 
    {
120
 
        if (mask & ResizeDownMask)
121
 
            cursor = downRightCursor;
122
 
        else if (mask & ResizeUpMask)
123
 
            cursor = upRightCursor;
124
 
        else
125
 
            cursor = rightCursor;
126
 
    }
127
 
    else if (mask & ResizeUpMask)
128
 
    {
129
 
        cursor = upCursor;
130
 
    }
131
 
    else
132
 
    {
133
 
        cursor = downCursor;
134
 
    }
135
 
 
136
 
    return cursor;
137
 
}
138
 
 
139
 
void
140
 
ResizeScreen::sendResizeNotify ()
141
 
{
142
 
    XEvent xev;
143
 
 
144
 
    xev.xclient.type    = ClientMessage;
145
 
    xev.xclient.display = screen->dpy ();
146
 
    xev.xclient.format  = 32;
147
 
 
148
 
    xev.xclient.message_type = resizeNotifyAtom;
149
 
    xev.xclient.window       = w->id ();
150
 
 
151
 
    xev.xclient.data.l[0] = geometry.x;
152
 
    xev.xclient.data.l[1] = geometry.y;
153
 
    xev.xclient.data.l[2] = geometry.width;
154
 
    xev.xclient.data.l[3] = geometry.height;
155
 
    xev.xclient.data.l[4] = 0;
156
 
 
157
 
    XSendEvent (screen->dpy (), screen->root (),        FALSE,
158
 
                SubstructureRedirectMask | SubstructureNotifyMask, &xev);
159
 
}
160
 
 
161
 
void
162
 
ResizeScreen::updateWindowProperty ()
163
 
{
164
 
    unsigned long data[4];
165
 
 
166
 
    data[0] = geometry.x;
167
 
    data[1] = geometry.y;
168
 
    data[2] = geometry.width;
169
 
    data[3] = geometry.height;
170
 
 
171
 
    XChangeProperty (screen->dpy (), w->id (), resizeInformationAtom,
172
 
                     XA_CARDINAL, 32, PropModeReplace,
173
 
                     (unsigned char*) data, 4);
174
 
}
175
 
 
176
 
void
177
 
ResizeScreen::finishResizing ()
178
 
{
179
 
    w->ungrabNotify ();
180
 
 
181
 
    XDeleteProperty (screen->dpy (), w->id (), resizeInformationAtom);
182
 
 
183
 
    w = NULL;
184
 
}
185
 
 
186
 
static bool
187
 
resizeInitiate (CompAction         *action,
188
 
                CompAction::State  state,
189
 
                CompOption::Vector &options)
190
 
{
191
 
    CompWindow *w;
192
 
    Window     xid;
193
 
 
194
 
    xid = CompOption::getIntOptionNamed (options, "window");
195
 
 
196
 
    w = screen->findWindow (xid);
197
 
    if (w && (w->actions () & CompWindowActionResizeMask))
198
 
    {
199
 
        unsigned int mask;
200
 
        int          x, y;
201
 
        int          button;
202
 
        int          i;
203
 
 
204
 
        RESIZE_SCREEN (screen);
205
 
 
206
 
        CompWindow::Geometry server = w->serverGeometry ();
207
 
        
208
 
        x = CompOption::getIntOptionNamed (options, "x", pointerX);
209
 
        y = CompOption::getIntOptionNamed (options, "y", pointerY);
210
 
 
211
 
        button = CompOption::getIntOptionNamed (options, "button", -1);
212
 
 
213
 
        mask = CompOption::getIntOptionNamed (options, "direction");
214
 
 
215
 
        /* Initiate the resize in the direction suggested by the
216
 
         * sector of the window the mouse is in, eg drag in top left
217
 
         * will resize up and to the left.  Keyboard resize starts out
218
 
         * with the cursor in the middle of the window and then starts
219
 
         * resizing the edge corresponding to the next key press. */
220
 
        if (state & CompAction::StateInitKey)
221
 
        {
222
 
            mask = 0;
223
 
        }
224
 
        else if (!mask)
225
 
        {
226
 
            unsigned int sectorSizeX = server.width () / 3;
227
 
            unsigned int sectorSizeY = server.height () / 3;
228
 
            unsigned int posX        = x - server.x ();
229
 
            unsigned int posY        = y - server.y ();
230
 
 
231
 
            if (posX < sectorSizeX)
232
 
                mask |= ResizeLeftMask;
233
 
            else if (posX > (2 * sectorSizeX))
234
 
                mask |= ResizeRightMask;
235
 
 
236
 
            if (posY < sectorSizeY)
237
 
                mask |= ResizeUpMask;
238
 
            else if (posY > (2 * sectorSizeY))
239
 
                mask |= ResizeDownMask;
240
 
 
241
 
            /* if the pointer was in the middle of the window,
242
 
               just prevent input to the window */
243
 
 
244
 
            if (!mask)
245
 
                return true;
246
 
        }
247
 
 
248
 
        if (screen->otherGrabExist ("resize", 0))
249
 
            return false;
250
 
 
251
 
        if (rs->w)
252
 
            return false;
253
 
 
254
 
        if (w->type () & (CompWindowTypeDesktopMask |
255
 
                          CompWindowTypeDockMask         |
256
 
                          CompWindowTypeFullscreenMask))
257
 
            return false;
258
 
 
259
 
        if (w->overrideRedirect ())
260
 
            return false;
261
 
 
262
 
        if (state & CompAction::StateInitButton)
263
 
            action->setState (action->state () | CompAction::StateTermButton);
264
 
 
265
 
        if (w->shaded ())
266
 
            mask &= ~(ResizeUpMask | ResizeDownMask);
267
 
 
268
 
        rs->w    = w;
269
 
        rs->mask = mask;
270
 
 
271
 
        rs->savedGeometry.x      = server.x ();
272
 
        rs->savedGeometry.y      = server.y ();
273
 
        rs->savedGeometry.width  = server.width ();
274
 
        rs->savedGeometry.height = server.height ();
275
 
 
276
 
        rs->geometry = rs->savedGeometry;
277
 
 
278
 
        rs->pointerDx = x - pointerX;
279
 
        rs->pointerDy = y - pointerY;
280
 
 
281
 
        if ((w->state () & MAXIMIZE_STATE) == MAXIMIZE_STATE)
282
 
        {
283
 
            /* if the window is fully maximized, showing the outline or
284
 
               rectangle would be visually distracting as the window can't
285
 
               be resized anyway; so we better don't use them in this case */
286
 
            rs->mode = RESIZE_MODE_NORMAL;
287
 
        }
288
 
        else
289
 
        {
290
 
            rs->mode = rs->opt[RESIZE_OPTION_MODE].value ().i ();
291
 
            for (i = 0; i <= RESIZE_MODE_LAST; i++)
292
 
            {
293
 
                if (action == &rs->opt[i].value ().action ())
294
 
                {
295
 
                    rs->mode = i;
296
 
                    break;
297
 
                }
298
 
            }
299
 
 
300
 
            if (i > RESIZE_MODE_LAST)
301
 
            {
302
 
                int index;
303
 
 
304
 
                for (i = 0; i <= RESIZE_MODE_LAST; i++)
305
 
                {
306
 
                    index = RESIZE_OPTION_NORMAL_MATCH + i;
307
 
                    if (rs->opt[index].value ().match ().evaluate (w))
308
 
                    {
309
 
                        rs->mode = i;
310
 
                        break;
311
 
                    }
312
 
                }
313
 
            }
314
 
 
315
 
            if (!rs->gScreen || !rs->cScreen ||
316
 
                rs->cScreen->compositingActive ())
317
 
                rs->mode = RESIZE_MODE_NORMAL;
318
 
        }
319
 
 
320
 
        if (rs->mode != RESIZE_MODE_NORMAL)
321
 
        {
322
 
            RESIZE_WINDOW (w);
323
 
            if (rw->gWindow && rs->mode == RESIZE_MODE_STRETCH)
324
 
                rw->gWindow->glPaintSetEnabled (rw, true);
325
 
            if (rw->cWindow && rs->mode == RESIZE_MODE_STRETCH)
326
 
                rw->cWindow->damageRectSetEnabled (rw, true);
327
 
            rs->gScreen->glPaintOutputSetEnabled (rs, true);
328
 
        }
329
 
 
330
 
        if (!rs->grabIndex)
331
 
        {
332
 
            Cursor cursor;
333
 
 
334
 
            if (state & CompAction::StateInitKey)
335
 
            {
336
 
                cursor = rs->middleCursor;
337
 
            }
338
 
            else
339
 
            {
340
 
                cursor = rs->cursorFromResizeMask (mask);
341
 
            }
342
 
 
343
 
            rs->grabIndex = screen->pushGrab (cursor, "resize");
344
 
        }
345
 
 
346
 
        if (rs->grabIndex)
347
 
        {
348
 
            BoxRec box;
349
 
 
350
 
            rs->releaseButton = button;
351
 
 
352
 
            w->grabNotify (x, y, state, CompWindowGrabResizeMask |
353
 
                           CompWindowGrabButtonMask);
354
 
 
355
 
            /* using the paint rectangle is enough here
356
 
               as we don't have any stretch yet */
357
 
            rs->getPaintRectangle (&box);
358
 
            rs->damageRectangle (&box);
359
 
 
360
 
            if (state & CompAction::StateInitKey)
361
 
            {
362
 
                int xRoot, yRoot;
363
 
 
364
 
                xRoot = server.x () + (server.width () / 2);
365
 
                yRoot = server.y () + (server.height () / 2);
366
 
 
367
 
                screen->warpPointer (xRoot - pointerX, yRoot - pointerY);
368
 
            }
369
 
        }
370
 
    }
371
 
 
372
 
    return false;
373
 
}
374
 
 
375
 
static bool
376
 
resizeTerminate (CompAction         *action,
377
 
                 CompAction::State  state,
378
 
                 CompOption::Vector &options)
379
 
{
380
 
    RESIZE_SCREEN (screen);
381
 
 
382
 
    if (rs->w)
383
 
    {
384
 
        CompWindow     *w = rs->w;
385
 
        XWindowChanges xwc;
386
 
        unsigned int   mask = 0;
387
 
 
388
 
        if (rs->mode == RESIZE_MODE_NORMAL)
389
 
        {
390
 
            if (state & CompAction::StateCancel)
391
 
            {
392
 
                xwc.x      = rs->savedGeometry.x;
393
 
                xwc.y      = rs->savedGeometry.y;
394
 
                xwc.width  = rs->savedGeometry.width;
395
 
                xwc.height = rs->savedGeometry.height;
396
 
 
397
 
                mask = CWX | CWY | CWWidth | CWHeight;
398
 
            }
399
 
        }
400
 
        else
401
 
        {
402
 
            XRectangle geometry;
403
 
 
404
 
            if (state & CompAction::StateCancel)
405
 
                geometry = rs->savedGeometry;
406
 
            else
407
 
                geometry = rs->geometry;
408
 
 
409
 
            if (memcmp (&geometry, &rs->savedGeometry, sizeof (geometry)) == 0)
410
 
            {
411
 
                BoxRec box;
412
 
 
413
 
                if (rs->mode == RESIZE_MODE_STRETCH)
414
 
                    rs->getStretchRectangle (&box);
415
 
                else
416
 
                    rs->getPaintRectangle (&box);
417
 
 
418
 
                rs->damageRectangle (&box);
419
 
            }
420
 
            else
421
 
            {
422
 
                xwc.x      = geometry.x;
423
 
                xwc.y      = geometry.y;
424
 
                xwc.width  = geometry.width;
425
 
                xwc.height = geometry.height;
426
 
 
427
 
                mask = CWX | CWY | CWWidth | CWHeight;
428
 
            }
429
 
 
430
 
            if (rs->mode != RESIZE_MODE_NORMAL)
431
 
            {
432
 
                RESIZE_WINDOW (rs->w);
433
 
                if (rw->gWindow && rs->mode == RESIZE_MODE_STRETCH)
434
 
                    rw->gWindow->glPaintSetEnabled (rw, false);
435
 
                if (rw->cWindow && rs->mode == RESIZE_MODE_STRETCH)
436
 
                    rw->cWindow->damageRectSetEnabled (rw, false);
437
 
                rs->gScreen->glPaintOutputSetEnabled (rs, false);
438
 
            }
439
 
        }
440
 
 
441
 
        if ((mask & CWWidth) &&
442
 
            xwc.width == (int) w->serverGeometry ().width ())
443
 
            mask &= ~CWWidth;
444
 
 
445
 
        if ((mask & CWHeight) &&
446
 
            xwc.height == (int) w->serverGeometry ().height ())
447
 
            mask &= ~CWHeight;
448
 
 
449
 
        if (mask)
450
 
        {
451
 
            if (mask & (CWWidth | CWHeight))
452
 
                w->sendSyncRequest ();
453
 
 
454
 
            w->configureXWindow (mask, &xwc);
455
 
        }
456
 
 
457
 
        if (!(mask & (CWWidth | CWHeight)))
458
 
            rs->finishResizing ();
459
 
 
460
 
        if (rs->grabIndex)
461
 
        {
462
 
            screen->removeGrab (rs->grabIndex, NULL);
463
 
            rs->grabIndex = 0;
464
 
        }
465
 
 
466
 
        rs->releaseButton = 0;
467
 
    }
468
 
 
469
 
    action->setState (action->state () & ~(CompAction::StateTermKey |
470
 
                      CompAction::StateTermButton));
471
 
 
472
 
    return false;
473
 
}
474
 
 
475
 
 
476
 
void
477
 
ResizeScreen::updateWindowSize ()
478
 
{
479
 
    if (w->syncWait ())
480
 
        return;
481
 
 
482
 
    if (w->serverGeometry ().width ()  != geometry.width ||
483
 
        w->serverGeometry ().height () != geometry.height)
484
 
    {
485
 
        XWindowChanges xwc;
486
 
 
487
 
        xwc.x      = geometry.x;
488
 
        xwc.y      = geometry.y;
489
 
        xwc.width  = geometry.width;
490
 
        xwc.height = geometry.height;
491
 
 
492
 
        w->sendSyncRequest ();
493
 
 
494
 
        w->configureXWindow (CWX | CWY | CWWidth | CWHeight, &xwc);
495
 
    }
496
 
}
497
 
 
498
 
void
499
 
ResizeScreen::handleKeyEvent (KeyCode keycode)
500
 
{
501
 
    if (grabIndex && w)
502
 
    {
503
 
        int        widthInc, heightInc;
504
 
 
505
 
        widthInc  = w->sizeHints ().width_inc;
506
 
        heightInc = w->sizeHints ().height_inc;
507
 
 
508
 
        if (widthInc < MIN_KEY_WIDTH_INC)
509
 
            widthInc = MIN_KEY_WIDTH_INC;
510
 
 
511
 
        if (heightInc < MIN_KEY_HEIGHT_INC)
512
 
            heightInc = MIN_KEY_HEIGHT_INC;
513
 
 
514
 
        for (unsigned int i = 0; i < NUM_KEYS; i++)
515
 
        {
516
 
            if (keycode != key[i])
517
 
                continue;
518
 
 
519
 
            if (mask & rKeys[i].warpMask)
520
 
            {
521
 
                XWarpPointer (screen->dpy (), None, None, 0, 0, 0, 0,
522
 
                              rKeys[i].dx * widthInc, rKeys[i].dy * heightInc);
523
 
            }
524
 
            else
525
 
            {
526
 
                int x, y, left, top, width, height;
527
 
 
528
 
                CompWindow::Geometry server = w->serverGeometry ();
529
 
                CompWindowExtents    input  = w->input ();
530
 
 
531
 
                left   = server.x () - input.left;
532
 
                top    = server.y () - input.top;
533
 
                width  = input.left + server.width () + input.right;
534
 
                height = input.top  + server.height () + input.bottom;
535
 
 
536
 
                x = left + width  * (rKeys[i].dx + 1) / 2;
537
 
                y = top  + height * (rKeys[i].dy + 1) / 2;
538
 
 
539
 
                screen->warpPointer (x - pointerX, y - pointerY);
540
 
 
541
 
                mask = rKeys[i].resizeMask;
542
 
 
543
 
                screen->updateGrab (grabIndex, cursor[i]);
544
 
            }
545
 
            break;
546
 
        }
547
 
    }
548
 
}
549
 
 
550
 
void
551
 
ResizeScreen::handleMotionEvent (int xRoot, int yRoot)
552
 
{
553
 
    if (grabIndex)
554
 
    {
555
 
        BoxRec box;
556
 
        int    wi, he;
557
 
 
558
 
        wi = savedGeometry.width;
559
 
        he = savedGeometry.height;
560
 
 
561
 
        if (!mask)
562
 
        {
563
 
            int        xDist, yDist;
564
 
            int        minPointerOffsetX, minPointerOffsetY;
565
 
 
566
 
            CompWindow::Geometry server = w->serverGeometry ();
567
 
 
568
 
            xDist = xRoot - (server.x () + (server.width () / 2));
569
 
            yDist = yRoot - (server.y () + (server.height () / 2));
570
 
 
571
 
            /* decision threshold is 10% of window size */
572
 
            minPointerOffsetX = MIN (20, server.width () / 10);
573
 
            minPointerOffsetY = MIN (20, server.height () / 10);
574
 
 
575
 
            /* if we reached the threshold in one direction,
576
 
               make the threshold in the other direction smaller
577
 
               so there is a chance that this threshold also can
578
 
               be reached (by diagonal movement) */
579
 
            if (abs (xDist) > minPointerOffsetX)
580
 
                minPointerOffsetY /= 2;
581
 
            else if (abs (yDist) > minPointerOffsetY)
582
 
                minPointerOffsetX /= 2;
583
 
 
584
 
            if (abs (xDist) > minPointerOffsetX)
585
 
            {
586
 
                if (xDist > 0)
587
 
                    mask |= ResizeRightMask;
588
 
                else
589
 
                    mask |= ResizeLeftMask;
590
 
            }
591
 
 
592
 
            if (abs (yDist) > minPointerOffsetY)
593
 
            {
594
 
                if (yDist > 0)
595
 
                    mask |= ResizeDownMask;
596
 
                else
597
 
                    mask |= ResizeUpMask;
598
 
            }
599
 
 
600
 
            /* if the pointer movement was enough to determine a
601
 
               direction, warp the pointer to the appropriate edge
602
 
               and set the right cursor */
603
 
            if (mask)
604
 
            {
605
 
                Cursor     cursor;
606
 
                CompAction *action;
607
 
                int        pointerAdjustX = 0;
608
 
                int        pointerAdjustY = 0;
609
 
                int        option = RESIZE_OPTION_INITIATE_KEY;
610
 
 
611
 
                action = &opt[option].value ().action ();
612
 
                action->setState (action->state () |
613
 
                                  CompAction::StateTermButton);
614
 
 
615
 
                if (mask & ResizeRightMask)
616
 
                        pointerAdjustX = server.x () + server.width () +
617
 
                                         w->input ().right - xRoot;
618
 
                else if (mask & ResizeLeftMask)
619
 
                        pointerAdjustX = server.x () - w->input ().left -
620
 
                                         xRoot;
621
 
 
622
 
                if (mask & ResizeDownMask)
623
 
                        pointerAdjustY = server.x () + server.height () +
624
 
                                         w->input ().bottom - yRoot;
625
 
                else if (mask & ResizeUpMask)
626
 
                        pointerAdjustY = server.y () - w->input ().top - yRoot;
627
 
 
628
 
                screen->warpPointer (pointerAdjustX, pointerAdjustY);
629
 
 
630
 
                cursor = cursorFromResizeMask (mask);
631
 
                screen->updateGrab (grabIndex, cursor);
632
 
            }
633
 
        }
634
 
        else
635
 
        {
636
 
            /* only accumulate pointer movement if a mask is
637
 
               already set as we don't have a use for the
638
 
               difference information otherwise */
639
 
            pointerDx += xRoot - lastPointerX;
640
 
            pointerDy += yRoot - lastPointerY;
641
 
        }
642
 
 
643
 
        if (mask & ResizeLeftMask)
644
 
            wi -= pointerDx;
645
 
        else if (mask & ResizeRightMask)
646
 
            wi += pointerDx;
647
 
 
648
 
        if (mask & ResizeUpMask)
649
 
            he -= pointerDy;
650
 
        else if (mask & ResizeDownMask)
651
 
            he += pointerDy;
652
 
 
653
 
        if (w->state () & CompWindowStateMaximizedVertMask)
654
 
            he = w->serverGeometry ().height ();
655
 
 
656
 
        if (w->state () & CompWindowStateMaximizedHorzMask)
657
 
            wi = w->serverGeometry ().width ();
658
 
 
659
 
        w->constrainNewWindowSize (wi, he, &wi, &he);
660
 
 
661
 
        if (mode != RESIZE_MODE_NORMAL)
662
 
        {
663
 
            if (mode == RESIZE_MODE_STRETCH)
664
 
                getStretchRectangle (&box);
665
 
            else
666
 
                getPaintRectangle (&box);
667
 
 
668
 
            damageRectangle (&box);
669
 
        }
670
 
 
671
 
        if (mask & ResizeLeftMask)
672
 
            geometry.x -= wi - geometry.width;
673
 
 
674
 
        if (mask & ResizeUpMask)
675
 
            geometry.y -= he - geometry.height;
676
 
 
677
 
        geometry.width  = wi;
678
 
        geometry.height = he;
679
 
 
680
 
        if (mode != RESIZE_MODE_NORMAL)
681
 
        {
682
 
            if (mode == RESIZE_MODE_STRETCH)
683
 
                getStretchRectangle (&box);
684
 
            else
685
 
                getPaintRectangle (&box);
686
 
 
687
 
            damageRectangle (&box);
688
 
        }
689
 
        else
690
 
        {
691
 
            updateWindowSize ();
692
 
        }
693
 
 
694
 
        updateWindowProperty ();
695
 
        sendResizeNotify ();
696
 
    }
697
 
}
698
 
 
699
 
void
700
 
ResizeScreen::handleEvent (XEvent *event)
701
 
{
702
 
    switch (event->type) {
703
 
        case KeyPress:
704
 
            if (event->xkey.root == screen->root ())
705
 
                handleKeyEvent (event->xkey.keycode);
706
 
            break;
707
 
        case ButtonRelease:
708
 
            if (event->xbutton.root == screen->root ())
709
 
            {
710
 
                if (grabIndex)
711
 
                {
712
 
                    if (releaseButton         == -1 ||
713
 
                        (int) event->xbutton.button == releaseButton)
714
 
                    {
715
 
                        int        opt = RESIZE_OPTION_INITIATE_BUTTON;
716
 
                        CompAction *action = &this->opt[opt].value ().action ();
717
 
 
718
 
                        resizeTerminate (action, CompAction::StateTermButton,
719
 
                                         noOptions);
720
 
                    }
721
 
                }
722
 
            }
723
 
            break;
724
 
        case MotionNotify:
725
 
            if (event->xmotion.root == screen->root ())
726
 
                handleMotionEvent (pointerX, pointerY);
727
 
            break;
728
 
        case EnterNotify:
729
 
        case LeaveNotify:
730
 
            if (event->xcrossing.root == screen->root ())
731
 
                handleMotionEvent (pointerX, pointerY);
732
 
            break;
733
 
        case ClientMessage:
734
 
            if (event->xclient.message_type == Atoms::wmMoveResize)
735
 
            {
736
 
                CompWindow    *w;
737
 
                unsigned long type = event->xclient.data.l[2];
738
 
 
739
 
                RESIZE_SCREEN (screen);
740
 
 
741
 
                if (type <= WmMoveResizeSizeLeft ||
742
 
                    type == WmMoveResizeSizeKeyboard)
743
 
                {
744
 
                    w = screen->findWindow (event->xclient.window);
745
 
                    if (w)
746
 
                    {
747
 
                        CompOption::Vector o (0);
748
 
                        int            option;
749
 
 
750
 
                        o.push_back (CompOption ("window",
751
 
                                     CompOption::TypeInt));
752
 
                        o[0].value ().set ((int) event->xclient.window);
753
 
 
754
 
                        if (event->xclient.data.l[2] == WmMoveResizeSizeKeyboard)
755
 
                        {
756
 
                            option = RESIZE_OPTION_INITIATE_KEY;
757
 
 
758
 
                            resizeInitiate (&opt[option].value ().action (),
759
 
                                            CompAction::StateInitKey, o);
760
 
                        }
761
 
                        else
762
 
                        {
763
 
                            static unsigned int mask[] = {
764
 
                                ResizeUpMask | ResizeLeftMask,
765
 
                                ResizeUpMask,
766
 
                                ResizeUpMask | ResizeRightMask,
767
 
                                ResizeRightMask,
768
 
                                ResizeDownMask | ResizeRightMask,
769
 
                                ResizeDownMask,
770
 
                                ResizeDownMask | ResizeLeftMask,
771
 
                                ResizeLeftMask,
772
 
                            };
773
 
                            unsigned int mods;
774
 
                            Window           root, child;
775
 
                            int      xRoot, yRoot, i;
776
 
 
777
 
                            option = RESIZE_OPTION_INITIATE_BUTTON;
778
 
 
779
 
                            XQueryPointer (screen->dpy (),
780
 
                                           screen->root (),
781
 
                                           &root, &child, &xRoot, &yRoot,
782
 
                                           &i, &i, &mods);
783
 
 
784
 
                            /* TODO: not only button 1 */
785
 
                            if (mods & Button1Mask)
786
 
                            {
787
 
                                o.push_back (CompOption ("modifiers",
788
 
                                             CompOption::TypeInt));
789
 
                                o.push_back (CompOption ("x",
790
 
                                             CompOption::TypeInt));
791
 
                                o.push_back (CompOption ("y",
792
 
                                             CompOption::TypeInt));
793
 
                                o.push_back (CompOption ("direction",
794
 
                                             CompOption::TypeInt));
795
 
                                o.push_back (CompOption ("button",
796
 
                                             CompOption::TypeInt));
797
 
                                
798
 
                                o[1].value ().set ((int) mods);
799
 
                                o[2].value ().set
800
 
                                    ((int) event->xclient.data.l[0]);
801
 
                                o[3].value ().set
802
 
                                    ((int) event->xclient.data.l[1]);
803
 
                                o[4].value ().set
804
 
                                    ((int) mask[event->xclient.data.l[2]]);
805
 
                                o[5].value ().set
806
 
                                    ((int) (event->xclient.data.l[3] ?
807
 
                                     event->xclient.data.l[3] : -1));
808
 
                        
809
 
                                resizeInitiate (&opt[option].value ().action (),
810
 
                                                CompAction::StateInitButton, o);
811
 
 
812
 
                                ResizeScreen::get (screen)->
813
 
                                    handleMotionEvent (xRoot, yRoot);
814
 
                            }
815
 
                        }
816
 
                    }
817
 
                }
818
 
                else if (rs->w && type == WmMoveResizeCancel)
819
 
                {
820
 
                    if (rs->w->id () == event->xclient.window)
821
 
                    {
822
 
                        int option;
823
 
 
824
 
                        option = RESIZE_OPTION_INITIATE_BUTTON;
825
 
                        resizeTerminate (&opt[option].value ().action (),
826
 
                                         CompAction::StateCancel, noOptions);
827
 
                        option = RESIZE_OPTION_INITIATE_KEY;
828
 
                        resizeTerminate (&opt[option].value ().action (),
829
 
                                         CompAction::StateCancel, noOptions);
830
 
                    }
831
 
                }
832
 
            }
833
 
            break;
834
 
        case DestroyNotify:
835
 
            if (w && w->id () == event->xdestroywindow.window)
836
 
            {
837
 
                int option;
838
 
 
839
 
                option = RESIZE_OPTION_INITIATE_BUTTON;
840
 
                resizeTerminate (&opt[option].value ().action (), 0, noOptions);
841
 
                option = RESIZE_OPTION_INITIATE_KEY;
842
 
                resizeTerminate (&opt[option].value ().action (), 0, noOptions);
843
 
            }
844
 
            break;
845
 
        case UnmapNotify:
846
 
            if (w && w->id () == event->xunmap.window)
847
 
            {
848
 
                int option;
849
 
 
850
 
                option = RESIZE_OPTION_INITIATE_BUTTON;
851
 
                resizeTerminate (&opt[option].value ().action (), 0, noOptions);
852
 
                option = RESIZE_OPTION_INITIATE_KEY;
853
 
                resizeTerminate (&opt[option].value ().action (), 0, noOptions);
854
 
            }
855
 
        default:
856
 
            break;
857
 
    }
858
 
 
859
 
    screen->handleEvent (event);
860
 
 
861
 
    if (event->type == screen->syncEvent () + XSyncAlarmNotify)
862
 
    {
863
 
        if (w)
864
 
        {
865
 
            XSyncAlarmNotifyEvent *sa;
866
 
 
867
 
            sa = (XSyncAlarmNotifyEvent *) event;
868
 
 
869
 
            if (w->syncAlarm () == sa->alarm)
870
 
                updateWindowSize ();
871
 
        }
872
 
    }
873
 
}
874
 
 
875
 
void
876
 
ResizeWindow::resizeNotify (int dx, int dy, int dwidth, int dheight)
877
 
{
878
 
    window->resizeNotify (dx, dy, dwidth, dheight);
879
 
 
880
 
    if (rScreen->w == window && !rScreen->grabIndex)
881
 
        rScreen->finishResizing ();
882
 
}
883
 
 
884
 
void
885
 
ResizeScreen::glPaintRectangle (const GLScreenPaintAttrib &sAttrib,
886
 
                                const GLMatrix            &transform,
887
 
                                CompOutput                *output,
888
 
                                unsigned short            *borderColor,
889
 
                                unsigned short            *fillColor)
890
 
{
891
 
    BoxRec   box;
892
 
    GLMatrix sTransform (transform);
893
 
 
894
 
    getPaintRectangle (&box);
895
 
 
896
 
    glPushMatrix ();
897
 
 
898
 
    sTransform.toScreenSpace (output, -DEFAULT_Z_CAMERA);
899
 
 
900
 
    glLoadMatrixf (sTransform.getMatrix ());
901
 
 
902
 
    glDisableClientState (GL_TEXTURE_COORD_ARRAY);
903
 
    glEnable (GL_BLEND);
904
 
 
905
 
    /* fill rectangle */
906
 
    if (fillColor)
907
 
    {
908
 
        glColor4usv (fillColor);
909
 
        glRecti (box.x1, box.y2, box.x2, box.y1);
910
 
    }
911
 
 
912
 
    /* draw outline */
913
 
    glColor4usv (borderColor);
914
 
    glLineWidth (2.0);
915
 
    glBegin (GL_LINE_LOOP);
916
 
    glVertex2i (box.x1, box.y1);
917
 
    glVertex2i (box.x2, box.y1);
918
 
    glVertex2i (box.x2, box.y2);
919
 
    glVertex2i (box.x1, box.y2);
920
 
    glEnd ();
921
 
 
922
 
    /* clean up */
923
 
    glColor4usv (defaultColor);
924
 
    glDisable (GL_BLEND);
925
 
    glEnableClientState (GL_TEXTURE_COORD_ARRAY);
926
 
    glPopMatrix ();
927
 
}
928
 
 
929
 
bool
930
 
ResizeScreen::glPaintOutput (const GLScreenPaintAttrib &sAttrib,
931
 
                             const GLMatrix            &transform,
932
 
                             const CompRegion          &region,
933
 
                             CompOutput                *output,
934
 
                             unsigned int              mask)
935
 
{
936
 
    bool status;
937
 
 
938
 
    if (w)
939
 
    {
940
 
        if (mode == RESIZE_MODE_STRETCH)
941
 
            mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK;
942
 
    }
943
 
 
944
 
    status = gScreen->glPaintOutput (sAttrib, transform, region, output, mask);
945
 
 
946
 
    if (status && w)
947
 
    {
948
 
        unsigned short *border, *fill;
949
 
 
950
 
        border = opt[RESIZE_OPTION_BORDER_COLOR].value ().c ();
951
 
        fill   = opt[RESIZE_OPTION_FILL_COLOR].value ().c ();
952
 
 
953
 
        switch (mode) {
954
 
            case RESIZE_MODE_OUTLINE:
955
 
                glPaintRectangle (sAttrib, transform, output, border, NULL);
956
 
                break;
957
 
            case RESIZE_MODE_RECTANGLE:
958
 
                glPaintRectangle (sAttrib, transform, output, border, fill);
959
 
            default:
960
 
                break;
961
 
        }
962
 
    }
963
 
 
964
 
    return status;
965
 
}
966
 
 
967
 
bool
968
 
ResizeWindow::glPaint (const GLWindowPaintAttrib &attrib,
969
 
                       const GLMatrix            &transform,
970
 
                       const CompRegion          &region,
971
 
                       unsigned int              mask)
972
 
{
973
 
    bool       status;
974
 
 
975
 
    if (window == rScreen->w && rScreen->mode == RESIZE_MODE_STRETCH)
976
 
    {
977
 
        GLMatrix       wTransform (transform);
978
 
        BoxRec         box;
979
 
        float          xOrigin, yOrigin;
980
 
        float          xScale, yScale;
981
 
        int            x, y;
982
 
 
983
 
        if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK)
984
 
            return false;
985
 
 
986
 
        status = gWindow->glPaint (attrib, transform, region,
987
 
                                   mask | PAINT_WINDOW_NO_CORE_INSTANCE_MASK);
988
 
 
989
 
        GLFragment::Attrib fragment (gWindow->lastPaintAttrib ());
990
 
 
991
 
        if (window->alpha () || fragment.getOpacity () != OPAQUE)
992
 
            mask |= PAINT_WINDOW_TRANSLUCENT_MASK;
993
 
 
994
 
        rScreen->getPaintRectangle (&box);
995
 
        getStretchScale (&box, &xScale, &yScale);
996
 
 
997
 
        x = window->geometry (). x ();
998
 
        y = window->geometry (). y ();
999
 
 
1000
 
        xOrigin = x - window->input ().left;
1001
 
        yOrigin = y - window->input ().top;
1002
 
 
1003
 
        wTransform.translate (xOrigin, yOrigin, 0.0f);
1004
 
        wTransform.scale (xScale, yScale, 1.0f);
1005
 
        wTransform.translate ((rScreen->geometry.x - x) / xScale - xOrigin,
1006
 
                              (rScreen->geometry.y - y) / yScale - yOrigin,
1007
 
                              0.0f);
1008
 
 
1009
 
        glPushMatrix ();
1010
 
        glLoadMatrixf (wTransform.getMatrix ());
1011
 
 
1012
 
        gWindow->glDraw (wTransform, fragment, region,
1013
 
                         mask | PAINT_WINDOW_TRANSFORMED_MASK);
1014
 
 
1015
 
        glPopMatrix ();
1016
 
    }
1017
 
    else
1018
 
    {
1019
 
        status = gWindow->glPaint (attrib, transform, region, mask);
1020
 
    }
1021
 
 
1022
 
    return status;
1023
 
}
1024
 
 
1025
 
bool
1026
 
ResizeWindow::damageRect (bool initial, const CompRect &rect)
1027
 
{
1028
 
    bool status = false;
1029
 
 
1030
 
    if (window == rScreen->w && rScreen->mode == RESIZE_MODE_STRETCH)
1031
 
    {
1032
 
        BoxRec box;
1033
 
 
1034
 
        rScreen->getStretchRectangle (&box);
1035
 
        rScreen->damageRectangle (&box);
1036
 
 
1037
 
        status = true;
1038
 
    }
1039
 
 
1040
 
    status |= cWindow->damageRect (initial, rect);
1041
 
 
1042
 
    return status;
1043
 
}
1044
 
 
1045
 
CompOption::Vector &
1046
 
ResizeScreen::getOptions ()
1047
 
{
1048
 
    return opt;
1049
 
}
1050
 
 
1051
 
bool
1052
 
ResizeScreen::setOption (const char        *name,
1053
 
                         CompOption::Value &value)
1054
 
{
1055
 
    CompOption   *o;
1056
 
    unsigned int index;
1057
 
 
1058
 
    o = CompOption::findOption (opt, name, &index);
1059
 
    if (!o)
1060
 
        return false;
1061
 
 
1062
 
    return CompOption::setOption (*o, value);
1063
 
 
1064
 
}
1065
 
 
1066
 
static const CompMetadata::OptionInfo resizeOptionInfo[] = {
1067
 
    { "initiate_normal_key", "key", 0, resizeInitiate, resizeTerminate },
1068
 
    { "initiate_outline_key", "key", 0, resizeInitiate, resizeTerminate },
1069
 
    { "initiate_rectangle_key", "key", 0, resizeInitiate, resizeTerminate },
1070
 
    { "initiate_stretch_key", "key", 0, resizeInitiate, resizeTerminate },
1071
 
    { "initiate_button", "button", 0, resizeInitiate, resizeTerminate },
1072
 
    { "initiate_key", "key", 0, resizeInitiate, resizeTerminate },
1073
 
    { "mode", "int", RESTOSTRING (0, RESIZE_MODE_LAST), 0, 0 },
1074
 
    { "border_color", "color", 0, 0, 0 },
1075
 
    { "fill_color", "color", 0, 0, 0 },
1076
 
    { "normal_match", "match", 0, 0, 0 },
1077
 
    { "outline_match", "match", 0, 0, 0 },
1078
 
    { "rectangle_match", "match", 0, 0, 0 },
1079
 
    { "stretch_match", "match", 0, 0, 0 }
1080
 
};
1081
 
 
1082
 
ResizeScreen::ResizeScreen (CompScreen *s) :
1083
 
    PrivateHandler<ResizeScreen,CompScreen> (s),
1084
 
    gScreen (GLScreen::get (s)),
1085
 
    cScreen (CompositeScreen::get (s)),
1086
 
    w (NULL),
1087
 
    releaseButton (0),
1088
 
    opt (RESIZE_OPTION_NUM)
1089
 
{
1090
 
 
1091
 
    Display *dpy = s->dpy ();
1092
 
 
1093
 
    if (!resizeVTable->getMetadata ()->initOptions (resizeOptionInfo,
1094
 
                                                    RESIZE_OPTION_NUM, opt))
1095
 
    {
1096
 
        setFailed ();
1097
 
        return;
1098
 
    }
1099
 
 
1100
 
    resizeNotifyAtom      = XInternAtom (s->dpy (),
1101
 
                                         "_COMPIZ_RESIZE_NOTIFY", 0);
1102
 
    resizeInformationAtom = XInternAtom (s->dpy (),
1103
 
                                         "_COMPIZ_RESIZE_INFORMATION", 0);
1104
 
 
1105
 
    for (unsigned int i = 0; i < NUM_KEYS; i++)
1106
 
        key[i] = XKeysymToKeycode (s->dpy (), XStringToKeysym (rKeys[i].name));
1107
 
 
1108
 
    grabIndex = 0;
1109
 
 
1110
 
    leftCursor      = XCreateFontCursor (dpy, XC_left_side);
1111
 
    rightCursor     = XCreateFontCursor (dpy, XC_right_side);
1112
 
    upCursor        = XCreateFontCursor (dpy, XC_top_side);
1113
 
    upLeftCursor    = XCreateFontCursor (dpy, XC_top_left_corner);
1114
 
    upRightCursor   = XCreateFontCursor (dpy, XC_top_right_corner);
1115
 
    downCursor      = XCreateFontCursor (dpy, XC_bottom_side);
1116
 
    downLeftCursor  = XCreateFontCursor (dpy, XC_bottom_left_corner);
1117
 
    downRightCursor = XCreateFontCursor (dpy, XC_bottom_right_corner);
1118
 
    middleCursor    = XCreateFontCursor (dpy, XC_fleur);
1119
 
 
1120
 
    cursor[0] = leftCursor;
1121
 
    cursor[1] = rightCursor;
1122
 
    cursor[2] = upCursor;
1123
 
    cursor[3] = downCursor;
1124
 
 
1125
 
    ScreenInterface::setHandler (s);
1126
 
 
1127
 
    if (gScreen)
1128
 
        GLScreenInterface::setHandler (gScreen, false);
1129
 
}
1130
 
 
1131
 
ResizeScreen::~ResizeScreen ()
1132
 
{
1133
 
    Display *dpy = screen->dpy ();
1134
 
 
1135
 
    if (leftCursor)
1136
 
        XFreeCursor (dpy, leftCursor);
1137
 
    if (rightCursor)
1138
 
        XFreeCursor (dpy, rightCursor);
1139
 
    if (upCursor)
1140
 
        XFreeCursor (dpy, upCursor);
1141
 
    if (downCursor)
1142
 
        XFreeCursor (dpy, downCursor);
1143
 
    if (middleCursor)
1144
 
        XFreeCursor (dpy, middleCursor);
1145
 
    if (upLeftCursor)
1146
 
        XFreeCursor (dpy, upLeftCursor);
1147
 
    if (upRightCursor)
1148
 
        XFreeCursor (dpy, upRightCursor);
1149
 
    if (downLeftCursor)
1150
 
        XFreeCursor (dpy, downLeftCursor);
1151
 
    if (downRightCursor)
1152
 
        XFreeCursor (dpy, downRightCursor);
1153
 
}
1154
 
 
1155
 
ResizeWindow::ResizeWindow (CompWindow *w) :
1156
 
    PrivateHandler<ResizeWindow,CompWindow> (w),
1157
 
    window (w),
1158
 
    gWindow (GLWindow::get (w)),
1159
 
    cWindow (CompositeWindow::get (w)),
1160
 
    rScreen (ResizeScreen::get (screen))
1161
 
{
1162
 
    WindowInterface::setHandler (window);
1163
 
 
1164
 
    if (cWindow)
1165
 
        CompositeWindowInterface::setHandler (cWindow, false);
1166
 
 
1167
 
    if (gWindow)
1168
 
        GLWindowInterface::setHandler (gWindow, false);
1169
 
}
1170
 
 
1171
 
 
1172
 
ResizeWindow::~ResizeWindow ()
1173
 
{
1174
 
}
1175
 
 
1176
 
 
1177
 
bool
1178
 
ResizePluginVTable::init ()
1179
 
{
1180
 
    if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION))
1181
 
         return false;
1182
 
 
1183
 
    getMetadata ()->addFromOptionInfo (resizeOptionInfo, RESIZE_OPTION_NUM);
1184
 
    getMetadata ()->addFromFile (name ());
1185
 
 
1186
 
    return true;
1187
 
}
1188