1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qworkspace.h"
43 #ifndef QT_NO_WORKSPACE
44 #include "qapplication.h"
45 #include "qbitmap.h"
46 #include "qcursor.h"
47 #include "qdesktopwidget.h"
48 #include "qevent.h"
49 #include "qhash.h"
50 #include "qicon.h"
51 #include "qimage.h"
52 #include "qlabel.h"
53 #include "qlayout.h"
54 #include "qmenubar.h"
55 #include "qmenu.h"
56 #include "qpainter.h"
57 #include "qpointer.h"
58 #include "qscrollbar.h"
59 #include "qstyle.h"
60 #include "qstyleoption.h"
61 #include "qelapsedtimer.h"
62 #include "qtooltip.h"
63 #include "qdebug.h"
64 #include <private/qwidget_p.h>
65 #include <private/qwidgetresizehandler_p.h>
66 #include <private/qlayoutengine_p.h>
67 
68 QT_BEGIN_NAMESPACE
69 
70 class QWorkspaceTitleBarPrivate;
71 
72 
73 /**************************************************************
74 * QMDIControl
75 *
76 * Used for displaying MDI controls in a maximized MDI window
77 *
78 */
79 class QMDIControl : public QWidget
80 {
81     Q_OBJECT
82 signals:
83     void _q_minimize();
84     void _q_restore();
85     void _q_close();
86 
87 public:
88     QMDIControl(QWidget *widget);
89 
90 private:
91     QSize sizeHint() const;
92     void paintEvent(QPaintEvent *event);
93     void mousePressEvent(QMouseEvent *event);
94     void mouseReleaseEvent(QMouseEvent *event);
95     void mouseMoveEvent(QMouseEvent *event);
96     void leaveEvent(QEvent *event);
97     bool event(QEvent *event);
98     void initStyleOption(QStyleOptionComplex *option) const;
99     QStyle::SubControl activeControl; //control locked by pressing and holding the mouse
100     QStyle::SubControl hoverControl; //previously active hover control, used for tracking repaints
101 };
102 
event(QEvent * event)103 bool QMDIControl::event(QEvent *event)
104 {
105     if (event->type() == QEvent::ToolTip) {
106         QStyleOptionComplex opt;
107         initStyleOption(&opt);
108 #ifndef QT_NO_TOOLTIP
109         QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
110         QStyle::SubControl ctrl = style()->hitTestComplexControl(QStyle::CC_MdiControls, &opt,
111                                                                  helpEvent->pos(), this);
112         if (ctrl == QStyle::SC_MdiCloseButton)
113             QToolTip::showText(helpEvent->globalPos(), QWorkspace::tr("Close"), this);
114         else if (ctrl == QStyle::SC_MdiMinButton)
115             QToolTip::showText(helpEvent->globalPos(), QWorkspace::tr("Minimize"), this);
116         else if (ctrl == QStyle::SC_MdiNormalButton)
117             QToolTip::showText(helpEvent->globalPos(), QWorkspace::tr("Restore Down"), this);
118         else
119             QToolTip::hideText();
120 #endif // QT_NO_TOOLTIP
121     }
122     return QWidget::event(event);
123 }
124 
initStyleOption(QStyleOptionComplex * option) const125 void QMDIControl::initStyleOption(QStyleOptionComplex *option) const
126 {
127     option->initFrom(this);
128     option->subControls = QStyle::SC_All;
129     option->activeSubControls = QStyle::SC_None;
130 }
131 
QMDIControl(QWidget * widget)132 QMDIControl::QMDIControl(QWidget *widget)
133     : QWidget(widget), activeControl(QStyle::SC_None),
134       hoverControl(QStyle::SC_None)
135 {
136     setObjectName(QLatin1String("qt_maxcontrols"));
137     setFocusPolicy(Qt::NoFocus);
138     setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
139     setMouseTracking(true);
140 }
141 
sizeHint() const142 QSize QMDIControl::sizeHint() const
143 {
144     ensurePolished();
145     QStyleOptionComplex opt;
146     initStyleOption(&opt);
147     QSize size(48, 16);
148     return style()->sizeFromContents(QStyle::CT_MdiControls, &opt, size, this);
149 }
150 
mousePressEvent(QMouseEvent * event)151 void QMDIControl::mousePressEvent(QMouseEvent *event)
152 {
153     if (event->button() != Qt::LeftButton) {
154         event->ignore();
155         return;
156     }
157     QStyleOptionComplex opt;
158     initStyleOption(&opt);
159     QStyle::SubControl ctrl = style()->hitTestComplexControl(QStyle::CC_MdiControls, &opt,
160                                                              event->pos(), this);
161     activeControl = ctrl;
162     update();
163 }
164 
mouseReleaseEvent(QMouseEvent * event)165 void QMDIControl::mouseReleaseEvent(QMouseEvent *event)
166 {
167     if (event->button() != Qt::LeftButton) {
168         event->ignore();
169         return;
170     }
171     QStyleOptionTitleBar opt;
172     initStyleOption(&opt);
173     QStyle::SubControl under_mouse = style()->hitTestComplexControl(QStyle::CC_MdiControls, &opt,
174                                                                     event->pos(), this);
175     if (under_mouse == activeControl) {
176         switch (activeControl) {
177         case QStyle::SC_MdiCloseButton:
178             emit _q_close();
179             break;
180         case QStyle::SC_MdiNormalButton:
181             emit _q_restore();
182             break;
183         case QStyle::SC_MdiMinButton:
184             emit _q_minimize();
185             break;
186         default:
187             break;
188         }
189     }
190     activeControl = QStyle::SC_None;
191     update();
192 }
193 
leaveEvent(QEvent *)194 void QMDIControl::leaveEvent(QEvent * /*event*/)
195 {
196     hoverControl = QStyle::SC_None;
197     update();
198 }
199 
mouseMoveEvent(QMouseEvent * event)200 void QMDIControl::mouseMoveEvent(QMouseEvent *event)
201 {
202     QStyleOptionTitleBar opt;
203     initStyleOption(&opt);
204     QStyle::SubControl under_mouse = style()->hitTestComplexControl(QStyle::CC_MdiControls, &opt,
205                                                                     event->pos(), this);
206     //test if hover state changes
207     if (hoverControl != under_mouse) {
208         hoverControl = under_mouse;
209         update();
210     }
211 }
212 
paintEvent(QPaintEvent *)213 void QMDIControl::paintEvent(QPaintEvent *)
214 {
215     QPainter p(this);
216     QStyleOptionComplex opt;
217     initStyleOption(&opt);
218     if (activeControl == hoverControl) {
219         opt.activeSubControls = activeControl;
220         opt.state |= QStyle::State_Sunken;
221     } else if (hoverControl != QStyle::SC_None && (activeControl == QStyle::SC_None)) {
222         opt.activeSubControls = hoverControl;
223         opt.state |= QStyle::State_MouseOver;
224     }
225     style()->drawComplexControl(QStyle::CC_MdiControls, &opt, &p, this);
226 }
227 
228 class QWorkspaceTitleBar : public QWidget
229 {
230     Q_OBJECT
231     Q_DECLARE_PRIVATE(QWorkspaceTitleBar)
232     Q_PROPERTY(bool autoRaise READ autoRaise WRITE setAutoRaise)
233     Q_PROPERTY(bool movable READ isMovable WRITE setMovable)
234 
235 public:
236     QWorkspaceTitleBar (QWidget *w, QWidget *parent, Qt::WindowFlags f = 0);
237     ~QWorkspaceTitleBar();
238 
239     bool isActive() const;
240     bool usesActiveColor() const;
241 
242     bool isMovable() const;
243     void setMovable(bool);
244 
245     bool autoRaise() const;
246     void setAutoRaise(bool);
247 
248     QWidget *window() const;
249     bool isTool() const;
250 
251     QSize sizeHint() const;
252     void initStyleOption(QStyleOptionTitleBar *option) const;
253 
254 public slots:
255     void setActive(bool);
256 
257 signals:
258     void doActivate();
259     void doNormal();
260     void doClose();
261     void doMaximize();
262     void doMinimize();
263     void doShade();
264     void showOperationMenu();
265     void popupOperationMenu(const QPoint&);
266     void doubleClicked();
267 
268 protected:
269     bool event(QEvent *);
270 #ifndef QT_NO_CONTEXTMENU
271     void contextMenuEvent(QContextMenuEvent *);
272 #endif
273     void mousePressEvent(QMouseEvent *);
274     void mouseDoubleClickEvent(QMouseEvent *);
275     void mouseReleaseEvent(QMouseEvent *);
276     void mouseMoveEvent(QMouseEvent *);
277     void enterEvent(QEvent *e);
278     void leaveEvent(QEvent *e);
279     void paintEvent(QPaintEvent *p);
280 
281 private:
282     Q_DISABLE_COPY(QWorkspaceTitleBar)
283 };
284 
285 
286 class QWorkspaceTitleBarPrivate : public QWidgetPrivate
287 {
288     Q_DECLARE_PUBLIC(QWorkspaceTitleBar)
289 public:
QWorkspaceTitleBarPrivate()290     QWorkspaceTitleBarPrivate()
291         :
292         lastControl(QStyle::SC_None),
293 #ifndef QT_NO_TOOLTIP
294         toolTip(0),
295 #endif
296         act(0), window(0), movable(1), pressed(0), autoraise(0), moving(0)
297     {
298     }
299 
300     Qt::WindowFlags flags;
301     QStyle::SubControl buttonDown;
302     QStyle::SubControl lastControl;
303     QPoint moveOffset;
304 #ifndef QT_NO_TOOLTIP
305     QToolTip *toolTip;
306 #endif
307     bool act                    :1;
308     QPointer<QWidget> window;
309     bool movable            :1;
310     bool pressed            :1;
311     bool autoraise          :1;
312     bool moving : 1;
313 
314     int titleBarState() const;
315     void readColors();
316 };
317 
titleBarState() const318 inline int QWorkspaceTitleBarPrivate::titleBarState() const
319 {
320     Q_Q(const QWorkspaceTitleBar);
321     uint state = window ? window->windowState() : static_cast<Qt::WindowStates>(Qt::WindowNoState);
322     state |= uint((act && q->isActiveWindow()) ? QStyle::State_Active : QStyle::State_None);
323     return (int)state;
324 }
325 
initStyleOption(QStyleOptionTitleBar * option) const326 void QWorkspaceTitleBar::initStyleOption(QStyleOptionTitleBar *option) const
327 {
328     Q_D(const QWorkspaceTitleBar);
329     option->initFrom(this);
330     //################
331     if (d->window && (d->flags & Qt::WindowTitleHint)) {
332         option->text = d->window->windowTitle();
333         QIcon icon = d->window->windowIcon();
334         QSize s = icon.actualSize(QSize(64, 64));
335         option->icon = icon.pixmap(s);
336     }
337     option->subControls = QStyle::SC_All;
338     option->activeSubControls = QStyle::SC_None;
339     option->titleBarState = d->titleBarState();
340     option->titleBarFlags = d->flags;
341     option->state &= ~QStyle::State_MouseOver;
342 }
343 
QWorkspaceTitleBar(QWidget * w,QWidget * parent,Qt::WindowFlags f)344 QWorkspaceTitleBar::QWorkspaceTitleBar(QWidget *w, QWidget *parent, Qt::WindowFlags f)
345     : QWidget(*new QWorkspaceTitleBarPrivate, parent, Qt::FramelessWindowHint)
346 {
347     Q_D(QWorkspaceTitleBar);
348     if (f == 0 && w)
349         f = w->windowFlags();
350     d->flags = f;
351     d->window = w;
352     d->buttonDown = QStyle::SC_None;
353     d->act = 0;
354     if (w) {
355         if (w->maximumSize() != QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX))
356             d->flags &= ~Qt::WindowMaximizeButtonHint;
357         setWindowTitle(w->windowTitle());
358     }
359 
360     d->readColors();
361     setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
362     setMouseTracking(true);
363     setAutoRaise(style()->styleHint(QStyle::SH_TitleBar_AutoRaise, 0, this));
364 }
365 
~QWorkspaceTitleBar()366 QWorkspaceTitleBar::~QWorkspaceTitleBar()
367 {
368 }
369 
370 
371 #ifdef Q_WS_WIN
colorref2qrgb(COLORREF col)372 static inline QRgb colorref2qrgb(COLORREF col)
373 {
374     return qRgb(GetRValue(col),GetGValue(col),GetBValue(col));
375 }
376 #endif
377 
readColors()378 void QWorkspaceTitleBarPrivate::readColors()
379 {
380     Q_Q(QWorkspaceTitleBar);
381     QPalette pal = q->palette();
382 
383     bool colorsInitialized = false;
384 
385 #ifdef Q_WS_WIN // ask system properties on windows
386 #ifndef SPI_GETGRADIENTCAPTIONS
387 #define SPI_GETGRADIENTCAPTIONS 0x1008
388 #endif
389 #ifndef COLOR_GRADIENTACTIVECAPTION
390 #define COLOR_GRADIENTACTIVECAPTION 27
391 #endif
392 #ifndef COLOR_GRADIENTINACTIVECAPTION
393 #define COLOR_GRADIENTINACTIVECAPTION 28
394 #endif
395     if (QApplication::desktopSettingsAware()) {
396         pal.setColor(QPalette::Active, QPalette::Highlight, colorref2qrgb(GetSysColor(COLOR_ACTIVECAPTION)));
397         pal.setColor(QPalette::Inactive, QPalette::Highlight, colorref2qrgb(GetSysColor(COLOR_INACTIVECAPTION)));
398         pal.setColor(QPalette::Active, QPalette::HighlightedText, colorref2qrgb(GetSysColor(COLOR_CAPTIONTEXT)));
399         pal.setColor(QPalette::Inactive, QPalette::HighlightedText, colorref2qrgb(GetSysColor(COLOR_INACTIVECAPTIONTEXT)));
400 
401         colorsInitialized = true;
402         BOOL gradient = false;
403         SystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0);
404 
405         if (gradient) {
406             pal.setColor(QPalette::Active, QPalette::Base, colorref2qrgb(GetSysColor(COLOR_GRADIENTACTIVECAPTION)));
407             pal.setColor(QPalette::Inactive, QPalette::Base, colorref2qrgb(GetSysColor(COLOR_GRADIENTINACTIVECAPTION)));
408         } else {
409             pal.setColor(QPalette::Active, QPalette::Base, pal.color(QPalette::Active, QPalette::Highlight));
410             pal.setColor(QPalette::Inactive, QPalette::Base, pal.color(QPalette::Inactive, QPalette::Highlight));
411         }
412     }
413 #endif // Q_WS_WIN
414     if (!colorsInitialized) {
415         pal.setColor(QPalette::Active, QPalette::Highlight,
416                       pal.color(QPalette::Active, QPalette::Highlight));
417         pal.setColor(QPalette::Active, QPalette::Base,
418                       pal.color(QPalette::Active, QPalette::Highlight));
419         pal.setColor(QPalette::Inactive, QPalette::Highlight,
420                       pal.color(QPalette::Inactive, QPalette::Dark));
421         pal.setColor(QPalette::Inactive, QPalette::Base,
422                       pal.color(QPalette::Inactive, QPalette::Dark));
423         pal.setColor(QPalette::Inactive, QPalette::HighlightedText,
424                       pal.color(QPalette::Inactive, QPalette::Window));
425     }
426 
427     q->setPalette(pal);
428     q->setActive(act);
429 }
430 
mousePressEvent(QMouseEvent * e)431 void QWorkspaceTitleBar::mousePressEvent(QMouseEvent *e)
432 {
433     Q_D(QWorkspaceTitleBar);
434     if (!d->act)
435         emit doActivate();
436     if (e->button() == Qt::LeftButton) {
437         if (style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, 0)
438             && !rect().adjusted(5, 5, -5, 0).contains(e->pos())) {
439             // propagate border events to the QWidgetResizeHandler
440             e->ignore();
441             return;
442         }
443 
444         d->pressed = true;
445         QStyleOptionTitleBar opt;
446         initStyleOption(&opt);
447         QStyle::SubControl ctrl = style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt,
448                                                                  e->pos(), this);
449         switch (ctrl) {
450         case QStyle::SC_TitleBarSysMenu:
451             if (d->flags & Qt::WindowSystemMenuHint) {
452                 d->buttonDown = QStyle::SC_None;
453                 static QElapsedTimer *t = 0;
454                 static QWorkspaceTitleBar *tc = 0;
455                 if (!t)
456                     t = new QElapsedTimer;
457                 if (tc != this || t->elapsed() > QApplication::doubleClickInterval()) {
458                     emit showOperationMenu();
459                     t->start();
460                     tc = this;
461                 } else {
462                     tc = 0;
463                     emit doClose();
464                     return;
465                 }
466             }
467             break;
468 
469         case QStyle::SC_TitleBarShadeButton:
470         case QStyle::SC_TitleBarUnshadeButton:
471             if (d->flags & Qt::WindowShadeButtonHint)
472                 d->buttonDown = ctrl;
473             break;
474 
475         case QStyle::SC_TitleBarNormalButton:
476                 d->buttonDown = ctrl;
477             break;
478 
479         case QStyle::SC_TitleBarMinButton:
480             if (d->flags & Qt::WindowMinimizeButtonHint)
481                 d->buttonDown = ctrl;
482             break;
483 
484         case QStyle::SC_TitleBarMaxButton:
485             if (d->flags & Qt::WindowMaximizeButtonHint)
486                 d->buttonDown = ctrl;
487             break;
488 
489         case QStyle::SC_TitleBarCloseButton:
490             if (d->flags & Qt::WindowSystemMenuHint)
491                 d->buttonDown = ctrl;
492             break;
493 
494         case QStyle::SC_TitleBarLabel:
495             d->buttonDown = ctrl;
496             d->moveOffset = mapToParent(e->pos());
497             break;
498 
499         default:
500             break;
501         }
502         update();
503     } else {
504         d->pressed = false;
505     }
506 }
507 
508 #ifndef QT_NO_CONTEXTMENU
contextMenuEvent(QContextMenuEvent * e)509 void QWorkspaceTitleBar::contextMenuEvent(QContextMenuEvent *e)
510 {
511     QStyleOptionTitleBar opt;
512     initStyleOption(&opt);
513     QStyle::SubControl ctrl = style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt, e->pos(),
514                                                              this);
515     if(ctrl == QStyle::SC_TitleBarLabel || ctrl == QStyle::SC_TitleBarSysMenu) {
516         e->accept();
517         emit popupOperationMenu(e->globalPos());
518     } else {
519         e->ignore();
520     }
521 }
522 #endif // QT_NO_CONTEXTMENU
523 
mouseReleaseEvent(QMouseEvent * e)524 void QWorkspaceTitleBar::mouseReleaseEvent(QMouseEvent *e)
525 {
526     Q_D(QWorkspaceTitleBar);
527     if (!d->window) {
528         // could have been deleted as part of a double click event on the sysmenu
529         return;
530     }
531     if (e->button() == Qt::LeftButton && d->pressed) {
532         if (style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, 0)
533             && !rect().adjusted(5, 5, -5, 0).contains(e->pos())) {
534             // propagate border events to the QWidgetResizeHandler
535             e->ignore();
536             d->buttonDown = QStyle::SC_None;
537             d->pressed = false;
538             return;
539         }
540         e->accept();
541         QStyleOptionTitleBar opt;
542         initStyleOption(&opt);
543         QStyle::SubControl ctrl = style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt,
544                                                                  e->pos(), this);
545 
546         if (d->pressed) {
547             update();
548             d->pressed = false;
549             d->moving = false;
550         }
551         if (ctrl == d->buttonDown) {
552             d->buttonDown = QStyle::SC_None;
553             switch(ctrl) {
554             case QStyle::SC_TitleBarShadeButton:
555             case QStyle::SC_TitleBarUnshadeButton:
556                 if(d->flags & Qt::WindowShadeButtonHint)
557                     emit doShade();
558                 break;
559 
560             case QStyle::SC_TitleBarNormalButton:
561                 if(d->flags & Qt::WindowMinMaxButtonsHint)
562                     emit doNormal();
563                 break;
564 
565             case QStyle::SC_TitleBarMinButton:
566                 if(d->flags & Qt::WindowMinimizeButtonHint) {
567                     if (d->window && d->window->isMinimized())
568                         emit doNormal();
569                     else
570                         emit doMinimize();
571                 }
572                 break;
573 
574             case QStyle::SC_TitleBarMaxButton:
575                 if(d->flags & Qt::WindowMaximizeButtonHint) {
576                     if(d->window && d->window->isMaximized())
577                         emit doNormal();
578                     else
579                         emit doMaximize();
580                 }
581                 break;
582 
583             case QStyle::SC_TitleBarCloseButton:
584                 if(d->flags & Qt::WindowSystemMenuHint) {
585                     d->buttonDown = QStyle::SC_None;
586                     emit doClose();
587                     return;
588                 }
589                 break;
590 
591             default:
592                 break;
593             }
594         }
595     } else {
596         e->ignore();
597     }
598 }
599 
mouseMoveEvent(QMouseEvent * e)600 void QWorkspaceTitleBar::mouseMoveEvent(QMouseEvent *e)
601 {
602     Q_D(QWorkspaceTitleBar);
603     e->ignore();
604     if ((e->buttons() & Qt::LeftButton) && style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, 0)
605         && !rect().adjusted(5, 5, -5, 0).contains(e->pos()) && !d->pressed) {
606         // propagate border events to the QWidgetResizeHandler
607         return;
608     }
609 
610     QStyleOptionTitleBar opt;
611     initStyleOption(&opt);
612     QStyle::SubControl under_mouse = style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt,
613                                                                     e->pos(), this);
614     if(under_mouse != d->lastControl) {
615         d->lastControl = under_mouse;
616         update();
617     }
618 
619     switch (d->buttonDown) {
620     case QStyle::SC_None:
621         break;
622     case QStyle::SC_TitleBarSysMenu:
623         break;
624     case QStyle::SC_TitleBarLabel:
625         if (d->buttonDown == QStyle::SC_TitleBarLabel && d->movable && d->pressed) {
626             if (d->moving || (d->moveOffset - mapToParent(e->pos())).manhattanLength() >= 4) {
627                 d->moving = true;
628                 QPoint p = mapFromGlobal(e->globalPos());
629 
630                 QWidget *parent = d->window ? d->window->parentWidget() : 0;
631                 if(parent && parent->inherits("QWorkspaceChild")) {
632                     QWidget *workspace = parent->parentWidget();
633                     p = workspace->mapFromGlobal(e->globalPos());
634                     if (!workspace->rect().contains(p)) {
635                         if (p.x() < 0)
636                             p.rx() = 0;
637                         if (p.y() < 0)
638                             p.ry() = 0;
639                         if (p.x() > workspace->width())
640                             p.rx() = workspace->width();
641                         if (p.y() > workspace->height())
642                             p.ry() = workspace->height();
643                     }
644                 }
645 
646                 QPoint pp = p - d->moveOffset;
647                 if (!parentWidget()->isMaximized())
648                     parentWidget()->move(pp);
649             }
650         }
651         e->accept();
652         break;
653     default:
654         break;
655     }
656 }
657 
isTool() const658 bool QWorkspaceTitleBar::isTool() const
659 {
660     Q_D(const QWorkspaceTitleBar);
661     return (d->flags & Qt::WindowType_Mask) == Qt::Tool;
662 }
663 
664 // from qwidget.cpp
665 extern QString qt_setWindowTitle_helperHelper(const QString &, const QWidget*);
666 
paintEvent(QPaintEvent *)667 void QWorkspaceTitleBar::paintEvent(QPaintEvent *)
668 {
669     Q_D(QWorkspaceTitleBar);
670     QStyleOptionTitleBar opt;
671     initStyleOption(&opt);
672     opt.subControls = QStyle::SC_TitleBarLabel;
673     opt.activeSubControls = d->buttonDown;
674 
675     if (d->window && (d->flags & Qt::WindowTitleHint)) {
676         QString title = qt_setWindowTitle_helperHelper(opt.text, d->window);
677         int maxw = style()->subControlRect(QStyle::CC_TitleBar, &opt, QStyle::SC_TitleBarLabel,
678                                        this).width();
679         opt.text = fontMetrics().elidedText(title, Qt::ElideRight, maxw);
680     }
681 
682     if (d->flags & Qt::WindowSystemMenuHint) {
683         opt.subControls |= QStyle::SC_TitleBarSysMenu | QStyle::SC_TitleBarCloseButton;
684         if (d->window && (d->flags & Qt::WindowShadeButtonHint)) {
685             if (d->window->isMinimized())
686                 opt.subControls |= QStyle::SC_TitleBarUnshadeButton;
687             else
688                 opt.subControls |= QStyle::SC_TitleBarShadeButton;
689         }
690         if (d->window && (d->flags & Qt::WindowMinMaxButtonsHint)) {
691             if(d->window && d->window->isMinimized())
692                 opt.subControls |= QStyle::SC_TitleBarNormalButton;
693             else
694                 opt.subControls |= QStyle::SC_TitleBarMinButton;
695         }
696         if (d->window && (d->flags & Qt::WindowMaximizeButtonHint) && !d->window->isMaximized())
697             opt.subControls |= QStyle::SC_TitleBarMaxButton;
698     }
699 
700     QStyle::SubControl under_mouse = QStyle::SC_None;
701     under_mouse = style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt,
702                                                      mapFromGlobal(QCursor::pos()), this);
703     if ((d->buttonDown == under_mouse) && d->pressed) {
704         opt.state |= QStyle::State_Sunken;
705     } else if( autoRaise() && under_mouse != QStyle::SC_None && !d->pressed) {
706         opt.activeSubControls = under_mouse;
707         opt.state |= QStyle::State_MouseOver;
708     }
709     opt.palette.setCurrentColorGroup(usesActiveColor() ? QPalette::Active : QPalette::Inactive);
710 
711     QPainter p(this);
712     style()->drawComplexControl(QStyle::CC_TitleBar, &opt, &p, this);
713 }
714 
mouseDoubleClickEvent(QMouseEvent * e)715 void QWorkspaceTitleBar::mouseDoubleClickEvent(QMouseEvent *e)
716 {
717     Q_D(QWorkspaceTitleBar);
718     if (e->button() != Qt::LeftButton) {
719         e->ignore();
720         return;
721     }
722     e->accept();
723     QStyleOptionTitleBar opt;
724     initStyleOption(&opt);
725     switch (style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt, e->pos(), this)) {
726     case QStyle::SC_TitleBarLabel:
727         emit doubleClicked();
728         break;
729 
730     case QStyle::SC_TitleBarSysMenu:
731         if (d->flags & Qt::WindowSystemMenuHint)
732             emit doClose();
733         break;
734 
735     default:
736         break;
737     }
738 }
739 
leaveEvent(QEvent *)740 void QWorkspaceTitleBar::leaveEvent(QEvent *)
741 {
742     Q_D(QWorkspaceTitleBar);
743     d->lastControl = QStyle::SC_None;
744     if(autoRaise() && !d->pressed)
745         update();
746 }
747 
enterEvent(QEvent *)748 void QWorkspaceTitleBar::enterEvent(QEvent *)
749 {
750     Q_D(QWorkspaceTitleBar);
751     if(autoRaise() && !d->pressed)
752         update();
753     QEvent e(QEvent::Leave);
754     QApplication::sendEvent(parentWidget(), &e);
755 }
756 
setActive(bool active)757 void QWorkspaceTitleBar::setActive(bool active)
758 {
759     Q_D(QWorkspaceTitleBar);
760     if (d->act == active)
761         return ;
762 
763     d->act = active;
764     update();
765 }
766 
isActive() const767 bool QWorkspaceTitleBar::isActive() const
768 {
769     Q_D(const QWorkspaceTitleBar);
770     return d->act;
771 }
772 
usesActiveColor() const773 bool QWorkspaceTitleBar::usesActiveColor() const
774 {
775     return (isActive() && isActiveWindow()) ||
776         (!window() && QWidget::window()->isActiveWindow());
777 }
778 
window() const779 QWidget *QWorkspaceTitleBar::window() const
780 {
781     Q_D(const QWorkspaceTitleBar);
782     return d->window;
783 }
784 
event(QEvent * e)785 bool QWorkspaceTitleBar::event(QEvent *e)
786 {
787     Q_D(QWorkspaceTitleBar);
788     if (e->type() == QEvent::ApplicationPaletteChange) {
789         d->readColors();
790     } else if (e->type() == QEvent::WindowActivate
791                || e->type() == QEvent::WindowDeactivate) {
792         if (d->act)
793             update();
794     }
795     return QWidget::event(e);
796 }
797 
setMovable(bool b)798 void QWorkspaceTitleBar::setMovable(bool b)
799 {
800     Q_D(QWorkspaceTitleBar);
801     d->movable = b;
802 }
803 
isMovable() const804 bool QWorkspaceTitleBar::isMovable() const
805 {
806     Q_D(const QWorkspaceTitleBar);
807     return d->movable;
808 }
809 
setAutoRaise(bool b)810 void QWorkspaceTitleBar::setAutoRaise(bool b)
811 {
812     Q_D(QWorkspaceTitleBar);
813     d->autoraise = b;
814 }
815 
autoRaise() const816 bool QWorkspaceTitleBar::autoRaise() const
817 {
818     Q_D(const QWorkspaceTitleBar);
819     return d->autoraise;
820 }
821 
sizeHint() const822 QSize QWorkspaceTitleBar::sizeHint() const
823 {
824     ensurePolished();
825     QStyleOptionTitleBar opt;
826     initStyleOption(&opt);
827     QRect menur = style()->subControlRect(QStyle::CC_TitleBar, &opt,
828                                           QStyle::SC_TitleBarSysMenu, this);
829     return QSize(menur.width(), style()->pixelMetric(QStyle::PM_TitleBarHeight, &opt, this));
830 }
831 
832 /*!
833     \class QWorkspace
834     \obsolete
835     \brief The QWorkspace widget provides a workspace window that can be
836     used in an MDI application.
837 
838     This class is deprecated. Use QMdiArea instead.
839 
840     Multiple Document Interface (MDI) applications are typically
841     composed of a main window containing a menu bar, a toolbar, and
842     a central QWorkspace widget. The workspace itself is used to display
843     a number of child windows, each of which is a widget.
844 
845     The workspace itself is an ordinary Qt widget. It has a standard
846     constructor that takes a parent widget.
847     Workspaces can be placed in any layout, but are typically given
848     as the central widget in a QMainWindow:
849 
850     \snippet doc/src/snippets/code/src_gui_widgets_qworkspace.cpp 0
851 
852     Child windows (MDI windows) are standard Qt widgets that are
853     inserted into the workspace with addWindow(). As with top-level
854     widgets, you can call functions such as show(), hide(),
855     showMaximized(), and setWindowTitle() on a child window to change
856     its appearance within the workspace. You can also provide widget
857     flags to determine the layout of the decoration or the behavior of
858     the widget itself.
859 
860     To change or retrieve the geometry of a child window, you must
861     operate on its parentWidget(). The parentWidget() provides
862     access to the decorated frame that contains the child window
863     widget. When a child window is maximised, its decorated frame
864     is hidden. If the top-level widget contains a menu bar, it will display
865     the maximised window's operations menu to the left of the menu
866     entries, and the window's controls to the right.
867 
868     A child window becomes active when it gets the keyboard focus,
869     or when setFocus() is called. The user can activate a window by moving
870     focus in the usual ways, for example by clicking a window or by pressing
871     Tab. The workspace emits a signal windowActivated() when the active
872     window changes, and the function activeWindow() returns a pointer to the
873     active child window, or 0 if no window is active.
874 
875     The convenience function windowList() returns a list of all child
876     windows. This information could be used in a popup menu
877     containing a list of windows, for example. This feature is also
878     available as part of the \l{Window Menu} Solution.
879 
880     QWorkspace provides two built-in layout strategies for child
881     windows: cascade() and tile(). Both are slots so you can easily
882     connect menu entries to them.
883 
884     \table
885     \row \o \inlineimage mdi-cascade.png
886          \o \inlineimage mdi-tile.png
887     \endtable
888 
889     If you want your users to be able to work with child windows
890     larger than the visible workspace area, set the scrollBarsEnabled
891     property to true.
892 
893     \sa QDockWidget, {MDI Example}
894 */
895 
896 
897 class QWorkspaceChild : public QWidget
898 {
899     Q_OBJECT
900 
901     friend class QWorkspacePrivate;
902     friend class QWorkspace;
903     friend class QWorkspaceTitleBar;
904 
905 public:
906     QWorkspaceChild(QWidget* window, QWorkspace* parent=0, Qt::WindowFlags flags = 0);
907     ~QWorkspaceChild();
908 
909     void setActive(bool);
910     bool isActive() const;
911 
912     void adjustToFullscreen();
913 
914     QWidget* windowWidget() const;
915     QWidget* iconWidget() const;
916 
917     void doResize();
918     void doMove();
919 
920     QSize sizeHint() const;
921     QSize minimumSizeHint() const;
922 
923     QSize baseSize() const;
924 
925     int frameWidth() const;
926 
927     void show();
928 
929     bool isWindowOrIconVisible() const;
930 
931 signals:
932     void showOperationMenu();
933     void popupOperationMenu(const QPoint&);
934 
935 public slots:
936     void activate();
937     void showMinimized();
938     void showMaximized();
939     void showNormal();
940     void showShaded();
941     void internalRaise();
942     void titleBarDoubleClicked();
943 
944 protected:
945     void enterEvent(QEvent *);
946     void leaveEvent(QEvent *);
947     void childEvent(QChildEvent*);
948     void resizeEvent(QResizeEvent *);
949     void moveEvent(QMoveEvent *);
950     bool eventFilter(QObject *, QEvent *);
951 
952     void paintEvent(QPaintEvent *);
953     void changeEvent(QEvent *);
954 
955 private:
956     void updateMask();
957 
958     Q_DISABLE_COPY(QWorkspaceChild)
959 
960     QWidget *childWidget;
961     QWidgetResizeHandler *widgetResizeHandler;
962     QWorkspaceTitleBar *titlebar;
963     QPointer<QWorkspaceTitleBar> iconw;
964     QSize windowSize;
965     QSize shadeRestore;
966     QSize shadeRestoreMin;
967     bool act                  :1;
968     bool shademode            :1;
969 };
970 
frameWidth() const971 int QWorkspaceChild::frameWidth() const
972 {
973     return contentsRect().left();
974 }
975 
976 
977 
978 class QWorkspacePrivate : public QWidgetPrivate {
979     Q_DECLARE_PUBLIC(QWorkspace)
980 public:
981     QWorkspaceChild* active;
982     QList<QWorkspaceChild *> windows;
983     QList<QWorkspaceChild *> focus;
984     QList<QWidget *> icons;
985     QWorkspaceChild* maxWindow;
986     QRect maxRestore;
987     QPointer<QMDIControl> maxcontrols;
988     QPointer<QMenuBar> maxmenubar;
989     QHash<int, const char*> shortcutMap;
990 
991     int px;
992     int py;
993     QWidget *becomeActive;
994     QPointer<QLabel> maxtools;
995     QString topTitle;
996 
997     QMenu *popup, *toolPopup;
998     enum WSActs { RestoreAct, MoveAct, ResizeAct, MinimizeAct, MaximizeAct, CloseAct, StaysOnTopAct, ShadeAct, NCountAct };
999     QAction *actions[NCountAct];
1000 
1001     QScrollBar *vbar, *hbar;
1002     QWidget *corner;
1003     int yoffset, xoffset;
1004     QBrush background;
1005 
1006     void init();
1007     void insertIcon(QWidget* w);
1008     void removeIcon(QWidget* w);
1009     void place(QWidget*);
1010 
1011     QWorkspaceChild* findChild(QWidget* w);
1012     void showMaximizeControls();
1013     void hideMaximizeControls();
1014     void activateWindow(QWidget* w, bool change_focus = true);
1015     void hideChild(QWorkspaceChild *c);
1016     void showWindow(QWidget* w);
1017     void maximizeWindow(QWidget* w);
1018     void minimizeWindow(QWidget* w);
1019     void normalizeWindow(QWidget* w);
1020 
1021     QRect updateWorkspace();
1022 
1023 private:
1024     void _q_normalizeActiveWindow();
1025     void _q_minimizeActiveWindow();
1026     void _q_showOperationMenu();
1027     void _q_popupOperationMenu(const QPoint&);
1028     void _q_operationMenuActivated(QAction *);
1029     void _q_scrollBarChanged();
1030     void _q_updateActions();
1031     bool inTitleChange;
1032 };
1033 
isChildOf(QWidget * child,QWidget * parent)1034 static bool isChildOf(QWidget * child, QWidget * parent)
1035 {
1036     if (!parent || !child)
1037         return false;
1038     QWidget * w = child;
1039     while(w && w != parent)
1040         w = w->parentWidget();
1041     return w != 0;
1042 }
1043 
1044 /*!
1045     Constructs a workspace with the given \a parent.
1046 */
QWorkspace(QWidget * parent)1047 QWorkspace::QWorkspace(QWidget *parent)
1048     : QWidget(*new QWorkspacePrivate, parent, 0)
1049 {
1050     Q_D(QWorkspace);
1051     d->init();
1052 }
1053 
1054 #ifdef QT3_SUPPORT
1055 /*!
1056     Use one of the constructors that doesn't take the \a name
1057     argument and then use setObjectName() instead.
1058 */
QWorkspace(QWidget * parent,const char * name)1059 QWorkspace::QWorkspace(QWidget *parent, const char *name)
1060     : QWidget(*new QWorkspacePrivate, parent, 0)
1061 {
1062     Q_D(QWorkspace);
1063     setObjectName(QString::fromAscii(name));
1064     d->init();
1065 }
1066 #endif // QT3_SUPPORT
1067 
1068 /*!
1069     \internal
1070 */
1071 void
init()1072 QWorkspacePrivate::init()
1073 {
1074     Q_Q(QWorkspace);
1075 
1076     maxcontrols = 0;
1077     active = 0;
1078     maxWindow = 0;
1079     maxtools = 0;
1080     px = 0;
1081     py = 0;
1082     becomeActive = 0;
1083     popup = new QMenu(q);
1084     toolPopup = new QMenu(q);
1085     popup->setObjectName(QLatin1String("qt_internal_mdi_popup"));
1086     toolPopup->setObjectName(QLatin1String("qt_internal_mdi_tool_popup"));
1087 
1088     actions[QWorkspacePrivate::RestoreAct] = new QAction(QIcon(q->style()->standardPixmap(QStyle::SP_TitleBarNormalButton, 0, q)),
1089                                                          QWorkspace::tr("&Restore"), q);
1090     actions[QWorkspacePrivate::MoveAct] = new QAction(QWorkspace::tr("&Move"), q);
1091     actions[QWorkspacePrivate::ResizeAct] = new QAction(QWorkspace::tr("&Size"), q);
1092     actions[QWorkspacePrivate::MinimizeAct] = new QAction(QIcon(q->style()->standardPixmap(QStyle::SP_TitleBarMinButton, 0, q)),
1093                                                           QWorkspace::tr("Mi&nimize"), q);
1094     actions[QWorkspacePrivate::MaximizeAct] = new QAction(QIcon(q->style()->standardPixmap(QStyle::SP_TitleBarMaxButton, 0, q)),
1095                                                           QWorkspace::tr("Ma&ximize"), q);
1096     actions[QWorkspacePrivate::CloseAct] = new QAction(QIcon(q->style()->standardPixmap(QStyle::SP_TitleBarCloseButton, 0, q)),
1097                                                           QWorkspace::tr("&Close")
1098 #ifndef QT_NO_SHORTCUT
1099                                                           +QLatin1Char('\t')+(QString)QKeySequence(Qt::CTRL+Qt::Key_F4)
1100 #endif
1101                                                           ,q);
1102     QObject::connect(actions[QWorkspacePrivate::CloseAct], SIGNAL(triggered()), q, SLOT(closeActiveWindow()));
1103     actions[QWorkspacePrivate::StaysOnTopAct] = new QAction(QWorkspace::tr("Stay on &Top"), q);
1104     actions[QWorkspacePrivate::StaysOnTopAct]->setChecked(true);
1105     actions[QWorkspacePrivate::ShadeAct] = new QAction(QIcon(q->style()->standardPixmap(QStyle::SP_TitleBarShadeButton, 0, q)),
1106                                                           QWorkspace::tr("Sh&ade"), q);
1107 
1108     QObject::connect(popup, SIGNAL(aboutToShow()), q, SLOT(_q_updateActions()));
1109     QObject::connect(popup, SIGNAL(triggered(QAction*)), q, SLOT(_q_operationMenuActivated(QAction*)));
1110     popup->addAction(actions[QWorkspacePrivate::RestoreAct]);
1111     popup->addAction(actions[QWorkspacePrivate::MoveAct]);
1112     popup->addAction(actions[QWorkspacePrivate::ResizeAct]);
1113     popup->addAction(actions[QWorkspacePrivate::MinimizeAct]);
1114     popup->addAction(actions[QWorkspacePrivate::MaximizeAct]);
1115     popup->addSeparator();
1116     popup->addAction(actions[QWorkspacePrivate::CloseAct]);
1117 
1118     QObject::connect(toolPopup, SIGNAL(aboutToShow()), q, SLOT(_q_updateActions()));
1119     QObject::connect(toolPopup, SIGNAL(triggered(QAction*)), q, SLOT(_q_operationMenuActivated(QAction*)));
1120     toolPopup->addAction(actions[QWorkspacePrivate::MoveAct]);
1121     toolPopup->addAction(actions[QWorkspacePrivate::ResizeAct]);
1122     toolPopup->addAction(actions[QWorkspacePrivate::StaysOnTopAct]);
1123     toolPopup->addSeparator();
1124     toolPopup->addAction(actions[QWorkspacePrivate::ShadeAct]);
1125     toolPopup->addAction(actions[QWorkspacePrivate::CloseAct]);
1126 
1127 #ifndef QT_NO_SHORTCUT
1128     // Set up shortcut bindings (id -> slot), most used first
1129     QList <QKeySequence> shortcuts = QKeySequence::keyBindings(QKeySequence::NextChild);
1130     foreach (const QKeySequence &seq, shortcuts)
1131         shortcutMap.insert(q->grabShortcut(seq), "activateNextWindow");
1132 
1133     shortcuts = QKeySequence::keyBindings(QKeySequence::PreviousChild);
1134     foreach (const QKeySequence &seq, shortcuts)
1135         shortcutMap.insert(q->grabShortcut(seq), "activatePreviousWindow");
1136 
1137     shortcuts = QKeySequence::keyBindings(QKeySequence::Close);
1138     foreach (const QKeySequence &seq, shortcuts)
1139         shortcutMap.insert(q->grabShortcut(seq), "closeActiveWindow");
1140 
1141     shortcutMap.insert(q->grabShortcut(QKeySequence(QLatin1String("ALT+-"))), "_q_showOperationMenu");
1142 #endif // QT_NO_SHORTCUT
1143 
1144     q->setBackgroundRole(QPalette::Dark);
1145     q->setAutoFillBackground(true);
1146     q->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
1147 
1148     hbar = vbar = 0;
1149     corner = 0;
1150     xoffset = yoffset = 0;
1151 
1152     q->window()->installEventFilter(q);
1153 
1154     inTitleChange = false;
1155     updateWorkspace();
1156 }
1157 
1158 /*!
1159     Destroys the workspace and frees any allocated resources.
1160 */
1161 
~QWorkspace()1162 QWorkspace::~QWorkspace()
1163 {
1164 }
1165 
1166 /*! \reimp */
sizeHint() const1167 QSize QWorkspace::sizeHint() const
1168 {
1169     QSize s(QApplication::desktop()->size());
1170     return QSize(s.width()*2/3, s.height()*2/3);
1171 }
1172 
1173 
1174 #ifdef QT3_SUPPORT
1175 /*!
1176     Sets the background color to \a c.
1177     Use setBackground() instead.
1178 */
setPaletteBackgroundColor(const QColor & c)1179 void QWorkspace::setPaletteBackgroundColor(const QColor & c)
1180 {
1181     setBackground(c);
1182 }
1183 
1184 /*!
1185     Sets the background pixmap to \a pm.
1186     Use setBackground() instead.
1187 */
setPaletteBackgroundPixmap(const QPixmap & pm)1188 void QWorkspace::setPaletteBackgroundPixmap(const QPixmap & pm)
1189 {
1190     setBackground(pm);
1191 }
1192 #endif // QT3_SUPPORT
1193 
1194 /*!
1195     \property QWorkspace::background
1196     \brief the workspace's background
1197 */
background() const1198 QBrush QWorkspace::background() const
1199 {
1200     Q_D(const QWorkspace);
1201     if (d->background.style() == Qt::NoBrush)
1202         return palette().dark();
1203     return d->background;
1204 }
1205 
setBackground(const QBrush & background)1206 void QWorkspace::setBackground(const QBrush &background)
1207 {
1208     Q_D(QWorkspace);
1209     d->background = background;
1210     setAttribute(Qt::WA_OpaquePaintEvent, background.style() == Qt::NoBrush);
1211     update();
1212 }
1213 
1214 /*!
1215     Adds widget \a w as new sub window to the workspace.  If \a flags
1216     are non-zero, they will override the flags set on the widget.
1217 
1218     Returns the widget used for the window frame.
1219 
1220     To remove the widget \a w from the workspace, simply call
1221     setParent() with the new parent (or 0 to make it a stand-alone
1222     window).
1223 */
addWindow(QWidget * w,Qt::WindowFlags flags)1224 QWidget * QWorkspace::addWindow(QWidget *w, Qt::WindowFlags flags)
1225 {
1226     Q_D(QWorkspace);
1227     if (!w)
1228         return 0;
1229 
1230     w->setAutoFillBackground(true);
1231 
1232     QWidgetPrivate::adjustFlags(flags);
1233 
1234 #if 0
1235     bool wasMaximized = w->isMaximized();
1236     bool wasMinimized = w->isMinimized();
1237 #endif
1238     bool hasSize = w->testAttribute(Qt::WA_Resized);
1239     int x = w->x();
1240     int y = w->y();
1241     bool hasPos = w->testAttribute(Qt::WA_Moved);
1242     if (!hasSize && w->sizeHint().isValid())
1243         w->adjustSize();
1244 
1245     QWorkspaceChild* child = new QWorkspaceChild(w, this, flags);
1246     child->setObjectName(QLatin1String("qt_workspacechild"));
1247     child->installEventFilter(this);
1248 
1249     connect(child, SIGNAL(popupOperationMenu(QPoint)),
1250             this, SLOT(_q_popupOperationMenu(QPoint)));
1251     connect(child, SIGNAL(showOperationMenu()),
1252             this, SLOT(_q_showOperationMenu()));
1253     d->windows.append(child);
1254     if (child->isVisibleTo(this))
1255         d->focus.append(child);
1256     child->internalRaise();
1257 
1258     if (!hasPos)
1259         d->place(child);
1260     if (!hasSize)
1261         child->adjustSize();
1262     if (hasPos)
1263         child->move(x, y);
1264 
1265     return child;
1266 
1267 #if 0
1268     if (wasMaximized)
1269         w->showMaximized();
1270     else if (wasMinimized)
1271         w->showMinimized();
1272     else if (!hasBeenHidden)
1273         d->activateWindow(w);
1274 
1275     d->updateWorkspace();
1276     return child;
1277 #endif
1278 }
1279 
1280 /*! \reimp */
childEvent(QChildEvent * e)1281 void QWorkspace::childEvent(QChildEvent * e)
1282 {
1283     Q_D(QWorkspace);
1284     if (e->removed()) {
1285         if (d->windows.removeAll(static_cast<QWorkspaceChild*>(e->child()))) {
1286             d->focus.removeAll(static_cast<QWorkspaceChild*>(e->child()));
1287             if (d->maxWindow == e->child())
1288                 d->maxWindow = 0;
1289             d->updateWorkspace();
1290         }
1291     }
1292 }
1293 
1294 /*! \reimp */
1295 #ifndef QT_NO_WHEELEVENT
wheelEvent(QWheelEvent * e)1296 void QWorkspace::wheelEvent(QWheelEvent *e)
1297 {
1298     Q_D(QWorkspace);
1299     if (!scrollBarsEnabled())
1300         return;
1301     // the scroll bars are children of the workspace, so if we receive
1302     // a wheel event we redirect to the scroll bars using a direct event
1303     // call, /not/ using sendEvent() because if the scroll bar ignores the
1304     // event QApplication::sendEvent() will propagate the event to the parent widget,
1305     // which is us, who /just/ sent it.
1306     if (d->vbar && d->vbar->isVisible() && !(e->modifiers() & Qt::AltModifier))
1307         d->vbar->event(e);
1308     else if (d->hbar && d->hbar->isVisible())
1309         d->hbar->event(e);
1310 }
1311 #endif
1312 
activateWindow(QWidget * w,bool change_focus)1313 void QWorkspacePrivate::activateWindow(QWidget* w, bool change_focus)
1314 {
1315     Q_Q(QWorkspace);
1316     if (!w) {
1317         active = 0;
1318         emit q->windowActivated(0);
1319         return;
1320     }
1321     if (!q->isVisible()) {
1322         becomeActive = w;
1323         return;
1324     }
1325 
1326     if (active && active->windowWidget() == w) {
1327         if (!isChildOf(q->focusWidget(), w)) // child window does not have focus
1328             active->setActive(true);
1329         return;
1330     }
1331 
1332     active = 0;
1333     // First deactivate all other workspace clients
1334     QList<QWorkspaceChild *>::Iterator it(windows.begin());
1335     while (it != windows.end()) {
1336         QWorkspaceChild* c = *it;
1337         ++it;
1338         if (c->windowWidget() == w)
1339             active = c;
1340         else
1341             c->setActive(false);
1342     }
1343 
1344     if (!active)
1345         return;
1346 
1347     // Then activate the new one, so the focus is stored correctly
1348     active->setActive(true);
1349 
1350     if (!active)
1351         return;
1352 
1353     if (maxWindow && maxWindow != active && active->windowWidget() &&
1354         (active->windowWidget()->windowFlags() & Qt::WindowMaximizeButtonHint))
1355         active->showMaximized();
1356 
1357     active->internalRaise();
1358 
1359     if (change_focus) {
1360         int from = focus.indexOf(active);
1361         if (from >= 0)
1362             focus.move(from, focus.size() - 1);
1363     }
1364 
1365     updateWorkspace();
1366     emit q->windowActivated(w);
1367 }
1368 
1369 
1370 /*!
1371     Returns a pointer to the widget corresponding to the active child
1372     window, or 0 if no window is active.
1373 
1374     \sa setActiveWindow()
1375 */
activeWindow() const1376 QWidget* QWorkspace::activeWindow() const
1377 {
1378     Q_D(const QWorkspace);
1379     return d->active? d->active->windowWidget() : 0;
1380 }
1381 
1382 /*!
1383     Makes the child window that contains \a w the active child window.
1384 
1385     \sa activeWindow()
1386 */
setActiveWindow(QWidget * w)1387 void QWorkspace::setActiveWindow(QWidget *w)
1388 {
1389     Q_D(QWorkspace);
1390     d->activateWindow(w, true);
1391     if (w && w->isMinimized())
1392         w->setWindowState(w->windowState() & ~Qt::WindowMinimized);
1393 }
1394 
place(QWidget * w)1395 void QWorkspacePrivate::place(QWidget *w)
1396 {
1397     Q_Q(QWorkspace);
1398 
1399     QList<QWidget *> widgets;
1400     for (QList<QWorkspaceChild *>::Iterator it(windows.begin()); it != windows.end(); ++it)
1401         if (*it != w)
1402             widgets.append(*it);
1403 
1404     int overlap, minOverlap = 0;
1405     int possible;
1406 
1407     QRect r1(0, 0, 0, 0);
1408     QRect r2(0, 0, 0, 0);
1409     QRect maxRect = q->rect();
1410     int x = maxRect.left(), y = maxRect.top();
1411     QPoint wpos(maxRect.left(), maxRect.top());
1412 
1413     bool firstPass = true;
1414 
1415     do {
1416         if (y + w->height() > maxRect.bottom()) {
1417             overlap = -1;
1418         } else if(x + w->width() > maxRect.right()) {
1419             overlap = -2;
1420         } else {
1421             overlap = 0;
1422 
1423             r1.setRect(x, y, w->width(), w->height());
1424 
1425             QWidget *l;
1426             QList<QWidget *>::Iterator it(widgets.begin());
1427             while (it != widgets.end()) {
1428                 l = *it;
1429                 ++it;
1430 
1431                 if (maxWindow == l)
1432                     r2 = QStyle::visualRect(q->layoutDirection(), maxRect, maxRestore);
1433                 else
1434                     r2 = QStyle::visualRect(q->layoutDirection(), maxRect,
1435                                             QRect(l->x(), l->y(), l->width(), l->height()));
1436 
1437                 if (r2.intersects(r1)) {
1438                     r2.setCoords(qMax(r1.left(), r2.left()),
1439                                  qMax(r1.top(), r2.top()),
1440                                  qMin(r1.right(), r2.right()),
1441                                  qMin(r1.bottom(), r2.bottom())
1442                                 );
1443 
1444                     overlap += (r2.right() - r2.left()) *
1445                                (r2.bottom() - r2.top());
1446                 }
1447             }
1448         }
1449 
1450         if (overlap == 0) {
1451             wpos = QPoint(x, y);
1452             break;
1453         }
1454 
1455         if (firstPass) {
1456             firstPass = false;
1457             minOverlap = overlap;
1458         } else if (overlap >= 0 && overlap < minOverlap) {
1459             minOverlap = overlap;
1460             wpos = QPoint(x, y);
1461         }
1462 
1463         if (overlap > 0) {
1464             possible = maxRect.right();
1465             if (possible - w->width() > x) possible -= w->width();
1466 
1467             QWidget *l;
1468             QList<QWidget *>::Iterator it(widgets.begin());
1469             while (it != widgets.end()) {
1470                 l = *it;
1471                 ++it;
1472                 if (maxWindow == l)
1473                     r2 = QStyle::visualRect(q->layoutDirection(), maxRect, maxRestore);
1474                 else
1475                     r2 = QStyle::visualRect(q->layoutDirection(), maxRect,
1476                                             QRect(l->x(), l->y(), l->width(), l->height()));
1477 
1478                 if((y < r2.bottom()) && (r2.top() < w->height() + y)) {
1479                     if(r2.right() > x)
1480                         possible = possible < r2.right() ?
1481                                    possible : r2.right();
1482 
1483                     if(r2.left() - w->width() > x)
1484                         possible = possible < r2.left() - w->width() ?
1485                                    possible : r2.left() - w->width();
1486                 }
1487             }
1488 
1489             x = possible;
1490         } else if (overlap == -2) {
1491             x = maxRect.left();
1492             possible = maxRect.bottom();
1493 
1494             if (possible - w->height() > y) possible -= w->height();
1495 
1496             QWidget *l;
1497             QList<QWidget *>::Iterator it(widgets.begin());
1498             while (it != widgets.end()) {
1499                 l = *it;
1500                 ++it;
1501                 if (maxWindow == l)
1502                     r2 = QStyle::visualRect(q->layoutDirection(), maxRect, maxRestore);
1503                 else
1504                     r2 = QStyle::visualRect(q->layoutDirection(), maxRect,
1505                                             QRect(l->x(), l->y(), l->width(), l->height()));
1506 
1507                 if(r2.bottom() > y)
1508                     possible = possible < r2.bottom() ?
1509                                possible : r2.bottom();
1510 
1511                 if(r2.top() - w->height() > y)
1512                     possible = possible < r2.top() - w->height() ?
1513                                possible : r2.top() - w->height();
1514             }
1515 
1516             y = possible;
1517         }
1518     }
1519     while(overlap != 0 && overlap != -1);
1520 
1521     QRect resultRect = w->geometry();
1522     resultRect.moveTo(wpos);
1523     w->setGeometry(QStyle::visualRect(q->layoutDirection(), maxRect, resultRect));
1524     updateWorkspace();
1525 }
1526 
1527 
insertIcon(QWidget * w)1528 void QWorkspacePrivate::insertIcon(QWidget* w)
1529 {
1530     Q_Q(QWorkspace);
1531     if (!w || icons.contains(w))
1532         return;
1533     icons.append(w);
1534     if (w->parentWidget() != q) {
1535         w->setParent(q, 0);
1536         w->move(0,0);
1537     }
1538     QRect cr = updateWorkspace();
1539     int x = 0;
1540     int y = cr.height() - w->height();
1541 
1542     QList<QWidget *>::Iterator it(icons.begin());
1543     while (it != icons.end()) {
1544         QWidget* i = *it;
1545         ++it;
1546         if (x > 0 && x + i->width() > cr.width()){
1547             x = 0;
1548             y -= i->height();
1549         }
1550 
1551         if (i != w &&
1552             i->geometry().intersects(QRect(x, y, w->width(), w->height())))
1553             x += i->width();
1554     }
1555     w->move(x, y);
1556 
1557     if (q->isVisibleTo(q->parentWidget())) {
1558         w->show();
1559         w->lower();
1560     }
1561     updateWorkspace();
1562 }
1563 
1564 
removeIcon(QWidget * w)1565 void QWorkspacePrivate::removeIcon(QWidget* w)
1566 {
1567     if (icons.removeAll(w))
1568         w->hide();
1569 }
1570 
1571 
1572 /*! \reimp  */
resizeEvent(QResizeEvent *)1573 void QWorkspace::resizeEvent(QResizeEvent *)
1574 {
1575     Q_D(QWorkspace);
1576     if (d->maxWindow) {
1577         d->maxWindow->adjustToFullscreen();
1578         if (d->maxWindow->windowWidget())
1579             d->maxWindow->windowWidget()->overrideWindowState(Qt::WindowMaximized);
1580     }
1581     d->updateWorkspace();
1582 }
1583 
1584 /*! \reimp */
showEvent(QShowEvent * e)1585 void QWorkspace::showEvent(QShowEvent *e)
1586 {
1587     Q_D(QWorkspace);
1588     if (d->maxWindow)
1589         d->showMaximizeControls();
1590     QWidget::showEvent(e);
1591     if (d->becomeActive) {
1592         d->activateWindow(d->becomeActive);
1593         d->becomeActive = 0;
1594     } else if (d->windows.count() > 0 && !d->active) {
1595         d->activateWindow(d->windows.first()->windowWidget());
1596     }
1597 
1598 //     // force a frame repaint - this is a workaround for what seems to be a bug
1599 //     // introduced when changing the QWidget::show() implementation. Might be
1600 //     // a windows bug as well though.
1601 //     for (int i = 0; i < d->windows.count(); ++i) {
1602 //      QWorkspaceChild* c = d->windows.at(i);
1603 //         c->update(c->rect());
1604 //     }
1605 
1606     d->updateWorkspace();
1607 }
1608 
1609 /*! \reimp */
hideEvent(QHideEvent *)1610 void QWorkspace::hideEvent(QHideEvent *)
1611 {
1612     Q_D(QWorkspace);
1613     if (!isVisible())
1614         d->hideMaximizeControls();
1615 }
1616 
1617 /*! \reimp */
paintEvent(QPaintEvent *)1618 void QWorkspace::paintEvent(QPaintEvent *)
1619 {
1620     Q_D(QWorkspace);
1621 
1622     if (d->background.style() != Qt::NoBrush) {
1623         QPainter p(this);
1624         p.fillRect(0, 0, width(), height(), d->background);
1625     }
1626 }
1627 
minimizeWindow(QWidget * w)1628 void QWorkspacePrivate::minimizeWindow(QWidget* w)
1629 {
1630     QWorkspaceChild* c = findChild(w);
1631 
1632     if (!w || !(w->windowFlags() & Qt::WindowMinimizeButtonHint))
1633         return;
1634 
1635     if (c) {
1636         bool wasMax = false;
1637         if (c == maxWindow) {
1638             wasMax = true;
1639             maxWindow = 0;
1640             hideMaximizeControls();
1641             for (QList<QWorkspaceChild *>::Iterator it(windows.begin()); it != windows.end(); ++it) {
1642                 QWorkspaceChild* c = *it;
1643                 if (c->titlebar)
1644                     c->titlebar->setMovable(true);
1645                 c->widgetResizeHandler->setActive(true);
1646             }
1647         }
1648         c->hide();
1649         if (wasMax)
1650             c->setGeometry(maxRestore);
1651         if (!focus.contains(c))
1652             focus.append(c);
1653         insertIcon(c->iconWidget());
1654 
1655         if (!maxWindow)
1656             activateWindow(w);
1657 
1658         updateWorkspace();
1659 
1660         w->overrideWindowState(Qt::WindowMinimized);
1661         c->overrideWindowState(Qt::WindowMinimized);
1662     }
1663 }
1664 
normalizeWindow(QWidget * w)1665 void QWorkspacePrivate::normalizeWindow(QWidget* w)
1666 {
1667     Q_Q(QWorkspace);
1668     QWorkspaceChild* c = findChild(w);
1669     if (!w)
1670         return;
1671     if (c) {
1672         w->overrideWindowState(Qt::WindowNoState);
1673         hideMaximizeControls();
1674         if (!maxmenubar || q->style()->styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, 0, q) || !maxWindow) {
1675             if (w->minimumSize() != w->maximumSize())
1676                 c->widgetResizeHandler->setActive(true);
1677             if (c->titlebar)
1678                 c->titlebar->setMovable(true);
1679         }
1680         w->overrideWindowState(Qt::WindowNoState);
1681         c->overrideWindowState(Qt::WindowNoState);
1682 
1683         if (c == maxWindow) {
1684             c->setGeometry(maxRestore);
1685             maxWindow = 0;
1686         } else {
1687             if (c->iconw)
1688                 removeIcon(c->iconw->parentWidget());
1689             c->show();
1690         }
1691 
1692         hideMaximizeControls();
1693         for (QList<QWorkspaceChild *>::Iterator it(windows.begin()); it != windows.end(); ++it) {
1694             QWorkspaceChild* c = *it;
1695             if (c->titlebar)
1696                 c->titlebar->setMovable(true);
1697             if (c->childWidget && c->childWidget->minimumSize() != c->childWidget->maximumSize())
1698                 c->widgetResizeHandler->setActive(true);
1699         }
1700         activateWindow(w, true);
1701         updateWorkspace();
1702     }
1703 }
1704 
maximizeWindow(QWidget * w)1705 void QWorkspacePrivate::maximizeWindow(QWidget* w)
1706 {
1707     Q_Q(QWorkspace);
1708     QWorkspaceChild* c = findChild(w);
1709 
1710     if (!w || !(w->windowFlags() & Qt::WindowMaximizeButtonHint))
1711         return;
1712 
1713     if (!c || c == maxWindow)
1714         return;
1715 
1716     bool updatesEnabled = q->updatesEnabled();
1717     q->setUpdatesEnabled(false);
1718 
1719     if (c->iconw && icons.contains(c->iconw->parentWidget()))
1720         normalizeWindow(w);
1721     QRect r(c->geometry());
1722     QWorkspaceChild *oldMaxWindow = maxWindow;
1723     maxWindow = c;
1724 
1725     showMaximizeControls();
1726 
1727     c->adjustToFullscreen();
1728     c->show();
1729     c->internalRaise();
1730     if (oldMaxWindow != c) {
1731         if (oldMaxWindow) {
1732             oldMaxWindow->setGeometry(maxRestore);
1733             oldMaxWindow->overrideWindowState(Qt::WindowNoState);
1734             if(oldMaxWindow->windowWidget())
1735                 oldMaxWindow->windowWidget()->overrideWindowState(Qt::WindowNoState);
1736         }
1737         maxRestore = r;
1738     }
1739 
1740     activateWindow(w);
1741 
1742     if(!maxmenubar || q->style()->styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, 0, q)) {
1743         if (!active && becomeActive) {
1744             active = (QWorkspaceChild*)becomeActive->parentWidget();
1745             active->setActive(true);
1746             becomeActive = 0;
1747             emit q->windowActivated(active->windowWidget());
1748         }
1749         c->widgetResizeHandler->setActive(false);
1750         if (c->titlebar)
1751             c->titlebar->setMovable(false);
1752     }
1753     updateWorkspace();
1754 
1755     w->overrideWindowState(Qt::WindowMaximized);
1756     c->overrideWindowState(Qt::WindowMaximized);
1757     q->setUpdatesEnabled(updatesEnabled);
1758 }
1759 
showWindow(QWidget * w)1760 void QWorkspacePrivate::showWindow(QWidget* w)
1761 {
1762     if (w->isMinimized() && (w->windowFlags() & Qt::WindowMinimizeButtonHint))
1763         minimizeWindow(w);
1764     else if ((maxWindow || w->isMaximized()) && w->windowFlags() & Qt::WindowMaximizeButtonHint)
1765         maximizeWindow(w);
1766     else if (w->windowFlags() & Qt::WindowMaximizeButtonHint)
1767         normalizeWindow(w);
1768     else
1769         w->parentWidget()->show();
1770     if (maxWindow)
1771         maxWindow->internalRaise();
1772     updateWorkspace();
1773 }
1774 
1775 
findChild(QWidget * w)1776 QWorkspaceChild* QWorkspacePrivate::findChild(QWidget* w)
1777 {
1778     QList<QWorkspaceChild *>::Iterator it(windows.begin());
1779     while (it != windows.end()) {
1780         QWorkspaceChild* c = *it;
1781         ++it;
1782         if (c->windowWidget() == w)
1783             return c;
1784     }
1785     return 0;
1786 }
1787 
1788 /*!
1789     Returns a list of all visible or minimized child windows. If \a
1790     order is CreationOrder (the default), the windows are listed in
1791     the order in which they were inserted into the workspace. If \a
1792     order is StackingOrder, the windows are listed in their stacking
1793     order, with the topmost window as the last item in the list.
1794 */
windowList(WindowOrder order) const1795 QWidgetList QWorkspace::windowList(WindowOrder order) const
1796 {
1797     Q_D(const QWorkspace);
1798     QWidgetList windows;
1799     if (order == StackingOrder) {
1800         QObjectList cl = children();
1801         for (int i = 0; i < cl.size(); ++i) {
1802             QWorkspaceChild *c = qobject_cast<QWorkspaceChild*>(cl.at(i));
1803             if (c && c->isWindowOrIconVisible())
1804                 windows.append(c->windowWidget());
1805         }
1806     } else {
1807         QList<QWorkspaceChild *>::ConstIterator it(d->windows.begin());
1808         while (it != d->windows.end()) {
1809             QWorkspaceChild* c = *it;
1810             ++it;
1811             if (c && c->isWindowOrIconVisible())
1812                 windows.append(c->windowWidget());
1813         }
1814     }
1815     return windows;
1816 }
1817 
1818 
1819 /*! \reimp */
event(QEvent * e)1820 bool QWorkspace::event(QEvent *e)
1821 {
1822 #ifndef QT_NO_SHORTCUT
1823     Q_D(QWorkspace);
1824     if (e->type() == QEvent::Shortcut) {
1825         QShortcutEvent *se = static_cast<QShortcutEvent *>(e);
1826         const char *theSlot = d->shortcutMap.value(se->shortcutId(), 0);
1827         if (theSlot)
1828             QMetaObject::invokeMethod(this, theSlot);
1829     } else
1830 #endif
1831     if (e->type() == QEvent::FocusIn || e->type() == QEvent::FocusOut){
1832         return true;
1833     }
1834     return QWidget::event(e);
1835 }
1836 
1837 /*! \reimp */
eventFilter(QObject * o,QEvent * e)1838 bool QWorkspace::eventFilter(QObject *o, QEvent * e)
1839 {
1840     Q_D(QWorkspace);
1841     static QElapsedTimer* t = 0;
1842     static QWorkspace* tc = 0;
1843     if (o == d->maxtools) {
1844         switch (e->type()) {
1845         case QEvent::MouseButtonPress:
1846             {
1847                 QMenuBar* b = (QMenuBar*)o->parent();
1848                 if (!t)
1849                     t = new QElapsedTimer;
1850                 if (tc != this || t->elapsed() > QApplication::doubleClickInterval()) {
1851                     if (isRightToLeft()) {
1852                         QPoint p = b->mapToGlobal(QPoint(b->x() + b->width(), b->y() + b->height()));
1853                         p.rx() -= d->popup->sizeHint().width();
1854                         d->_q_popupOperationMenu(p);
1855                     } else {
1856                         d->_q_popupOperationMenu(b->mapToGlobal(QPoint(b->x(), b->y() + b->height())));
1857                     }
1858                     t->start();
1859                     tc = this;
1860                 } else {
1861                     tc = 0;
1862                     closeActiveWindow();
1863                 }
1864                 return true;
1865             }
1866         default:
1867             break;
1868         }
1869         return QWidget::eventFilter(o, e);
1870     }
1871     switch (e->type()) {
1872     case QEvent::HideToParent:
1873         break;
1874     case QEvent::ShowToParent:
1875         if (QWorkspaceChild *c = qobject_cast<QWorkspaceChild*>(o))
1876             if (!d->focus.contains(c))
1877                 d->focus.append(c);
1878         d->updateWorkspace();
1879         break;
1880     case QEvent::WindowTitleChange:
1881         if (!d->inTitleChange) {
1882             if (o == window())
1883                 d->topTitle = window()->windowTitle();
1884             if (d->maxWindow && d->maxWindow->windowWidget() && d->topTitle.size()) {
1885                 d->inTitleChange = true;
1886                 window()->setWindowTitle(tr("%1 - [%2]")
1887                                          .arg(d->topTitle).arg(d->maxWindow->windowWidget()->windowTitle()));
1888                 d->inTitleChange = false;
1889             }
1890         }
1891         break;
1892 
1893     case QEvent::ModifiedChange:
1894         if (o == d->maxWindow)
1895             window()->setWindowModified(d->maxWindow->isWindowModified());
1896         break;
1897 
1898     case QEvent::Close:
1899         if (o == window())
1900         {
1901             QList<QWorkspaceChild *>::Iterator it(d->windows.begin());
1902             while (it != d->windows.end()) {
1903                 QWorkspaceChild* c = *it;
1904                 ++it;
1905                 if (c->shademode)
1906                     c->showShaded();
1907             }
1908         } else if (qobject_cast<QWorkspaceChild*>(o)) {
1909             d->popup->hide();
1910         }
1911         d->updateWorkspace();
1912         break;
1913     default:
1914         break;
1915     }
1916     return QWidget::eventFilter(o, e);
1917 }
1918 
findMenuBar(QWidget * w)1919 static QMenuBar *findMenuBar(QWidget *w)
1920 {
1921     // don't search recursively to avoid finding a menu bar of a
1922     // mainwindow that happens to be a workspace window (like
1923     // a mainwindow in designer)
1924     QList<QObject *> children = w->children();
1925     for (int i = 0; i < children.count(); ++i) {
1926         QMenuBar *bar = qobject_cast<QMenuBar *>(children.at(i));
1927         if (bar)
1928             return bar;
1929     }
1930     return 0;
1931 }
1932 
showMaximizeControls()1933 void QWorkspacePrivate::showMaximizeControls()
1934 {
1935     Q_Q(QWorkspace);
1936     Q_ASSERT(maxWindow);
1937 
1938     // merge windowtitle and modified state
1939     if (!topTitle.size())
1940         topTitle = q->window()->windowTitle();
1941 
1942     if (maxWindow->windowWidget()) {
1943         QString docTitle = maxWindow->windowWidget()->windowTitle();
1944         if (topTitle.size() && docTitle.size()) {
1945             inTitleChange = true;
1946             q->window()->setWindowTitle(QWorkspace::tr("%1 - [%2]").arg(topTitle).arg(docTitle));
1947             inTitleChange = false;
1948         }
1949         q->window()->setWindowModified(maxWindow->windowWidget()->isWindowModified());
1950     }
1951 
1952     if (!q->style()->styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, 0, q)) {
1953         QMenuBar* b = 0;
1954 
1955         // Do a breadth-first search first on every parent,
1956         QWidget* w = q->parentWidget();
1957         while (w) {
1958             b = findMenuBar(w);
1959             if (b)
1960                 break;
1961             w = w->parentWidget();
1962         }
1963 
1964         // last attempt.
1965         if (!b)
1966             b = findMenuBar(q->window());
1967 
1968         if (!b)
1969             return;
1970 
1971         if (!maxcontrols) {
1972             maxmenubar = b;
1973             maxcontrols = new QMDIControl(b);
1974             QObject::connect(maxcontrols, SIGNAL(_q_minimize()),
1975                              q, SLOT(_q_minimizeActiveWindow()));
1976             QObject::connect(maxcontrols, SIGNAL(_q_restore()),
1977                              q, SLOT(_q_normalizeActiveWindow()));
1978             QObject::connect(maxcontrols, SIGNAL(_q_close()),
1979                              q, SLOT(closeActiveWindow()));
1980         }
1981 
1982         b->setCornerWidget(maxcontrols);
1983         if (b->isVisible())
1984             maxcontrols->show();
1985         if (!active && becomeActive) {
1986             active = (QWorkspaceChild*)becomeActive->parentWidget();
1987             active->setActive(true);
1988             becomeActive = 0;
1989             emit q->windowActivated(active->windowWidget());
1990         }
1991         if (active) {
1992             if (!maxtools) {
1993                 maxtools = new QLabel(q->window());
1994                 maxtools->setObjectName(QLatin1String("qt_maxtools"));
1995                 maxtools->installEventFilter(q);
1996             }
1997             if (active->windowWidget() && !active->windowWidget()->windowIcon().isNull()) {
1998                 QIcon icon = active->windowWidget()->windowIcon();
1999                 int iconSize = maxcontrols->size().height();
2000                 maxtools->setPixmap(icon.pixmap(QSize(iconSize, iconSize)));
2001             } else {
2002                 QPixmap pm = q->style()->standardPixmap(QStyle::SP_TitleBarMenuButton, 0, q);
2003                 if (pm.isNull()) {
2004                     pm = QPixmap(14,14);
2005                     pm.fill(Qt::black);
2006                 }
2007                 maxtools->setPixmap(pm);
2008             }
2009             b->setCornerWidget(maxtools, Qt::TopLeftCorner);
2010             if (b->isVisible())
2011                 maxtools->show();
2012         }
2013     }
2014 }
2015 
2016 
hideMaximizeControls()2017 void QWorkspacePrivate::hideMaximizeControls()
2018 {
2019     Q_Q(QWorkspace);
2020     if (maxmenubar && !q->style()->styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, 0, q)) {
2021         if (maxmenubar) {
2022             maxmenubar->setCornerWidget(0, Qt::TopLeftCorner);
2023             maxmenubar->setCornerWidget(0, Qt::TopRightCorner);
2024         }
2025         if (maxcontrols) {
2026             maxcontrols->deleteLater();
2027             maxcontrols = 0;
2028         }
2029         if (maxtools) {
2030             maxtools->deleteLater();
2031             maxtools = 0;
2032         }
2033     }
2034 
2035     //unmerge the title bar/modification state
2036     if (topTitle.size()) {
2037         inTitleChange = true;
2038         q->window()->setWindowTitle(topTitle);
2039         inTitleChange = false;
2040     }
2041     q->window()->setWindowModified(false);
2042 }
2043 
2044 /*!
2045     Closes the child window that is currently active.
2046 
2047     \sa closeAllWindows()
2048 */
closeActiveWindow()2049 void QWorkspace::closeActiveWindow()
2050 {
2051     Q_D(QWorkspace);
2052     if (d->maxWindow && d->maxWindow->windowWidget())
2053         d->maxWindow->windowWidget()->close();
2054     else if (d->active && d->active->windowWidget())
2055         d->active->windowWidget()->close();
2056     d->updateWorkspace();
2057 }
2058 
2059 /*!
2060     Closes all child windows.
2061 
2062     If any child window fails to accept the close event, the remaining windows
2063     will remain open.
2064 
2065     \sa closeActiveWindow()
2066 */
closeAllWindows()2067 void QWorkspace::closeAllWindows()
2068 {
2069     Q_D(QWorkspace);
2070     bool did_close = true;
2071     QList<QWorkspaceChild *>::const_iterator it = d->windows.constBegin();
2072     while (it != d->windows.constEnd() && did_close) {
2073         QWorkspaceChild *c = *it;
2074         ++it;
2075         if (c->windowWidget() && !c->windowWidget()->isHidden())
2076             did_close = c->windowWidget()->close();
2077     }
2078 }
2079 
_q_normalizeActiveWindow()2080 void QWorkspacePrivate::_q_normalizeActiveWindow()
2081 {
2082     if (maxWindow)
2083         maxWindow->showNormal();
2084     else if (active)
2085         active->showNormal();
2086 }
2087 
_q_minimizeActiveWindow()2088 void QWorkspacePrivate::_q_minimizeActiveWindow()
2089 {
2090     if (maxWindow)
2091         maxWindow->showMinimized();
2092     else if (active)
2093         active->showMinimized();
2094 }
2095 
_q_showOperationMenu()2096 void QWorkspacePrivate::_q_showOperationMenu()
2097 {
2098     Q_Q(QWorkspace);
2099     if  (!active || !active->windowWidget())
2100         return;
2101     Q_ASSERT((active->windowWidget()->windowFlags() & Qt::WindowSystemMenuHint));
2102     QPoint p;
2103     QMenu *popup = (active->titlebar && active->titlebar->isTool()) ? toolPopup : this->popup;
2104     if (q->isRightToLeft()) {
2105         p = QPoint(active->windowWidget()->mapToGlobal(QPoint(active->windowWidget()->width(),0)));
2106         p.rx() -= popup->sizeHint().width();
2107     } else {
2108         p = QPoint(active->windowWidget()->mapToGlobal(QPoint(0,0)));
2109     }
2110     if (!active->isVisible()) {
2111         p = active->iconWidget()->mapToGlobal(QPoint(0,0));
2112         p.ry() -= popup->sizeHint().height();
2113     }
2114     _q_popupOperationMenu(p);
2115 }
2116 
_q_popupOperationMenu(const QPoint & p)2117 void QWorkspacePrivate::_q_popupOperationMenu(const QPoint&  p)
2118 {
2119     if (!active || !active->windowWidget() || !(active->windowWidget()->windowFlags() & Qt::WindowSystemMenuHint))
2120         return;
2121     if (active->titlebar && active->titlebar->isTool())
2122         toolPopup->popup(p);
2123     else
2124         popup->popup(p);
2125 }
2126 
_q_updateActions()2127 void QWorkspacePrivate::_q_updateActions()
2128 {
2129     Q_Q(QWorkspace);
2130     for (int i = 1; i < NCountAct-1; i++) {
2131         bool enable = active != 0;
2132         actions[i]->setEnabled(enable);
2133     }
2134 
2135     if (!active || !active->windowWidget())
2136         return;
2137 
2138     QWidget *windowWidget = active->windowWidget();
2139     bool canResize = windowWidget->maximumSize() != windowWidget->minimumSize();
2140     actions[QWorkspacePrivate::ResizeAct]->setEnabled(canResize);
2141     actions[QWorkspacePrivate::MinimizeAct]->setEnabled((windowWidget->windowFlags() & Qt::WindowMinimizeButtonHint));
2142     actions[QWorkspacePrivate::MaximizeAct]->setEnabled((windowWidget->windowFlags() & Qt::WindowMaximizeButtonHint) && canResize);
2143 
2144     if (active == maxWindow) {
2145         actions[QWorkspacePrivate::MoveAct]->setEnabled(false);
2146         actions[QWorkspacePrivate::ResizeAct]->setEnabled(false);
2147         actions[QWorkspacePrivate::MaximizeAct]->setEnabled(false);
2148         actions[QWorkspacePrivate::RestoreAct]->setEnabled(true);
2149     } else if (active->isVisible()){
2150         actions[QWorkspacePrivate::RestoreAct]->setEnabled(false);
2151     } else {
2152         actions[QWorkspacePrivate::MoveAct]->setEnabled(false);
2153         actions[QWorkspacePrivate::ResizeAct]->setEnabled(false);
2154         actions[QWorkspacePrivate::MinimizeAct]->setEnabled(false);
2155         actions[QWorkspacePrivate::RestoreAct]->setEnabled(true);
2156     }
2157     if (active->shademode) {
2158         actions[QWorkspacePrivate::ShadeAct]->setIcon(
2159             QIcon(q->style()->standardPixmap(QStyle::SP_TitleBarUnshadeButton, 0, q)));
2160         actions[QWorkspacePrivate::ShadeAct]->setText(QWorkspace::tr("&Unshade"));
2161     } else {
2162         actions[QWorkspacePrivate::ShadeAct]->setIcon(
2163             QIcon(q->style()->standardPixmap(QStyle::SP_TitleBarShadeButton, 0, q)));
2164         actions[QWorkspacePrivate::ShadeAct]->setText(QWorkspace::tr("Sh&ade"));
2165     }
2166     actions[QWorkspacePrivate::StaysOnTopAct]->setEnabled(!active->shademode && canResize);
2167     actions[QWorkspacePrivate::StaysOnTopAct]->setChecked(
2168         (active->windowWidget()->windowFlags() & Qt::WindowStaysOnTopHint));
2169 }
2170 
_q_operationMenuActivated(QAction * action)2171 void QWorkspacePrivate::_q_operationMenuActivated(QAction *action)
2172 {
2173     if (!active)
2174         return;
2175     if(action == actions[QWorkspacePrivate::RestoreAct]) {
2176         active->showNormal();
2177     } else if(action == actions[QWorkspacePrivate::MoveAct]) {
2178         active->doMove();
2179     } else if(action == actions[QWorkspacePrivate::ResizeAct]) {
2180         if (active->shademode)
2181             active->showShaded();
2182         active->doResize();
2183     } else if(action == actions[QWorkspacePrivate::MinimizeAct]) {
2184         active->showMinimized();
2185     } else if(action == actions[QWorkspacePrivate::MaximizeAct]) {
2186         active->showMaximized();
2187     } else if(action == actions[QWorkspacePrivate::ShadeAct]) {
2188         active->showShaded();
2189     } else if(action == actions[QWorkspacePrivate::StaysOnTopAct]) {
2190         if(QWidget* w = active->windowWidget()) {
2191             if ((w->windowFlags() & Qt::WindowStaysOnTopHint)) {
2192                 w->overrideWindowFlags(w->windowFlags() & ~Qt::WindowStaysOnTopHint);
2193             } else {
2194                 w->overrideWindowFlags(w->windowFlags() | Qt::WindowStaysOnTopHint);
2195                 w->parentWidget()->raise();
2196             }
2197         }
2198     }
2199 }
2200 
2201 
hideChild(QWorkspaceChild * c)2202 void QWorkspacePrivate::hideChild(QWorkspaceChild *c)
2203 {
2204     Q_Q(QWorkspace);
2205 
2206 //     bool updatesEnabled = q->updatesEnabled();
2207 //     q->setUpdatesEnabled(false);
2208     focus.removeAll(c);
2209     QRect restore;
2210     if (maxWindow == c)
2211         restore = maxRestore;
2212     if (active == c) {
2213         q->setFocus();
2214         q->activatePreviousWindow();
2215     }
2216     if (active == c)
2217         activateWindow(0);
2218     if (maxWindow == c) {
2219         hideMaximizeControls();
2220         maxWindow = 0;
2221     }
2222     c->hide();
2223     if (!restore.isEmpty())
2224         c->setGeometry(restore);
2225 //     q->setUpdatesEnabled(updatesEnabled);
2226 }
2227 
2228 /*!
2229     Gives the input focus to the next window in the list of child
2230     windows.
2231 
2232     \sa activatePreviousWindow()
2233 */
activateNextWindow()2234 void QWorkspace::activateNextWindow()
2235 {
2236     Q_D(QWorkspace);
2237 
2238     if (d->focus.isEmpty())
2239         return;
2240     if (!d->active) {
2241         if (d->focus.first())
2242             d->activateWindow(d->focus.first()->windowWidget(), false);
2243         return;
2244     }
2245 
2246     int a = d->focus.indexOf(d->active) + 1;
2247 
2248     a = a % d->focus.count();
2249 
2250     if (d->focus.at(a))
2251         d->activateWindow(d->focus.at(a)->windowWidget(), false);
2252     else
2253         d->activateWindow(0);
2254 }
2255 
2256 /*!
2257     Gives the input focus to the previous window in the list of child
2258     windows.
2259 
2260     \sa activateNextWindow()
2261 */
activatePreviousWindow()2262 void QWorkspace::activatePreviousWindow()
2263 {
2264     Q_D(QWorkspace);
2265 
2266     if (d->focus.isEmpty())
2267         return;
2268     if (!d->active) {
2269         if (d->focus.last())
2270             d->activateWindow(d->focus.first()->windowWidget(), false);
2271         else
2272             d->activateWindow(0);
2273         return;
2274     }
2275 
2276     int a = d->focus.indexOf(d->active) - 1;
2277     if (a < 0)
2278         a = d->focus.count()-1;
2279 
2280     if (d->focus.at(a))
2281         d->activateWindow(d->focus.at(a)->windowWidget(), false);
2282     else
2283         d->activateWindow(0);
2284 }
2285 
2286 
2287 /*!
2288     \fn void QWorkspace::windowActivated(QWidget* w)
2289 
2290     This signal is emitted when the child window \a w becomes active.
2291     Note that \a w can be 0, and that more than one signal may be
2292     emitted for a single activation event.
2293 
2294     \sa activeWindow(), windowList()
2295 */
2296 
2297 /*!
2298     Arranges all the child windows in a cascade pattern.
2299 
2300     \sa tile(), arrangeIcons()
2301 */
cascade()2302 void QWorkspace::cascade()
2303 {
2304     Q_D(QWorkspace);
2305     blockSignals(true);
2306     if  (d->maxWindow)
2307         d->maxWindow->showNormal();
2308 
2309     if (d->vbar) {
2310         d->vbar->blockSignals(true);
2311         d->vbar->setValue(0);
2312         d->vbar->blockSignals(false);
2313         d->hbar->blockSignals(true);
2314         d->hbar->setValue(0);
2315         d->hbar->blockSignals(false);
2316         d->_q_scrollBarChanged();
2317     }
2318 
2319     const int xoffset = 13;
2320     const int yoffset = 20;
2321 
2322     // make a list of all relevant mdi clients
2323     QList<QWorkspaceChild *> widgets;
2324     QList<QWorkspaceChild *>::Iterator it(d->windows.begin());
2325     QWorkspaceChild* wc = 0;
2326 
2327     for (it = d->focus.begin(); it != d->focus.end(); ++it) {
2328         wc = *it;
2329         if (wc->windowWidget()->isVisibleTo(this) && !(wc->titlebar && wc->titlebar->isTool()))
2330             widgets.append(wc);
2331     }
2332 
2333     int x = 0;
2334     int y = 0;
2335 
2336     it = widgets.begin();
2337     while (it != widgets.end()) {
2338         QWorkspaceChild *child = *it;
2339         ++it;
2340 
2341         QSize prefSize = child->windowWidget()->sizeHint().expandedTo(qSmartMinSize(child->windowWidget()));
2342         if (!prefSize.isValid())
2343             prefSize = child->windowWidget()->size();
2344         prefSize = prefSize.expandedTo(qSmartMinSize(child->windowWidget()));
2345         if (prefSize.isValid())
2346             prefSize += QSize(child->baseSize().width(), child->baseSize().height());
2347 
2348         int w = prefSize.width();
2349         int h = prefSize.height();
2350 
2351         child->showNormal();
2352         if (y + h > height())
2353             y = 0;
2354         if (x + w > width())
2355             x = 0;
2356         child->setGeometry(x, y, w, h);
2357         x += xoffset;
2358         y += yoffset;
2359         child->internalRaise();
2360     }
2361     d->updateWorkspace();
2362     blockSignals(false);
2363 }
2364 
2365 /*!
2366     Arranges all child windows in a tile pattern.
2367 
2368     \sa cascade(), arrangeIcons()
2369 */
tile()2370 void QWorkspace::tile()
2371 {
2372     Q_D(QWorkspace);
2373     blockSignals(true);
2374     QWidget *oldActive = d->active ? d->active->windowWidget() : 0;
2375     if  (d->maxWindow)
2376         d->maxWindow->showNormal();
2377 
2378     if (d->vbar) {
2379         d->vbar->blockSignals(true);
2380         d->vbar->setValue(0);
2381         d->vbar->blockSignals(false);
2382         d->hbar->blockSignals(true);
2383         d->hbar->setValue(0);
2384         d->hbar->blockSignals(false);
2385         d->_q_scrollBarChanged();
2386     }
2387 
2388     int rows = 1;
2389     int cols = 1;
2390     int n = 0;
2391     QWorkspaceChild* c;
2392 
2393     QList<QWorkspaceChild *>::Iterator it(d->windows.begin());
2394     while (it != d->windows.end()) {
2395         c = *it;
2396         ++it;
2397         if (!c->windowWidget()->isHidden()
2398             && !(c->windowWidget()->windowFlags() & Qt::WindowStaysOnTopHint)
2399             && !c->iconw)
2400             n++;
2401     }
2402 
2403     while (rows * cols < n) {
2404         if (cols <= rows)
2405             cols++;
2406         else
2407             rows++;
2408     }
2409     int add = cols * rows - n;
2410     bool* used = new bool[cols*rows];
2411     for (int i = 0; i < rows*cols; i++)
2412         used[i] = false;
2413 
2414     int row = 0;
2415     int col = 0;
2416     int w = width() / cols;
2417     int h = height() / rows;
2418 
2419     it = d->windows.begin();
2420     while (it != d->windows.end()) {
2421         c = *it;
2422         ++it;
2423         if (c->iconw || c->windowWidget()->isHidden() || (c->titlebar && c->titlebar->isTool()))
2424             continue;
2425         if (!row && !col) {
2426             w -= c->baseSize().width();
2427             h -= c->baseSize().height();
2428         }
2429         if ((c->windowWidget()->windowFlags() & Qt::WindowStaysOnTopHint)) {
2430             QPoint p = c->pos();
2431             if (p.x()+c->width() < 0)
2432                 p.setX(0);
2433             if (p.x() > width())
2434                 p.setX(width() - c->width());
2435             if (p.y() + 10 < 0)
2436                 p.setY(0);
2437             if (p.y() > height())
2438                 p.setY(height() - c->height());
2439 
2440             if (p != c->pos())
2441                 c->QWidget::move(p);
2442         } else {
2443             c->showNormal();
2444             used[row*cols+col] = true;
2445             QSize sz(w, h);
2446             QSize bsize(c->baseSize());
2447             sz = sz.expandedTo(c->windowWidget()->minimumSize()).boundedTo(c->windowWidget()->maximumSize());
2448             sz += bsize;
2449 
2450             if ( add ) {
2451                 if (sz.height() == h + bsize.height()) // no relevant constrains
2452                     sz.rheight() *= 2;
2453                 used[(row+1)*cols+col] = true;
2454                 add--;
2455             }
2456 
2457             c->setGeometry(col*w + col*bsize.width(), row*h + row*bsize.height(), sz.width(), sz.height());
2458 
2459             while(row < rows && col < cols && used[row*cols+col]) {
2460                 col++;
2461                 if (col == cols) {
2462                     col = 0;
2463                     row++;
2464                 }
2465             }
2466         }
2467     }
2468     delete [] used;
2469 
2470     d->activateWindow(oldActive);
2471     d->updateWorkspace();
2472     blockSignals(false);
2473 }
2474 
2475 /*!
2476     Arranges all iconified windows at the bottom of the workspace.
2477 
2478     \sa cascade(), tile()
2479 */
arrangeIcons()2480 void QWorkspace::arrangeIcons()
2481 {
2482     Q_D(QWorkspace);
2483 
2484     QRect cr = d->updateWorkspace();
2485     int x = 0;
2486     int y = -1;
2487 
2488     QList<QWidget *>::Iterator it(d->icons.begin());
2489     while (it != d->icons.end()) {
2490         QWidget* i = *it;
2491         if (y == -1)
2492             y = cr.height() - i->height();
2493         if (x > 0 && x + i->width() > cr.width()) {
2494             x = 0;
2495             y -= i->height();
2496         }
2497         i->move(x, y);
2498         x += i->width();
2499         ++it;
2500     }
2501     d->updateWorkspace();
2502 }
2503 
2504 
QWorkspaceChild(QWidget * window,QWorkspace * parent,Qt::WindowFlags flags)2505 QWorkspaceChild::QWorkspaceChild(QWidget* window, QWorkspace *parent, Qt::WindowFlags flags)
2506     : QWidget(parent,
2507              Qt::FramelessWindowHint | Qt::SubWindow)
2508 {
2509     setAttribute(Qt::WA_DeleteOnClose);
2510     setAttribute(Qt::WA_NoMousePropagation);
2511     setMouseTracking(true);
2512     act = false;
2513     iconw = 0;
2514     shademode = false;
2515     titlebar = 0;
2516     setAutoFillBackground(true);
2517 
2518     setBackgroundRole(QPalette::Window);
2519     if (window) {
2520         flags |= (window->windowFlags() & Qt::MSWindowsOwnDC);
2521         if (flags)
2522             window->setParent(this, flags & ~Qt::WindowType_Mask);
2523         else
2524             window->setParent(this);
2525     }
2526 
2527     if (window && (flags & (Qt::WindowTitleHint
2528                             | Qt::WindowSystemMenuHint
2529                             | Qt::WindowMinimizeButtonHint
2530                             | Qt::WindowMaximizeButtonHint
2531                             | Qt::WindowContextHelpButtonHint))) {
2532         titlebar = new QWorkspaceTitleBar(window, this, flags);
2533         connect(titlebar, SIGNAL(doActivate()),
2534                  this, SLOT(activate()));
2535         connect(titlebar, SIGNAL(doClose()),
2536                  window, SLOT(close()));
2537         connect(titlebar, SIGNAL(doMinimize()),
2538                  this, SLOT(showMinimized()));
2539         connect(titlebar, SIGNAL(doNormal()),
2540                  this, SLOT(showNormal()));
2541         connect(titlebar, SIGNAL(doMaximize()),
2542                  this, SLOT(showMaximized()));
2543         connect(titlebar, SIGNAL(popupOperationMenu(QPoint)),
2544                  this, SIGNAL(popupOperationMenu(QPoint)));
2545         connect(titlebar, SIGNAL(showOperationMenu()),
2546                  this, SIGNAL(showOperationMenu()));
2547         connect(titlebar, SIGNAL(doShade()),
2548                  this, SLOT(showShaded()));
2549         connect(titlebar, SIGNAL(doubleClicked()),
2550                  this, SLOT(titleBarDoubleClicked()));
2551     }
2552 
2553     setMinimumSize(128, 0);
2554     int fw =  style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, 0, this);
2555     setContentsMargins(fw, fw, fw, fw);
2556 
2557     childWidget = window;
2558     if (!childWidget)
2559         return;
2560 
2561     setWindowTitle(childWidget->windowTitle());
2562 
2563     QPoint p;
2564     QSize s;
2565     QSize cs;
2566 
2567     bool hasBeenResized = childWidget->testAttribute(Qt::WA_Resized);
2568 
2569     if (!hasBeenResized)
2570         cs = childWidget->sizeHint().expandedTo(childWidget->minimumSizeHint()).expandedTo(childWidget->minimumSize()).boundedTo(childWidget->maximumSize());
2571     else
2572         cs = childWidget->size();
2573 
2574     windowSize = cs;
2575 
2576     int th = titlebar ? titlebar->sizeHint().height() : 0;
2577     if (titlebar) {
2578         if (!childWidget->windowIcon().isNull())
2579             titlebar->setWindowIcon(childWidget->windowIcon());
2580 
2581         if (style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar))
2582             th -= contentsRect().y();
2583 
2584         p = QPoint(contentsRect().x(),
2585                     th + contentsRect().y());
2586         s = QSize(cs.width() + 2*frameWidth(),
2587                    cs.height() + 2*frameWidth() + th);
2588     } else {
2589         p = QPoint(contentsRect().x(), contentsRect().y());
2590         s = QSize(cs.width() + 2*frameWidth(),
2591                    cs.height() + 2*frameWidth());
2592     }
2593 
2594     childWidget->move(p);
2595     resize(s);
2596 
2597     childWidget->installEventFilter(this);
2598 
2599     widgetResizeHandler = new QWidgetResizeHandler(this, window);
2600     widgetResizeHandler->setSizeProtection(!parent->scrollBarsEnabled());
2601     widgetResizeHandler->setFrameWidth(frameWidth());
2602     connect(widgetResizeHandler, SIGNAL(activate()),
2603              this, SLOT(activate()));
2604     if (!style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar))
2605         widgetResizeHandler->setExtraHeight(th + contentsRect().y() - 2*frameWidth());
2606     else
2607         widgetResizeHandler->setExtraHeight(th + contentsRect().y() - frameWidth());
2608     if (childWidget->minimumSize() == childWidget->maximumSize())
2609         widgetResizeHandler->setActive(QWidgetResizeHandler::Resize, false);
2610     setBaseSize(baseSize());
2611 }
2612 
~QWorkspaceChild()2613 QWorkspaceChild::~QWorkspaceChild()
2614 {
2615     QWorkspace *workspace = qobject_cast<QWorkspace*>(parentWidget());
2616     if (iconw) {
2617         if (workspace)
2618             workspace->d_func()->removeIcon(iconw->parentWidget());
2619         delete iconw->parentWidget();
2620     }
2621 
2622     if (workspace) {
2623         workspace->d_func()->focus.removeAll(this);
2624         if (workspace->d_func()->active == this)
2625             workspace->activatePreviousWindow();
2626         if (workspace->d_func()->active == this)
2627             workspace->d_func()->activateWindow(0);
2628         if (workspace->d_func()->maxWindow == this) {
2629             workspace->d_func()->hideMaximizeControls();
2630             workspace->d_func()->maxWindow = 0;
2631         }
2632     }
2633 }
2634 
moveEvent(QMoveEvent *)2635 void QWorkspaceChild::moveEvent(QMoveEvent *)
2636 {
2637     ((QWorkspace*)parentWidget())->d_func()->updateWorkspace();
2638 }
2639 
resizeEvent(QResizeEvent *)2640 void QWorkspaceChild::resizeEvent(QResizeEvent *)
2641 {
2642     bool wasMax = isMaximized();
2643     QRect r = contentsRect();
2644     QRect cr;
2645 
2646     updateMask();
2647 
2648     if (titlebar) {
2649         int th = titlebar->sizeHint().height();
2650         QRect tbrect(0, 0, width(), th);
2651         if (!style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar))
2652             tbrect = QRect(r.x(), r.y(), r.width(), th);
2653         titlebar->setGeometry(tbrect);
2654 
2655         if (style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar))
2656             th -= frameWidth();
2657         cr = QRect(r.x(), r.y() + th + (shademode ? (frameWidth() * 3) : 0),
2658                     r.width(), r.height() - th);
2659     } else {
2660         cr = r;
2661     }
2662 
2663     if (!childWidget)
2664         return;
2665 
2666     bool doContentsResize = (windowSize == childWidget->size()
2667                              || !(childWidget->testAttribute(Qt::WA_Resized) && childWidget->testAttribute(Qt::WA_PendingResizeEvent))
2668                              ||childWidget->isMaximized());
2669 
2670     windowSize = cr.size();
2671     childWidget->move(cr.topLeft());
2672     if (doContentsResize)
2673         childWidget->resize(cr.size());
2674     ((QWorkspace*)parentWidget())->d_func()->updateWorkspace();
2675 
2676     if (wasMax) {
2677         overrideWindowState(Qt::WindowMaximized);
2678         childWidget->overrideWindowState(Qt::WindowMaximized);
2679     }
2680 }
2681 
baseSize() const2682 QSize QWorkspaceChild::baseSize() const
2683 {
2684     int th = titlebar ? titlebar->sizeHint().height() : 0;
2685     if (style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar))
2686         th -= frameWidth();
2687     return QSize(2*frameWidth(), 2*frameWidth() + th);
2688 }
2689 
sizeHint() const2690 QSize QWorkspaceChild::sizeHint() const
2691 {
2692     if (!childWidget)
2693         return QWidget::sizeHint() + baseSize();
2694 
2695     QSize prefSize = windowWidget()->sizeHint().expandedTo(windowWidget()->minimumSizeHint());
2696     prefSize = prefSize.expandedTo(windowWidget()->minimumSize()).boundedTo(windowWidget()->maximumSize());
2697     prefSize += baseSize();
2698 
2699     return prefSize;
2700 }
2701 
minimumSizeHint() const2702 QSize QWorkspaceChild::minimumSizeHint() const
2703 {
2704     if (!childWidget)
2705         return QWidget::minimumSizeHint() + baseSize();
2706     QSize s = childWidget->minimumSize();
2707     if (s.isEmpty())
2708         s = childWidget->minimumSizeHint();
2709     return s + baseSize();
2710 }
2711 
activate()2712 void QWorkspaceChild::activate()
2713 {
2714     ((QWorkspace*)parentWidget())->d_func()->activateWindow(windowWidget());
2715 }
2716 
eventFilter(QObject * o,QEvent * e)2717 bool QWorkspaceChild::eventFilter(QObject * o, QEvent * e)
2718 {
2719     if (!isActive()
2720         && (e->type() == QEvent::MouseButtonPress || e->type() == QEvent::FocusIn)) {
2721         if (iconw) {
2722             ((QWorkspace*)parentWidget())->d_func()->normalizeWindow(windowWidget());
2723             if (iconw) {
2724                 ((QWorkspace*)parentWidget())->d_func()->removeIcon(iconw->parentWidget());
2725                 delete iconw->parentWidget();
2726                 iconw = 0;
2727             }
2728         }
2729         activate();
2730     }
2731 
2732     // for all widgets except the window, that's the only thing we
2733     // process, and if we have no childWidget we skip totally
2734     if (o != childWidget || childWidget == 0)
2735         return false;
2736 
2737     switch (e->type()) {
2738     case QEvent::ShowToParent:
2739         if (((QWorkspace*)parentWidget())->d_func()->focus.indexOf(this) < 0)
2740             ((QWorkspace*)parentWidget())->d_func()->focus.append(this);
2741 
2742         if (windowWidget() && (windowWidget()->windowFlags() & Qt::WindowStaysOnTopHint)) {
2743             internalRaise();
2744             show();
2745         }
2746         ((QWorkspace*)parentWidget())->d_func()->showWindow(windowWidget());
2747         break;
2748     case QEvent::WindowStateChange: {
2749         if (static_cast<QWindowStateChangeEvent*>(e)->isOverride())
2750             break;
2751         Qt::WindowStates state = windowWidget()->windowState();
2752 
2753         if (state & Qt::WindowMinimized) {
2754             ((QWorkspace*)parentWidget())->d_func()->minimizeWindow(windowWidget());
2755         } else if (state & Qt::WindowMaximized) {
2756             if (windowWidget()->maximumSize().isValid() &&
2757                 (windowWidget()->maximumWidth() < parentWidget()->width() ||
2758                  windowWidget()->maximumHeight() < parentWidget()->height())) {
2759                 windowWidget()->resize(windowWidget()->maximumSize());
2760                 windowWidget()->overrideWindowState(Qt::WindowNoState);
2761                 if (titlebar)
2762                     titlebar->update();
2763                 break;
2764             }
2765             if ((windowWidget()->windowFlags() & Qt::WindowMaximizeButtonHint))
2766                 ((QWorkspace*)parentWidget())->d_func()->maximizeWindow(windowWidget());
2767             else
2768                 ((QWorkspace*)parentWidget())->d_func()->normalizeWindow(windowWidget());
2769         } else {
2770             ((QWorkspace*)parentWidget())->d_func()->normalizeWindow(windowWidget());
2771             if (iconw) {
2772                 ((QWorkspace*)parentWidget())->d_func()->removeIcon(iconw->parentWidget());
2773                 delete iconw->parentWidget();
2774             }
2775         }
2776     } break;
2777     case QEvent::HideToParent:
2778     {
2779         QWidget * w = iconw;
2780         if (w && (w = w->parentWidget())) {
2781             ((QWorkspace*)parentWidget())->d_func()->removeIcon(w);
2782             delete w;
2783         }
2784         ((QWorkspace*)parentWidget())->d_func()->hideChild(this);
2785     } break;
2786     case QEvent::WindowIconChange:
2787         {
2788             QWorkspace* ws = (QWorkspace*)parentWidget();
2789             if (ws->d_func()->maxtools && ws->d_func()->maxWindow == this) {
2790                 int iconSize = ws->d_func()->maxtools->size().height();
2791                 ws->d_func()->maxtools->setPixmap(childWidget->windowIcon().pixmap(QSize(iconSize, iconSize)));
2792             }
2793         }
2794         // fall through
2795     case QEvent::WindowTitleChange:
2796         setWindowTitle(windowWidget()->windowTitle());
2797         if (titlebar)
2798             titlebar->update();
2799         if (iconw)
2800             iconw->update();
2801         break;
2802     case QEvent::ModifiedChange:
2803         setWindowModified(windowWidget()->isWindowModified());
2804         if (titlebar)
2805             titlebar->update();
2806         if (iconw)
2807             iconw->update();
2808         break;
2809     case QEvent::Resize:
2810         {
2811             QResizeEvent* re = (QResizeEvent*)e;
2812             if (re->size() != windowSize && !shademode) {
2813                 resize(re->size() + baseSize());
2814                 childWidget->update(); //workaround
2815             }
2816         }
2817         break;
2818 
2819     case QEvent::WindowDeactivate:
2820         if (titlebar && titlebar->isActive()) {
2821             update();
2822         }
2823         break;
2824 
2825     case QEvent::WindowActivate:
2826         if (titlebar && titlebar->isActive()) {
2827             update();
2828         }
2829         break;
2830 
2831     default:
2832         break;
2833     }
2834 
2835     return QWidget::eventFilter(o, e);
2836 }
2837 
childEvent(QChildEvent * e)2838 void QWorkspaceChild::childEvent(QChildEvent* e)
2839 {
2840     if (e->type() == QEvent::ChildRemoved && e->child() == childWidget) {
2841         childWidget = 0;
2842         if (iconw) {
2843             ((QWorkspace*)parentWidget())->d_func()->removeIcon(iconw->parentWidget());
2844             delete iconw->parentWidget();
2845         }
2846         close();
2847     }
2848 }
2849 
2850 
doResize()2851 void QWorkspaceChild::doResize()
2852 {
2853     widgetResizeHandler->doResize();
2854 }
2855 
doMove()2856 void QWorkspaceChild::doMove()
2857 {
2858     widgetResizeHandler->doMove();
2859 }
2860 
enterEvent(QEvent *)2861 void QWorkspaceChild::enterEvent(QEvent *)
2862 {
2863 }
2864 
leaveEvent(QEvent *)2865 void QWorkspaceChild::leaveEvent(QEvent *)
2866 {
2867 #ifndef QT_NO_CURSOR
2868     if (!widgetResizeHandler->isButtonDown())
2869         setCursor(Qt::ArrowCursor);
2870 #endif
2871 }
2872 
paintEvent(QPaintEvent *)2873 void QWorkspaceChild::paintEvent(QPaintEvent *)
2874 {
2875     QPainter p(this);
2876     QStyleOptionFrame opt;
2877     opt.rect = rect();
2878     opt.palette = palette();
2879     opt.state = QStyle::State_None;
2880     opt.lineWidth = style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, 0, this);
2881     opt.midLineWidth = 1;
2882 
2883     if (titlebar && titlebar->isActive() && isActiveWindow())
2884         opt.state |= QStyle::State_Active;
2885 
2886     style()->drawPrimitive(QStyle::PE_FrameWindow, &opt, &p, this);
2887 }
2888 
changeEvent(QEvent * ev)2889 void QWorkspaceChild::changeEvent(QEvent *ev)
2890 {
2891     if(ev->type() == QEvent::StyleChange) {
2892         resizeEvent(0);
2893         if (iconw) {
2894             QFrame *frame = qobject_cast<QFrame*>(iconw->parentWidget());
2895             Q_ASSERT(frame);
2896             if (!style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar)) {
2897                 frame->setFrameStyle(QFrame::StyledPanel | QFrame::Raised);
2898                 frame->resize(196+2*frame->frameWidth(), 20 + 2*frame->frameWidth());
2899             } else {
2900                 frame->resize(196, 20);
2901             }
2902         }
2903         updateMask();
2904     }
2905     QWidget::changeEvent(ev);
2906 }
2907 
setActive(bool b)2908 void QWorkspaceChild::setActive(bool b)
2909 {
2910     if (!childWidget)
2911         return;
2912 
2913     bool hasFocus = isChildOf(window()->focusWidget(), this);
2914     if (act == b && (act == hasFocus))
2915         return;
2916 
2917     act = b;
2918 
2919     if (titlebar)
2920         titlebar->setActive(act);
2921     if (iconw)
2922         iconw->setActive(act);
2923     update();
2924 
2925     QList<QWidget*> wl = childWidget->findChildren<QWidget*>();
2926     if (act) {
2927         for (int i = 0; i < wl.size(); ++i) {
2928             QWidget *w = wl.at(i);
2929             w->removeEventFilter(this);
2930         }
2931         if (!hasFocus) {
2932             QWidget *lastfocusw = childWidget->focusWidget();
2933             if (lastfocusw && lastfocusw->focusPolicy() != Qt::NoFocus) {
2934                 lastfocusw->setFocus();
2935             } else if (childWidget->focusPolicy() != Qt::NoFocus) {
2936                 childWidget->setFocus();
2937             } else {
2938                 // find something, anything, that accepts focus, and use that.
2939                 for (int i = 0; i < wl.size(); ++i) {
2940                     QWidget *w = wl.at(i);
2941                     if(w->focusPolicy() != Qt::NoFocus) {
2942                         w->setFocus();
2943                         hasFocus = true;
2944                         break;
2945                     }
2946                 }
2947                 if (!hasFocus)
2948                     setFocus();
2949             }
2950         }
2951     } else {
2952         for (int i = 0; i < wl.size(); ++i) {
2953             QWidget *w = wl.at(i);
2954             w->removeEventFilter(this);
2955             w->installEventFilter(this);
2956         }
2957     }
2958 }
2959 
isActive() const2960 bool QWorkspaceChild::isActive() const
2961 {
2962     return act;
2963 }
2964 
windowWidget() const2965 QWidget* QWorkspaceChild::windowWidget() const
2966 {
2967     return childWidget;
2968 }
2969 
isWindowOrIconVisible() const2970 bool QWorkspaceChild::isWindowOrIconVisible() const
2971 {
2972     return childWidget && (!isHidden()  || (iconw && !iconw->isHidden()));
2973 }
2974 
updateMask()2975 void QWorkspaceChild::updateMask()
2976 {
2977     QStyleOptionTitleBar titleBarOptions;
2978     titleBarOptions.rect = rect();
2979     titleBarOptions.titleBarFlags = windowFlags();
2980     titleBarOptions.titleBarState = windowState();
2981 
2982     QStyleHintReturnMask frameMask;
2983     if (style()->styleHint(QStyle::SH_WindowFrame_Mask, &titleBarOptions, this, &frameMask)) {
2984         setMask(frameMask.region);
2985     } else if (!mask().isEmpty()) {
2986         clearMask();
2987     }
2988 
2989     if (iconw) {
2990         QFrame *frame = qobject_cast<QFrame *>(iconw->parentWidget());
2991         Q_ASSERT(frame);
2992 
2993         titleBarOptions.rect = frame->rect();
2994         titleBarOptions.titleBarFlags = frame->windowFlags();
2995         titleBarOptions.titleBarState = frame->windowState() | Qt::WindowMinimized;
2996         if (style()->styleHint(QStyle::SH_WindowFrame_Mask, &titleBarOptions, frame, &frameMask)) {
2997             frame->setMask(frameMask.region);
2998         } else if (!frame->mask().isEmpty()) {
2999             frame->clearMask();
3000         }
3001     }
3002 }
3003 
iconWidget() const3004 QWidget* QWorkspaceChild::iconWidget() const
3005 {
3006     if (!iconw) {
3007         QWorkspaceChild* that = (QWorkspaceChild*) this;
3008 
3009         QFrame* frame = new QFrame(that, Qt::Window);
3010         QVBoxLayout *vbox = new QVBoxLayout(frame);
3011         vbox->setMargin(0);
3012         QWorkspaceTitleBar *tb = new QWorkspaceTitleBar(windowWidget(), frame);
3013         vbox->addWidget(tb);
3014         tb->setObjectName(QLatin1String("_workspacechild_icon_"));
3015         QStyleOptionTitleBar opt;
3016         tb->initStyleOption(&opt);
3017         int th = style()->pixelMetric(QStyle::PM_TitleBarHeight, &opt, tb);
3018         int iconSize = style()->pixelMetric(QStyle::PM_MdiSubWindowMinimizedWidth, 0, this);
3019         if (!style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar)) {
3020             frame->setFrameStyle(QFrame::StyledPanel | QFrame::Raised);
3021             frame->resize(iconSize+2*frame->frameWidth(), th+2*frame->frameWidth());
3022         } else {
3023             frame->resize(iconSize, th);
3024         }
3025 
3026         that->iconw = tb;
3027         that->updateMask();
3028         iconw->setActive(isActive());
3029 
3030         connect(iconw, SIGNAL(doActivate()),
3031                  this, SLOT(activate()));
3032         connect(iconw, SIGNAL(doClose()),
3033                  windowWidget(), SLOT(close()));
3034         connect(iconw, SIGNAL(doNormal()),
3035                  this, SLOT(showNormal()));
3036         connect(iconw, SIGNAL(doMaximize()),
3037                  this, SLOT(showMaximized()));
3038         connect(iconw, SIGNAL(popupOperationMenu(QPoint)),
3039                  this, SIGNAL(popupOperationMenu(QPoint)));
3040         connect(iconw, SIGNAL(showOperationMenu()),
3041                  this, SIGNAL(showOperationMenu()));
3042         connect(iconw, SIGNAL(doubleClicked()),
3043                  this, SLOT(titleBarDoubleClicked()));
3044     }
3045     if (windowWidget()) {
3046         iconw->setWindowTitle(windowWidget()->windowTitle());
3047     }
3048     return iconw->parentWidget();
3049 }
3050 
showMinimized()3051 void QWorkspaceChild::showMinimized()
3052 {
3053     windowWidget()->setWindowState(Qt::WindowMinimized | (windowWidget()->windowState() & ~Qt::WindowMaximized));
3054 }
3055 
showMaximized()3056 void QWorkspaceChild::showMaximized()
3057 {
3058     windowWidget()->setWindowState(Qt::WindowMaximized | (windowWidget()->windowState() & ~Qt::WindowMinimized));
3059 }
3060 
showNormal()3061 void QWorkspaceChild::showNormal()
3062 {
3063     windowWidget()->setWindowState(windowWidget()->windowState() & ~(Qt::WindowMinimized|Qt::WindowMaximized));
3064 }
3065 
showShaded()3066 void QWorkspaceChild::showShaded()
3067 {
3068     if (!titlebar)
3069         return;
3070     ((QWorkspace*)parentWidget())->d_func()->activateWindow(windowWidget());
3071     QWidget* w = windowWidget();
3072     if (shademode) {
3073         w->overrideWindowState(Qt::WindowNoState);
3074         overrideWindowState(Qt::WindowNoState);
3075 
3076         shademode = false;
3077         resize(shadeRestore.expandedTo(minimumSizeHint()));
3078         setMinimumSize(shadeRestoreMin);
3079         style()->polish(this);
3080     } else {
3081         shadeRestore = size();
3082         shadeRestoreMin = minimumSize();
3083         setMinimumHeight(0);
3084         shademode = true;
3085         w->overrideWindowState(Qt::WindowMinimized);
3086         overrideWindowState(Qt::WindowMinimized);
3087 
3088         if (style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar))
3089             resize(width(), titlebar->height());
3090         else
3091             resize(width(), titlebar->height() + 2*frameWidth() + 1);
3092         style()->polish(this);
3093     }
3094     titlebar->update();
3095 }
3096 
titleBarDoubleClicked()3097 void QWorkspaceChild::titleBarDoubleClicked()
3098 {
3099     if (!windowWidget())
3100         return;
3101     if (iconw)
3102         showNormal();
3103     else if (windowWidget()->windowFlags() & Qt::WindowShadeButtonHint)
3104             showShaded();
3105     else if (windowWidget()->windowFlags() & Qt::WindowMaximizeButtonHint)
3106         showMaximized();
3107 }
3108 
adjustToFullscreen()3109 void QWorkspaceChild::adjustToFullscreen()
3110 {
3111     if (!childWidget)
3112         return;
3113 
3114     if(!((QWorkspace*)parentWidget())->d_func()->maxmenubar || style()->styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, 0, this)) {
3115         setGeometry(parentWidget()->rect());
3116     } else {
3117         int fw =  style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, 0, this);
3118         bool noBorder = style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar);
3119         int th = titlebar ? titlebar->sizeHint().height() : 0;
3120         int w = parentWidget()->width() + 2*fw;
3121         int h = parentWidget()->height() + (noBorder ? fw : 2*fw) + th;
3122         w = qMax(w, childWidget->minimumWidth());
3123         h = qMax(h, childWidget->minimumHeight());
3124         setGeometry(-fw, (noBorder ? 0 : -fw) - th, w, h);
3125     }
3126     childWidget->overrideWindowState(Qt::WindowMaximized);
3127     overrideWindowState(Qt::WindowMaximized);
3128 }
3129 
internalRaise()3130 void QWorkspaceChild::internalRaise()
3131 {
3132 
3133     QWidget *stackUnderWidget = 0;
3134     if (!windowWidget() || (windowWidget()->windowFlags() & Qt::WindowStaysOnTopHint) == 0) {
3135 
3136         QList<QWorkspaceChild *>::Iterator it(((QWorkspace*)parent())->d_func()->windows.begin());
3137         while (it != ((QWorkspace*)parent())->d_func()->windows.end()) {
3138             QWorkspaceChild* c = *it;
3139             ++it;
3140             if (c->windowWidget() &&
3141                 !c->windowWidget()->isHidden() &&
3142                 (c->windowWidget()->windowFlags() & Qt::WindowStaysOnTopHint)) {
3143                 if (stackUnderWidget)
3144                     c->stackUnder(stackUnderWidget);
3145                 else
3146                     c->raise();
3147                 stackUnderWidget = c;
3148             }
3149         }
3150     }
3151 
3152     if (stackUnderWidget) {
3153         if (iconw)
3154             iconw->parentWidget()->stackUnder(stackUnderWidget);
3155         stackUnder(stackUnderWidget);
3156     } else {
3157         if (iconw)
3158             iconw->parentWidget()->raise();
3159         raise();
3160     }
3161 
3162 }
3163 
show()3164 void QWorkspaceChild::show()
3165 {
3166     if (childWidget && childWidget->isHidden())
3167         childWidget->show();
3168     QWidget::show();
3169 }
3170 
scrollBarsEnabled() const3171 bool QWorkspace::scrollBarsEnabled() const
3172 {
3173     Q_D(const QWorkspace);
3174     return d->vbar != 0;
3175 }
3176 
3177 /*!
3178     \property QWorkspace::scrollBarsEnabled
3179     \brief whether the workspace provides scroll bars
3180 
3181     If this property is true, the workspace will provide scroll bars if any
3182     of the child windows extend beyond the edges of the visible
3183     workspace. The workspace area will automatically increase to
3184     contain child windows if they are resized beyond the right or
3185     bottom edges of the visible area.
3186 
3187     If this property is false (the default), resizing child windows
3188     out of the visible area of the workspace is not permitted, although
3189     it is still possible to position them partially outside the visible area.
3190 */
setScrollBarsEnabled(bool enable)3191 void QWorkspace::setScrollBarsEnabled(bool enable)
3192 {
3193     Q_D(QWorkspace);
3194     if ((d->vbar != 0) == enable)
3195         return;
3196 
3197     d->xoffset = d->yoffset = 0;
3198     if (enable) {
3199         d->vbar = new QScrollBar(Qt::Vertical, this);
3200         d->vbar->setObjectName(QLatin1String("vertical scrollbar"));
3201         connect(d->vbar, SIGNAL(valueChanged(int)), this, SLOT(_q_scrollBarChanged()));
3202         d->hbar = new QScrollBar(Qt::Horizontal, this);
3203         d->hbar->setObjectName(QLatin1String("horizontal scrollbar"));
3204         connect(d->hbar, SIGNAL(valueChanged(int)), this, SLOT(_q_scrollBarChanged()));
3205         d->corner = new QWidget(this);
3206         d->corner->setBackgroundRole(QPalette::Window);
3207         d->corner->setObjectName(QLatin1String("qt_corner"));
3208         d->updateWorkspace();
3209     } else {
3210         delete d->vbar;
3211         delete d->hbar;
3212         delete d->corner;
3213         d->vbar = d->hbar = 0;
3214         d->corner = 0;
3215     }
3216 
3217     QList<QWorkspaceChild *>::Iterator it(d->windows.begin());
3218     while (it != d->windows.end()) {
3219         QWorkspaceChild *child = *it;
3220         ++it;
3221         child->widgetResizeHandler->setSizeProtection(!enable);
3222     }
3223 }
3224 
updateWorkspace()3225 QRect QWorkspacePrivate::updateWorkspace()
3226 {
3227     Q_Q(QWorkspace);
3228     QRect cr(q->rect());
3229 
3230     if (q->scrollBarsEnabled() && !maxWindow) {
3231         corner->raise();
3232         vbar->raise();
3233         hbar->raise();
3234         if (maxWindow)
3235             maxWindow->internalRaise();
3236 
3237         QRect r(0, 0, 0, 0);
3238         QList<QWorkspaceChild *>::Iterator it(windows.begin());
3239         while (it != windows.end()) {
3240             QWorkspaceChild *child = *it;
3241             ++it;
3242             if (!child->isHidden())
3243                 r = r.unite(child->geometry());
3244         }
3245         vbar->blockSignals(true);
3246         hbar->blockSignals(true);
3247 
3248         int hsbExt = hbar->sizeHint().height();
3249         int vsbExt = vbar->sizeHint().width();
3250 
3251 
3252         bool showv = yoffset || yoffset + r.bottom() - q->height() + 1 > 0 || yoffset + r.top() < 0;
3253         bool showh = xoffset || xoffset + r.right() - q->width() + 1 > 0 || xoffset + r.left() < 0;
3254 
3255         if (showh && !showv)
3256             showv = yoffset + r.bottom() - q->height() + hsbExt + 1 > 0;
3257         if (showv && !showh)
3258             showh = xoffset + r.right() - q->width() + vsbExt  + 1 > 0;
3259 
3260         if (!showh)
3261             hsbExt = 0;
3262         if (!showv)
3263             vsbExt = 0;
3264 
3265         if (showv) {
3266             vbar->setSingleStep(qMax(q->height() / 12, 30));
3267             vbar->setPageStep(q->height() - hsbExt);
3268             vbar->setMinimum(qMin(0, yoffset + qMin(0, r.top())));
3269             vbar->setMaximum(qMax(0, yoffset + qMax(0, r.bottom() - q->height() + hsbExt + 1)));
3270             vbar->setGeometry(q->width() - vsbExt, 0, vsbExt, q->height() - hsbExt);
3271             vbar->setValue(yoffset);
3272             vbar->show();
3273         } else {
3274             vbar->hide();
3275         }
3276 
3277         if (showh) {
3278             hbar->setSingleStep(qMax(q->width() / 12, 30));
3279             hbar->setPageStep(q->width() - vsbExt);
3280             hbar->setMinimum(qMin(0, xoffset + qMin(0, r.left())));
3281             hbar->setMaximum(qMax(0, xoffset + qMax(0, r.right() - q->width() + vsbExt  + 1)));
3282             hbar->setGeometry(0, q->height() - hsbExt, q->width() - vsbExt, hsbExt);
3283             hbar->setValue(xoffset);
3284             hbar->show();
3285         } else {
3286             hbar->hide();
3287         }
3288 
3289         if (showh && showv) {
3290             corner->setGeometry(q->width() - vsbExt, q->height() - hsbExt, vsbExt, hsbExt);
3291             corner->show();
3292         } else {
3293             corner->hide();
3294         }
3295 
3296         vbar->blockSignals(false);
3297         hbar->blockSignals(false);
3298 
3299         cr.setRect(0, 0, q->width() - vsbExt, q->height() - hsbExt);
3300     }
3301 
3302     QList<QWidget *>::Iterator ii(icons.begin());
3303     while (ii != icons.end()) {
3304         QWidget* w = *ii;
3305         ++ii;
3306         int x = w->x();
3307         int y = w->y();
3308         bool m = false;
3309         if (x+w->width() > cr.width()) {
3310             m = true;
3311             x =  cr.width() - w->width();
3312         }
3313         if (y+w->height() >  cr.height()) {
3314             y =  cr.height() - w->height();
3315             m = true;
3316         }
3317         if (m) {
3318             if (QWorkspaceChild *child = qobject_cast<QWorkspaceChild*>(w))
3319                 child->move(x, y);
3320             else
3321                 w->move(x, y);
3322         }
3323     }
3324 
3325     return cr;
3326 
3327 }
3328 
_q_scrollBarChanged()3329 void QWorkspacePrivate::_q_scrollBarChanged()
3330 {
3331     int ver = yoffset - vbar->value();
3332     int hor = xoffset - hbar->value();
3333     yoffset = vbar->value();
3334     xoffset = hbar->value();
3335 
3336     QList<QWorkspaceChild *>::Iterator it(windows.begin());
3337     while (it != windows.end()) {
3338         QWorkspaceChild *child = *it;
3339         ++it;
3340         // we do not use move() due to the reimplementation in QWorkspaceChild
3341         child->setGeometry(child->x() + hor, child->y() + ver, child->width(), child->height());
3342     }
3343     updateWorkspace();
3344 }
3345 
3346 /*!
3347     \enum QWorkspace::WindowOrder
3348 
3349     Specifies the order in which child windows are returned from windowList().
3350 
3351     \value CreationOrder The windows are returned in the order of their creation
3352     \value StackingOrder The windows are returned in the order of their stacking
3353 */
3354 
3355 /*!\reimp */
changeEvent(QEvent * ev)3356 void QWorkspace::changeEvent(QEvent *ev)
3357 {
3358     Q_D(QWorkspace);
3359     if(ev->type() == QEvent::StyleChange) {
3360         if (isVisible() && d->maxWindow && d->maxmenubar) {
3361             if(style()->styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, 0, this)) {
3362                 d->hideMaximizeControls(); //hide any visible maximized controls
3363                 d->showMaximizeControls(); //updates the modification state as well
3364             }
3365         }
3366     }
3367     QWidget::changeEvent(ev);
3368 }
3369 
3370 QT_END_NAMESPACE
3371 
3372 #include "moc_qworkspace.cpp"
3373 
3374 #include "qworkspace.moc"
3375 
3376 #endif // QT_NO_WORKSPACE
3377