source: trunk/src/gui/embedded/qwsmanager_qws.cpp@ 694

Last change on this file since 694 was 651, checked in by Dmitry A. Kuminov, 16 years ago

trunk: Merged in qt 4.6.2 sources.

  • Property svn:eol-style set to native
File size: 15.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qwsmanager_qws.h"
43
44#ifndef QT_NO_QWS_MANAGER
45
46#include "qdrawutil.h"
47#include "qapplication.h"
48#include "qstyle.h"
49#include "qwidget.h"
50#include "qmenu.h"
51#include "qpainter.h"
52#include "private/qpainter_p.h"
53#include "qregion.h"
54#include "qevent.h"
55#include "qcursor.h"
56#include "qwsdisplay_qws.h"
57#include "qdesktopwidget.h"
58
59#include <private/qapplication_p.h>
60#include <private/qwidget_p.h>
61#include <private/qbackingstore_p.h>
62#include <private/qwindowsurface_qws_p.h>
63#include "qdecorationfactory_qws.h"
64
65#include "qlayout.h"
66
67#include "qwsmanager_p.h"
68
69#include <qdebug.h>
70
71QT_BEGIN_NAMESPACE
72
73QWidget *QWSManagerPrivate::active = 0;
74QPoint QWSManagerPrivate::mousePos;
75
76
77QWSManagerPrivate::QWSManagerPrivate()
78 : QObjectPrivate(), activeRegion(QDecoration::None), managed(0), popup(0),
79 previousRegionType(0), previousRegionRepainted(false), entireDecorationNeedsRepaint(false)
80{
81 cached_region.regionType = 0;
82}
83
84QRegion &QWSManager::cachedRegion()
85{
86 return d_func()->cached_region.region;
87}
88
89/*!
90 \class QWSManager
91 \ingroup qws
92 \internal
93*/
94
95/*!
96
97*/
98QWSManager::QWSManager(QWidget *w)
99 : QObject(*new QWSManagerPrivate, (QObject*)0)
100{
101 d_func()->managed = w;
102
103}
104
105QWSManager::~QWSManager()
106{
107 Q_D(QWSManager);
108#ifndef QT_NO_MENU
109 if (d->popup)
110 delete d->popup;
111#endif
112 if (d->managed == QWSManagerPrivate::active)
113 QWSManagerPrivate::active = 0;
114}
115
116QWidget *QWSManager::widget()
117{
118 Q_D(QWSManager);
119 return d->managed;
120}
121
122QWidget *QWSManager::grabbedMouse()
123{
124 return QWSManagerPrivate::active;
125}
126
127QRegion QWSManager::region()
128{
129 Q_D(QWSManager);
130 return QApplication::qwsDecoration().region(d->managed, d->managed->geometry());
131}
132
133bool QWSManager::event(QEvent *e)
134{
135 if (QObject::event(e))
136 return true;
137
138 switch (e->type()) {
139 case QEvent::MouseMove:
140 mouseMoveEvent((QMouseEvent*)e);
141 break;
142
143 case QEvent::MouseButtonPress:
144 mousePressEvent((QMouseEvent*)e);
145 break;
146
147 case QEvent::MouseButtonRelease:
148 mouseReleaseEvent((QMouseEvent*)e);
149 break;
150
151 case QEvent::MouseButtonDblClick:
152 mouseDoubleClickEvent((QMouseEvent*)e);
153 break;
154
155 case QEvent::Paint:
156 paintEvent((QPaintEvent*)e);
157 break;
158
159 default:
160 return false;
161 break;
162 }
163
164 return true;
165}
166
167void QWSManager::mousePressEvent(QMouseEvent *e)
168{
169 Q_D(QWSManager);
170 d->mousePos = e->globalPos();
171 d->activeRegion = QApplication::qwsDecoration().regionAt(d->managed, d->mousePos);
172 if(d->cached_region.regionType)
173 d->previousRegionRepainted |= repaintRegion(d->cached_region.regionType, QDecoration::Pressed);
174
175 if (d->activeRegion == QDecoration::Menu) {
176 QPoint pos = (QApplication::layoutDirection() == Qt::LeftToRight
177 ? d->managed->geometry().topLeft()
178 : d->managed->geometry().topRight());
179 menu(pos);
180 }
181 if (d->activeRegion != QDecoration::None &&
182 d->activeRegion != QDecoration::Menu) {
183 d->active = d->managed;
184 d->managed->grabMouse();
185 }
186 if (d->activeRegion != QDecoration::None &&
187 d->activeRegion != QDecoration::Close &&
188 d->activeRegion != QDecoration::Minimize &&
189 d->activeRegion != QDecoration::Menu) {
190 d->managed->raise();
191 }
192
193 if (e->button() == Qt::RightButton) {
194 menu(e->globalPos());
195 }
196}
197
198void QWSManager::mouseReleaseEvent(QMouseEvent *e)
199{
200 Q_D(QWSManager);
201 d->managed->releaseMouse();
202 if (d->cached_region.regionType && d->previousRegionRepainted && QApplication::mouseButtons() == 0) {
203 bool doesHover = repaintRegion(d->cached_region.regionType, QDecoration::Hover);
204 if (!doesHover) {
205 repaintRegion(d->cached_region.regionType, QDecoration::Normal);
206 d->previousRegionRepainted = false;
207 }
208 }
209
210 if (e->button() == Qt::LeftButton) {
211 //handleMove();
212 int itm = QApplication::qwsDecoration().regionAt(d->managed, e->globalPos());
213 int activatedItem = d->activeRegion;
214 d->activeRegion = QDecoration::None;
215 d->active = 0;
216 if (activatedItem == itm)
217 QApplication::qwsDecoration().regionClicked(d->managed, itm);
218 } else if (d->activeRegion == QDecoration::None) {
219 d->active = 0;
220 }
221}
222
223void QWSManager::mouseDoubleClickEvent(QMouseEvent *e)
224{
225 Q_D(QWSManager);
226 if (e->button() == Qt::LeftButton)
227 QApplication::qwsDecoration().regionDoubleClicked(d->managed,
228 QApplication::qwsDecoration().regionAt(d->managed, e->globalPos()));
229}
230
231static inline Qt::CursorShape regionToShape(int region)
232{
233 if (region == QDecoration::None)
234 return Qt::ArrowCursor;
235
236 static const struct {
237 int region;
238 Qt::CursorShape shape;
239 } r2s[] = {
240 { QDecoration::TopLeft, Qt::SizeFDiagCursor },
241 { QDecoration::Top, Qt::SizeVerCursor},
242 { QDecoration::TopRight, Qt::SizeBDiagCursor},
243 { QDecoration::Left, Qt::SizeHorCursor},
244 { QDecoration::Right, Qt::SizeHorCursor},
245 { QDecoration::BottomLeft, Qt::SizeBDiagCursor},
246 { QDecoration::Bottom, Qt::SizeVerCursor},
247 { QDecoration::BottomRight, Qt::SizeFDiagCursor},
248 { QDecoration::None, Qt::ArrowCursor}
249 };
250
251 int i = 0;
252 while (region != r2s[i].region && r2s[i].region)
253 ++i;
254 return r2s[i].shape;
255}
256
257void QWSManager::mouseMoveEvent(QMouseEvent *e)
258{
259 Q_D(QWSManager);
260 if (d->newCachedRegion(e->globalPos())) {
261 if(d->previousRegionType && d->previousRegionRepainted)
262 repaintRegion(d->previousRegionType, QDecoration::Normal);
263 if(d->cached_region.regionType) {
264 d->previousRegionRepainted = repaintRegion(d->cached_region.regionType, QDecoration::Hover);
265 }
266 }
267
268
269#ifndef QT_NO_CURSOR
270 QWSDisplay *qwsd = QApplication::desktop()->qwsDisplay();
271 qwsd->selectCursor(d->managed, regionToShape(d->cachedRegionAt()));
272#endif //QT_NO_CURSOR
273
274 if (d->activeRegion)
275 handleMove(e->globalPos());
276}
277
278void QWSManager::handleMove(QPoint g)
279{
280 Q_D(QWSManager);
281
282 // don't allow dragging to where the user probably cannot click!
283 QApplicationPrivate *ap = QApplicationPrivate::instance();
284 const QRect maxWindowRect = ap->maxWindowRect(qt_screen);
285 if (maxWindowRect.isValid()) {
286 if (g.x() < maxWindowRect.x())
287 g.setX(maxWindowRect.x());
288 if (g.y() < maxWindowRect.y())
289 g.setY(maxWindowRect.y());
290 if (g.x() > maxWindowRect.right())
291 g.setX(maxWindowRect.right());
292 if (g.y() > maxWindowRect.bottom())
293 g.setY(maxWindowRect.bottom());
294 }
295
296 if (g == d->mousePos)
297 return;
298
299 if ( d->managed->isMaximized() )
300 return;
301
302 int x = d->managed->geometry().x();
303 int y = d->managed->geometry().y();
304 int w = d->managed->width();
305 int h = d->managed->height();
306
307 QRect geom(d->managed->geometry());
308
309 QPoint delta = g - d->mousePos;
310 d->mousePos = g;
311
312 if (d->activeRegion == QDecoration::Title) {
313 geom = QRect(x + delta.x(), y + delta.y(), w, h);
314 } else {
315 bool keepTop = true;
316 bool keepLeft = true;
317 switch (d->activeRegion) {
318 case QDecoration::Top:
319 geom.setTop(geom.top() + delta.y());
320 keepTop = false;
321 break;
322 case QDecoration::Bottom:
323 geom.setBottom(geom.bottom() + delta.y());
324 keepTop = true;
325 break;
326 case QDecoration::Left:
327 geom.setLeft(geom.left() + delta.x());
328 keepLeft = false;
329 break;
330 case QDecoration::Right:
331 geom.setRight(geom.right() + delta.x());
332 keepLeft = true;
333 break;
334 case QDecoration::TopRight:
335 geom.setTopRight(geom.topRight() + delta);
336 keepLeft = true;
337 keepTop = false;
338 break;
339 case QDecoration::TopLeft:
340 geom.setTopLeft(geom.topLeft() + delta);
341 keepLeft = false;
342 keepTop = false;
343 break;
344 case QDecoration::BottomLeft:
345 geom.setBottomLeft(geom.bottomLeft() + delta);
346 keepLeft = false;
347 keepTop = true;
348 break;
349 case QDecoration::BottomRight:
350 geom.setBottomRight(geom.bottomRight() + delta);
351 keepLeft = true;
352 keepTop = true;
353 break;
354 default:
355 return;
356 }
357
358 QSize newSize = QLayout::closestAcceptableSize(d->managed, geom.size());
359
360 int dx = newSize.width() - geom.width();
361 int dy = newSize.height() - geom.height();
362
363 if (keepTop) {
364 geom.setBottom(geom.bottom() + dy);
365 d->mousePos.ry() += dy;
366 } else {
367 geom.setTop(geom.top() - dy);
368 d->mousePos.ry() -= dy;
369 }
370 if (keepLeft) {
371 geom.setRight(geom.right() + dx);
372 d->mousePos.rx() += dx;
373 } else {
374 geom.setLeft(geom.left() - dx);
375 d->mousePos.rx() -= dx;
376 }
377 }
378 if (geom != d->managed->geometry()) {
379 QApplication::sendPostedEvents();
380 d->managed->setGeometry(geom);
381 }
382}
383
384void QWSManager::paintEvent(QPaintEvent *)
385{
386 Q_D(QWSManager);
387 d->dirtyRegion(QDecoration::All, QDecoration::Normal);
388}
389
390void QWSManagerPrivate::dirtyRegion(int decorationRegion,
391 QDecoration::DecorationState state,
392 const QRegion &clip)
393{
394 QTLWExtra *topextra = managed->d_func()->extra->topextra;
395 QWidgetBackingStore *bs = topextra->backingStore;
396 const bool pendingUpdateRequest = bs->isDirty();
397
398 if (decorationRegion == QDecoration::All) {
399 if (clip.isEmpty())
400 entireDecorationNeedsRepaint = true;
401 dirtyRegions.clear();
402 dirtyStates.clear();
403 }
404 int i = dirtyRegions.indexOf(decorationRegion);
405 if (i >= 0) {
406 dirtyRegions.removeAt(i);
407 dirtyStates.removeAt(i);
408 }
409
410 dirtyRegions.append(decorationRegion);
411 dirtyStates.append(state);
412 if (!entireDecorationNeedsRepaint)
413 dirtyClip += clip;
414
415 if (!pendingUpdateRequest)
416 QApplication::postEvent(managed, new QEvent(QEvent::UpdateRequest), Qt::LowEventPriority);
417}
418
419void QWSManagerPrivate::clearDirtyRegions()
420{
421 dirtyRegions.clear();
422 dirtyStates.clear();
423 dirtyClip = QRegion();
424 entireDecorationNeedsRepaint = false;
425}
426
427bool QWSManager::repaintRegion(int decorationRegion, QDecoration::DecorationState state)
428{
429 Q_D(QWSManager);
430
431 d->dirtyRegion(decorationRegion, state);
432 return true;
433}
434
435void QWSManager::menu(const QPoint &pos)
436{
437#ifdef QT_NO_MENU
438 Q_UNUSED(pos);
439#else
440 Q_D(QWSManager);
441 if (d->popup)
442 delete d->popup;
443
444 // Basic window operation menu
445 d->popup = new QMenu();
446 QApplication::qwsDecoration().buildSysMenu(d->managed, d->popup);
447 connect(d->popup, SIGNAL(triggered(QAction*)), SLOT(menuTriggered(QAction*)));
448
449 d->popup->popup(pos);
450 d->activeRegion = QDecoration::None;
451#endif // QT_NO_MENU
452}
453
454void QWSManager::menuTriggered(QAction *action)
455{
456#ifdef QT_NO_MENU
457 Q_UNUSED(action);
458#else
459 Q_D(QWSManager);
460 QApplication::qwsDecoration().menuTriggered(d->managed, action);
461 d->popup->deleteLater();
462 d->popup = 0;
463#endif
464}
465
466void QWSManager::startMove()
467{
468 Q_D(QWSManager);
469 d->mousePos = QCursor::pos();
470 d->activeRegion = QDecoration::Title;
471 d->active = d->managed;
472 d->managed->grabMouse();
473}
474
475void QWSManager::startResize()
476{
477 Q_D(QWSManager);
478 d->activeRegion = QDecoration::BottomRight;
479 d->active = d->managed;
480 d->managed->grabMouse();
481}
482
483void QWSManager::maximize()
484{
485 Q_D(QWSManager);
486 // find out how much space the decoration needs
487 const int screen = QApplication::desktop()->screenNumber(d->managed);
488 const QRect desk = QApplication::desktop()->availableGeometry(screen);
489 QRect dummy(0, 0, 1, 1);
490 QRect nr;
491 QRegion r = QApplication::qwsDecoration().region(d->managed, dummy);
492 if (r.isEmpty()) {
493 nr = desk;
494 } else {
495 r += dummy; // make sure we get the full window region in case of 0 width borders
496 QRect rect = r.boundingRect();
497 nr = QRect(desk.x()-rect.x(), desk.y()-rect.y(),
498 desk.width() - (rect.width()==1 ? 0 : rect.width()-1), // ==1 -> dummy
499 desk.height() - (rect.height()==1 ? 0 : rect.height()-1));
500 }
501 d->managed->setGeometry(nr);
502}
503
504bool QWSManagerPrivate::newCachedRegion(const QPoint &pos)
505{
506 // Check if anything has changed that would affect the region caching
507 if (managed->windowFlags() == cached_region.windowFlags
508 && managed->geometry() == cached_region.windowGeometry
509 && cached_region.region.contains(pos))
510 return false;
511
512 // Update the cached region
513 int reg = QApplication::qwsDecoration().regionAt(managed, pos);
514 if (QWidget::mouseGrabber())
515 reg = QDecoration::None;
516
517 previousRegionType = cached_region.regionType;
518 cached_region.regionType = reg;
519 cached_region.region = QApplication::qwsDecoration().region(managed, managed->geometry(),
520 reg);
521 // Make room for borders around the widget, even if the decoration doesn't have a frame.
522 if (reg && !(reg & int(QDecoration::Borders))) {
523 cached_region.region -= QApplication::qwsDecoration().region(managed, managed->geometry(), QDecoration::Borders);
524 }
525 cached_region.windowFlags = managed->windowFlags();
526 cached_region.windowGeometry = managed->geometry();
527// QRect rec = cached_region.region.boundingRect();
528// qDebug("Updated cached region: 0x%04x (%d, %d) (%d, %d, %d, %d)",
529// reg, pos.x(), pos.y(), rec.x(), rec.y(), rec.right(), rec.bottom());
530 return true;
531}
532
533QT_END_NAMESPACE
534
535#endif //QT_NO_QWS_MANAGER
Note: See TracBrowser for help on using the repository browser.