VirtualBox

Changeset 91109 in vbox for trunk/src


Ignore:
Timestamp:
Sep 3, 2021 3:31:49 PM (3 years ago)
Author:
vboxsync
Message:

FE/Qt: bugref:10067: Move window geometry stuff from UICommon to UIDesktopWidgetWatchdog.

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  
    2222#include "QIDialog.h"
    2323#include "UICommon.h"
     24#include "UIDesktopWidgetWatchdog.h"
    2425
    2526
     
    124125
    125126    /* Explicit centering according to our parent: */
    126     UICommon::centerWidget(this, parentWidget(), false);
     127    UIDesktopWidgetWatchdog::centerWidget(this, parentWidget(), false);
    127128}
  • trunk/src/VBox/Frontends/VirtualBox/src/extensions/QIMainDialog.cpp

    r87718 r91109  
    3030#include "QIMainDialog.h"
    3131#include "UICommon.h"
     32#include "UIDesktopWidgetWatchdog.h"
    3233#include "VBoxUtils.h"
    3334
     
    233234    /* Explicit centering according to our parent: */
    234235    if (m_fIsAutoCentering)
    235         UICommon::centerWidget(this, parentWidget(), false);
     236        UIDesktopWidgetWatchdog::centerWidget(this, parentWidget(), false);
    236237}
    237238
  • trunk/src/VBox/Frontends/VirtualBox/src/extensions/QIManagerDialog.cpp

    r88798 r91109  
    121121
    122122    /* Center according requested widget: */
    123     UICommon::centerWidget(this, m_pCenterWidget, false);
     123    UIDesktopWidgetWatchdog::centerWidget(this, m_pCenterWidget, false);
    124124
    125125    /* Load the dialog's settings from extradata */
  • trunk/src/VBox/Frontends/VirtualBox/src/extradata/UIExtraDataManager.cpp

    r90083 r91109  
    733733    activateWindow();
    734734//    /* Center according passed widget: */
    735 //    UICommon::centerWidget(this, pCenterWidget, false);
     735//    UIDesktopWidgetWatchdog::centerWidget(this, pCenterWidget, false);
    736736}
    737737
     
    50515051    /* Make sure resulting geometry is within current bounds: */
    50525052    if (!availableGeometry.contains(geometry))
    5053         geometry = UICommon::getNormalized(geometry, QRegion(availableGeometry));
     5053        geometry = UIDesktopWidgetWatchdog::getNormalized(geometry, QRegion(availableGeometry));
    50545054#endif /* VBOX_WS_WIN */
    50555055
  • trunk/src/VBox/Frontends/VirtualBox/src/globals/QIWithRestorableGeometry.h

    r87718 r91109  
    113113#else
    114114        /* Use the new approach otherwise: */
    115         UICommon::setTopLevelGeometry(this, m_geometry);
     115        UIDesktopWidgetWatchdog::setTopLevelGeometry(this, m_geometry);
    116116#endif
    117117
  • trunk/src/VBox/Frontends/VirtualBox/src/globals/UICommon.cpp

    r91094 r91109  
    12621262
    12631263/* 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 contained
    1267      * inside @a boundRegion region by moving & resizing (if @a fCanResize is specified) @a rectangle if
    1268      * 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 boundRegion
    1291      * by moving @a rectangle if necessary. If @a rectangle is larger than @a boundRegion, top left
    1292      * 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             else
    1312                 ++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             else
    1321                 ++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             else
    1329                 ++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 size
    1376          * 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 &region)
    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 within
    1415      * the available desktop area. If pWidget is bigger then this area, it will also
    1416      * be resized unless fCanResize is false or there is an inappropriate minimum
    1417      * size limit (in which case the top left corner will be simply aligned with the top
    1418      * 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-level
    1420      * widget will be used for calculations. pRelative can also be NULL, in which case
    1421      * 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 level
    1434         // 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     else
    1441     {
    1442         deskGeo = gpDesktop->availableGeometry();
    1443         parentGeo = deskGeo;
    1444     }
    1445 
    1446     // WORKAROUND:
    1447     // On X11, there is no way to determine frame geometry (including WM
    1448     // decorations) before the widget is shown for the first time. Stupidly
    1449     // enumerate other top level widgets to find the thickest frame. The code
    1450     // 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_MAC
    1482     // WORKAROUND:
    1483     // No idea why, but Qt doesn't respect if there is a unified toolbar on the
    1484     // ::move call. So manually add the height of the toolbar before setting
    1485     // 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 (   fCanResize
    1493         && (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_X11
    1502 # 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 on
    1507         // the top-level window.  Unfortunately, current at Qt 5.6 and 5.7, Qt
    1508         // assumes that the change will succeed, and resizes all sub-windows
    1509         // unconditionally.  By calling ConfigureWindow directly, Qt will see
    1510         // our change request as an externally triggered one on success and not
    1511         // at all if it is rejected.
    1512         const double dDPR = gpDesktop->devicePixelRatio(pWidget);
    1513         uint16_t fMask =   XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y
    1514                          | 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     else
    1548         // WORKAROUND:
    1549         // Call the Qt method if the window is not visible as otherwise no
    1550         // 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 #else
    1578 
    1579     NOREF(wId);
    1580     NOREF(fSwitchDesktop);
    1581     AssertFailed();
    1582     fResult = false;
    1583 
    1584 #endif
    1585 
    1586     if (!fResult)
    1587         Log1WarningFunc(("Couldn't activate wId=%08X\n", wId));
    1588 
    1589     return fResult;
    1590 }
    1591 
    1592 /* static */
    15931264void UICommon::setMinimumWidthAccordingSymbolCount(QSpinBox *pSpinBox, int cCount)
    15941265{
     
    16971368#if defined(VBOX_WS_WIN) || defined(VBOX_WS_X11)
    16981369
    1699     return activateWindow(id, true);
     1370    return UIDesktopWidgetWatchdog::activateWindow(id, true);
    17001371
    17011372#elif defined(VBOX_WS_MAC)
  • trunk/src/VBox/Frontends/VirtualBox/src/globals/UICommon.h

    r91079 r91109  
    314314    /** @} */
    315315
    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 &region);
    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     * @{ */
    340318        /** Assigns minimum @a pSpinBox to correspond to @a cCount digits. */
    341319        static void setMinimumWidthAccordingSymbolCount(QSpinBox *pSpinBox, int cCount);
     
    448426        QUuid openMediumWithFileOpenDialog(UIMediumDeviceType enmMediumType, QWidget *pParent = 0,
    449427                                             const QString &strDefaultFolder = QString(), bool fUseLastFolder = false);
    450 
    451428
    452429        /** Creates and shows a UIMediumSelector dialog.
  • trunk/src/VBox/Frontends/VirtualBox/src/globals/UIDesktopWidgetWatchdog.cpp

    r85121 r91109  
    2929/* GUI includes: */
    3030#include "UIDesktopWidgetWatchdog.h"
     31#ifdef VBOX_WS_WIN
     32#include "VBoxUtils-win.h"
     33#endif
    3134#ifdef VBOX_WS_X11
    3235# include "UICommon.h"
    33 #endif /* VBOX_WS_X11 */
     36# include "VBoxUtils-x11.h"
     37#endif
    3438
    3539/* Other VBox includes: */
     
    478482}
    479483
     484/* static */
     485QRect 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 */
     511QRect 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 */
     626void 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 */
     714void 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 */
     774void UIDesktopWidgetWatchdog::setTopLevelGeometry(QWidget *pWidget, const QRect &rect)
     775{
     776    UIDesktopWidgetWatchdog::setTopLevelGeometry(pWidget, rect.x(), rect.y(), rect.width(), rect.height());
     777}
     778
     779/* static */
     780bool 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
    480808void UIDesktopWidgetWatchdog::sltHostScreenAdded(QScreen *pHostScreen)
    481809{
     
    627955}
    628956
     957/* static */
     958QRegion UIDesktopWidgetWatchdog::flip(const QRegion &region)
     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
    629968#if defined(VBOX_WS_X11) && !defined(VBOX_GUI_WITH_CUSTOMIZATIONS1)
    630969void UIDesktopWidgetWatchdog::updateHostScreenConfiguration(int cHostScreenCount /* = -1 */)
  • trunk/src/VBox/Frontends/VirtualBox/src/globals/UIDesktopWidgetWatchdog.h

    r91001 r91109  
    55
    66/*
    7  * Copyright (C) 2015-2020 Oracle Corporation
     7 * Copyright (C) 2015-2021 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2424/* Qt includes: */
    2525#include <QObject>
     26#include <QWindow>
    2627#ifdef VBOX_WS_X11
     28# include <QRect>
    2729# include <QVector>
    28 # include <QRect>
    2930#endif
    3031
     
    4445    UIDesktopWidgetWatchdog();
    4546    /** Destructs desktop-widget watchdog. */
    46     ~UIDesktopWidgetWatchdog();
     47    virtual ~UIDesktopWidgetWatchdog() /* override final */;
    4748
    4849signals:
     
    123124    /** Returns actual device-pixel-ratio of the host-screen which contains @a pWidget. */
    124125    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);
    125152
    126153private slots:
     
    147174    void cleanup();
    148175
     176    /** Returns the flipped (transposed) @a region. */
     177    static QRegion flip(const QRegion &region);
     178
    149179    /** Holds the static instance of the desktop-widget watchdog. */
    150180    static UIDesktopWidgetWatchdog *s_pInstance;
     
    172202
    173203#endif /* !FEQT_INCLUDED_SRC_globals_UIDesktopWidgetWatchdog_h */
    174 
  • trunk/src/VBox/Frontends/VirtualBox/src/medium/UIMediumSelector.cpp

    r90425 r91109  
    613613
    614614    if (m_pParent)
    615         UICommon::centerWidget(this, m_pParent, false);
     615        UIDesktopWidgetWatchdog::centerWidget(this, m_pParent, false);
    616616}
    617617
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineWindowFullscreen.cpp

    r91066 r91109  
    381381        /* Move window to the center of working-area: */
    382382        geo.moveCenter(workingArea.center());
    383         UICommon::setTopLevelGeometry(this, geo);
     383        UIDesktopWidgetWatchdog::setTopLevelGeometry(this, geo);
    384384    }
    385385
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineWindowNormal.cpp

    r90685 r91109  
    393393            /* Restore window geometry: */
    394394            m_geometry = geo;
    395             UICommon::setTopLevelGeometry(this, m_geometry);
     395            UIDesktopWidgetWatchdog::setTopLevelGeometry(this, m_geometry);
    396396
    397397            /* If previous machine-state was NOT SAVED => normalize window to the optimal-size: */
     
    413413            m_geometry = geometry();
    414414            m_geometry.moveCenter(gpDesktop->availableGeometry(this).center());
    415             UICommon::setTopLevelGeometry(this, m_geometry);
     415            UIDesktopWidgetWatchdog::setTopLevelGeometry(this, m_geometry);
    416416        }
    417417
     
    625625    /* Adjust position if necessary: */
    626626    if (fAdjustPosition)
    627         frGeo = UICommon::normalizeGeometry(frGeo, gpDesktop->overallAvailableRegion());
     627        frGeo = UIDesktopWidgetWatchdog::normalizeGeometry(frGeo, gpDesktop->overallAvailableRegion());
    628628
    629629    /* Finally, set the frame geometry: */
    630     UICommon::setTopLevelGeometry(this, frGeo.left() + dl, frGeo.top() + dt,
     630    UIDesktopWidgetWatchdog::setTopLevelGeometry(this, frGeo.left() + dl, frGeo.top() + dt,
    631631                                    frGeo.width() - dl - dr, frGeo.height() - dt - db);
    632632#else /* VBOX_GUI_WITH_CUSTOMIZATIONS1 */
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/scale/UIMachineWindowScale.cpp

    r90567 r91109  
    107107            /* Restore window geometry: */
    108108            m_geometry = geo;
    109             UICommon::setTopLevelGeometry(this, m_geometry);
     109            UIDesktopWidgetWatchdog::setTopLevelGeometry(this, m_geometry);
    110110
    111111            /* Maximize (if necessary): */
     
    126126            m_geometry = geometry();
    127127            m_geometry.moveCenter(availableGeo.center());
    128             UICommon::setTopLevelGeometry(this, m_geometry);
     128            UIDesktopWidgetWatchdog::setTopLevelGeometry(this, m_geometry);
    129129        }
    130130
     
    197197    /* Adjust position if necessary: */
    198198    if (fAdjustPosition)
    199         frGeo = UICommon::normalizeGeometry(frGeo, gpDesktop->overallAvailableRegion());
     199        frGeo = UIDesktopWidgetWatchdog::normalizeGeometry(frGeo, gpDesktop->overallAvailableRegion());
    200200
    201201    /* Finally, set the frame geometry: */
    202     UICommon::setTopLevelGeometry(this, frGeo.left() + dl, frGeo.top() + dt,
     202    UIDesktopWidgetWatchdog::setTopLevelGeometry(this, frGeo.left() + dl, frGeo.top() + dt,
    203203                                    frGeo.width() - dl - dr, frGeo.height() - dt - db);
    204204}
  • trunk/src/VBox/Frontends/VirtualBox/src/snapshots/UISnapshotDetailsWidget.cpp

    r91003 r91109  
    502502
    503503    /* Center according requested widget: */
    504     UICommon::centerWidget(this, parentWidget(), false);
     504    UIDesktopWidgetWatchdog::centerWidget(this, parentWidget(), false);
    505505}
    506506
  • trunk/src/VBox/Frontends/VirtualBox/src/widgets/UIPopupStack.cpp

    r91003 r91109  
    2727#include "UICommon.h"
    2828#include "UICursor.h"
     29#include "UIDesktopWidgetWatchdog.h"
    2930#include "UIPopupStack.h"
    3031#include "UIPopupStackViewport.h"
     
    203204
    204205    /* Adjust geometry: */
    205     UICommon::setTopLevelGeometry(this, iX, iY, iWidth, iHeight);
     206    UIDesktopWidgetWatchdog::setTopLevelGeometry(this, iX, iY, iWidth, iHeight);
    206207}
    207208
  • trunk/src/VBox/Frontends/VirtualBox/src/widgets/UISlidingToolBar.cpp

    r88862 r91109  
    2121/* GUI includes: */
    2222#include "UICommon.h"
     23#include "UIDesktopWidgetWatchdog.h"
    2324#include "UISlidingToolBar.h"
    2425#include "UIAnimationFramework.h"
     
    187188        case Position_Top:
    188189        {
    189             UICommon::setTopLevelGeometry(this, m_parentRect.x(), m_parentRect.y()                         + m_indentRect.height(),
     190            UIDesktopWidgetWatchdog::setTopLevelGeometry(this, m_parentRect.x(), m_parentRect.y()                         + m_indentRect.height(),
    190191                                                  qMax(m_parentRect.width(), sh.width()), sh.height());
    191192            m_pWidget->setGeometry(0, -sh.height(), qMax(width(), sh.width()), sh.height());
     
    194195        case Position_Bottom:
    195196        {
    196             UICommon::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(),
    197198                                                  qMax(m_parentRect.width(), sh.width()), sh.height());
    198199            m_pWidget->setGeometry(0,  sh.height(), qMax(width(), sh.width()), sh.height());
     
    245246        case Position_Top:
    246247        {
    247             UICommon::setTopLevelGeometry(this, m_parentRect.x(), m_parentRect.y()                         + m_indentRect.height(),
     248            UIDesktopWidgetWatchdog::setTopLevelGeometry(this, m_parentRect.x(), m_parentRect.y()                         + m_indentRect.height(),
    248249                                                  qMax(m_parentRect.width(), sh.width()), sh.height());
    249250            break;
     
    251252        case Position_Bottom:
    252253        {
    253             UICommon::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(),
    254255                                                  qMax(m_parentRect.width(), sh.width()), sh.height());
    255256            break;
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette