~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to kwin/placement.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/********************************************************************
 
2
 KWin - the KDE window manager
 
3
 This file is part of the KDE project.
 
4
 
 
5
Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
 
6
Copyright (C) 1997 to 2002 Cristian Tibirna <tibirna@kde.org>
 
7
Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
 
8
 
 
9
This program is free software; you can redistribute it and/or modify
 
10
it under the terms of the GNU General Public License as published by
 
11
the Free Software Foundation; either version 2 of the License, or
 
12
(at your option) any later version.
 
13
 
 
14
This program is distributed in the hope that it will be useful,
 
15
but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
GNU General Public License for more details.
 
18
 
 
19
You should have received a copy of the GNU General Public License
 
20
along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
21
*********************************************************************/
 
22
 
 
23
#include "placement.h"
 
24
 
 
25
#include <QRect>
 
26
#include <assert.h>
 
27
 
 
28
#include <QTextStream>
 
29
 
 
30
#ifndef KCMRULES
 
31
#include "workspace.h"
 
32
#include "client.h"
 
33
#include "options.h"
 
34
#include "rules.h"
 
35
#endif
 
36
 
 
37
namespace KWin
 
38
{
 
39
 
 
40
#ifndef KCMRULES
 
41
 
 
42
Placement::Placement(Workspace* w)
 
43
{
 
44
    m_WorkspacePtr = w;
 
45
 
 
46
    reinitCascading(0);
 
47
}
 
48
 
 
49
/*!
 
50
  Places the client \a c according to the workspace's layout policy
 
51
 */
 
52
void Placement::place(Client* c, QRect& area)
 
53
{
 
54
    Policy policy = c->rules()->checkPlacement(Default);
 
55
    if (policy != Default) {
 
56
        place(c, area, policy);
 
57
        return;
 
58
    }
 
59
 
 
60
    if (c->isUtility())
 
61
        placeUtility(c, area, options->placement);
 
62
    else if (c->isDialog())
 
63
        placeDialog(c, area, options->placement);
 
64
    else if (c->isSplash())
 
65
        placeOnMainWindow(c, area);   // on mainwindow, if any, otherwise centered
 
66
    else
 
67
        place(c, area, options->placement);
 
68
}
 
69
 
 
70
void Placement::place(Client* c, QRect& area, Policy policy, Policy nextPlacement)
 
71
{
 
72
    if (policy == Unknown)
 
73
        policy = Default;
 
74
    if (policy == Default)
 
75
        policy = options->placement;
 
76
    if (policy == NoPlacement)
 
77
        return;
 
78
    else if (policy == Random)
 
79
        placeAtRandom(c, area, nextPlacement);
 
80
    else if (policy == Cascade)
 
81
        placeCascaded(c, area, nextPlacement);
 
82
    else if (policy == Centered)
 
83
        placeCentered(c, area, nextPlacement);
 
84
    else if (policy == ZeroCornered)
 
85
        placeZeroCornered(c, area, nextPlacement);
 
86
    else if (policy == UnderMouse)
 
87
        placeUnderMouse(c, area, nextPlacement);
 
88
    else if (policy == OnMainWindow)
 
89
        placeOnMainWindow(c, area, nextPlacement);
 
90
    else if (policy == Maximizing)
 
91
        placeMaximizing(c, area, nextPlacement);
 
92
    else
 
93
        placeSmart(c, area, nextPlacement);
 
94
}
 
95
 
 
96
/*!
 
97
  Place the client \a c according to a simply "random" placement algorithm.
 
98
 */
 
99
void Placement::placeAtRandom(Client* c, const QRect& area, Policy /*next*/)
 
100
{
 
101
    const int step  = 24;
 
102
    static int px = step;
 
103
    static int py = 2 * step;
 
104
    int tx, ty;
 
105
 
 
106
    const QRect maxRect = checkArea(c, area);
 
107
 
 
108
    if (px < maxRect.x())
 
109
        px = maxRect.x();
 
110
    if (py < maxRect.y())
 
111
        py = maxRect.y();
 
112
 
 
113
    px += step;
 
114
    py += 2 * step;
 
115
 
 
116
    if (px > maxRect.width() / 2)
 
117
        px =  maxRect.x() + step;
 
118
    if (py > maxRect.height() / 2)
 
119
        py =  maxRect.y() + step;
 
120
    tx = px;
 
121
    ty = py;
 
122
    if (tx + c->width() > maxRect.right()) {
 
123
        tx = maxRect.right() - c->width();
 
124
        if (tx < 0)
 
125
            tx = 0;
 
126
        px =  maxRect.x();
 
127
    }
 
128
    if (ty + c->height() > maxRect.bottom()) {
 
129
        ty = maxRect.bottom() - c->height();
 
130
        if (ty < 0)
 
131
            ty = 0;
 
132
        py =  maxRect.y();
 
133
    }
 
134
    c->move(tx, ty);
 
135
}
 
136
 
 
137
/*!
 
138
  Place the client \a c according to a really smart placement algorithm :-)
 
139
*/
 
140
void Placement::placeSmart(Client* c, const QRect& area, Policy /*next*/)
 
141
{
 
142
    /*
 
143
     * SmartPlacement by Cristian Tibirna (tibirna@kde.org)
 
144
     * adapted for kwm (16-19jan98) and for kwin (16Nov1999) using (with
 
145
     * permission) ideas from fvwm, authored by
 
146
     * Anthony Martin (amartin@engr.csulb.edu).
 
147
     * Xinerama supported added by Balaji Ramani (balaji@yablibli.com)
 
148
     * with ideas from xfce.
 
149
     */
 
150
 
 
151
    const int none = 0, h_wrong = -1, w_wrong = -2; // overlap types
 
152
    long int overlap, min_overlap = 0;
 
153
    int x_optimal, y_optimal;
 
154
    int possible;
 
155
    int desktop = c->desktop() == 0 || c->isOnAllDesktops() ? m_WorkspacePtr->currentDesktop() : c->desktop();
 
156
 
 
157
    int cxl, cxr, cyt, cyb;     //temp coords
 
158
    int  xl, xr, yt, yb;     //temp coords
 
159
    int basket;                 //temp holder
 
160
 
 
161
    // get the maximum allowed windows space
 
162
    const QRect maxRect = checkArea(c, area);
 
163
    int x = maxRect.left(), y = maxRect.top();
 
164
    x_optimal = x; y_optimal = y;
 
165
 
 
166
    //client gabarit
 
167
    int ch = c->height() - 1;
 
168
    int cw = c->width()  - 1;
 
169
 
 
170
    bool first_pass = true; //CT lame flag. Don't like it. What else would do?
 
171
 
 
172
    //loop over possible positions
 
173
    do {
 
174
        //test if enough room in x and y directions
 
175
        if (y + ch > maxRect.bottom() && ch < maxRect.height())
 
176
            overlap = h_wrong; // this throws the algorithm to an exit
 
177
        else if (x + cw > maxRect.right())
 
178
            overlap = w_wrong;
 
179
        else {
 
180
            overlap = none; //initialize
 
181
 
 
182
            cxl = x; cxr = x + cw;
 
183
            cyt = y; cyb = y + ch;
 
184
            ClientList::ConstIterator l;
 
185
            for (l = m_WorkspacePtr->stackingOrder().constBegin(); l != m_WorkspacePtr->stackingOrder().constEnd() ; ++l) {
 
186
                if ((*l)->isOnDesktop(desktop) &&
 
187
                        (*l)->isShown(false) && (*l) != c) {
 
188
 
 
189
                    xl = (*l)->x();          yt = (*l)->y();
 
190
                    xr = xl + (*l)->width(); yb = yt + (*l)->height();
 
191
 
 
192
                    //if windows overlap, calc the overall overlapping
 
193
                    if ((cxl < xr) && (cxr > xl) &&
 
194
                            (cyt < yb) && (cyb > yt)) {
 
195
                        xl = qMax(cxl, xl); xr = qMin(cxr, xr);
 
196
                        yt = qMax(cyt, yt); yb = qMin(cyb, yb);
 
197
                        if ((*l)->keepAbove())
 
198
                            overlap += 16 * (xr - xl) * (yb - yt);
 
199
                        else if ((*l)->keepBelow() && !(*l)->isDock()) // ignore KeepBelow windows
 
200
                            overlap += 0; // for placement (see Client::belongsToLayer() for Dock)
 
201
                        else
 
202
                            overlap += (xr - xl) * (yb - yt);
 
203
                    }
 
204
                }
 
205
            }
 
206
        }
 
207
 
 
208
        //CT first time we get no overlap we stop.
 
209
        if (overlap == none) {
 
210
            x_optimal = x;
 
211
            y_optimal = y;
 
212
            break;
 
213
        }
 
214
 
 
215
        if (first_pass) {
 
216
            first_pass = false;
 
217
            min_overlap = overlap;
 
218
        }
 
219
        //CT save the best position and the minimum overlap up to now
 
220
        else if (overlap >= none && overlap < min_overlap) {
 
221
            min_overlap = overlap;
 
222
            x_optimal = x;
 
223
            y_optimal = y;
 
224
        }
 
225
 
 
226
        // really need to loop? test if there's any overlap
 
227
        if (overlap > none) {
 
228
 
 
229
            possible = maxRect.right();
 
230
            if (possible - cw > x) possible -= cw;
 
231
 
 
232
            // compare to the position of each client on the same desk
 
233
            ClientList::ConstIterator l;
 
234
            for (l = m_WorkspacePtr->stackingOrder().constBegin(); l != m_WorkspacePtr->stackingOrder().constEnd() ; ++l) {
 
235
 
 
236
                if ((*l)->isOnDesktop(desktop) &&
 
237
                        (*l)->isShown(false) && (*l) != c) {
 
238
 
 
239
                    xl = (*l)->x();          yt = (*l)->y();
 
240
                    xr = xl + (*l)->width(); yb = yt + (*l)->height();
 
241
 
 
242
                    // if not enough room above or under the current tested client
 
243
                    // determine the first non-overlapped x position
 
244
                    if ((y < yb) && (yt < ch + y)) {
 
245
 
 
246
                        if ((xr > x) && (possible > xr)) possible = xr;
 
247
 
 
248
                        basket = xl - cw;
 
249
                        if ((basket > x) && (possible > basket)) possible = basket;
 
250
                    }
 
251
                }
 
252
            }
 
253
            x = possible;
 
254
        }
 
255
 
 
256
        // ... else ==> not enough x dimension (overlap was wrong on horizontal)
 
257
        else if (overlap == w_wrong) {
 
258
            x = maxRect.left();
 
259
            possible = maxRect.bottom();
 
260
 
 
261
            if (possible - ch > y) possible -= ch;
 
262
 
 
263
            //test the position of each window on the desk
 
264
            ClientList::ConstIterator l;
 
265
            for (l = m_WorkspacePtr->stackingOrder().constBegin(); l != m_WorkspacePtr->stackingOrder().constEnd() ; ++l) {
 
266
                if ((*l)->isOnDesktop(desktop) &&
 
267
                        (*l) != c   &&  c->isShown(false)) {
 
268
 
 
269
                    xl = (*l)->x();          yt = (*l)->y();
 
270
                    xr = xl + (*l)->width(); yb = yt + (*l)->height();
 
271
 
 
272
                    // if not enough room to the left or right of the current tested client
 
273
                    // determine the first non-overlapped y position
 
274
                    if ((yb > y) && (possible > yb)) possible = yb;
 
275
 
 
276
                    basket = yt - ch;
 
277
                    if ((basket > y) && (possible > basket)) possible = basket;
 
278
                }
 
279
            }
 
280
            y = possible;
 
281
        }
 
282
    } while ((overlap != none) && (overlap != h_wrong) && (y < maxRect.bottom()));
 
283
 
 
284
    if (ch >= maxRect.height())
 
285
        y_optimal = maxRect.top();
 
286
 
 
287
    // place the window
 
288
    c->move(x_optimal, y_optimal);
 
289
 
 
290
}
 
291
 
 
292
void Placement::reinitCascading(int desktop)
 
293
{
 
294
    // desktop == 0 - reinit all
 
295
    if (desktop == 0) {
 
296
        cci.clear();
 
297
        for (int i = 0; i < m_WorkspacePtr->numberOfDesktops(); i++) {
 
298
            DesktopCascadingInfo inf;
 
299
            inf.pos = QPoint(-1, -1);
 
300
            inf.col = 0;
 
301
            inf.row = 0;
 
302
            cci.append(inf);
 
303
        }
 
304
    } else {
 
305
        cci[desktop - 1].pos = QPoint(-1, -1);
 
306
        cci[desktop - 1].col = cci[desktop - 1].row = 0;
 
307
    }
 
308
}
 
309
 
 
310
/*!
 
311
  Place windows in a cascading order, remembering positions for each desktop
 
312
*/
 
313
void Placement::placeCascaded(Client* c, QRect& area, Policy nextPlacement)
 
314
{
 
315
    /* cascadePlacement by Cristian Tibirna (tibirna@kde.org) (30Jan98)
 
316
     */
 
317
    // work coords
 
318
    int xp, yp;
 
319
 
 
320
    //CT how do I get from the 'Client' class the size that NW squarish "handle"
 
321
    const int delta_x = 24;
 
322
    const int delta_y = 24;
 
323
 
 
324
    const int dn = c->desktop() == 0 || c->isOnAllDesktops() ? (m_WorkspacePtr->currentDesktop() - 1) : (c->desktop() - 1);
 
325
 
 
326
    // get the maximum allowed windows space and desk's origin
 
327
    QRect maxRect = checkArea(c, area);
 
328
 
 
329
    // initialize often used vars: width and height of c; we gain speed
 
330
    const int ch = c->height();
 
331
    const int cw = c->width();
 
332
    const int X = maxRect.left();
 
333
    const int Y = maxRect.top();
 
334
    const int H = maxRect.height();
 
335
    const int W = maxRect.width();
 
336
 
 
337
    if (nextPlacement == Unknown)
 
338
        nextPlacement = Smart;
 
339
 
 
340
    //initialize if needed
 
341
    if (cci[dn].pos.x() < 0 || cci[dn].pos.x() < X || cci[dn].pos.y() < Y) {
 
342
        cci[dn].pos = QPoint(X, Y);
 
343
        cci[dn].col = cci[dn].row = 0;
 
344
    }
 
345
 
 
346
 
 
347
    xp = cci[dn].pos.x();
 
348
    yp = cci[dn].pos.y();
 
349
 
 
350
    //here to touch in case people vote for resize on placement
 
351
    if ((yp + ch) > H) yp = Y;
 
352
 
 
353
    if ((xp + cw) > W) {
 
354
        if (!yp) {
 
355
            place(c, area, nextPlacement);
 
356
            return;
 
357
        } else xp = X;
 
358
    }
 
359
 
 
360
    //if this isn't the first window
 
361
    if (cci[dn].pos.x() != X && cci[dn].pos.y() != Y) {
 
362
        /* The following statements cause an internal compiler error with
 
363
         * egcs-2.91.66 on SuSE Linux 6.3. The equivalent forms compile fine.
 
364
         * 22-Dec-1999 CS
 
365
         *
 
366
         * if (xp != X && yp == Y) xp = delta_x * (++(cci[dn].col));
 
367
         * if (yp != Y && xp == X) yp = delta_y * (++(cci[dn].row));
 
368
         */
 
369
        if (xp != X && yp == Y) {
 
370
            ++(cci[dn].col);
 
371
            xp = delta_x * cci[dn].col;
 
372
        }
 
373
        if (yp != Y && xp == X) {
 
374
            ++(cci[dn].row);
 
375
            yp = delta_y * cci[dn].row;
 
376
        }
 
377
 
 
378
        // last resort: if still doesn't fit, smart place it
 
379
        if (((xp + cw) > W - X) || ((yp + ch) > H - Y)) {
 
380
            place(c, area, nextPlacement);
 
381
            return;
 
382
        }
 
383
    }
 
384
 
 
385
    // place the window
 
386
    c->move(QPoint(xp, yp));
 
387
 
 
388
    // new position
 
389
    cci[dn].pos = QPoint(xp + delta_x, yp + delta_y);
 
390
}
 
391
 
 
392
/*!
 
393
  Place windows centered, on top of all others
 
394
*/
 
395
void Placement::placeCentered(Client* c, const QRect& area, Policy /*next*/)
 
396
{
 
397
 
 
398
    // get the maximum allowed windows space and desk's origin
 
399
    const QRect maxRect = checkArea(c, area);
 
400
 
 
401
    const int xp = maxRect.left() + (maxRect.width() -  c->width())  / 2;
 
402
    const int yp = maxRect.top()  + (maxRect.height() - c->height()) / 2;
 
403
 
 
404
    // place the window
 
405
    c->move(QPoint(xp, yp));
 
406
}
 
407
 
 
408
/*!
 
409
  Place windows in the (0,0) corner, on top of all others
 
410
*/
 
411
void Placement::placeZeroCornered(Client* c, const QRect& area, Policy /*next*/)
 
412
{
 
413
    // get the maximum allowed windows space and desk's origin
 
414
    const QRect maxRect = checkArea(c, area);
 
415
 
 
416
    // place the window
 
417
    c->move(QPoint(maxRect.left(), maxRect.top()));
 
418
}
 
419
 
 
420
void Placement::placeUtility(Client* c, QRect& area, Policy /*next*/)
 
421
{
 
422
// TODO kwin should try to place utility windows next to their mainwindow,
 
423
// preferably at the right edge, and going down if there are more of them
 
424
// if there's not enough place outside the mainwindow, it should prefer
 
425
// top-right corner
 
426
    // use the default placement for now
 
427
    place(c, area, Default);
 
428
}
 
429
 
 
430
 
 
431
void Placement::placeDialog(Client* c, QRect& area, Policy nextPlacement)
 
432
{
 
433
    placeOnMainWindow(c, area, nextPlacement);
 
434
}
 
435
 
 
436
void Placement::placeUnderMouse(Client* c, QRect& area, Policy /*next*/)
 
437
{
 
438
    area = checkArea(c, area);
 
439
    QRect geom = c->geometry();
 
440
    geom.moveCenter(cursorPos());
 
441
    c->move(geom.topLeft());
 
442
    c->keepInArea(area);   // make sure it's kept inside workarea
 
443
}
 
444
 
 
445
void Placement::placeOnMainWindow(Client* c, QRect& area, Policy nextPlacement)
 
446
{
 
447
    if (nextPlacement == Unknown)
 
448
        nextPlacement = Centered;
 
449
    if (nextPlacement == Maximizing)   // maximize if needed
 
450
        placeMaximizing(c, area, NoPlacement);
 
451
    area = checkArea(c, area);
 
452
    ClientList mainwindows = c->mainClients();
 
453
    Client* place_on = NULL;
 
454
    Client* place_on2 = NULL;
 
455
    int mains_count = 0;
 
456
    for (ClientList::ConstIterator it = mainwindows.constBegin();
 
457
            it != mainwindows.constEnd();
 
458
            ++it) {
 
459
        if (mainwindows.count() > 1 && (*it)->isSpecialWindow())
 
460
            continue; // don't consider toolbars etc when placing
 
461
        ++mains_count;
 
462
        place_on2 = *it;
 
463
        if ((*it)->isOnCurrentDesktop()) {
 
464
            if (place_on == NULL)
 
465
                place_on = *it;
 
466
            else {
 
467
                // two or more on current desktop -> center
 
468
                // That's the default at least. However, with maximizing placement
 
469
                // policy as the default, the dialog should be either maximized or
 
470
                // made as large as its maximum size and then placed centered.
 
471
                // So the nextPlacement argument allows chaining. In this case, nextPlacement
 
472
                // is Maximizing and it will call placeCentered().
 
473
                place(c, area, Centered);
 
474
                return;
 
475
            }
 
476
        }
 
477
    }
 
478
    if (place_on == NULL) {
 
479
        // 'mains_count' is used because it doesn't include ignored mainwindows
 
480
        if (mains_count != 1) {
 
481
            place(c, area, Centered);
 
482
            return;
 
483
        }
 
484
        place_on = place_on2; // use the only window filtered together with 'mains_count'
 
485
    }
 
486
    if (place_on->isDesktop()) {
 
487
        place(c, area, Centered);
 
488
        return;
 
489
    }
 
490
    QRect geom = c->geometry();
 
491
    geom.moveCenter(place_on->geometry().center());
 
492
    c->move(geom.topLeft());
 
493
    // get area again, because the mainwindow may be on different xinerama screen
 
494
    area = checkArea(c, QRect());
 
495
    c->keepInArea(area);   // make sure it's kept inside workarea
 
496
}
 
497
 
 
498
void Placement::placeMaximizing(Client* c, QRect& area, Policy nextPlacement)
 
499
{
 
500
    if (nextPlacement == Unknown)
 
501
        nextPlacement = Smart;
 
502
    if (c->isMaximizable() && c->maxSize().width() >= area.width() && c->maxSize().height() >= area.height()) {
 
503
        if (m_WorkspacePtr->clientArea(MaximizeArea, c) == area)
 
504
            c->maximize(Client::MaximizeFull);
 
505
        else { // if the geometry doesn't match default maximize area (xinerama case?),
 
506
            // it's probably better to use the given area
 
507
            c->setGeometry(area);
 
508
        }
 
509
    } else {
 
510
        c->resizeWithChecks(c->maxSize().boundedTo(area.size()));
 
511
        place(c, area, nextPlacement);
 
512
    }
 
513
}
 
514
 
 
515
QRect Placement::checkArea(const Client* c, const QRect& area)
 
516
{
 
517
    if (area.isNull())
 
518
        return m_WorkspacePtr->clientArea(PlacementArea, c->geometry().center(), c->desktop());
 
519
    return area;
 
520
}
 
521
 
 
522
#endif
 
523
 
 
524
 
 
525
Placement::Policy Placement::policyFromString(const QString& policy, bool no_special)
 
526
{
 
527
    if (policy == "NoPlacement")
 
528
        return NoPlacement;
 
529
    else if (policy == "Default" && !no_special)
 
530
        return Default;
 
531
    else if (policy == "Random")
 
532
        return Random;
 
533
    else if (policy == "Cascade")
 
534
        return Cascade;
 
535
    else if (policy == "Centered")
 
536
        return Centered;
 
537
    else if (policy == "ZeroCornered")
 
538
        return ZeroCornered;
 
539
    else if (policy == "UnderMouse" && !no_special)
 
540
        return UnderMouse;
 
541
    else if (policy == "OnMainWindow" && !no_special)
 
542
        return OnMainWindow;
 
543
    else if (policy == "Maximizing")
 
544
        return Maximizing;
 
545
    else
 
546
        return Smart;
 
547
}
 
548
 
 
549
const char* Placement::policyToString(Policy policy)
 
550
{
 
551
    const char* const policies[] = {
 
552
        "NoPlacement", "Default", "XXX should never see", "Random", "Smart", "Cascade", "Centered",
 
553
        "ZeroCornered", "UnderMouse", "OnMainWindow", "Maximizing"
 
554
    };
 
555
    assert(policy < int(sizeof(policies) / sizeof(policies[ 0 ])));
 
556
    return policies[ policy ];
 
557
}
 
558
 
 
559
 
 
560
#ifndef KCMRULES
 
561
 
 
562
// ********************
 
563
// Workspace
 
564
// ********************
 
565
 
 
566
/*!
 
567
  Moves active window left until in bumps into another window or workarea edge.
 
568
 */
 
569
void Workspace::slotWindowPackLeft()
 
570
{
 
571
    if (active_client && active_client->isMovable())
 
572
        active_client->move(packPositionLeft(active_client, active_client->geometry().left(), true),
 
573
                            active_client->y());
 
574
}
 
575
 
 
576
void Workspace::slotWindowPackRight()
 
577
{
 
578
    if (active_client && active_client->isMovable())
 
579
        active_client->move(
 
580
            packPositionRight(active_client, active_client->geometry().right(), true)
 
581
            - active_client->width() + 1, active_client->y());
 
582
}
 
583
 
 
584
void Workspace::slotWindowPackUp()
 
585
{
 
586
    if (active_client && active_client->isMovable())
 
587
        active_client->move(active_client->x(),
 
588
                            packPositionUp(active_client, active_client->geometry().top(), true));
 
589
}
 
590
 
 
591
void Workspace::slotWindowPackDown()
 
592
{
 
593
    if (active_client && active_client->isMovable())
 
594
        active_client->move(active_client->x(),
 
595
                            packPositionDown(active_client, active_client->geometry().bottom(), true) - active_client->height() + 1);
 
596
}
 
597
 
 
598
void Workspace::slotWindowGrowHorizontal()
 
599
{
 
600
    if (active_client)
 
601
        active_client->growHorizontal();
 
602
}
 
603
 
 
604
void Client::growHorizontal()
 
605
{
 
606
    if (!isResizable() || isShade())
 
607
        return;
 
608
    QRect geom = geometry();
 
609
    geom.setRight(workspace()->packPositionRight(this, geom.right(), true));
 
610
    QSize adjsize = adjustedSize(geom.size(), SizemodeFixedW);
 
611
    if (geometry().size() == adjsize && geom.size() != adjsize && xSizeHint.width_inc > 1) { // take care of size increments
 
612
        int newright = workspace()->packPositionRight(this, geom.right() + xSizeHint.width_inc - 1, true);
 
613
        // check that it hasn't grown outside of the area, due to size increments
 
614
        // TODO this may be wrong?
 
615
        if (workspace()->clientArea(MovementArea,
 
616
                                   QPoint((x() + newright) / 2, geometry().center().y()), desktop()).right() >= newright)
 
617
            geom.setRight(newright);
 
618
    }
 
619
    geom.setSize(adjustedSize(geom.size(), SizemodeFixedW));
 
620
    setGeometry(geom);
 
621
}
 
622
 
 
623
void Workspace::slotWindowShrinkHorizontal()
 
624
{
 
625
    if (active_client)
 
626
        active_client->shrinkHorizontal();
 
627
}
 
628
 
 
629
void Client::shrinkHorizontal()
 
630
{
 
631
    if (!isResizable() || isShade())
 
632
        return;
 
633
    QRect geom = geometry();
 
634
    geom.setRight(workspace()->packPositionLeft(this, geom.right(), false));
 
635
    if (geom.width() <= 1)
 
636
        return;
 
637
    geom.setSize(adjustedSize(geom.size(), SizemodeFixedW));
 
638
    if (geom.width() > 20)
 
639
        setGeometry(geom);
 
640
}
 
641
 
 
642
void Workspace::slotWindowGrowVertical()
 
643
{
 
644
    if (active_client)
 
645
        active_client->growVertical();
 
646
}
 
647
 
 
648
void Client::growVertical()
 
649
{
 
650
    if (!isResizable() || isShade())
 
651
        return;
 
652
    QRect geom = geometry();
 
653
    geom.setBottom(workspace()->packPositionDown(this, geom.bottom(), true));
 
654
    QSize adjsize = adjustedSize(geom.size(), SizemodeFixedH);
 
655
    if (geometry().size() == adjsize && geom.size() != adjsize && xSizeHint.height_inc > 1) { // take care of size increments
 
656
        int newbottom = workspace()->packPositionDown(this, geom.bottom() + xSizeHint.height_inc - 1, true);
 
657
        // check that it hasn't grown outside of the area, due to size increments
 
658
        if (workspace()->clientArea(MovementArea,
 
659
                                   QPoint(geometry().center().x(), (y() + newbottom) / 2), desktop()).bottom() >= newbottom)
 
660
            geom.setBottom(newbottom);
 
661
    }
 
662
    geom.setSize(adjustedSize(geom.size(), SizemodeFixedH));
 
663
    setGeometry(geom);
 
664
}
 
665
 
 
666
 
 
667
void Workspace::slotWindowShrinkVertical()
 
668
{
 
669
    if (active_client)
 
670
        active_client->shrinkVertical();
 
671
}
 
672
 
 
673
void Client::shrinkVertical()
 
674
{
 
675
    if (!isResizable() || isShade())
 
676
        return;
 
677
    QRect geom = geometry();
 
678
    geom.setBottom(workspace()->packPositionUp(this, geom.bottom(), false));
 
679
    if (geom.height() <= 1)
 
680
        return;
 
681
    geom.setSize(adjustedSize(geom.size(), SizemodeFixedH));
 
682
    if (geom.height() > 20)
 
683
        setGeometry(geom);
 
684
}
 
685
 
 
686
 
 
687
void Workspace::slotWindowQuickTileLeft()
 
688
{
 
689
    if (!active_client)
 
690
        return;
 
691
 
 
692
    active_client->setQuickTileMode(QuickTileLeft, true);
 
693
}
 
694
 
 
695
void Workspace::slotWindowQuickTileRight()
 
696
{
 
697
    if (!active_client)
 
698
        return;
 
699
 
 
700
    active_client->setQuickTileMode(QuickTileRight, true);
 
701
}
 
702
 
 
703
void Workspace::slotWindowQuickTileTopLeft()
 
704
{
 
705
    if (!active_client) {
 
706
        return;
 
707
    }
 
708
    active_client->setQuickTileMode(QuickTileTop|QuickTileLeft, true);
 
709
}
 
710
 
 
711
void Workspace::slotWindowQuickTileTopRight()
 
712
{
 
713
    if (!active_client) {
 
714
        return;
 
715
    }
 
716
    active_client->setQuickTileMode(QuickTileTop|QuickTileRight, true);
 
717
}
 
718
 
 
719
void Workspace::slotWindowQuickTileBottomLeft()
 
720
{
 
721
    if (!active_client) {
 
722
        return;
 
723
    }
 
724
    active_client->setQuickTileMode(QuickTileBottom|QuickTileLeft, true);
 
725
}
 
726
 
 
727
void Workspace::slotWindowQuickTileBottomRight()
 
728
{
 
729
    if (!active_client) {
 
730
        return;
 
731
    }
 
732
    active_client->setQuickTileMode(QuickTileBottom|QuickTileRight, true);
 
733
}
 
734
 
 
735
int Workspace::packPositionLeft(const Client* cl, int oldx, bool left_edge) const
 
736
{
 
737
    int newx = clientArea(MovementArea, cl).left();
 
738
    if (oldx <= newx)   // try another Xinerama screen
 
739
        newx = clientArea(MovementArea,
 
740
                          QPoint(cl->geometry().left() - 1, cl->geometry().center().y()), cl->desktop()).left();
 
741
    if (oldx <= newx)
 
742
        return oldx;
 
743
    for (ClientList::ConstIterator it = clients.constBegin();
 
744
            it != clients.constEnd();
 
745
            ++it) {
 
746
        if (!(*it)->isShown(false) || !(*it)->isOnDesktop(active_client->desktop()))
 
747
            continue;
 
748
        int x = left_edge ? (*it)->geometry().right() + 1 : (*it)->geometry().left() - 1;
 
749
        if (x > newx && x < oldx
 
750
                && !(cl->geometry().top() > (*it)->geometry().bottom()  // they overlap in Y direction
 
751
                     || cl->geometry().bottom() < (*it)->geometry().top()))
 
752
            newx = x;
 
753
    }
 
754
    return newx;
 
755
}
 
756
 
 
757
int Workspace::packPositionRight(const Client* cl, int oldx, bool right_edge) const
 
758
{
 
759
    int newx = clientArea(MovementArea, cl).right();
 
760
    if (oldx >= newx)   // try another Xinerama screen
 
761
        newx = clientArea(MovementArea,
 
762
                          QPoint(cl->geometry().right() + 1, cl->geometry().center().y()), cl->desktop()).right();
 
763
    if (oldx >= newx)
 
764
        return oldx;
 
765
    for (ClientList::ConstIterator it = clients.constBegin();
 
766
            it != clients.constEnd();
 
767
            ++it) {
 
768
        if (!(*it)->isShown(false) || !(*it)->isOnDesktop(cl->desktop()))
 
769
            continue;
 
770
        int x = right_edge ? (*it)->geometry().left() - 1 : (*it)->geometry().right() + 1;
 
771
        if (x < newx && x > oldx
 
772
                && !(cl->geometry().top() > (*it)->geometry().bottom()
 
773
                     || cl->geometry().bottom() < (*it)->geometry().top()))
 
774
            newx = x;
 
775
    }
 
776
    return newx;
 
777
}
 
778
 
 
779
int Workspace::packPositionUp(const Client* cl, int oldy, bool top_edge) const
 
780
{
 
781
    int newy = clientArea(MovementArea, cl).top();
 
782
    if (oldy <= newy)   // try another Xinerama screen
 
783
        newy = clientArea(MovementArea,
 
784
                          QPoint(cl->geometry().center().x(), cl->geometry().top() - 1), cl->desktop()).top();
 
785
    if (oldy <= newy)
 
786
        return oldy;
 
787
    for (ClientList::ConstIterator it = clients.constBegin();
 
788
            it != clients.constEnd();
 
789
            ++it) {
 
790
        if (!(*it)->isShown(false) || !(*it)->isOnDesktop(cl->desktop()))
 
791
            continue;
 
792
        int y = top_edge ? (*it)->geometry().bottom() + 1 : (*it)->geometry().top() - 1;
 
793
        if (y > newy && y < oldy
 
794
                && !(cl->geometry().left() > (*it)->geometry().right()  // they overlap in X direction
 
795
                     || cl->geometry().right() < (*it)->geometry().left()))
 
796
            newy = y;
 
797
    }
 
798
    return newy;
 
799
}
 
800
 
 
801
int Workspace::packPositionDown(const Client* cl, int oldy, bool bottom_edge) const
 
802
{
 
803
    int newy = clientArea(MovementArea, cl).bottom();
 
804
    if (oldy >= newy)   // try another Xinerama screen
 
805
        newy = clientArea(MovementArea,
 
806
                          QPoint(cl->geometry().center().x(), cl->geometry().bottom() + 1), cl->desktop()).bottom();
 
807
    if (oldy >= newy)
 
808
        return oldy;
 
809
    for (ClientList::ConstIterator it = clients.constBegin();
 
810
            it != clients.constEnd();
 
811
            ++it) {
 
812
        if (!(*it)->isShown(false) || !(*it)->isOnDesktop(cl->desktop()))
 
813
            continue;
 
814
        int y = bottom_edge ? (*it)->geometry().top() - 1 : (*it)->geometry().bottom() + 1;
 
815
        if (y < newy && y > oldy
 
816
                && !(cl->geometry().left() > (*it)->geometry().right()
 
817
                     || cl->geometry().right() < (*it)->geometry().left()))
 
818
            newy = y;
 
819
    }
 
820
    return newy;
 
821
}
 
822
 
 
823
/*!
 
824
  Asks the internal positioning object to place a client
 
825
*/
 
826
void Workspace::place(Client* c, QRect& area)
 
827
{
 
828
    initPositioning->place(c, area);
 
829
}
 
830
 
 
831
void Workspace::placeSmart(Client* c, const QRect& area)
 
832
{
 
833
    initPositioning->placeSmart(c, area);
 
834
}
 
835
 
 
836
#endif
 
837
 
 
838
} // namespace