From c4c94473ae4f7b3d01c4852105412f11f2575187 Mon Sep 17 00:00:00 2001 From: nerix Date: Sat, 2 Dec 2023 12:56:03 +0100 Subject: [PATCH] Do bounds-checking on more windows (#4797) Co-authored-by: pajlada --- CHANGELOG.md | 1 + src/singletons/WindowManager.cpp | 3 +-- src/util/InitUpdateButton.cpp | 2 +- src/util/WidgetHelpers.cpp | 13 +++++++++++ src/util/WidgetHelpers.hpp | 10 ++++++++ src/widgets/BaseWindow.cpp | 11 +++++++++ src/widgets/BaseWindow.hpp | 23 ++++++++++++------- src/widgets/dialogs/ColorPickerDialog.cpp | 9 ++++++-- src/widgets/dialogs/QualityPopup.cpp | 8 +++++-- src/widgets/dialogs/SelectChannelDialog.cpp | 11 ++++++--- src/widgets/dialogs/SettingsDialog.cpp | 15 ++++++++---- .../dialogs/switcher/QuickSwitcherPopup.cpp | 11 ++++++--- src/widgets/helper/ChannelView.cpp | 4 ++-- src/widgets/helper/SearchPopup.cpp | 10 ++++++-- src/widgets/settingspages/AboutPage.cpp | 10 +++++--- src/widgets/settingspages/FiltersPage.cpp | 5 ++-- src/widgets/splits/Split.cpp | 12 +++++++--- 17 files changed, 120 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5cf1e8662..1ee1403f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ - Bugfix: Fixed lookahead/-behind not working in _Ignores_. (#4965) - Bugfix: Fixed Image Uploader accidentally deleting images with some hosts when link resolver was enabled. (#4971) - Bugfix: Fixed rare crash with Image Uploader when closing a split right after starting an upload. (#4971) +- Bugfix: Fixed some windows appearing between screens. (#4797) - Dev: Run miniaudio in a separate thread, and simplify it to not manage the device ourselves. There's a chance the simplification is a bad idea. (#4978) - Dev: Change clang-format from v14 to v16. (#4929) - Dev: Fixed UTF16 encoding of `modes` file for the installer. (#4791) diff --git a/src/singletons/WindowManager.cpp b/src/singletons/WindowManager.cpp index a86fdbc5a..be352588c 100644 --- a/src/singletons/WindowManager.cpp +++ b/src/singletons/WindowManager.cpp @@ -87,8 +87,7 @@ void WindowManager::showAccountSelectPopup(QPoint point) w->refresh(); - QPoint buttonPos = point; - w->move(buttonPos.x() - 30, buttonPos.y()); + w->moveTo(point - QPoint(30, 0), widgets::BoundsChecking::CursorPosition); w->show(); w->setFocus(); } diff --git a/src/util/InitUpdateButton.cpp b/src/util/InitUpdateButton.cpp index 7d687b667..b381af01e 100644 --- a/src/util/InitUpdateButton.cpp +++ b/src/util/InitUpdateButton.cpp @@ -24,7 +24,7 @@ void initUpdateButton(Button &button, globalPoint.setX(0); } - dialog->move(globalPoint); + dialog->moveTo(globalPoint, widgets::BoundsChecking::DesiredPosition); dialog->show(); dialog->raise(); diff --git a/src/util/WidgetHelpers.cpp b/src/util/WidgetHelpers.cpp index 7e6872760..b5e6fa9a3 100644 --- a/src/util/WidgetHelpers.cpp +++ b/src/util/WidgetHelpers.cpp @@ -79,4 +79,17 @@ void moveWindowTo(QWidget *window, QPoint position, BoundsChecking mode) } } +void showAndMoveWindowTo(QWidget *window, QPoint position, BoundsChecking mode) +{ +#ifdef Q_OS_WINDOWS + window->show(); + + moveWindowTo(window, position, mode); +#else + moveWindowTo(window, position, mode); + + window->show(); +#endif +} + } // namespace chatterino::widgets diff --git a/src/util/WidgetHelpers.hpp b/src/util/WidgetHelpers.hpp index 7f57ad393..b09e93d0b 100644 --- a/src/util/WidgetHelpers.hpp +++ b/src/util/WidgetHelpers.hpp @@ -26,4 +26,14 @@ enum class BoundsChecking { void moveWindowTo(QWidget *window, QPoint position, BoundsChecking mode = BoundsChecking::DesiredPosition); +/// Moves the `window` to the (global) `position` +/// while doing bounds-checking according to `mode` to ensure the window stays on one screen. +/// Will also call show on the `window`, order is dependant on platform. +/// +/// @param window The window to move. +/// @param position The global position to move the window to. +/// @param mode The desired bounds checking. +void showAndMoveWindowTo(QWidget *window, QPoint position, + BoundsChecking mode = BoundsChecking::DesiredPosition); + } // namespace chatterino::widgets diff --git a/src/widgets/BaseWindow.cpp b/src/widgets/BaseWindow.cpp index ad12fe185..a98ab8da8 100644 --- a/src/widgets/BaseWindow.cpp +++ b/src/widgets/BaseWindow.cpp @@ -508,6 +508,11 @@ void BaseWindow::moveTo(QPoint point, widgets::BoundsChecking mode) widgets::moveWindowTo(this, point, mode); } +void BaseWindow::showAndMoveTo(QPoint point, widgets::BoundsChecking mode) +{ + widgets::showAndMoveWindowTo(this, point, mode); +} + void BaseWindow::resizeEvent(QResizeEvent *) { // Queue up save because: Window resized @@ -559,6 +564,12 @@ void BaseWindow::closeEvent(QCloseEvent *) void BaseWindow::showEvent(QShowEvent *) { +#ifdef Q_OS_WIN + if (this->flags_.has(BoundsCheckOnShow)) + { + this->moveTo(this->pos(), widgets::BoundsChecking::CursorPosition); + } +#endif } #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) diff --git a/src/widgets/BaseWindow.hpp b/src/widgets/BaseWindow.hpp index 197618657..3b46aea6b 100644 --- a/src/widgets/BaseWindow.hpp +++ b/src/widgets/BaseWindow.hpp @@ -27,14 +27,15 @@ class BaseWindow : public BaseWidget public: enum Flags { None = 0, - EnableCustomFrame = 1, - Frameless = 2, - TopMost = 4, - DisableCustomScaling = 8, - FramelessDraggable = 16, - DontFocus = 32, - Dialog = 64, - DisableLayoutSave = 128, + EnableCustomFrame = 1 << 0, + Frameless = 1 << 1, + TopMost = 1 << 2, + DisableCustomScaling = 1 << 3, + FramelessDraggable = 1 << 4, + DontFocus = 1 << 5, + Dialog = 1 << 6, + DisableLayoutSave = 1 << 7, + BoundsCheckOnShow = 1 << 8, }; enum ActionOnFocusLoss { Nothing, Delete, Close, Hide }; @@ -57,6 +58,12 @@ public: void moveTo(QPoint point, widgets::BoundsChecking mode); + /** + * Moves the window to the given point and does bounds checking according to `mode` + * Depending on the platform, either the move or the show will take place first + **/ + void showAndMoveTo(QPoint point, widgets::BoundsChecking mode); + float scale() const override; float qtFontScale() const; diff --git a/src/widgets/dialogs/ColorPickerDialog.cpp b/src/widgets/dialogs/ColorPickerDialog.cpp index c15e4b16a..5d1096d81 100644 --- a/src/widgets/dialogs/ColorPickerDialog.cpp +++ b/src/widgets/dialogs/ColorPickerDialog.cpp @@ -13,8 +13,13 @@ namespace chatterino { ColorPickerDialog::ColorPickerDialog(const QColor &initial, QWidget *parent) - : BasePopup({BaseWindow::EnableCustomFrame, BaseWindow::DisableLayoutSave}, - parent) + : BasePopup( + { + BaseWindow::EnableCustomFrame, + BaseWindow::DisableLayoutSave, + BaseWindow::BoundsCheckOnShow, + }, + parent) , color_() , dialogConfirmed_(false) { diff --git a/src/widgets/dialogs/QualityPopup.cpp b/src/widgets/dialogs/QualityPopup.cpp index 9c7d519db..f090bee3d 100644 --- a/src/widgets/dialogs/QualityPopup.cpp +++ b/src/widgets/dialogs/QualityPopup.cpp @@ -9,8 +9,12 @@ namespace chatterino { QualityPopup::QualityPopup(const QString &channelURL, QStringList options) - : BasePopup({BaseWindow::DisableLayoutSave}, - static_cast(&(getApp()->windows->getMainWindow()))) + : BasePopup( + { + BaseWindow::DisableLayoutSave, + BaseWindow::BoundsCheckOnShow, + }, + static_cast(&(getApp()->windows->getMainWindow()))) , channelURL_(channelURL) { this->ui_.selector = new QComboBox(this); diff --git a/src/widgets/dialogs/SelectChannelDialog.cpp b/src/widgets/dialogs/SelectChannelDialog.cpp index 4c1dba085..c74bfcc2c 100644 --- a/src/widgets/dialogs/SelectChannelDialog.cpp +++ b/src/widgets/dialogs/SelectChannelDialog.cpp @@ -31,9 +31,14 @@ namespace chatterino { SelectChannelDialog::SelectChannelDialog(QWidget *parent) - : BaseWindow({BaseWindow::Flags::EnableCustomFrame, - BaseWindow::Flags::Dialog, BaseWindow::DisableLayoutSave}, - parent) + : BaseWindow( + { + BaseWindow::Flags::EnableCustomFrame, + BaseWindow::Flags::Dialog, + BaseWindow::DisableLayoutSave, + BaseWindow::BoundsCheckOnShow, + }, + parent) , selectedChannel_(Channel::getEmpty()) { this->setWindowTitle("Select a channel to join"); diff --git a/src/widgets/dialogs/SettingsDialog.cpp b/src/widgets/dialogs/SettingsDialog.cpp index 1ee94b4cf..2fcfa3166 100644 --- a/src/widgets/dialogs/SettingsDialog.cpp +++ b/src/widgets/dialogs/SettingsDialog.cpp @@ -6,6 +6,7 @@ #include "controllers/hotkeys/HotkeyController.hpp" #include "singletons/Settings.hpp" #include "util/LayoutCreator.hpp" +#include "widgets/BaseWindow.hpp" #include "widgets/helper/Button.hpp" #include "widgets/helper/SettingsDialogTab.hpp" #include "widgets/settingspages/AboutPage.hpp" @@ -29,9 +30,14 @@ namespace chatterino { SettingsDialog::SettingsDialog(QWidget *parent) - : BaseWindow({BaseWindow::Flags::DisableCustomScaling, - BaseWindow::Flags::Dialog, BaseWindow::DisableLayoutSave}, - parent) + : BaseWindow( + { + BaseWindow::Flags::DisableCustomScaling, + BaseWindow::Flags::Dialog, + BaseWindow::DisableLayoutSave, + BaseWindow::BoundsCheckOnShow, + }, + parent) { this->setObjectName("SettingsDialog"); this->setWindowTitle("Chatterino Settings"); @@ -380,9 +386,10 @@ void SettingsDialog::themeChangedEvent() this->setPalette(palette); } -void SettingsDialog::showEvent(QShowEvent *) +void SettingsDialog::showEvent(QShowEvent *e) { this->ui_.search->setText(""); + BaseWindow::showEvent(e); } ///// Widget creation helpers diff --git a/src/widgets/dialogs/switcher/QuickSwitcherPopup.cpp b/src/widgets/dialogs/switcher/QuickSwitcherPopup.cpp index 5110b51e3..7841d06b4 100644 --- a/src/widgets/dialogs/switcher/QuickSwitcherPopup.cpp +++ b/src/widgets/dialogs/switcher/QuickSwitcherPopup.cpp @@ -37,9 +37,14 @@ QList openPages(Window *window) namespace chatterino { QuickSwitcherPopup::QuickSwitcherPopup(Window *parent) - : BasePopup({BaseWindow::Flags::Frameless, BaseWindow::Flags::TopMost, - BaseWindow::DisableLayoutSave}, - parent) + : BasePopup( + { + BaseWindow::Flags::Frameless, + BaseWindow::Flags::TopMost, + BaseWindow::DisableLayoutSave, + BaseWindow::BoundsCheckOnShow, + }, + parent) , switcherModel_(this) , window(parent) { diff --git a/src/widgets/helper/ChannelView.cpp b/src/widgets/helper/ChannelView.cpp index ff180f01c..c0f1f5212 100644 --- a/src/widgets/helper/ChannelView.cpp +++ b/src/widgets/helper/ChannelView.cpp @@ -2914,8 +2914,8 @@ void ChannelView::showReplyThreadPopup(const MessagePtr &message) popup->setThread(message->replyThread); QPoint offset(int(150 * this->scale()), int(70 * this->scale())); - popup->move(QCursor::pos() - offset); - popup->show(); + popup->showAndMoveTo(QCursor::pos() - offset, + widgets::BoundsChecking::CursorPosition); popup->giveFocus(Qt::MouseFocusReason); } diff --git a/src/widgets/helper/SearchPopup.cpp b/src/widgets/helper/SearchPopup.cpp index f768bdd1e..329dff068 100644 --- a/src/widgets/helper/SearchPopup.cpp +++ b/src/widgets/helper/SearchPopup.cpp @@ -63,7 +63,12 @@ ChannelPtr SearchPopup::filter(const QString &text, const QString &channelName, } SearchPopup::SearchPopup(QWidget *parent, Split *split) - : BasePopup({BaseWindow::DisableLayoutSave}, parent) + : BasePopup( + { + BaseWindow::DisableLayoutSave, + BaseWindow::BoundsCheckOnShow, + }, + parent) , split_(split) { this->initLayout(); @@ -180,9 +185,10 @@ void SearchPopup::updateWindowTitle() this->setWindowTitle("Searching in " + historyName + " history"); } -void SearchPopup::showEvent(QShowEvent *) +void SearchPopup::showEvent(QShowEvent *e) { this->search(); + BaseWindow::showEvent(e); } bool SearchPopup::eventFilter(QObject *object, QEvent *event) diff --git a/src/widgets/settingspages/AboutPage.cpp b/src/widgets/settingspages/AboutPage.cpp index affea98cd..87c5caa7e 100644 --- a/src/widgets/settingspages/AboutPage.cpp +++ b/src/widgets/settingspages/AboutPage.cpp @@ -227,9 +227,13 @@ void AboutPage::addLicense(QFormLayout *form, const QString &name, auto *b = new QLabel("show license"); QObject::connect( b, &QLabel::linkActivated, [parent = this, name, licenseLink] { - auto window = new BasePopup({BaseWindow::Flags::EnableCustomFrame, - BaseWindow::DisableLayoutSave}, - parent); + auto *window = new BasePopup( + { + BaseWindow::EnableCustomFrame, + BaseWindow::DisableLayoutSave, + BaseWindow::BoundsCheckOnShow, + }, + parent); window->setWindowTitle("Chatterino - License for " + name); window->setAttribute(Qt::WA_DeleteOnClose); auto layout = new QVBoxLayout(); diff --git a/src/widgets/settingspages/FiltersPage.cpp b/src/widgets/settingspages/FiltersPage.cpp index d367a3e32..c66b139be 100644 --- a/src/widgets/settingspages/FiltersPage.cpp +++ b/src/widgets/settingspages/FiltersPage.cpp @@ -45,9 +45,8 @@ FiltersPage::FiltersPage() }); // We can safely ignore this signal connection since we own the view - std::ignore = view->addButtonPressed.connect([] { - ChannelFilterEditorDialog d( - static_cast(&(getApp()->windows->getMainWindow()))); + std::ignore = view->addButtonPressed.connect([this] { + ChannelFilterEditorDialog d(this->window()); if (d.exec() == QDialog::Accepted) { getSettings()->filterRecords.append( diff --git a/src/widgets/splits/Split.cpp b/src/widgets/splits/Split.cpp index 7d1a2b91e..046b905ae 100644 --- a/src/widgets/splits/Split.cpp +++ b/src/widgets/splits/Split.cpp @@ -192,8 +192,12 @@ namespace { void showTutorialVideo(QWidget *parent, const QString &source, const QString &title, const QString &description) { - auto window = - new BasePopup(BaseWindow::Flags::EnableCustomFrame, parent); + auto *window = new BasePopup( + { + BaseWindow::EnableCustomFrame, + BaseWindow::BoundsCheckOnShow, + }, + parent); window->setWindowTitle("Chatterino - " + title); window->setAttribute(Qt::WA_DeleteOnClose); auto layout = new QVBoxLayout(); @@ -1393,7 +1397,9 @@ void Split::showChatterList() multiWidget->setLayout(dockVbox); chatterDock->setWidget(multiWidget); chatterDock->setFloating(true); - chatterDock->show(); + widgets::showAndMoveWindowTo( + chatterDock, this->mapToGlobal(QPoint{0, this->header_->height()}), + widgets::BoundsChecking::CursorPosition); chatterDock->activateWindow(); }