- Timestamp:
- Sep 3, 2021 3:31:49 PM (3 years ago)
- Location:
- trunk/src/VBox/Frontends/VirtualBox/src
- Files:
-
- 16 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VirtualBox/src/extensions/QIDialog.cpp
r87718 r91109 22 22 #include "QIDialog.h" 23 23 #include "UICommon.h" 24 #include "UIDesktopWidgetWatchdog.h" 24 25 25 26 … … 124 125 125 126 /* Explicit centering according to our parent: */ 126 UI Common::centerWidget(this, parentWidget(), false);127 UIDesktopWidgetWatchdog::centerWidget(this, parentWidget(), false); 127 128 } -
trunk/src/VBox/Frontends/VirtualBox/src/extensions/QIMainDialog.cpp
r87718 r91109 30 30 #include "QIMainDialog.h" 31 31 #include "UICommon.h" 32 #include "UIDesktopWidgetWatchdog.h" 32 33 #include "VBoxUtils.h" 33 34 … … 233 234 /* Explicit centering according to our parent: */ 234 235 if (m_fIsAutoCentering) 235 UI Common::centerWidget(this, parentWidget(), false);236 UIDesktopWidgetWatchdog::centerWidget(this, parentWidget(), false); 236 237 } 237 238 -
trunk/src/VBox/Frontends/VirtualBox/src/extensions/QIManagerDialog.cpp
r88798 r91109 121 121 122 122 /* Center according requested widget: */ 123 UI Common::centerWidget(this, m_pCenterWidget, false);123 UIDesktopWidgetWatchdog::centerWidget(this, m_pCenterWidget, false); 124 124 125 125 /* Load the dialog's settings from extradata */ -
trunk/src/VBox/Frontends/VirtualBox/src/extradata/UIExtraDataManager.cpp
r90083 r91109 733 733 activateWindow(); 734 734 // /* Center according passed widget: */ 735 // UI Common::centerWidget(this, pCenterWidget, false);735 // UIDesktopWidgetWatchdog::centerWidget(this, pCenterWidget, false); 736 736 } 737 737 … … 5051 5051 /* Make sure resulting geometry is within current bounds: */ 5052 5052 if (!availableGeometry.contains(geometry)) 5053 geometry = UI Common::getNormalized(geometry, QRegion(availableGeometry));5053 geometry = UIDesktopWidgetWatchdog::getNormalized(geometry, QRegion(availableGeometry)); 5054 5054 #endif /* VBOX_WS_WIN */ 5055 5055 -
trunk/src/VBox/Frontends/VirtualBox/src/globals/QIWithRestorableGeometry.h
r87718 r91109 113 113 #else 114 114 /* Use the new approach otherwise: */ 115 UI Common::setTopLevelGeometry(this, m_geometry);115 UIDesktopWidgetWatchdog::setTopLevelGeometry(this, m_geometry); 116 116 #endif 117 117 -
trunk/src/VBox/Frontends/VirtualBox/src/globals/UICommon.cpp
r91094 r91109 1262 1262 1263 1263 /* static */ 1264 QRect UICommon::normalizeGeometry(const QRect &rectangle, const QRegion &boundRegion, bool fCanResize /* = true */)1265 {1266 /* Perform direct and flipped search of position for @a rectangle to make sure it is fully contained1267 * inside @a boundRegion region by moving & resizing (if @a fCanResize is specified) @a rectangle if1268 * necessary. Selects the minimum shifted result between direct and flipped variants. */1269 1270 /* Direct search for normalized rectangle: */1271 QRect var1(getNormalized(rectangle, boundRegion, fCanResize));1272 1273 /* Flipped search for normalized rectangle: */1274 QRect var2(flip(getNormalized(flip(rectangle).boundingRect(),1275 flip(boundRegion), fCanResize)).boundingRect());1276 1277 /* Calculate shift from starting position for both variants: */1278 double dLength1 = sqrt(pow((double)(var1.x() - rectangle.x()), (double)2) +1279 pow((double)(var1.y() - rectangle.y()), (double)2));1280 double dLength2 = sqrt(pow((double)(var2.x() - rectangle.x()), (double)2) +1281 pow((double)(var2.y() - rectangle.y()), (double)2));1282 1283 /* Return minimum shifted variant: */1284 return dLength1 > dLength2 ? var2 : var1;1285 }1286 1287 /* static */1288 QRect UICommon::getNormalized(const QRect &rectangle, const QRegion &boundRegion, bool /* fCanResize = true */)1289 {1290 /* Ensures that the given rectangle @a rectangle is fully contained within the region @a boundRegion1291 * by moving @a rectangle if necessary. If @a rectangle is larger than @a boundRegion, top left1292 * corner of @a rectangle is aligned with the top left corner of maximum available rectangle and,1293 * if @a fCanResize is true, @a rectangle is shrinked to become fully visible. */1294 1295 /* Storing available horizontal sub-rectangles & vertical shifts: */1296 const int iWindowVertical = rectangle.center().y();1297 QList<QRect> rectanglesList;1298 QList<int> shiftsList;1299 foreach (QRect currentItem, boundRegion.rects())1300 {1301 const int iCurrentDelta = qAbs(iWindowVertical - currentItem.center().y());1302 const int iShift2Top = currentItem.top() - rectangle.top();1303 const int iShift2Bot = currentItem.bottom() - rectangle.bottom();1304 1305 int iTtemPosition = 0;1306 foreach (QRect item, rectanglesList)1307 {1308 const int iDelta = qAbs(iWindowVertical - item.center().y());1309 if (iDelta > iCurrentDelta)1310 break;1311 else1312 ++iTtemPosition;1313 }1314 rectanglesList.insert(iTtemPosition, currentItem);1315 1316 int iShift2TopPos = 0;1317 foreach (int iShift, shiftsList)1318 if (qAbs(iShift) > qAbs(iShift2Top))1319 break;1320 else1321 ++iShift2TopPos;1322 shiftsList.insert(iShift2TopPos, iShift2Top);1323 1324 int iShift2BotPos = 0;1325 foreach (int iShift, shiftsList)1326 if (qAbs(iShift) > qAbs(iShift2Bot))1327 break;1328 else1329 ++iShift2BotPos;1330 shiftsList.insert(iShift2BotPos, iShift2Bot);1331 }1332 1333 /* Trying to find the appropriate place for window: */1334 QRect result;1335 for (int i = -1; i < shiftsList.size(); ++i)1336 {1337 /* Move to appropriate vertical: */1338 QRect newRectangle(rectangle);1339 if (i >= 0)1340 newRectangle.translate(0, shiftsList[i]);1341 1342 /* Search horizontal shift: */1343 int iMaxShift = 0;1344 foreach (QRect item, rectanglesList)1345 {1346 QRect trectangle(newRectangle.translated(item.left() - newRectangle.left(), 0));1347 if (!item.intersects(trectangle))1348 continue;1349 1350 if (newRectangle.left() < item.left())1351 {1352 const int iShift = item.left() - newRectangle.left();1353 iMaxShift = qAbs(iShift) > qAbs(iMaxShift) ? iShift : iMaxShift;1354 }1355 else if (newRectangle.right() > item.right())1356 {1357 const int iShift = item.right() - newRectangle.right();1358 iMaxShift = qAbs(iShift) > qAbs(iMaxShift) ? iShift : iMaxShift;1359 }1360 }1361 1362 /* Shift across the horizontal direction: */1363 newRectangle.translate(iMaxShift, 0);1364 1365 /* Check the translated rectangle to feat the rules: */1366 if (boundRegion.united(newRectangle) == boundRegion)1367 result = newRectangle;1368 1369 if (!result.isNull())1370 break;1371 }1372 1373 if (result.isNull())1374 {1375 /* Resize window to feat desirable size1376 * using max of available rectangles: */1377 QRect maxRectangle;1378 quint64 uMaxSquare = 0;1379 foreach (QRect item, rectanglesList)1380 {1381 const quint64 uSquare = item.width() * item.height();1382 if (uSquare > uMaxSquare)1383 {1384 uMaxSquare = uSquare;1385 maxRectangle = item;1386 }1387 }1388 1389 result = rectangle;1390 result.moveTo(maxRectangle.x(), maxRectangle.y());1391 if (maxRectangle.right() < result.right())1392 result.setRight(maxRectangle.right());1393 if (maxRectangle.bottom() < result.bottom())1394 result.setBottom(maxRectangle.bottom());1395 }1396 1397 return result;1398 }1399 1400 /* static */1401 QRegion UICommon::flip(const QRegion ®ion)1402 {1403 QRegion result;1404 QVector<QRect> rectangles(region.rects());1405 foreach (QRect rectangle, rectangles)1406 result += QRect(rectangle.y(), rectangle.x(),1407 rectangle.height(), rectangle.width());1408 return result;1409 }1410 1411 /* static */1412 void UICommon::centerWidget(QWidget *pWidget, QWidget *pRelative, bool fCanResize /* = true */)1413 {1414 /* If necessary, pWidget's position is adjusted to make it fully visible within1415 * the available desktop area. If pWidget is bigger then this area, it will also1416 * be resized unless fCanResize is false or there is an inappropriate minimum1417 * size limit (in which case the top left corner will be simply aligned with the top1418 * left corner of the available desktop area). pWidget must be a top-level widget.1419 * pRelative may be any widget, but if it's not top-level itself, its top-level1420 * widget will be used for calculations. pRelative can also be NULL, in which case1421 * pWidget will be centered relative to the available desktop area. */1422 1423 AssertReturnVoid(pWidget);1424 AssertReturnVoid(pWidget->isTopLevel());1425 1426 QRect deskGeo, parentGeo;1427 if (pRelative)1428 {1429 pRelative = pRelative->window();1430 deskGeo = gpDesktop->availableGeometry(pRelative);1431 parentGeo = pRelative->frameGeometry();1432 // WORKAROUND:1433 // On X11/Gnome, geo/frameGeo.x() and y() are always 0 for top level1434 // widgets with parents, what a shame. Use mapToGlobal() to workaround.1435 QPoint d = pRelative->mapToGlobal(QPoint(0, 0));1436 d.rx() -= pRelative->geometry().x() - pRelative->x();1437 d.ry() -= pRelative->geometry().y() - pRelative->y();1438 parentGeo.moveTopLeft(d);1439 }1440 else1441 {1442 deskGeo = gpDesktop->availableGeometry();1443 parentGeo = deskGeo;1444 }1445 1446 // WORKAROUND:1447 // On X11, there is no way to determine frame geometry (including WM1448 // decorations) before the widget is shown for the first time. Stupidly1449 // enumerate other top level widgets to find the thickest frame. The code1450 // is based on the idea taken from QDialog::adjustPositionInternal().1451 1452 int iExtraW = 0;1453 int iExtraH = 0;1454 1455 QWidgetList list = QApplication::topLevelWidgets();1456 QListIterator<QWidget*> it(list);1457 while ((iExtraW == 0 || iExtraH == 0) && it.hasNext())1458 {1459 int iFrameW, iFrameH;1460 QWidget *pCurrent = it.next();1461 if (!pCurrent->isVisible())1462 continue;1463 1464 iFrameW = pCurrent->frameGeometry().width() - pCurrent->width();1465 iFrameH = pCurrent->frameGeometry().height() - pCurrent->height();1466 1467 iExtraW = qMax(iExtraW, iFrameW);1468 iExtraH = qMax(iExtraH, iFrameH);1469 }1470 1471 /* On non-X11 platforms, the following would be enough instead of the above workaround: */1472 // QRect geo = frameGeometry();1473 QRect geo = QRect(0, 0, pWidget->width() + iExtraW,1474 pWidget->height() + iExtraH);1475 1476 geo.moveCenter(QPoint(parentGeo.x() + (parentGeo.width() - 1) / 2,1477 parentGeo.y() + (parentGeo.height() - 1) / 2));1478 1479 /* Ensure the widget is within the available desktop area: */1480 QRect newGeo = normalizeGeometry(geo, deskGeo, fCanResize);1481 #ifdef VBOX_WS_MAC1482 // WORKAROUND:1483 // No idea why, but Qt doesn't respect if there is a unified toolbar on the1484 // ::move call. So manually add the height of the toolbar before setting1485 // the position.1486 if (pRelative)1487 newGeo.translate(0, ::darwinWindowToolBarHeight(pWidget));1488 #endif /* VBOX_WS_MAC */1489 1490 pWidget->move(newGeo.topLeft());1491 1492 if ( fCanResize1493 && (geo.width() != newGeo.width() || geo.height() != newGeo.height()))1494 pWidget->resize(newGeo.width() - iExtraW, newGeo.height() - iExtraH);1495 }1496 1497 /* static */1498 void UICommon::setTopLevelGeometry(QWidget *pWidget, int x, int y, int w, int h)1499 {1500 AssertPtrReturnVoid(pWidget);1501 #ifdef VBOX_WS_X111502 # define QWINDOWSIZE_MAX ((1<<24)-1)1503 if (pWidget->isWindow() && pWidget->isVisible())1504 {1505 // WORKAROUND:1506 // X11 window managers are not required to accept geometry changes on1507 // the top-level window. Unfortunately, current at Qt 5.6 and 5.7, Qt1508 // assumes that the change will succeed, and resizes all sub-windows1509 // unconditionally. By calling ConfigureWindow directly, Qt will see1510 // our change request as an externally triggered one on success and not1511 // at all if it is rejected.1512 const double dDPR = gpDesktop->devicePixelRatio(pWidget);1513 uint16_t fMask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y1514 | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;1515 uint32_t values[] = { (uint32_t)(x * dDPR), (uint32_t)(y * dDPR), (uint32_t)(w * dDPR), (uint32_t)(h * dDPR) };1516 xcb_configure_window(QX11Info::connection(), (xcb_window_t)pWidget->winId(),1517 fMask, values);1518 xcb_size_hints_t hints;1519 hints.flags = 1 /* XCB_ICCCM_SIZE_HINT_US_POSITION */1520 | 2 /* XCB_ICCCM_SIZE_HINT_US_SIZE */1521 | 512 /* XCB_ICCCM_SIZE_P_WIN_GRAVITY */;1522 hints.x = x * dDPR;1523 hints.y = y * dDPR;1524 hints.width = w * dDPR;1525 hints.height = h * dDPR;1526 hints.min_width = pWidget->minimumSize().width() * dDPR;1527 hints.min_height = pWidget->minimumSize().height() * dDPR;1528 hints.max_width = pWidget->maximumSize().width() * dDPR;1529 hints.max_height = pWidget->maximumSize().height() * dDPR;1530 hints.width_inc = pWidget->sizeIncrement().width() * dDPR;1531 hints.height_inc = pWidget->sizeIncrement().height() * dDPR;1532 hints.base_width = pWidget->baseSize().width() * dDPR;1533 hints.base_height = pWidget->baseSize().height() * dDPR;1534 hints.win_gravity = XCB_GRAVITY_STATIC;1535 if (hints.min_width > 0 || hints.min_height > 0)1536 hints.flags |= 16 /* XCB_ICCCM_SIZE_HINT_P_MIN_SIZE */;1537 if (hints.max_width < QWINDOWSIZE_MAX || hints.max_height < QWINDOWSIZE_MAX)1538 hints.flags |= 32 /* XCB_ICCCM_SIZE_HINT_P_MAX_SIZE */;1539 if (hints.width_inc > 0 || hints.height_inc)1540 hints.flags |= 64 /* XCB_ICCCM_SIZE_HINT_P_MIN_SIZE */1541 | 256 /* XCB_ICCCM_SIZE_HINT_BASE_SIZE */;1542 xcb_change_property(QX11Info::connection(), XCB_PROP_MODE_REPLACE,1543 (xcb_window_t)pWidget->winId(), XCB_ATOM_WM_NORMAL_HINTS,1544 XCB_ATOM_WM_SIZE_HINTS, 32, sizeof(hints) >> 2, &hints);1545 xcb_flush(QX11Info::connection());1546 }1547 else1548 // WORKAROUND:1549 // Call the Qt method if the window is not visible as otherwise no1550 // Configure event will arrive to tell Qt what geometry we want.1551 pWidget->setGeometry(x, y, w, h);1552 # else /* !VBOX_WS_X11 */1553 pWidget->setGeometry(x, y, w, h);1554 # endif /* !VBOX_WS_X11 */1555 }1556 1557 /* static */1558 void UICommon::setTopLevelGeometry(QWidget *pWidget, const QRect &rect)1559 {1560 UICommon::setTopLevelGeometry(pWidget, rect.x(), rect.y(), rect.width(), rect.height());1561 }1562 1563 /* static */1564 bool UICommon::activateWindow(WId wId, bool fSwitchDesktop /* = true */)1565 {1566 Q_UNUSED(fSwitchDesktop);1567 bool fResult = true;1568 1569 #if defined(VBOX_WS_WIN)1570 1571 fResult &= NativeWindowSubsystem::WinActivateWindow(wId, fSwitchDesktop);1572 1573 #elif defined(VBOX_WS_X11)1574 1575 fResult &= NativeWindowSubsystem::X11ActivateWindow(wId, fSwitchDesktop);1576 1577 #else1578 1579 NOREF(wId);1580 NOREF(fSwitchDesktop);1581 AssertFailed();1582 fResult = false;1583 1584 #endif1585 1586 if (!fResult)1587 Log1WarningFunc(("Couldn't activate wId=%08X\n", wId));1588 1589 return fResult;1590 }1591 1592 /* static */1593 1264 void UICommon::setMinimumWidthAccordingSymbolCount(QSpinBox *pSpinBox, int cCount) 1594 1265 { … … 1697 1368 #if defined(VBOX_WS_WIN) || defined(VBOX_WS_X11) 1698 1369 1699 return activateWindow(id, true);1370 return UIDesktopWidgetWatchdog::activateWindow(id, true); 1700 1371 1701 1372 #elif defined(VBOX_WS_MAC) -
trunk/src/VBox/Frontends/VirtualBox/src/globals/UICommon.h
r91079 r91109 314 314 /** @} */ 315 315 316 /** @name Window/widget stuff. 317 * @{ */ 318 /** Search position for @a rectangle to make sure it is fully contained @a boundRegion. */ 319 static QRect normalizeGeometry(const QRect &rectangle, const QRegion &boundRegion, 320 bool fCanResize = true); 321 /** Ensures that the given rectangle @a rectangle is fully contained within the region @a boundRegion. */ 322 static QRect getNormalized(const QRect &rectangle, const QRegion &boundRegion, 323 bool fCanResize = true); 324 /** Returns the flipped (transposed) @a region. */ 325 static QRegion flip(const QRegion ®ion); 326 327 /** Aligns the center of @a pWidget with the center of @a pRelative. */ 328 static void centerWidget(QWidget *pWidget, QWidget *pRelative, bool fCanResize = true); 329 330 /** Assigns top-level @a pWidget geometry passed as QRect coordinates. 331 * @note Take into account that this request may fail on X11. */ 332 static void setTopLevelGeometry(QWidget *pWidget, int x, int y, int w, int h); 333 /** Assigns top-level @a pWidget geometry passed as @a rect. 334 * @note Take into account that this request may fail on X11. */ 335 static void setTopLevelGeometry(QWidget *pWidget, const QRect &rect); 336 337 /** Activates the specified window with given @a wId. Can @a fSwitchDesktop if requested. */ 338 static bool activateWindow(WId wId, bool fSwitchDesktop = true); 339 316 /** @name Widget stuff. 317 * @{ */ 340 318 /** Assigns minimum @a pSpinBox to correspond to @a cCount digits. */ 341 319 static void setMinimumWidthAccordingSymbolCount(QSpinBox *pSpinBox, int cCount); … … 448 426 QUuid openMediumWithFileOpenDialog(UIMediumDeviceType enmMediumType, QWidget *pParent = 0, 449 427 const QString &strDefaultFolder = QString(), bool fUseLastFolder = false); 450 451 428 452 429 /** Creates and shows a UIMediumSelector dialog. -
trunk/src/VBox/Frontends/VirtualBox/src/globals/UIDesktopWidgetWatchdog.cpp
r85121 r91109 29 29 /* GUI includes: */ 30 30 #include "UIDesktopWidgetWatchdog.h" 31 #ifdef VBOX_WS_WIN 32 #include "VBoxUtils-win.h" 33 #endif 31 34 #ifdef VBOX_WS_X11 32 35 # include "UICommon.h" 33 #endif /* VBOX_WS_X11 */ 36 # include "VBoxUtils-x11.h" 37 #endif 34 38 35 39 /* Other VBox includes: */ … … 478 482 } 479 483 484 /* static */ 485 QRect UIDesktopWidgetWatchdog::normalizeGeometry(const QRect &rectangle, 486 const QRegion &boundRegion, 487 bool fCanResize /* = true */) 488 { 489 /* Perform direct and flipped search of position for @a rectangle to make sure it is fully contained 490 * inside @a boundRegion region by moving & resizing (if @a fCanResize is specified) @a rectangle if 491 * necessary. Selects the minimum shifted result between direct and flipped variants. */ 492 493 /* Direct search for normalized rectangle: */ 494 QRect var1(getNormalized(rectangle, boundRegion, fCanResize)); 495 496 /* Flipped search for normalized rectangle: */ 497 QRect var2(flip(getNormalized(flip(rectangle).boundingRect(), 498 flip(boundRegion), fCanResize)).boundingRect()); 499 500 /* Calculate shift from starting position for both variants: */ 501 double dLength1 = sqrt(pow((double)(var1.x() - rectangle.x()), (double)2) + 502 pow((double)(var1.y() - rectangle.y()), (double)2)); 503 double dLength2 = sqrt(pow((double)(var2.x() - rectangle.x()), (double)2) + 504 pow((double)(var2.y() - rectangle.y()), (double)2)); 505 506 /* Return minimum shifted variant: */ 507 return dLength1 > dLength2 ? var2 : var1; 508 } 509 510 /* static */ 511 QRect UIDesktopWidgetWatchdog::getNormalized(const QRect &rectangle, 512 const QRegion &boundRegion, 513 bool /* fCanResize = true */) 514 { 515 /* Ensures that the given rectangle @a rectangle is fully contained within the region @a boundRegion 516 * by moving @a rectangle if necessary. If @a rectangle is larger than @a boundRegion, top left 517 * corner of @a rectangle is aligned with the top left corner of maximum available rectangle and, 518 * if @a fCanResize is true, @a rectangle is shrinked to become fully visible. */ 519 520 /* Storing available horizontal sub-rectangles & vertical shifts: */ 521 const int iWindowVertical = rectangle.center().y(); 522 QList<QRect> rectanglesList; 523 QList<int> shiftsList; 524 foreach (QRect currentItem, boundRegion.rects()) 525 { 526 const int iCurrentDelta = qAbs(iWindowVertical - currentItem.center().y()); 527 const int iShift2Top = currentItem.top() - rectangle.top(); 528 const int iShift2Bot = currentItem.bottom() - rectangle.bottom(); 529 530 int iTtemPosition = 0; 531 foreach (QRect item, rectanglesList) 532 { 533 const int iDelta = qAbs(iWindowVertical - item.center().y()); 534 if (iDelta > iCurrentDelta) 535 break; 536 else 537 ++iTtemPosition; 538 } 539 rectanglesList.insert(iTtemPosition, currentItem); 540 541 int iShift2TopPos = 0; 542 foreach (int iShift, shiftsList) 543 if (qAbs(iShift) > qAbs(iShift2Top)) 544 break; 545 else 546 ++iShift2TopPos; 547 shiftsList.insert(iShift2TopPos, iShift2Top); 548 549 int iShift2BotPos = 0; 550 foreach (int iShift, shiftsList) 551 if (qAbs(iShift) > qAbs(iShift2Bot)) 552 break; 553 else 554 ++iShift2BotPos; 555 shiftsList.insert(iShift2BotPos, iShift2Bot); 556 } 557 558 /* Trying to find the appropriate place for window: */ 559 QRect result; 560 for (int i = -1; i < shiftsList.size(); ++i) 561 { 562 /* Move to appropriate vertical: */ 563 QRect newRectangle(rectangle); 564 if (i >= 0) 565 newRectangle.translate(0, shiftsList[i]); 566 567 /* Search horizontal shift: */ 568 int iMaxShift = 0; 569 foreach (QRect item, rectanglesList) 570 { 571 QRect trectangle(newRectangle.translated(item.left() - newRectangle.left(), 0)); 572 if (!item.intersects(trectangle)) 573 continue; 574 575 if (newRectangle.left() < item.left()) 576 { 577 const int iShift = item.left() - newRectangle.left(); 578 iMaxShift = qAbs(iShift) > qAbs(iMaxShift) ? iShift : iMaxShift; 579 } 580 else if (newRectangle.right() > item.right()) 581 { 582 const int iShift = item.right() - newRectangle.right(); 583 iMaxShift = qAbs(iShift) > qAbs(iMaxShift) ? iShift : iMaxShift; 584 } 585 } 586 587 /* Shift across the horizontal direction: */ 588 newRectangle.translate(iMaxShift, 0); 589 590 /* Check the translated rectangle to feat the rules: */ 591 if (boundRegion.united(newRectangle) == boundRegion) 592 result = newRectangle; 593 594 if (!result.isNull()) 595 break; 596 } 597 598 if (result.isNull()) 599 { 600 /* Resize window to feat desirable size 601 * using max of available rectangles: */ 602 QRect maxRectangle; 603 quint64 uMaxSquare = 0; 604 foreach (QRect item, rectanglesList) 605 { 606 const quint64 uSquare = item.width() * item.height(); 607 if (uSquare > uMaxSquare) 608 { 609 uMaxSquare = uSquare; 610 maxRectangle = item; 611 } 612 } 613 614 result = rectangle; 615 result.moveTo(maxRectangle.x(), maxRectangle.y()); 616 if (maxRectangle.right() < result.right()) 617 result.setRight(maxRectangle.right()); 618 if (maxRectangle.bottom() < result.bottom()) 619 result.setBottom(maxRectangle.bottom()); 620 } 621 622 return result; 623 } 624 625 /* static */ 626 void UIDesktopWidgetWatchdog::centerWidget(QWidget *pWidget, 627 QWidget *pRelative, 628 bool fCanResize /* = true */) 629 { 630 /* If necessary, pWidget's position is adjusted to make it fully visible within 631 * the available desktop area. If pWidget is bigger then this area, it will also 632 * be resized unless fCanResize is false or there is an inappropriate minimum 633 * size limit (in which case the top left corner will be simply aligned with the top 634 * left corner of the available desktop area). pWidget must be a top-level widget. 635 * pRelative may be any widget, but if it's not top-level itself, its top-level 636 * widget will be used for calculations. pRelative can also be NULL, in which case 637 * pWidget will be centered relative to the available desktop area. */ 638 639 AssertReturnVoid(pWidget); 640 AssertReturnVoid(pWidget->isTopLevel()); 641 642 QRect deskGeo, parentGeo; 643 if (pRelative) 644 { 645 pRelative = pRelative->window(); 646 deskGeo = gpDesktop->availableGeometry(pRelative); 647 parentGeo = pRelative->frameGeometry(); 648 // WORKAROUND: 649 // On X11/Gnome, geo/frameGeo.x() and y() are always 0 for top level 650 // widgets with parents, what a shame. Use mapToGlobal() to workaround. 651 QPoint d = pRelative->mapToGlobal(QPoint(0, 0)); 652 d.rx() -= pRelative->geometry().x() - pRelative->x(); 653 d.ry() -= pRelative->geometry().y() - pRelative->y(); 654 parentGeo.moveTopLeft(d); 655 } 656 else 657 { 658 deskGeo = gpDesktop->availableGeometry(); 659 parentGeo = deskGeo; 660 } 661 662 // WORKAROUND: 663 // On X11, there is no way to determine frame geometry (including WM 664 // decorations) before the widget is shown for the first time. Stupidly 665 // enumerate other top level widgets to find the thickest frame. The code 666 // is based on the idea taken from QDialog::adjustPositionInternal(). 667 668 int iExtraW = 0; 669 int iExtraH = 0; 670 671 QWidgetList list = QApplication::topLevelWidgets(); 672 QListIterator<QWidget*> it(list); 673 while ((iExtraW == 0 || iExtraH == 0) && it.hasNext()) 674 { 675 int iFrameW, iFrameH; 676 QWidget *pCurrent = it.next(); 677 if (!pCurrent->isVisible()) 678 continue; 679 680 iFrameW = pCurrent->frameGeometry().width() - pCurrent->width(); 681 iFrameH = pCurrent->frameGeometry().height() - pCurrent->height(); 682 683 iExtraW = qMax(iExtraW, iFrameW); 684 iExtraH = qMax(iExtraH, iFrameH); 685 } 686 687 /* On non-X11 platforms, the following would be enough instead of the above workaround: */ 688 // QRect geo = frameGeometry(); 689 QRect geo = QRect(0, 0, pWidget->width() + iExtraW, 690 pWidget->height() + iExtraH); 691 692 geo.moveCenter(QPoint(parentGeo.x() + (parentGeo.width() - 1) / 2, 693 parentGeo.y() + (parentGeo.height() - 1) / 2)); 694 695 /* Ensure the widget is within the available desktop area: */ 696 QRect newGeo = normalizeGeometry(geo, deskGeo, fCanResize); 697 #ifdef VBOX_WS_MAC 698 // WORKAROUND: 699 // No idea why, but Qt doesn't respect if there is a unified toolbar on the 700 // ::move call. So manually add the height of the toolbar before setting 701 // the position. 702 if (pRelative) 703 newGeo.translate(0, ::darwinWindowToolBarHeight(pWidget)); 704 #endif /* VBOX_WS_MAC */ 705 706 pWidget->move(newGeo.topLeft()); 707 708 if ( fCanResize 709 && (geo.width() != newGeo.width() || geo.height() != newGeo.height())) 710 pWidget->resize(newGeo.width() - iExtraW, newGeo.height() - iExtraH); 711 } 712 713 /* static */ 714 void UIDesktopWidgetWatchdog::setTopLevelGeometry(QWidget *pWidget, int x, int y, int w, int h) 715 { 716 AssertPtrReturnVoid(pWidget); 717 #ifdef VBOX_WS_X11 718 # define QWINDOWSIZE_MAX ((1<<24)-1) 719 if (pWidget->isWindow() && pWidget->isVisible()) 720 { 721 // WORKAROUND: 722 // X11 window managers are not required to accept geometry changes on 723 // the top-level window. Unfortunately, current at Qt 5.6 and 5.7, Qt 724 // assumes that the change will succeed, and resizes all sub-windows 725 // unconditionally. By calling ConfigureWindow directly, Qt will see 726 // our change request as an externally triggered one on success and not 727 // at all if it is rejected. 728 const double dDPR = gpDesktop->devicePixelRatio(pWidget); 729 uint16_t fMask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y 730 | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT; 731 uint32_t values[] = { (uint32_t)(x * dDPR), (uint32_t)(y * dDPR), (uint32_t)(w * dDPR), (uint32_t)(h * dDPR) }; 732 xcb_configure_window(QX11Info::connection(), (xcb_window_t)pWidget->winId(), 733 fMask, values); 734 xcb_size_hints_t hints; 735 hints.flags = 1 /* XCB_ICCCM_SIZE_HINT_US_POSITION */ 736 | 2 /* XCB_ICCCM_SIZE_HINT_US_SIZE */ 737 | 512 /* XCB_ICCCM_SIZE_P_WIN_GRAVITY */; 738 hints.x = x * dDPR; 739 hints.y = y * dDPR; 740 hints.width = w * dDPR; 741 hints.height = h * dDPR; 742 hints.min_width = pWidget->minimumSize().width() * dDPR; 743 hints.min_height = pWidget->minimumSize().height() * dDPR; 744 hints.max_width = pWidget->maximumSize().width() * dDPR; 745 hints.max_height = pWidget->maximumSize().height() * dDPR; 746 hints.width_inc = pWidget->sizeIncrement().width() * dDPR; 747 hints.height_inc = pWidget->sizeIncrement().height() * dDPR; 748 hints.base_width = pWidget->baseSize().width() * dDPR; 749 hints.base_height = pWidget->baseSize().height() * dDPR; 750 hints.win_gravity = XCB_GRAVITY_STATIC; 751 if (hints.min_width > 0 || hints.min_height > 0) 752 hints.flags |= 16 /* XCB_ICCCM_SIZE_HINT_P_MIN_SIZE */; 753 if (hints.max_width < QWINDOWSIZE_MAX || hints.max_height < QWINDOWSIZE_MAX) 754 hints.flags |= 32 /* XCB_ICCCM_SIZE_HINT_P_MAX_SIZE */; 755 if (hints.width_inc > 0 || hints.height_inc) 756 hints.flags |= 64 /* XCB_ICCCM_SIZE_HINT_P_MIN_SIZE */ 757 | 256 /* XCB_ICCCM_SIZE_HINT_BASE_SIZE */; 758 xcb_change_property(QX11Info::connection(), XCB_PROP_MODE_REPLACE, 759 (xcb_window_t)pWidget->winId(), XCB_ATOM_WM_NORMAL_HINTS, 760 XCB_ATOM_WM_SIZE_HINTS, 32, sizeof(hints) >> 2, &hints); 761 xcb_flush(QX11Info::connection()); 762 } 763 else 764 // WORKAROUND: 765 // Call the Qt method if the window is not visible as otherwise no 766 // Configure event will arrive to tell Qt what geometry we want. 767 pWidget->setGeometry(x, y, w, h); 768 # else /* !VBOX_WS_X11 */ 769 pWidget->setGeometry(x, y, w, h); 770 # endif /* !VBOX_WS_X11 */ 771 } 772 773 /* static */ 774 void UIDesktopWidgetWatchdog::setTopLevelGeometry(QWidget *pWidget, const QRect &rect) 775 { 776 UIDesktopWidgetWatchdog::setTopLevelGeometry(pWidget, rect.x(), rect.y(), rect.width(), rect.height()); 777 } 778 779 /* static */ 780 bool UIDesktopWidgetWatchdog::activateWindow(WId wId, bool fSwitchDesktop /* = true */) 781 { 782 Q_UNUSED(fSwitchDesktop); 783 bool fResult = true; 784 785 #if defined(VBOX_WS_WIN) 786 787 fResult &= NativeWindowSubsystem::WinActivateWindow(wId, fSwitchDesktop); 788 789 #elif defined(VBOX_WS_X11) 790 791 fResult &= NativeWindowSubsystem::X11ActivateWindow(wId, fSwitchDesktop); 792 793 #else 794 795 NOREF(wId); 796 NOREF(fSwitchDesktop); 797 AssertFailed(); 798 fResult = false; 799 800 #endif 801 802 if (!fResult) 803 Log1WarningFunc(("Couldn't activate wId=%08X\n", wId)); 804 805 return fResult; 806 } 807 480 808 void UIDesktopWidgetWatchdog::sltHostScreenAdded(QScreen *pHostScreen) 481 809 { … … 627 955 } 628 956 957 /* static */ 958 QRegion UIDesktopWidgetWatchdog::flip(const QRegion ®ion) 959 { 960 QRegion result; 961 QVector<QRect> rectangles(region.rects()); 962 foreach (QRect rectangle, rectangles) 963 result += QRect(rectangle.y(), rectangle.x(), 964 rectangle.height(), rectangle.width()); 965 return result; 966 } 967 629 968 #if defined(VBOX_WS_X11) && !defined(VBOX_GUI_WITH_CUSTOMIZATIONS1) 630 969 void UIDesktopWidgetWatchdog::updateHostScreenConfiguration(int cHostScreenCount /* = -1 */) -
trunk/src/VBox/Frontends/VirtualBox/src/globals/UIDesktopWidgetWatchdog.h
r91001 r91109 5 5 6 6 /* 7 * Copyright (C) 2015-202 0Oracle Corporation7 * Copyright (C) 2015-2021 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 24 24 /* Qt includes: */ 25 25 #include <QObject> 26 #include <QWindow> 26 27 #ifdef VBOX_WS_X11 28 # include <QRect> 27 29 # include <QVector> 28 # include <QRect>29 30 #endif 30 31 … … 44 45 UIDesktopWidgetWatchdog(); 45 46 /** Destructs desktop-widget watchdog. */ 46 ~UIDesktopWidgetWatchdog();47 virtual ~UIDesktopWidgetWatchdog() /* override final */; 47 48 48 49 signals: … … 123 124 /** Returns actual device-pixel-ratio of the host-screen which contains @a pWidget. */ 124 125 double devicePixelRatioActual(QWidget *pWidget); 126 127 /** Search position for @a rectangle to make sure it is fully 128 * contained within @a boundRegion, performing resize if allowed. */ 129 static QRect normalizeGeometry(const QRect &rectangle, 130 const QRegion &boundRegion, 131 bool fCanResize = true); 132 /** Ensures that the given rectangle @a rectangle is fully 133 * contained within the region @a boundRegion, performing resize if allowed. */ 134 static QRect getNormalized(const QRect &rectangle, 135 const QRegion &boundRegion, 136 bool fCanResize = true); 137 /** Aligns the center of @a pWidget with the center 138 * of @a pRelative, performing resize if allowed. */ 139 static void centerWidget(QWidget *pWidget, 140 QWidget *pRelative, 141 bool fCanResize = true); 142 143 /** Assigns top-level @a pWidget geometry passed as QRect coordinates. 144 * @note Take into account that this request may fail on X11. */ 145 static void setTopLevelGeometry(QWidget *pWidget, int x, int y, int w, int h); 146 /** Assigns top-level @a pWidget geometry passed as @a rect. 147 * @note Take into account that this request may fail on X11. */ 148 static void setTopLevelGeometry(QWidget *pWidget, const QRect &rect); 149 150 /** Activates the specified window with given @a wId. Can @a fSwitchDesktop if requested. */ 151 static bool activateWindow(WId wId, bool fSwitchDesktop = true); 125 152 126 153 private slots: … … 147 174 void cleanup(); 148 175 176 /** Returns the flipped (transposed) @a region. */ 177 static QRegion flip(const QRegion ®ion); 178 149 179 /** Holds the static instance of the desktop-widget watchdog. */ 150 180 static UIDesktopWidgetWatchdog *s_pInstance; … … 172 202 173 203 #endif /* !FEQT_INCLUDED_SRC_globals_UIDesktopWidgetWatchdog_h */ 174 -
trunk/src/VBox/Frontends/VirtualBox/src/medium/UIMediumSelector.cpp
r90425 r91109 613 613 614 614 if (m_pParent) 615 UI Common::centerWidget(this, m_pParent, false);615 UIDesktopWidgetWatchdog::centerWidget(this, m_pParent, false); 616 616 } 617 617 -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineWindowFullscreen.cpp
r91066 r91109 381 381 /* Move window to the center of working-area: */ 382 382 geo.moveCenter(workingArea.center()); 383 UI Common::setTopLevelGeometry(this, geo);383 UIDesktopWidgetWatchdog::setTopLevelGeometry(this, geo); 384 384 } 385 385 -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineWindowNormal.cpp
r90685 r91109 393 393 /* Restore window geometry: */ 394 394 m_geometry = geo; 395 UI Common::setTopLevelGeometry(this, m_geometry);395 UIDesktopWidgetWatchdog::setTopLevelGeometry(this, m_geometry); 396 396 397 397 /* If previous machine-state was NOT SAVED => normalize window to the optimal-size: */ … … 413 413 m_geometry = geometry(); 414 414 m_geometry.moveCenter(gpDesktop->availableGeometry(this).center()); 415 UI Common::setTopLevelGeometry(this, m_geometry);415 UIDesktopWidgetWatchdog::setTopLevelGeometry(this, m_geometry); 416 416 } 417 417 … … 625 625 /* Adjust position if necessary: */ 626 626 if (fAdjustPosition) 627 frGeo = UI Common::normalizeGeometry(frGeo, gpDesktop->overallAvailableRegion());627 frGeo = UIDesktopWidgetWatchdog::normalizeGeometry(frGeo, gpDesktop->overallAvailableRegion()); 628 628 629 629 /* Finally, set the frame geometry: */ 630 UI Common::setTopLevelGeometry(this, frGeo.left() + dl, frGeo.top() + dt,630 UIDesktopWidgetWatchdog::setTopLevelGeometry(this, frGeo.left() + dl, frGeo.top() + dt, 631 631 frGeo.width() - dl - dr, frGeo.height() - dt - db); 632 632 #else /* VBOX_GUI_WITH_CUSTOMIZATIONS1 */ -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/scale/UIMachineWindowScale.cpp
r90567 r91109 107 107 /* Restore window geometry: */ 108 108 m_geometry = geo; 109 UI Common::setTopLevelGeometry(this, m_geometry);109 UIDesktopWidgetWatchdog::setTopLevelGeometry(this, m_geometry); 110 110 111 111 /* Maximize (if necessary): */ … … 126 126 m_geometry = geometry(); 127 127 m_geometry.moveCenter(availableGeo.center()); 128 UI Common::setTopLevelGeometry(this, m_geometry);128 UIDesktopWidgetWatchdog::setTopLevelGeometry(this, m_geometry); 129 129 } 130 130 … … 197 197 /* Adjust position if necessary: */ 198 198 if (fAdjustPosition) 199 frGeo = UI Common::normalizeGeometry(frGeo, gpDesktop->overallAvailableRegion());199 frGeo = UIDesktopWidgetWatchdog::normalizeGeometry(frGeo, gpDesktop->overallAvailableRegion()); 200 200 201 201 /* Finally, set the frame geometry: */ 202 UI Common::setTopLevelGeometry(this, frGeo.left() + dl, frGeo.top() + dt,202 UIDesktopWidgetWatchdog::setTopLevelGeometry(this, frGeo.left() + dl, frGeo.top() + dt, 203 203 frGeo.width() - dl - dr, frGeo.height() - dt - db); 204 204 } -
trunk/src/VBox/Frontends/VirtualBox/src/snapshots/UISnapshotDetailsWidget.cpp
r91003 r91109 502 502 503 503 /* Center according requested widget: */ 504 UI Common::centerWidget(this, parentWidget(), false);504 UIDesktopWidgetWatchdog::centerWidget(this, parentWidget(), false); 505 505 } 506 506 -
trunk/src/VBox/Frontends/VirtualBox/src/widgets/UIPopupStack.cpp
r91003 r91109 27 27 #include "UICommon.h" 28 28 #include "UICursor.h" 29 #include "UIDesktopWidgetWatchdog.h" 29 30 #include "UIPopupStack.h" 30 31 #include "UIPopupStackViewport.h" … … 203 204 204 205 /* Adjust geometry: */ 205 UI Common::setTopLevelGeometry(this, iX, iY, iWidth, iHeight);206 UIDesktopWidgetWatchdog::setTopLevelGeometry(this, iX, iY, iWidth, iHeight); 206 207 } 207 208 -
trunk/src/VBox/Frontends/VirtualBox/src/widgets/UISlidingToolBar.cpp
r88862 r91109 21 21 /* GUI includes: */ 22 22 #include "UICommon.h" 23 #include "UIDesktopWidgetWatchdog.h" 23 24 #include "UISlidingToolBar.h" 24 25 #include "UIAnimationFramework.h" … … 187 188 case Position_Top: 188 189 { 189 UI Common::setTopLevelGeometry(this, m_parentRect.x(), m_parentRect.y() + m_indentRect.height(),190 UIDesktopWidgetWatchdog::setTopLevelGeometry(this, m_parentRect.x(), m_parentRect.y() + m_indentRect.height(), 190 191 qMax(m_parentRect.width(), sh.width()), sh.height()); 191 192 m_pWidget->setGeometry(0, -sh.height(), qMax(width(), sh.width()), sh.height()); … … 194 195 case Position_Bottom: 195 196 { 196 UI Common::setTopLevelGeometry(this, m_parentRect.x(), m_parentRect.y() + m_parentRect.height() - m_indentRect.height() - sh.height(),197 UIDesktopWidgetWatchdog::setTopLevelGeometry(this, m_parentRect.x(), m_parentRect.y() + m_parentRect.height() - m_indentRect.height() - sh.height(), 197 198 qMax(m_parentRect.width(), sh.width()), sh.height()); 198 199 m_pWidget->setGeometry(0, sh.height(), qMax(width(), sh.width()), sh.height()); … … 245 246 case Position_Top: 246 247 { 247 UI Common::setTopLevelGeometry(this, m_parentRect.x(), m_parentRect.y() + m_indentRect.height(),248 UIDesktopWidgetWatchdog::setTopLevelGeometry(this, m_parentRect.x(), m_parentRect.y() + m_indentRect.height(), 248 249 qMax(m_parentRect.width(), sh.width()), sh.height()); 249 250 break; … … 251 252 case Position_Bottom: 252 253 { 253 UI Common::setTopLevelGeometry(this, m_parentRect.x(), m_parentRect.y() + m_parentRect.height() - m_indentRect.height() - sh.height(),254 UIDesktopWidgetWatchdog::setTopLevelGeometry(this, m_parentRect.x(), m_parentRect.y() + m_parentRect.height() - m_indentRect.height() - sh.height(), 254 255 qMax(m_parentRect.width(), sh.width()), sh.height()); 255 256 break;
Note:
See TracChangeset
for help on using the changeset viewer.