// $Id: DlgGeometryMgr.cpp,v 1.6 2008/12/08 22:57:38 philw Exp $ // // CLASSES: // class DlgGeometryMgr : public QObject // class DlgGeomMgrTestWindow : public QMainWindow (support) // // DESCRIPTION: // // The DlgGeometryMgr provides static methods supporting persistance for // dialog positions and sizes within the current session. // // USAGE: Client QMainWindows and QDialogs need to re-implement these // two virtual methods from QWidget: // // virtual void showEvent (QShowEvent*) // virtual void hideEvent (QHideEvent*) // // From those re-implementations, calls to the following static methods // should be made: // // void DlgGeometryMgr::processShow (const char* dlgClassName, // void* refObj, // QWidget* dlgWidget, // QShowEvent*) // // void DlgGeometryMgr::processHide (const char* dlgClassName, // void* refObj, // QWidget* dlgWidget, // QHideEvent*) // // SEE the initial test implementation in Q3GUI/OpenObjectDlg. // // The DlgGeomMgrTestWindow is used to compute horizontal and vertical // offsets required for correct repositioning of windows on Solaris // (X11, X Window System). The problem is that the Window Decorations // (Window Title Bar and Borders) aren't considered when this application // queries the window position, but they are relevant when a window is moved. // //- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // Module Config static const bool DBG_OUT (false); //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- #ifndef DlgGeometryMgrINCLUDED #include "DlgGeometryMgr.hpp" #endif #include #include #include #include #include #include #include #include //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // ****************************** // *** Class DlgGeometryMgr *** // ****************************** // Static data members DlgGeometryMgr* DlgGeometryMgr::_instance (NULL); //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // static DlgGeometryMgr* DlgGeometryMgr::instance() { if (_instance == NULL) { _instance = new DlgGeometryMgr(); } return (_instance); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // constructor 1 of 1 DlgGeometryMgr::DlgGeometryMgr() : QObject(), _dlgGeometryMap(), _windowDecorationDeltasComputed (false), _windowDecorationDeltaX (0), _windowDecorationDeltaY (0) { computeWindowDecorationDeltas(); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- DlgGeometryMgr::~DlgGeometryMgr() { _dlgGeometryMap.clear(); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void DlgGeometryMgr::computeWindowDecorationDeltas() { static const char (*mname) ("DlgGeometryMgr::computeWindowDecorationDeltas"); // Note: The Window Decoration Deltas are relevant only for Solaris (X11). // The problem is that the Window Decorations (Window Title Bar and Borders) // aren't considered when this application queries the window position, // but they are relevant when a window is moved. #ifdef Q_WS_X11 { // The Window Decoration Delta needs to be computed only once. if (_windowDecorationDeltasComputed) return; //----------------------------------------->> // Create a test window. The test window is self-driven. After // a sequence of automatic shows and hides, the result is reported // to this object via a Qt signal. QMainWindow* testWindow = new DlgGeomMgrTestWindow(); connect (testWindow, SIGNAL (decorationDeltasComputed (int, int)), this, SLOT (setDecorationDeltas (int, int))); } #endif } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // static void DlgGeometryMgr::initialize() { // Create instance if not already created. DlgGeometryMgr* inst (instance()); inst; // avoid Windows compilation warning. } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // static void DlgGeometryMgr::processShow (const char* dlgClassName, void* refObj, QWidget* dlgWidget, QShowEvent* evt) { static const char (*mname) ("DlgGeometryMgr::processShow"); // Map from (Dialog Class Name, Reference Object) to (Window Geometry). // QMap , QRect> _dlgGeometryMap; const bool isSpont (evt ? evt->spontaneous() : false); const char (*isSpontStr) (isSpont ? "Spontaneous" : "NOT Spontaneous"); const QString dlgClassNameStr (dlgClassName ? dlgClassName : ""); const QPair specKey (dlgClassNameStr, refObj); // This may have the effect of starting the sequence to compute the // X11 Window Manager "Decoration Deltas". If that sequence isn't // completed by the first re-showing of any dialog (following the // hiding of a previously shown dialog using this mechanism), then // the X11 "decoration" correction will not be applied, which isn't // terrible. // DlgGeometryMgr* inst (instance()); if (dlgWidget) { const Qt::WindowStates winStates = dlgWidget->windowState(); const char* isMiniStr = (dlgWidget->isMinimized() ? "Minimized" : "NOT Minimized"); if (DBG_OUT) { std::cout << mname << " [" << qPrintable (dlgClassNameStr) << ", " << std::hex << (unsigned long) refObj << std::dec << "] " << "windowStates: " << "0x" << std::hex << (unsigned int) winStates << std::dec << ", " << isMiniStr << ", " << isSpontStr << std::endl; } } if (inst->_dlgGeometryMap.contains (specKey)) { // Remove the Geometry Record for this Dialog. This will be recreated // on the next Hide operation. const QRect savedGeom (inst->_dlgGeometryMap.take (specKey)); int restoreX = savedGeom.x(); int restoreY = savedGeom.y(); static const bool applyDecorationDeltas (true); // XXX if (applyDecorationDeltas) { restoreX -= std::max (0, inst->_windowDecorationDeltaX); restoreY -= std::max (0, inst->_windowDecorationDeltaY); } if (DBG_OUT) { std::cout << mname << " [" << qPrintable (dlgClassNameStr) << ", " << std::hex << (unsigned long) refObj << std::dec << "] " << "(" << savedGeom.x() << "," << savedGeom.y() << ") " << "(" << savedGeom.width() << "," << savedGeom.height() << ") " << " RestorePos: " << "(" << restoreX << "," << restoreY << ")" << ", " << isSpontStr << std::endl; } // Note: At least with the Hummingbird Exceed for Windows NT 6.0, // Minimization Restore operations are characterized with the // "spontaneous" event flag, and don't need repositioning. // In fact, the geometry computations which work for other 'show' // operations (other than Minimization Restore) don't work for // the Minimization Restore case. // const bool doRestoreGeom (!isSpont); if (doRestoreGeom) { if (dlgWidget) { dlgWidget->move (restoreX, restoreY); dlgWidget->resize (savedGeom.width(), savedGeom.height()); } } else // (Not doRestoreGeom) { if (DBG_OUT) { std::cout << mname << " [" << qPrintable (dlgClassNameStr) << ", " << std::hex << (unsigned long) refObj << std::dec << "] " << "SKIPPING GEOM RESTORE" << std::endl; } } } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // static void DlgGeometryMgr::processHide (const char* dlgClassName, void* refObj, QWidget* dlgWidget, QHideEvent* evt) { static const char (*mname) ("DlgGeometryMgr::processHide"); // Map from (Dialog Class Name, Reference Object) to (Window Geometry). // QMap , QRect> _dlgGeometryMap; const bool isSpont (evt ? evt->spontaneous() : false); const char (*isSpontStr) (isSpont ? "Spontaneous" : "NOT Spontaneous"); const QString dlgClassNameStr (dlgClassName ? dlgClassName : ""); const QPair specKey (dlgClassNameStr, refObj); DlgGeometryMgr* inst (instance()); if (inst->_dlgGeometryMap.contains (specKey)) { inst->_dlgGeometryMap.remove (specKey); } if (dlgWidget) { const Qt::WindowStates winStates = dlgWidget->windowState(); const char* isMiniStr = (dlgWidget->isMinimized() ? "Minimized" : "NOT Minimized"); if (DBG_OUT) { std::cout << mname << " [" << qPrintable (dlgClassNameStr) << ", " << std::hex << (unsigned long) refObj << std::dec << "] " << "windowStates: " << "0x" << std::hex << (unsigned int) winStates << std::dec << ", " << isMiniStr << ", " << isSpontStr << std::endl; } // On Solaris (or any Unix X11 platform), geometry computations depend // on whether the window hide operation is initiated from within the // RiverWare executable or from outside (in particular, from the X // Window Manager). Also different X11 Window Managers may give // different results, but the following algorithm behaves reasonably // well with the default Window Managers for the following two // X Window System clients: // // Solaris 8 (Sun OpenWindows CDE) // BlueZone PC X Server 9.2 [2008] // const QPoint winPos (dlgWidget->pos()); const QSize winSize (dlgWidget->size()); const QRect nativeFrameGeom (dlgWidget->frameGeometry()); const QRect altFrameGeom (winPos, winSize); QRect newGeom; bool doSaveGeom (false); // tentative bool fromX11WindowManager (false); #ifdef Q_WS_X11 { const bool fromX11WindowManager = isSpont; } #endif if (false && fromX11WindowManager) // XXX { const int bordAndTitHgt = inst->_windowDecorationDeltaY; const int borderSize = inst->_windowDecorationDeltaX; const int x = altFrameGeom.x() + borderSize; const int y = altFrameGeom.y() + bordAndTitHgt; const int wdt = altFrameGeom.width() - (2 * borderSize); const int hgt = altFrameGeom.height() - (bordAndTitHgt + borderSize); newGeom = QRect (x, y, wdt, hgt); // *** DISABLE the saving of this computation. This doesn't yet // work. On Solaris (X Server) the frame geometry seems to be // computed from the iconized icon (when hiding occurs as a result // of a window "minimization" operation). // // doSaveGeom = false; } else // (Not fromX11WindowManager) { // newGeom = nativeFrameGeom; newGeom = altFrameGeom; doSaveGeom = true; } if (DBG_OUT) { std::cout << mname << " [" << qPrintable (dlgClassNameStr) << ", " << std::hex << (unsigned long) refObj << std::dec << "] " << (fromX11WindowManager ? "From Win Mgr" : "Local") << " " << (doSaveGeom ? "Do Save" : "SKIP Save") << " " << "Geom (" << newGeom.x() << "," << newGeom.y() << ") " << "(" << newGeom.width() << "," << newGeom.height() << ") " << "Pos (" << winPos.x() << "," << winPos.y() << ")" << std::endl; } if (doSaveGeom) { inst->_dlgGeometryMap.insert (specKey, newGeom); } } } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void DlgGeometryMgr::setDecorationDeltas (int deltaX, int deltaY) { static const char (*mname) ("DlgGeometryMgr::setDecorationDeltas"); if (DBG_OUT) { std::cout << mname << ": deltaX " << deltaX << ", deltaY " << deltaY << std::endl; } _windowDecorationDeltaX = deltaX; _windowDecorationDeltaY = deltaY; _windowDecorationDeltasComputed = true; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // ************************************************** // *** Class DlgGeomMgrTestWindow : QMainWindow *** // ************************************************** // The DlgGeomMgrTestWindow is used to compute horizontal and vertical // offsets required for correct repositioning of windows on Solaris // (X11, X Window System). The problem is that the Window Decorations // (Window Title Bar and Borders) aren't considered when this application // queries the window position, but they are relevant when a window is moved. DlgGeomMgrTestWindow::DlgGeomMgrTestWindow() : QMainWindow(), _showCnt (0), _hideCnt (0) { setWindowTitle ("RiverWare Geometry Test"); // Show a test window move (_initialX, _initialY); // Schedule Show. This needs to be a non-trivial amount of time in // order to give the X11 Window Manager an opportunity to respond. QTimer::singleShot (1000 /*[msecs]*/, this, SLOT (show())); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // virtual from QWidget void DlgGeomMgrTestWindow::showEvent (QShowEvent* evt) { static const char (*mname) ("DlgGeomMgrTestWindow::showEvent"); ++_showCnt; // Call base class method QMainWindow::showEvent (evt); const QRect frameGeom (frameGeometry()); const QPoint winPos (pos()); if (DBG_OUT) { std::cout << mname << " [#" << _showCnt << "] " << "Frame (" << frameGeom.x() << "," << frameGeom.y() << "), " << "Pos (" << winPos.x() << "," << winPos.y() << ")" << std::endl; } // Schedule Hide. This needs to be a non-trivial amount of time in // order to give the X11 Window Manager an opportunity to respond. QTimer::singleShot (1000 /*[msecs]*/, this, SLOT (hide())); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // virtual from QWidget void DlgGeomMgrTestWindow::hideEvent (QHideEvent* evt) { static const char (*mname) ("DlgGeomMgrTestWindow::hideEvent"); ++_hideCnt; const QRect frameGeom (frameGeometry()); const QPoint winPos (pos()); if (DBG_OUT) { std::cout << mname << " [#" << _hideCnt << "] " << "Frame (" << frameGeom.x() << "," << frameGeom.y() << "), " << "Pos (" << winPos.x() << "," << winPos.y() << ")" << std::endl; } // Examine the resulting window frame position, including the window // mananer decoration (window title bar and border). const int decorationDeltaX = frameGeom.x() - _initialX; const int decorationDeltaY = frameGeom.y() - _initialY; if (DBG_OUT) { std::cout << mname << " [#" << _hideCnt << "]" << ": deltaX " << decorationDeltaX << ", deltaY " << decorationDeltaY << std::endl; } // Notify client of decoration delta result emit decorationDeltasComputed (decorationDeltaX, decorationDeltaY); // Call base class method QMainWindow::hideEvent (evt); // Close and Delete setAttribute (Qt::WA_DeleteOnClose, true); QTimer::singleShot (100 /*[msecs]*/, this, SLOT (close())); } //--- (end DlgGeometryMgr.cpp) ---