/src/gui/embedded/qwsmanager_qws.cpp

https://bitbucket.org/ultra_iter/qt-vtl · C++ · 537 lines · 408 code · 71 blank · 58 comment · 80 complexity · 3cc97417deb5c22b91f87f7101b4dc9e MD5 · raw file

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