Allow to use a window without titlebar

This might look better than a popup on Windows 11 because we'd still get
the round window corners.
This commit is contained in:
Martchus 2023-02-18 21:27:09 +01:00
parent 5bf8a4e25a
commit 1b72e61c86
7 changed files with 68 additions and 22 deletions

View File

@ -19,7 +19,7 @@ namespace QtGui {
TrayMenu::TrayMenu(TrayIcon *trayIcon, QWidget *parent) TrayMenu::TrayMenu(TrayIcon *trayIcon, QWidget *parent)
: QMenu(parent) : QMenu(parent)
, m_trayIcon(trayIcon) , m_trayIcon(trayIcon)
, m_windowed(false) , m_windowType(WindowType::Popup)
{ {
setObjectName(QStringLiteral("QtGui::TrayMenu")); setObjectName(QStringLiteral("QtGui::TrayMenu"));
auto *const menuLayout = new QHBoxLayout; auto *const menuLayout = new QHBoxLayout;
@ -68,23 +68,50 @@ void TrayMenu::showUsingPositioningSettings()
activateWindow(); activateWindow();
} }
void TrayMenu::setWindowed(bool windowed) void TrayMenu::setWindowType(int windowType)
{ {
if (m_windowed != windowed) { if (windowType >= 0 && windowType <= 2) {
setWindowFlags((m_windowed = windowed) ? Qt::Window : Qt::FramelessWindowHint | Qt::Popup); setWindowType(static_cast<WindowType>(windowType));
} }
} }
void TrayMenu::setWindowType(WindowType windowType)
{
if (m_windowType == windowType) {
return;
}
auto flags = Qt::WindowFlags();
switch (m_windowType = windowType) {
case WindowType::Popup:
flags = Qt::FramelessWindowHint | Qt::Popup;
break;
case WindowType::NormalWindow:
flags = Qt::Window;
break;
case WindowType::CustomWindow:
flags = Qt::Dialog | Qt::CustomizeWindowHint;
break;
}
setWindowFlags(flags);
}
void TrayMenu::mousePressEvent(QMouseEvent *event) void TrayMenu::mousePressEvent(QMouseEvent *event)
{ {
if (!m_windowed) { if (m_windowType != TrayMenu::WindowType::NormalWindow) {
QMenu::mousePressEvent(event); QMenu::mousePressEvent(event);
} }
} }
void TrayMenu::mouseReleaseEvent(QMouseEvent *event)
{
if (m_windowType != TrayMenu::WindowType::NormalWindow) {
QMenu::mouseReleaseEvent(event);
}
}
void TrayMenu::paintEvent(QPaintEvent *event) void TrayMenu::paintEvent(QPaintEvent *event)
{ {
if (!m_windowed) { if (m_windowType == WindowType::Popup) {
QMenu::paintEvent(event); QMenu::paintEvent(event);
} else { } else {
QPainter(this).fillRect(event->rect(), palette().window()); QPainter(this).fillRect(event->rect(), palette().window());
@ -92,10 +119,13 @@ void TrayMenu::paintEvent(QPaintEvent *event)
} }
} }
void TrayMenu::mouseReleaseEvent(QMouseEvent *event) void TrayMenu::focusOutEvent(QFocusEvent *)
{ {
if (!m_windowed) { if (m_windowType == WindowType::CustomWindow) {
QMenu::mouseReleaseEvent(event); if (const auto *fw = focusWidget(); fw->hasFocus()) {
return;
}
close();
} }
} }

View File

@ -10,30 +10,37 @@ class TrayWidget;
class TrayMenu : public QMenu { class TrayMenu : public QMenu {
Q_OBJECT Q_OBJECT
Q_PROPERTY(bool windowed READ isWindowed WRITE setWindowed)
public: public:
enum class WindowType {
Popup,
NormalWindow,
CustomWindow,
};
explicit TrayMenu(TrayIcon *trayIcon = nullptr, QWidget *parent = nullptr); explicit TrayMenu(TrayIcon *trayIcon = nullptr, QWidget *parent = nullptr);
QSize sizeHint() const override; QSize sizeHint() const override;
TrayWidget &widget(); TrayWidget &widget();
const TrayWidget &widget() const; const TrayWidget &widget() const;
TrayIcon *icon(); TrayIcon *icon();
bool isWindowed() const; WindowType windowType() const;
void setWindowType(int windowType);
void setWindowType(WindowType windowType);
public Q_SLOTS: public Q_SLOTS:
void showUsingPositioningSettings(); void showUsingPositioningSettings();
void setWindowed(bool windowed);
protected: protected:
void mouseReleaseEvent(QMouseEvent *) override; void mouseReleaseEvent(QMouseEvent *) override;
void mousePressEvent(QMouseEvent *) override; void mousePressEvent(QMouseEvent *) override;
void paintEvent(QPaintEvent *) override; void paintEvent(QPaintEvent *) override;
void focusOutEvent(QFocusEvent *) override;
private: private:
TrayWidget *m_trayWidget; TrayWidget *m_trayWidget;
TrayIcon *m_trayIcon; TrayIcon *m_trayIcon;
bool m_windowed = false; WindowType m_windowType;
}; };
inline TrayWidget &TrayMenu::widget() inline TrayWidget &TrayMenu::widget()
@ -51,9 +58,9 @@ inline TrayIcon *TrayMenu::icon()
return m_trayIcon; return m_trayIcon;
} }
inline bool TrayMenu::isWindowed() const inline TrayMenu::WindowType TrayMenu::windowType() const
{ {
return m_windowed; return m_windowType;
} }
} // namespace QtGui } // namespace QtGui

