mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-13 19:49:51 +01:00
feat: add option to change the top-most status of a window (#5135)
* feat: add option to pin a popup * chore: add changelog entry * chore: change changelog entry
This commit is contained in:
parent
8e9aa87a08
commit
af8eba0323
|
@ -31,6 +31,7 @@
|
||||||
- Minor: Added the `--incognito/--no-incognito` options to the `/openurl` command, allowing you to override the "Open links in incognito/private mode" setting. (#5149)
|
- Minor: Added the `--incognito/--no-incognito` options to the `/openurl` command, allowing you to override the "Open links in incognito/private mode" setting. (#5149)
|
||||||
- Minor: Added support for the `{input.text}` placeholder in the **Split** -> **Run a command** hotkey. (#5130)
|
- Minor: Added support for the `{input.text}` placeholder in the **Split** -> **Run a command** hotkey. (#5130)
|
||||||
- Minor: Add a new Channel API for experimental plugins feature. (#5141)
|
- Minor: Add a new Channel API for experimental plugins feature. (#5141)
|
||||||
|
- Minor: Added the ability to change the top-most status of a window regardless of the _Always on top_ setting (right click the notebook). (#5135)
|
||||||
- Bugfix: Fixed an issue where certain emojis did not send to Twitch chat correctly. (#4840)
|
- Bugfix: Fixed an issue where certain emojis did not send to Twitch chat correctly. (#4840)
|
||||||
- Bugfix: Fixed capitalized channel names in log inclusion list not being logged. (#4848)
|
- Bugfix: Fixed capitalized channel names in log inclusion list not being logged. (#4848)
|
||||||
- Bugfix: Trimmed custom streamlink paths on all platforms making sure you don't accidentally add spaces at the beginning or end of its path. (#4834)
|
- Bugfix: Trimmed custom streamlink paths on all platforms making sure you don't accidentally add spaces at the beginning or end of its path. (#4834)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "widgets/BaseWindow.hpp"
|
#include "widgets/BaseWindow.hpp"
|
||||||
|
|
||||||
#include "Application.hpp"
|
#include "Application.hpp"
|
||||||
|
#include "common/QLogging.hpp"
|
||||||
#include "singletons/Settings.hpp"
|
#include "singletons/Settings.hpp"
|
||||||
#include "singletons/Theme.hpp"
|
#include "singletons/Theme.hpp"
|
||||||
#include "singletons/WindowManager.hpp"
|
#include "singletons/WindowManager.hpp"
|
||||||
|
@ -207,37 +208,52 @@ void BaseWindow::init()
|
||||||
// }
|
// }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USEWINSDK
|
|
||||||
// fourtf: don't ask me why we need to delay this
|
|
||||||
if (!this->flags_.has(TopMost))
|
|
||||||
{
|
|
||||||
QTimer::singleShot(1, this, [this] {
|
|
||||||
getSettings()->windowTopMost.connect(
|
|
||||||
[this](bool topMost, auto) {
|
|
||||||
::SetWindowPos(HWND(this->winId()),
|
|
||||||
topMost ? HWND_TOPMOST : HWND_NOTOPMOST, 0,
|
|
||||||
0, 0, 0,
|
|
||||||
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
|
|
||||||
},
|
|
||||||
this->connections_);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
// TopMost flag overrides setting
|
// TopMost flag overrides setting
|
||||||
if (!this->flags_.has(TopMost))
|
if (!this->flags_.has(TopMost))
|
||||||
{
|
{
|
||||||
getSettings()->windowTopMost.connect(
|
getSettings()->windowTopMost.connect(
|
||||||
[this](bool topMost, auto) {
|
[this](bool topMost) {
|
||||||
auto isVisible = this->isVisible();
|
this->setTopMost(topMost);
|
||||||
this->setWindowFlag(Qt::WindowStaysOnTopHint, topMost);
|
|
||||||
if (isVisible)
|
|
||||||
{
|
|
||||||
this->show();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
this->connections_);
|
this->connections_);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseWindow::setTopMost(bool topMost)
|
||||||
|
{
|
||||||
|
if (this->flags_.has(TopMost))
|
||||||
|
{
|
||||||
|
qCWarning(chatterinoWidget)
|
||||||
|
<< "Called setTopMost on a window with the `TopMost` flag set.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->isTopMost_ == topMost)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USEWINSDK
|
||||||
|
::SetWindowPos(reinterpret_cast<HWND>(this->winId()),
|
||||||
|
topMost ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0,
|
||||||
|
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
|
||||||
|
|
||||||
|
#else
|
||||||
|
auto isVisible = this->isVisible();
|
||||||
|
this->setWindowFlag(Qt::WindowStaysOnTopHint, topMost);
|
||||||
|
if (isVisible)
|
||||||
|
{
|
||||||
|
this->show();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
this->isTopMost_ = topMost;
|
||||||
|
this->topMostChanged(this->isTopMost_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BaseWindow::isTopMost() const
|
||||||
|
{
|
||||||
|
return this->isTopMost_ || this->flags_.has(TopMost);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseWindow::setActionOnFocusLoss(ActionOnFocusLoss value)
|
void BaseWindow::setActionOnFocusLoss(ActionOnFocusLoss value)
|
||||||
|
@ -559,6 +575,15 @@ void BaseWindow::showEvent(QShowEvent *)
|
||||||
{
|
{
|
||||||
this->moveTo(this->pos(), widgets::BoundsChecking::CursorPosition);
|
this->moveTo(this->pos(), widgets::BoundsChecking::CursorPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this->flags_.has(TopMost))
|
||||||
|
{
|
||||||
|
QTimer::singleShot(1, this, [this] {
|
||||||
|
::SetWindowPos(reinterpret_cast<HWND>(this->winId()),
|
||||||
|
this->isTopMost_ ? HWND_TOPMOST : HWND_NOTOPMOST, 0,
|
||||||
|
0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
|
||||||
|
});
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,10 +68,20 @@ public:
|
||||||
float scale() const override;
|
float scale() const override;
|
||||||
float qtFontScale() const;
|
float qtFontScale() const;
|
||||||
|
|
||||||
|
/// @returns true if the window is the top-most window.
|
||||||
|
/// Either #setTopMost was called or the `TopMost` flag is set which overrides this
|
||||||
|
bool isTopMost() const;
|
||||||
|
/// Updates the window's top-most status
|
||||||
|
/// If the `TopMost` flag is set, this is a no-op
|
||||||
|
void setTopMost(bool topMost);
|
||||||
|
|
||||||
pajlada::Signals::NoArgSignal closing;
|
pajlada::Signals::NoArgSignal closing;
|
||||||
|
|
||||||
static bool supportsCustomWindowFrame();
|
static bool supportsCustomWindowFrame();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void topMostChanged(bool topMost);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
bool nativeEvent(const QByteArray &eventType, void *message,
|
bool nativeEvent(const QByteArray &eventType, void *message,
|
||||||
|
@ -131,6 +141,7 @@ private:
|
||||||
FlagsEnum<Flags> flags_;
|
FlagsEnum<Flags> flags_;
|
||||||
float nativeScale_ = 1;
|
float nativeScale_ = 1;
|
||||||
bool isResizeFixing_ = false;
|
bool isResizeFixing_ = false;
|
||||||
|
bool isTopMost_ = false;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
QLayout *windowLayout = nullptr;
|
QLayout *windowLayout = nullptr;
|
||||||
|
|
|
@ -59,6 +59,28 @@ Notebook::Notebook(QWidget *parent)
|
||||||
});
|
});
|
||||||
this->updateTabVisibilityMenuAction();
|
this->updateTabVisibilityMenuAction();
|
||||||
|
|
||||||
|
this->toggleTopMostAction_ = new QAction("Top most window", this);
|
||||||
|
this->toggleTopMostAction_->setCheckable(true);
|
||||||
|
auto *window = dynamic_cast<BaseWindow *>(this->window());
|
||||||
|
if (window)
|
||||||
|
{
|
||||||
|
auto updateTopMost = [this, window] {
|
||||||
|
this->toggleTopMostAction_->setChecked(window->isTopMost());
|
||||||
|
};
|
||||||
|
updateTopMost();
|
||||||
|
QObject::connect(this->toggleTopMostAction_, &QAction::triggered,
|
||||||
|
window, [window] {
|
||||||
|
window->setTopMost(!window->isTopMost());
|
||||||
|
});
|
||||||
|
QObject::connect(window, &BaseWindow::topMostChanged, this,
|
||||||
|
updateTopMost);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qCWarning(chatterinoApp)
|
||||||
|
<< "Notebook must be created within a BaseWindow";
|
||||||
|
}
|
||||||
|
|
||||||
this->addNotebookActionsToMenu(&this->menu_);
|
this->addNotebookActionsToMenu(&this->menu_);
|
||||||
|
|
||||||
// Manually resize the add button so the initial paint uses the correct
|
// Manually resize the add button so the initial paint uses the correct
|
||||||
|
@ -1181,6 +1203,8 @@ void Notebook::addNotebookActionsToMenu(QMenu *menu)
|
||||||
menu->addAction(this->showTabsAction_);
|
menu->addAction(this->showTabsAction_);
|
||||||
|
|
||||||
menu->addAction(this->lockNotebookLayoutAction_);
|
menu->addAction(this->lockNotebookLayoutAction_);
|
||||||
|
|
||||||
|
menu->addAction(this->toggleTopMostAction_);
|
||||||
}
|
}
|
||||||
|
|
||||||
NotebookButton *Notebook::getAddButton()
|
NotebookButton *Notebook::getAddButton()
|
||||||
|
|
|
@ -196,6 +196,7 @@ private:
|
||||||
NotebookTabLocation tabLocation_ = NotebookTabLocation::Top;
|
NotebookTabLocation tabLocation_ = NotebookTabLocation::Top;
|
||||||
QAction *lockNotebookLayoutAction_;
|
QAction *lockNotebookLayoutAction_;
|
||||||
QAction *showTabsAction_;
|
QAction *showTabsAction_;
|
||||||
|
QAction *toggleTopMostAction_;
|
||||||
|
|
||||||
// This filter, if set, is used to figure out the visibility of
|
// This filter, if set, is used to figure out the visibility of
|
||||||
// the tabs in this notebook.
|
// the tabs in this notebook.
|
||||||
|
@ -224,7 +225,6 @@ private:
|
||||||
|
|
||||||
// Main window on Windows has basically a duplicate of this in Window
|
// Main window on Windows has basically a duplicate of this in Window
|
||||||
NotebookButton *streamerModeIcon_{};
|
NotebookButton *streamerModeIcon_{};
|
||||||
|
|
||||||
void updateStreamerModeIcon();
|
void updateStreamerModeIcon();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue