2929#include < QSizePolicy>
3030#include < QGridLayout>
3131#include < QLabel>
32+ #include < QPointer>
3233#include < QLineEdit>
3334#include < QSpacerItem>
3435#include < QVBoxLayout>
4142#include < QApplication>
4243#include < QDateTime>
4344#include < QGuiApplication>
45+ #include < QScreen>
46+ #include < QWindow>
4447#include < QDebug>
4548#include < cmath>
4649
5356#include " eidos_value.h"
5457
5558
59+ bool QtSLiMIsMostlyOnScreen (QWidget *window)
60+ {
61+ #if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
62+ QRect f = window->frameGeometry ();
63+ QScreen *screen1 = QGuiApplication::screenAt (f.topLeft ());
64+ QScreen *screen2 = QGuiApplication::screenAt (f.topRight ());
65+ QScreen *screen3 = QGuiApplication::screenAt (f.bottomLeft ());
66+ QScreen *screen4 = QGuiApplication::screenAt (f.bottomRight ());
67+ QScreen *screen5 = QGuiApplication::screenAt (f.center ());
68+ int cornerCount = (!!screen1) + (!!screen2) + (!!screen3) + (!!screen4);
69+ if (!screen5) cornerCount = 0 ;
70+ return (cornerCount >= 2 );
71+ #else
72+ Q_UNUSED (window);
73+ return true ;
74+ #endif
75+ }
76+
77+ void QtSLiMRelocateQuietly (QWidget *window)
78+ {
79+ #if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
80+ QScreen *primary = QGuiApplication::primaryScreen ();
81+ QRect avail = primary ? primary->availableGeometry () : QRect (0 ,0 ,1024 ,768 );
82+ window->resize (window->size ().boundedTo (avail.size ()));
83+ window->move (avail.topLeft () + QPoint (50 , 50 ));
84+ #else
85+ Q_UNUSED (window);
86+ #endif
87+ }
88+
5689void QtSLiMMakeWindowVisibleAndExposed (QWidget *window)
5790{
5891 // we've had lots of problems in SLiMgui with windows not showing when the user expects them to show; this function
@@ -67,6 +100,14 @@ void QtSLiMMakeWindowVisibleAndExposed(QWidget *window)
67100 // I'm not sure how this is normally dealt with by operating systems, since I never use full-screen mode
68101 // on macOS it seems to work OK; the new window goes full-screen also, in front of the other, which
69102 // I assume is the standard behavior...? I'll wait for reported bugs on this one, I don't know. FIXME
103+
104+ // Fullscreen note: on Windows, "fullscreen" often means a borderless maximized window that can be
105+ // overlaid by another normal window that calls show/raise/activate. We intentionally do that here so
106+ // SLiMgui presents visibly on the current screen if possible, without minimizing/altering other apps.
107+ // If the window still isn't exposed (e.g., truly exclusive fullscreen), we will attempt relocation to
108+ // another monitor after a short delay; if that also fails, we flash the app icon to notify the user. -Chris
109+
110+ // Still unclear how this will behave on Linux systems, hopefuly the same as macOS?
70111
71112 // un-miniaturize the window if it is miniaturized
72113 if (window->windowState () & Qt::WindowMinimized)
@@ -77,26 +118,45 @@ void QtSLiMMakeWindowVisibleAndExposed(QWidget *window)
77118 window->raise ();
78119 window->activateWindow ();
79120
80- // check the coordinates of the window and make sure it is actually visible on-screen
81- // This requires Qt 5.10 or later
121+ // If not sufficiently visible, relocate to a safe point on the primary screen
122+ if (!QtSLiMIsMostlyOnScreen (window))
123+ QtSLiMRelocateQuietly (window);
124+
82125#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
83- QScreen *screen1 = QGuiApplication::screenAt (window->frameGeometry ().topLeft ());
84- QScreen *screen2 = QGuiApplication::screenAt (window->frameGeometry ().topRight ());
85- QScreen *screen3 = QGuiApplication::screenAt (window->frameGeometry ().bottomLeft ());
86- QScreen *screen4 = QGuiApplication::screenAt (window->frameGeometry ().bottomRight ());
87- QScreen *screen5 = QGuiApplication::screenAt (window->frameGeometry ().center ());
88- int cornerCount = (!!screen1) + (!!screen2) + (!!screen3) + (!!screen4);
89-
90- if (!screen5)
91- cornerCount = 0 ;
92-
93- if (cornerCount >= 2 ) // 2 corners plus the center are visible
94- return ;
95-
96- // we're not very visible on-screen, so move ourselves so that we are; this is obviously ungraceful
97- // it would be nice to move the window to some concept of a "closest point to the current position
98- // that is fully visible", but I'm not sure how to do that, for the general case; (100, 100) seems ok
99- window->move (100 , 100 );
126+ // If still not actually exposed (e.g., exclusive fullscreen), re-check shortly and then try other screens
127+ if (QWindow *w = window->windowHandle ())
128+ {
129+ if (!w->isExposed ())
130+ {
131+ QPointer<QWidget> safeWindow (window);
132+ QTimer::singleShot (200 , qApp, [safeWindow]() {
133+ if (!safeWindow)
134+ return ;
135+ QWidget *win = safeWindow.data ();
136+ QWindow *wh = win->windowHandle ();
137+ if (!wh)
138+ return ;
139+ if (wh->isExposed ())
140+ return ; // became exposed in the meantime; do nothing
141+
142+ QScreen *currentScreen = QGuiApplication::screenAt (win->frameGeometry ().center ());
143+ const QList<QScreen*> screens = QGuiApplication::screens ();
144+ for (QScreen *screen : screens)
145+ {
146+ if (screen == currentScreen)
147+ continue ;
148+ QRect avail = screen->availableGeometry ();
149+ win->move (avail.topLeft () + QPoint (50 , 50 ));
150+ win->raise ();
151+ win->activateWindow ();
152+ if (wh->isExposed ())
153+ return ;
154+ }
155+ // If we still are not exposed anywhere, alert the user via taskbar/dock
156+ qApp->alert (win);
157+ });
158+ }
159+ }
100160#endif
101161}
102162
0 commit comments