View File

@ -596,7 +596,7 @@ void TrayWidget::applySettings(const QString &connectionConfig)
} }
} }
if (m_menu) { if (m_menu) {
m_menu->setWindowed(settings.appearance.windowed); m_menu->setWindowType(settings.appearance.windowType);
} }
// update status icon and text of tray icon because reconnect interval might have changed // update status icon and text of tray icon because reconnect interval might have changed
@ -934,7 +934,7 @@ void TrayWidget::concludeWizard(const QString &errorMessage)
void TrayWidget::showDialog(QWidget *dlg, bool maximized) void TrayWidget::showDialog(QWidget *dlg, bool maximized)
{ {
if (m_menu && !m_menu->isWindowed()) { if (m_menu && m_menu->windowType() != TrayMenu::WindowType::NormalWindow) {
m_menu->close(); m_menu->close();
} }
if (maximized) { if (maximized) {

View File

@ -383,6 +383,11 @@
<string>Normal window</string> <string>Normal window</string>
</property> </property>
</item> </item>
<item>
<property name="text">
<string>Window without titlebar</string>
</property>
</item>
</widget> </widget>
</item> </item>
<item row="2" column="0"> <item row="2" column="0">

View File

@ -347,7 +347,11 @@ bool restore()
auto &appearance = v.appearance; auto &appearance = v.appearance;
appearance.showTraffic = settings.value(QStringLiteral("showTraffic"), appearance.showTraffic).toBool(); appearance.showTraffic = settings.value(QStringLiteral("showTraffic"), appearance.showTraffic).toBool();
appearance.showTabTexts = settings.value(QStringLiteral("showTabTexts"), appearance.showTabTexts).toBool(); appearance.showTabTexts = settings.value(QStringLiteral("showTabTexts"), appearance.showTabTexts).toBool();
appearance.windowed = settings.value(QStringLiteral("windowed"), appearance.windowed).toBool(); if (auto windowType = settings.value(QStringLiteral("windowType")); windowType.isValid()) {
appearance.windowType = windowType.toInt();
} else if (auto windowed = settings.value(QStringLiteral("windowed")); windowed.isValid()) {
appearance.windowType = !windowed.toBool() ? 0 : 1;
}
appearance.trayMenuSize = settings.value(QStringLiteral("trayMenuSize"), appearance.trayMenuSize).toSize(); appearance.trayMenuSize = settings.value(QStringLiteral("trayMenuSize"), appearance.trayMenuSize).toSize();
appearance.frameStyle = settings.value(QStringLiteral("frameStyle"), appearance.frameStyle).toInt(); appearance.frameStyle = settings.value(QStringLiteral("frameStyle"), appearance.frameStyle).toInt();
appearance.tabPosition = settings.value(QStringLiteral("tabPos"), appearance.tabPosition).toInt(); appearance.tabPosition = settings.value(QStringLiteral("tabPos"), appearance.tabPosition).toInt();
@ -471,7 +475,7 @@ bool save()
const auto &appearance = v.appearance; const auto &appearance = v.appearance;
settings.setValue(QStringLiteral("showTraffic"), appearance.showTraffic); settings.setValue(QStringLiteral("showTraffic"), appearance.showTraffic);
settings.setValue(QStringLiteral("showTabTexts"), appearance.showTabTexts); settings.setValue(QStringLiteral("showTabTexts"), appearance.showTabTexts);
settings.setValue(QStringLiteral("windowed"), appearance.windowed); settings.setValue(QStringLiteral("windowType"), appearance.windowType);
settings.setValue(QStringLiteral("trayMenuSize"), appearance.trayMenuSize); settings.setValue(QStringLiteral("trayMenuSize"), appearance.trayMenuSize);
settings.setValue(QStringLiteral("frameStyle"), appearance.frameStyle); settings.setValue(QStringLiteral("frameStyle"), appearance.frameStyle);
settings.setValue(QStringLiteral("tabPos"), appearance.tabPosition); settings.setValue(QStringLiteral("tabPos"), appearance.tabPosition);

View File

@ -64,7 +64,7 @@ struct SYNCTHINGWIDGETS_EXPORT NotifyOn {
struct SYNCTHINGWIDGETS_EXPORT Appearance { struct SYNCTHINGWIDGETS_EXPORT Appearance {
bool showTraffic = true; bool showTraffic = true;
bool showTabTexts = true; bool showTabTexts = true;
bool windowed = false; int windowType = 0; // corresponds to TrayMenu::WindowType
QSize trayMenuSize = QSize(575, 475); QSize trayMenuSize = QSize(575, 475);
int frameStyle = static_cast<int>(QFrame::NoFrame) | static_cast<int>(QFrame::Plain); int frameStyle = static_cast<int>(QFrame::NoFrame) | static_cast<int>(QFrame::Plain);
int tabPosition = QTabWidget::South; int tabPosition = QTabWidget::South;

View File

@ -465,7 +465,7 @@ bool AppearanceOptionPage::apply()
{ {
auto &v = values(); auto &v = values();
auto &settings = v.appearance; auto &settings = v.appearance;
settings.windowed = ui()->windowTypeComboBox->currentIndex() == 1; settings.windowType = ui()->windowTypeComboBox->currentIndex();
settings.trayMenuSize.setWidth(ui()->widthSpinBox->value()); settings.trayMenuSize.setWidth(ui()->widthSpinBox->value());
settings.trayMenuSize.setHeight(ui()->heightSpinBox->value()); settings.trayMenuSize.setHeight(ui()->heightSpinBox->value());
settings.showTraffic = ui()->showTrafficCheckBox->isChecked(); settings.showTraffic = ui()->showTrafficCheckBox->isChecked();
@ -508,7 +508,7 @@ void AppearanceOptionPage::reset()
{ {
const auto &v = values(); const auto &v = values();
const auto &settings = v.appearance; const auto &settings = v.appearance;
ui()->windowTypeComboBox->setCurrentIndex(settings.windowed ? 1 : 0); ui()->windowTypeComboBox->setCurrentIndex(settings.windowType);
ui()->widthSpinBox->setValue(settings.trayMenuSize.width()); ui()->widthSpinBox->setValue(settings.trayMenuSize.width());
ui()->heightSpinBox->setValue(settings.trayMenuSize.height()); ui()->heightSpinBox->setValue(settings.trayMenuSize.height());
ui()->showTrafficCheckBox->setChecked(settings.showTraffic); ui()->showTrafficCheckBox->setChecked(settings.showTraffic);