diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index feb9d996b..906f4dea5 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -163,7 +163,6 @@ if (LINUX) ) target_compile_definitions(Telegram PRIVATE G_LOG_DOMAIN="Kotatogram") - target_compile_options(Telegram PRIVATE -Wno-register) if (NOT TDESKTOP_DISABLE_GTK_INTEGRATION) find_package(PkgConfig REQUIRED) diff --git a/Telegram/SourceFiles/mainwindow.cpp b/Telegram/SourceFiles/mainwindow.cpp index e59b53c19..445954901 100644 --- a/Telegram/SourceFiles/mainwindow.cpp +++ b/Telegram/SourceFiles/mainwindow.cpp @@ -39,6 +39,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "apiwrap.h" #include "api/api_updates.h" #include "settings/settings_intro.h" +#include "platform/platform_specific.h" #include "platform/platform_notifications_manager.h" #include "base/platform/base_platform_info.h" #include "base/call_delayed.h" @@ -102,7 +103,12 @@ MainWindow::MainWindow(not_null controller) }, lifetime()); setAttribute(Qt::WA_NoSystemBackground); - setAttribute(Qt::WA_OpaquePaintEvent); + + if (Platform::WindowsNeedShadow()) { + setAttribute(Qt::WA_TranslucentBackground); + } else { + setAttribute(Qt::WA_OpaquePaintEvent); + } } void MainWindow::initHook() { @@ -761,7 +767,9 @@ void MainWindow::handleTrayIconActication( } if (reason == QSystemTrayIcon::Context) { updateTrayMenu(true); - QTimer::singleShot(1, this, SLOT(psShowTrayMenu())); + base::call_delayed(1, this, [=] { + psShowTrayMenu(); + }); } else if (!skipTrayClick()) { if (Platform::IsWayland() ? isVisible() : isActive()) { minimizeToTray(); diff --git a/Telegram/SourceFiles/platform/linux/main_window_linux.cpp b/Telegram/SourceFiles/platform/linux/main_window_linux.cpp index ce0523acc..bae5b338f 100644 --- a/Telegram/SourceFiles/platform/linux/main_window_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/main_window_linux.cpp @@ -467,7 +467,12 @@ void MainWindow::initHook() { sniWatcher, &QDBusServiceWatcher::serviceOwnerChanged, this, - &MainWindow::onSNIOwnerChanged); + [=]( + const QString &service, + const QString &oldOwner, + const QString &newOwner) { + handleSNIOwnerChanged(service, oldOwner, newOwner); + }); AppMenuSupported = IsAppMenuSupported(); @@ -481,13 +486,18 @@ void MainWindow::initHook() { appMenuWatcher, &QDBusServiceWatcher::serviceOwnerChanged, this, - &MainWindow::onAppMenuOwnerChanged); + [=]( + const QString &service, + const QString &oldOwner, + const QString &newOwner) { + handleAppMenuOwnerChanged(service, oldOwner, newOwner); + }); connect( windowHandle(), &QWindow::visibleChanged, this, - &MainWindow::onVisibleChanged); + [=](bool visible) { handleVisibleChanged(visible); }); if (AppMenuSupported) { LOG(("Using D-Bus global menu.")); @@ -591,7 +601,7 @@ void MainWindow::attachToSNITrayIcon() { updateTrayMenu(); } -void MainWindow::onSNIOwnerChanged( +void MainWindow::handleSNIOwnerChanged( const QString &service, const QString &oldOwner, const QString &newOwner) { @@ -627,7 +637,7 @@ void MainWindow::onSNIOwnerChanged( } } -void MainWindow::onAppMenuOwnerChanged( +void MainWindow::handleAppMenuOwnerChanged( const QString &service, const QString &oldOwner, const QString &newOwner) { @@ -804,7 +814,7 @@ void MainWindow::createGlobalMenu() { auto quit = file->addAction( tr::lng_mac_menu_quit_telegram(tr::now, lt_telegram, qsl("Kotatogram")), App::wnd(), - SLOT(quitFromTray()), + [=] { App::wnd()->quitFromTray(); }, QKeySequence::Quit); quit->setMenuRole(QAction::QuitRole); @@ -814,13 +824,13 @@ void MainWindow::createGlobalMenu() { psUndo = edit->addAction( tr::lng_linux_menu_undo(tr::now), this, - SLOT(psLinuxUndo()), + [=] { psLinuxUndo(); }, QKeySequence::Undo); psRedo = edit->addAction( tr::lng_linux_menu_redo(tr::now), this, - SLOT(psLinuxRedo()), + [=] { psLinuxRedo(); }, QKeySequence::Redo); edit->addSeparator(); @@ -828,24 +838,24 @@ void MainWindow::createGlobalMenu() { psCut = edit->addAction( tr::lng_mac_menu_cut(tr::now), this, - SLOT(psLinuxCut()), + [=] { psLinuxCut(); }, QKeySequence::Cut); psCopy = edit->addAction( tr::lng_mac_menu_copy(tr::now), this, - SLOT(psLinuxCopy()), + [=] { psLinuxCopy(); }, QKeySequence::Copy); psPaste = edit->addAction( tr::lng_mac_menu_paste(tr::now), this, - SLOT(psLinuxPaste()), + [=] { psLinuxPaste(); }, QKeySequence::Paste); psDelete = edit->addAction( tr::lng_mac_menu_delete(tr::now), this, - SLOT(psLinuxDelete()), + [=] { psLinuxDelete(); }, QKeySequence(Qt::ControlModifier | Qt::Key_Backspace)); edit->addSeparator(); @@ -853,44 +863,44 @@ void MainWindow::createGlobalMenu() { psBold = edit->addAction( tr::lng_menu_formatting_bold(tr::now), this, - SLOT(psLinuxBold()), + [=] { psLinuxBold(); }, QKeySequence::Bold); psItalic = edit->addAction( tr::lng_menu_formatting_italic(tr::now), this, - SLOT(psLinuxItalic()), + [=] { psLinuxItalic(); }, QKeySequence::Italic); psUnderline = edit->addAction( tr::lng_menu_formatting_underline(tr::now), this, - SLOT(psLinuxUnderline()), + [=] { psLinuxUnderline(); }, QKeySequence::Underline); psStrikeOut = edit->addAction( tr::lng_menu_formatting_strike_out(tr::now), this, - SLOT(psLinuxStrikeOut()), + [=] { psLinuxStrikeOut(); }, Ui::kStrikeOutSequence); psMonospace = edit->addAction( tr::lng_menu_formatting_monospace(tr::now), this, - SLOT(psLinuxMonospace()), + [=] { psLinuxMonospace(); }, Ui::kMonospaceSequence); psClearFormat = edit->addAction( tr::lng_menu_formatting_clear(tr::now), this, - SLOT(psLinuxClearFormat()), + [=] { psLinuxClearFormat(); }, Ui::kClearFormatSequence); edit->addSeparator(); psSelectAll = edit->addAction( tr::lng_mac_menu_select_all(tr::now), - this, SLOT(psLinuxSelectAll()), + this, [=] { psLinuxSelectAll(); }, QKeySequence::SelectAll); edit->addSeparator(); @@ -898,7 +908,7 @@ void MainWindow::createGlobalMenu() { auto prefs = edit->addAction( tr::lng_mac_menu_preferences(tr::now), App::wnd(), - SLOT(showSettings()), + [=] { App::wnd()->showSettings(); }, QKeySequence(Qt::ControlModifier | Qt::Key_Comma)); prefs->setMenuRole(QAction::PreferencesRole); @@ -933,19 +943,19 @@ void MainWindow::createGlobalMenu() { psAddContact = tools->addAction( tr::lng_mac_menu_add_contact(tr::now), App::wnd(), - SLOT(onShowAddContact())); + [=] { App::wnd()->onShowAddContact(); }); tools->addSeparator(); psNewGroup = tools->addAction( tr::lng_mac_menu_new_group(tr::now), App::wnd(), - SLOT(onShowNewGroup())); + [=] { App::wnd()->onShowNewGroup(); }); psNewChannel = tools->addAction( tr::lng_mac_menu_new_channel(tr::now), App::wnd(), - SLOT(onShowNewChannel())); + [=] { App::wnd()->onShowNewChannel(); }); auto help = psMainMenu->addMenu(tr::lng_linux_menu_help(tr::now)); @@ -1090,7 +1100,7 @@ void MainWindow::updateGlobalMenuHook() { ForceDisabled(psClearFormat, !markdownEnabled); } -void MainWindow::onVisibleChanged(bool visible) { +void MainWindow::handleVisibleChanged(bool visible) { if (AppMenuSupported && !_mainMenuPath.path().isEmpty()) { if (visible) { RegisterAppMenu(winId(), _mainMenuPath); diff --git a/Telegram/SourceFiles/platform/linux/main_window_linux.h b/Telegram/SourceFiles/platform/linux/main_window_linux.h index 5a911f7ea..0190b4262 100644 --- a/Telegram/SourceFiles/platform/linux/main_window_linux.h +++ b/Telegram/SourceFiles/platform/linux/main_window_linux.h @@ -21,8 +21,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Platform { class MainWindow : public Window::MainWindow { - Q_OBJECT - public: explicit MainWindow(not_null controller); @@ -33,43 +31,12 @@ public: style::color fg, bool smallIcon) = 0; + void psShowTrayMenu(); + static void LibsLoaded(); ~MainWindow(); -public slots: - void psShowTrayMenu(); - -#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION - void onSNIOwnerChanged( - const QString &service, - const QString &oldOwner, - const QString &newOwner); - - void onAppMenuOwnerChanged( - const QString &service, - const QString &oldOwner, - const QString &newOwner); - - void psLinuxUndo(); - void psLinuxRedo(); - void psLinuxCut(); - void psLinuxCopy(); - void psLinuxPaste(); - void psLinuxDelete(); - void psLinuxSelectAll(); - - void psLinuxBold(); - void psLinuxItalic(); - void psLinuxUnderline(); - void psLinuxStrikeOut(); - void psLinuxMonospace(); - void psLinuxClearFormat(); - - void onVisibleChanged(bool visible); - -#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION - protected: void initHook() override; void unreadCounterChangedHook() override; @@ -100,6 +67,7 @@ private: void updateIconCounters(); void updateWaylandDecorationColors(); + void handleVisibleChanged(bool visible); #ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION StatusNotifierItem *_sniTrayIcon = nullptr; @@ -131,6 +99,31 @@ private: void setSNITrayIcon(int counter, bool muted); void attachToSNITrayIcon(); + + void handleSNIOwnerChanged( + const QString &service, + const QString &oldOwner, + const QString &newOwner); + + void handleAppMenuOwnerChanged( + const QString &service, + const QString &oldOwner, + const QString &newOwner); + + void psLinuxUndo(); + void psLinuxRedo(); + void psLinuxCut(); + void psLinuxCopy(); + void psLinuxPaste(); + void psLinuxDelete(); + void psLinuxSelectAll(); + + void psLinuxBold(); + void psLinuxItalic(); + void psLinuxUnderline(); + void psLinuxStrikeOut(); + void psLinuxMonospace(); + void psLinuxClearFormat(); #endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION }; diff --git a/Telegram/SourceFiles/platform/linux/specific_linux.cpp b/Telegram/SourceFiles/platform/linux/specific_linux.cpp index 25ce6d76d..ebd4d2518 100644 --- a/Telegram/SourceFiles/platform/linux/specific_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/specific_linux.cpp @@ -81,6 +81,8 @@ constexpr auto kXDGDesktopPortalService = "org.freedesktop.portal.Desktop"_cs; constexpr auto kXDGDesktopPortalObjectPath = "/org/freedesktop/portal/desktop"_cs; constexpr auto kPropertiesInterface = "org.freedesktop.DBus.Properties"_cs; +constexpr auto kXCBFrameExtentsAtomName = "_GTK_FRAME_EXTENTS"_cs; + QStringList PlatformThemes; bool IsTrayIconSupported = true; @@ -298,6 +300,105 @@ bool GetImageFromClipboardSupported() { } #endif // !TDESKTOP_DISABLE_GTK_INTEGRATION +std::optional GetXCBAtom( + xcb_connection_t *connection, + const QString &name) { + const auto cookie = xcb_intern_atom( + connection, + 0, + name.size(), + name.toUtf8()); + + auto reply = xcb_intern_atom_reply( + connection, + cookie, + nullptr); + + if (!reply) { + return std::nullopt; + } + + const auto atom = reply->atom; + free(reply); + + return atom; +} + +bool IsXCBExtensionPresent( + xcb_connection_t *connection, + xcb_extension_t *ext) { + const auto reply = xcb_get_extension_data( + connection, + ext); + + if (!reply) { + return false; + } + + return reply->present; +} + +std::vector GetXCBWMSupported(xcb_connection_t *connection) { + auto netWmAtoms = std::vector{}; + + const auto native = QGuiApplication::platformNativeInterface(); + if (!native) { + return netWmAtoms; + } + + const auto root = static_cast(reinterpret_cast( + native->nativeResourceForIntegration(QByteArray("rootwindow")))); + + const auto supportedAtom = GetXCBAtom(connection, "_NET_SUPPORTED"); + if (!supportedAtom.has_value()) { + return netWmAtoms; + } + + auto offset = 0; + auto remaining = 0; + + do { + const auto cookie = xcb_get_property( + connection, + false, + root, + *supportedAtom, + XCB_ATOM_ATOM, + offset, + 1024); + + auto reply = xcb_get_property_reply( + connection, + cookie, + nullptr); + + if (!reply) { + break; + } + + remaining = 0; + + if (reply->type == XCB_ATOM_ATOM && reply->format == 32) { + const auto len = xcb_get_property_value_length(reply) + / sizeof(xcb_atom_t); + + const auto atoms = reinterpret_cast( + xcb_get_property_value(reply)); + + const auto s = netWmAtoms.size(); + netWmAtoms.resize(s + len); + memcpy(netWmAtoms.data() + s, atoms, len * sizeof(xcb_atom_t)); + + remaining = reply->bytes_after; + offset += len; + } + + free(reply); + } while (remaining > 0); + + return netWmAtoms; +} + std::optional XCBLastUserInputTime() { const auto native = QGuiApplication::platformNativeInterface(); if (!native) { @@ -311,24 +412,28 @@ std::optional XCBLastUserInputTime() { return std::nullopt; } - const auto screen = xcb_setup_roots_iterator(xcb_get_setup(connection)).data; - if (!screen) { + if (!IsXCBExtensionPresent(connection, &xcb_screensaver_id)) { return std::nullopt; } - const auto cookie = xcb_screensaver_query_info(connection, screen->root); + const auto root = static_cast(reinterpret_cast( + native->nativeResourceForIntegration(QByteArray("rootwindow")))); - auto info = xcb_screensaver_query_info_reply( + const auto cookie = xcb_screensaver_query_info( + connection, + root); + + auto reply = xcb_screensaver_query_info_reply( connection, cookie, nullptr); - if (!info) { + if (!reply) { return std::nullopt; } - const auto idle = info->ms_since_user_input; - free(info); + const auto idle = reply->ms_since_user_input; + free(reply); return (crl::now() - static_cast(idle)); } @@ -391,7 +496,7 @@ std::optional MutterDBusLastUserInputTime() { qsl("org.gnome.Mutter.IdleMonitor"), qsl("GetIdletime")); - const QDBusReply reply = QDBusConnection::sessionBus().call( + const QDBusReply reply = QDBusConnection::sessionBus().call( Message); static const auto NotSupportedErrors = { @@ -468,7 +573,6 @@ enum wl_shell_surface_resize WlResizeFromEdges(Qt::Edges edges) { bool StartXCBMoveResize(QWindow *window, int edges) { const auto native = QGuiApplication::platformNativeInterface(); - if (!native) { return false; } @@ -487,29 +591,16 @@ bool StartXCBMoveResize(QWindow *window, int edges) { return false; } - const auto moveResizeCookie = xcb_intern_atom( - connection, - 0, - strlen("_NET_WM_MOVERESIZE"), - "_NET_WM_MOVERESIZE"); - - auto moveResizeReply = xcb_intern_atom_reply( - connection, - moveResizeCookie, - nullptr); - - if (!moveResizeReply) { + const auto moveResize = GetXCBAtom(connection, "_NET_WM_MOVERESIZE"); + if (!moveResize.has_value()) { return false; } - const auto moveResize = moveResizeReply->atom; - free(moveResizeReply); - const auto globalPos = QCursor::pos(); xcb_client_message_event_t xev; xev.response_type = XCB_CLIENT_MESSAGE; - xev.type = moveResize; + xev.type = *moveResize; xev.sequence = 0; xev.window = window->winId(); xev.format = 32; @@ -582,6 +673,116 @@ bool ShowWaylandWindowMenu(QWindow *window) { return false; } +bool XCBFrameExtentsSupported() { + const auto native = QGuiApplication::platformNativeInterface(); + if (!native) { + return false; + } + + const auto connection = reinterpret_cast( + native->nativeResourceForIntegration(QByteArray("connection"))); + + if (!connection) { + return false; + } + + const auto frameExtentsAtom = GetXCBAtom( + connection, + kXCBFrameExtentsAtomName.utf16()); + + if (!frameExtentsAtom.has_value()) { + return false; + } + + return ranges::contains(GetXCBWMSupported(connection), *frameExtentsAtom); +} + +bool SetXCBFrameExtents(QWindow *window, const QMargins &extents) { + const auto native = QGuiApplication::platformNativeInterface(); + if (!native) { + return false; + } + + const auto connection = reinterpret_cast( + native->nativeResourceForIntegration(QByteArray("connection"))); + + if (!connection) { + return false; + } + + const auto frameExtentsAtom = GetXCBAtom( + connection, + kXCBFrameExtentsAtomName.utf16()); + + if (!frameExtentsAtom.has_value()) { + return false; + } + + const auto extentsVector = std::vector{ + uint(extents.left()), + uint(extents.right()), + uint(extents.top()), + uint(extents.bottom()), + }; + + xcb_change_property( + connection, + XCB_PROP_MODE_REPLACE, + window->winId(), + *frameExtentsAtom, + XCB_ATOM_CARDINAL, + 32, + extentsVector.size(), + extentsVector.data()); + + return true; +} + +bool UnsetXCBFrameExtents(QWindow *window) { + const auto native = QGuiApplication::platformNativeInterface(); + if (!native) { + return false; + } + + const auto connection = reinterpret_cast( + native->nativeResourceForIntegration(QByteArray("connection"))); + + if (!connection) { + return false; + } + + const auto frameExtentsAtom = GetXCBAtom( + connection, + kXCBFrameExtentsAtomName.utf16()); + + if (!frameExtentsAtom.has_value()) { + return false; + } + + xcb_delete_property( + connection, + window->winId(), + *frameExtentsAtom); + + return true; +} + +bool SetWaylandWindowGeometry(QWindow *window, const QRect &geometry) { +#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) || defined DESKTOP_APP_QT_PATCHED + if (const auto waylandWindow = static_cast( + window->handle())) { + if (const auto seat = waylandWindow->display()->lastInputDevice()) { + if (const auto shellSurface = waylandWindow->shellSurface()) { + shellSurface->setWindowGeometry(geometry); + return true; + } + } + } +#endif // Qt >= 5.13 || DESKTOP_APP_QT_PATCHED + + return false; +} + Window::Control GtkKeywordToWindowControl(const QString &keyword) { if (keyword == qstr("minimize")) { return Window::Control::Minimize; @@ -925,6 +1126,40 @@ bool ShowWindowMenu(QWindow *window) { return false; } +bool SetWindowExtents(QWindow *window, const QMargins &extents) { + if (IsWayland()) { + const auto geometry = QRect(QPoint(), window->size()) + .marginsRemoved(extents); + + return SetWaylandWindowGeometry(window, geometry); + } else { + return SetXCBFrameExtents(window, extents); + } +} + +bool UnsetWindowExtents(QWindow *window) { + if (IsWayland()) { + const auto geometry = QRect(QPoint(), window->size()); + return SetWaylandWindowGeometry(window, geometry); + } else { + return UnsetXCBFrameExtents(window); + } +} + +bool WindowsNeedShadow() { +#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) || defined DESKTOP_APP_QT_PATCHED + if (IsWayland()) { + return true; + } +#endif // Qt >= 5.13 || DESKTOP_APP_QT_PATCHED + + if (!IsWayland() && XCBFrameExtentsSupported()) { + return true; + } + + return false; +} + Window::ControlsLayout WindowControlsLayout() { #ifndef TDESKTOP_DISABLE_GTK_INTEGRATION if (Libs::GtkSettingSupported() diff --git a/Telegram/SourceFiles/platform/mac/main_window_mac.h b/Telegram/SourceFiles/platform/mac/main_window_mac.h index b5fd21dee..f9179a3e0 100644 --- a/Telegram/SourceFiles/platform/mac/main_window_mac.h +++ b/Telegram/SourceFiles/platform/mac/main_window_mac.h @@ -35,11 +35,11 @@ public: void updateWindowIcon() override; + void psShowTrayMenu(); + class Private; public slots: - void psShowTrayMenu(); - void psMacUndo(); void psMacRedo(); void psMacCut(); diff --git a/Telegram/SourceFiles/platform/mac/specific_mac.h b/Telegram/SourceFiles/platform/mac/specific_mac.h index 2b57ef97c..ee0b288cf 100644 --- a/Telegram/SourceFiles/platform/mac/specific_mac.h +++ b/Telegram/SourceFiles/platform/mac/specific_mac.h @@ -46,6 +46,18 @@ inline bool TrayIconSupported() { return true; } +inline bool SetWindowExtents(QWindow *window, const QMargins &extents) { + return false; +} + +inline bool UnsetWindowExtents(QWindow *window) { + return false; +} + +inline bool WindowsNeedShadow() { + return false; +} + NSImage *ToNSImage(const QPixmap &pixmap); namespace ThirdParty { diff --git a/Telegram/SourceFiles/platform/platform_specific.h b/Telegram/SourceFiles/platform/platform_specific.h index ec419bab7..cbdbb2ec3 100644 --- a/Telegram/SourceFiles/platform/platform_specific.h +++ b/Telegram/SourceFiles/platform/platform_specific.h @@ -56,6 +56,9 @@ QImage GetImageFromClipboard(); bool StartSystemMove(QWindow *window); bool StartSystemResize(QWindow *window, Qt::Edges edges); bool ShowWindowMenu(QWindow *window); +bool WindowsNeedShadow(); +bool SetWindowExtents(QWindow *window, const QMargins &extents); +bool UnsetWindowExtents(QWindow *window); Window::ControlsLayout WindowControlsLayout(); namespace ThirdParty { diff --git a/Telegram/SourceFiles/platform/win/main_window_win.h b/Telegram/SourceFiles/platform/win/main_window_win.h index b02225111..2ac8161e6 100644 --- a/Telegram/SourceFiles/platform/win/main_window_win.h +++ b/Telegram/SourceFiles/platform/win/main_window_win.h @@ -21,8 +21,6 @@ class PopupMenu; namespace Platform { class MainWindow : public Window::MainWindow { - Q_OBJECT - public: explicit MainWindow(not_null controller); @@ -58,11 +56,10 @@ public: return _deltaTop; } - ~MainWindow(); - -public slots: void psShowTrayMenu(); + ~MainWindow(); + protected: void initHook() override; int32 screenNameChecksum(const QString &name) const override; diff --git a/Telegram/SourceFiles/platform/win/specific_win.h b/Telegram/SourceFiles/platform/win/specific_win.h index 71a7ff30a..1ef5471c1 100644 --- a/Telegram/SourceFiles/platform/win/specific_win.h +++ b/Telegram/SourceFiles/platform/win/specific_win.h @@ -38,6 +38,18 @@ inline bool TrayIconSupported() { return true; } +inline bool SetWindowExtents(QWindow *window, const QMargins &extents) { + return false; +} + +inline bool UnsetWindowExtents(QWindow *window) { + return false; +} + +inline bool WindowsNeedShadow() { + return false; +} + namespace ThirdParty { void start(); diff --git a/Telegram/SourceFiles/window/main_window.cpp b/Telegram/SourceFiles/window/main_window.cpp index 0fde90a9b..d2b680337 100644 --- a/Telegram/SourceFiles/window/main_window.cpp +++ b/Telegram/SourceFiles/window/main_window.cpp @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "storage/localstorage.h" #include "platform/platform_window_title.h" #include "base/platform/base_platform_info.h" +#include "ui/platform/ui_platform_utility.h" #include "history/history.h" #include "window/themes/window_theme.h" #include "window/window_session_controller.h" @@ -33,6 +34,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "facades.h" #include "app.h" #include "styles/style_window.h" +#include "styles/style_calls.h" // st::callShadow #include #include @@ -281,6 +283,8 @@ void MainWindow::init() { void MainWindow::handleStateChanged(Qt::WindowState state) { stateChangedHook(state); + updateShadowSize(); + updateControlsGeometry(); if (state == Qt::WindowMinimized) { controller().updateIsActiveBlur(); } else { @@ -321,6 +325,17 @@ HitTestResult MainWindow::hitTest(const QPoint &p) const { return Window::HitTestResult::None; } +bool MainWindow::hasShadow() const { + const auto center = geometry().center(); + return Platform::WindowsNeedShadow() + && Ui::Platform::TranslucentWindowsSupported(center) + && _title; +} + +QRect MainWindow::inner() const { + return rect().marginsRemoved(_padding); +} + int MainWindow::computeMinWidth() const { auto result = st::windowMinWidth; if (const auto session = _controller->sessionController()) { @@ -331,7 +346,7 @@ int MainWindow::computeMinWidth() const { if (_rightColumn) { result += _rightColumn->width(); } - return result; + return result + _padding.left() + _padding.right(); } int MainWindow::computeMinHeight() const { @@ -340,10 +355,10 @@ int MainWindow::computeMinHeight() const { if (!_outdated) { return 0; } - _outdated->resizeToWidth(st::windowMinWidth); + _outdated->resizeToWidth(st::windowMinWidth - _padding.left() - _padding.right()); return _outdated->height(); }(); - return title + outdated + st::windowMinHeight; + return title + outdated + st::windowMinHeight + _padding.top() + _padding.bottom(); } void MainWindow::refreshTitleWidget() { @@ -366,7 +381,20 @@ void MainWindow::updateMinimumSize() { setMinimumHeight(computeMinHeight()); } +void MainWindow::updateShadowSize() { + _padding = hasShadow() && !isMaximized() + ? st::callShadow.extend + : style::margins(); +} + void MainWindow::recountGeometryConstraints() { +#ifdef Q_OS_LINUX + const auto hasShadow = this->hasShadow(); + setWindowFlag(Qt::NoDropShadowWindowHint, hasShadow); + setAttribute(Qt::WA_OpaquePaintEvent, !hasShadow); +#endif // Q_OS_LINUX + + updateShadowSize(); updateMinimumSize(); updateControlsGeometry(); fixOrder(); @@ -466,7 +494,15 @@ void MainWindow::attachToTrayIcon(not_null icon) { App::wnd()->updateTrayMenu(); } +void MainWindow::paintEvent(QPaintEvent *e) { + if (hasShadow() && !isMaximized()) { + QPainter p(this); + Ui::Shadow::paint(p, inner(), width(), st::callShadow); + } +} + void MainWindow::resizeEvent(QResizeEvent *e) { + updateShadowSize(); updateControlsGeometry(); } @@ -479,27 +515,28 @@ void MainWindow::leaveEventHook(QEvent *e) { } void MainWindow::updateControlsGeometry() { - auto bodyLeft = 0; - auto bodyTop = 0; - auto bodyWidth = width(); + const auto inner = this->inner(); + auto bodyLeft = inner.x(); + auto bodyTop = inner.y(); + auto bodyWidth = inner.width(); if (_title && !_title->isHidden()) { - _title->setGeometry(0, bodyTop, width(), _title->height()); + _title->setGeometry(inner.x(), bodyTop, inner.width(), _title->height()); bodyTop += _title->height(); } if (_titleShadow) { - _titleShadow->setGeometry(0, bodyTop, width(), st::lineWidth); + _titleShadow->setGeometry(inner.x(), bodyTop, inner.width(), st::lineWidth); } if (_outdated) { Ui::SendPendingMoveResizeEvents(_outdated.data()); - _outdated->resizeToWidth(width()); - _outdated->moveToLeft(0, bodyTop); + _outdated->resizeToWidth(inner.width()); + _outdated->moveToLeft(inner.x(), bodyTop); bodyTop += _outdated->height(); } if (_rightColumn) { bodyWidth -= _rightColumn->width(); - _rightColumn->setGeometry(bodyWidth, bodyTop, width() - bodyWidth, height() - bodyTop); + _rightColumn->setGeometry(bodyWidth, bodyTop, inner.width() - bodyWidth, inner.height() - (bodyTop - inner.y())); } - _body->setGeometry(bodyLeft, bodyTop, bodyWidth, height() - bodyTop); + _body->setGeometry(bodyLeft, bodyTop, bodyWidth, inner.height() - (bodyTop - inner.y())); } void MainWindow::updateUnreadCounter() { @@ -629,12 +666,12 @@ void MainWindow::showRightColumn(object_ptr widget) { int MainWindow::maximalExtendBy() const { auto desktop = QDesktopWidget().availableGeometry(this); - return std::max(desktop.width() - geometry().width(), 0); + return std::max(desktop.width() - inner().width(), 0); } bool MainWindow::canExtendNoMove(int extendBy) const { auto desktop = QDesktopWidget().availableGeometry(this); - auto inner = geometry(); + auto inner = geometry().marginsRemoved(_padding); auto innerRight = (inner.x() + inner.width() + extendBy); auto desktopRight = (desktop.x() + desktop.width()); return innerRight <= desktopRight; diff --git a/Telegram/SourceFiles/window/main_window.h b/Telegram/SourceFiles/window/main_window.h index 5d09511cb..29cf024e0 100644 --- a/Telegram/SourceFiles/window/main_window.h +++ b/Telegram/SourceFiles/window/main_window.h @@ -102,12 +102,15 @@ public: void clearWidgets(); + QRect inner() const; int computeMinWidth() const; int computeMinHeight() const; void recountGeometryConstraints(); virtual void updateControlsGeometry(); + bool hasShadow() const; + public slots: bool minimizeToTray(); void updateGlobalMenu() { @@ -115,6 +118,7 @@ public slots: } protected: + void paintEvent(QPaintEvent *e) override; void resizeEvent(QResizeEvent *e) override; void leaveEventHook(QEvent *e) override; @@ -180,6 +184,7 @@ protected: private: void refreshTitleWidget(); void updateMinimumSize(); + void updateShadowSize(); void updatePalette(); void initSize(); @@ -200,6 +205,7 @@ private: bool _usingSupportIcon = false; int _customIconId = 0; QString _titleText; + style::margins _padding; bool _isActive = false; diff --git a/Telegram/SourceFiles/window/window_title_qt.cpp b/Telegram/SourceFiles/window/window_title_qt.cpp index a8a02de5b..4446437a3 100644 --- a/Telegram/SourceFiles/window/window_title_qt.cpp +++ b/Telegram/SourceFiles/window/window_title_qt.cpp @@ -8,11 +8,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "window/window_title_qt.h" #include "platform/platform_specific.h" +#include "base/platform/base_platform_info.h" +#include "ui/platform/ui_platform_utility.h" #include "ui/widgets/buttons.h" #include "ui/widgets/shadow.h" #include "core/core_settings.h" #include "core/application.h" #include "styles/style_window.h" +#include "styles/style_calls.h" // st::callShadow #include "base/call_delayed.h" #include @@ -27,6 +30,10 @@ namespace { // that window. If we show the window back with this delay it works. constexpr auto kShowAfterFramelessToggleDelay = crl::time(1000); +style::margins ShadowExtents() { + return st::callShadow.extend; +} + } // namespace TitleWidgetQt::TitleWidgetQt(QWidget *parent) @@ -63,19 +70,29 @@ TitleWidgetQt::TitleWidgetQt(QWidget *parent) QCoreApplication::instance()->installEventFilter(this); - _windowWasFrameless = (window()->windowFlags() & Qt::FramelessWindowHint) != 0; + _windowWasFrameless = (window()->windowFlags() + & Qt::FramelessWindowHint) != 0; + if (!_windowWasFrameless) { toggleFramelessWindow(true); } + setAttribute(Qt::WA_OpaquePaintEvent); resize(width(), _st.height); + + updateWindowExtents(); } TitleWidgetQt::~TitleWidgetQt() { restoreCursor(); + if (!_windowWasFrameless) { toggleFramelessWindow(false); } + + if (_extentsSet) { + Platform::UnsetWindowExtents(window()->windowHandle()); + } } void TitleWidgetQt::toggleFramelessWindow(bool enabled) { @@ -98,11 +115,22 @@ void TitleWidgetQt::init() { &QWindow::windowStateChanged, this, [=](Qt::WindowState state) { windowStateChanged(state); }); + connect( + window()->windowHandle(), + &QWindow::visibleChanged, + this, + [=](bool visible) { visibleChanged(visible); }); _maximizedState = (window()->windowState() & Qt::WindowMaximized); _activeState = isActiveWindow(); updateButtonsState(); } +bool TitleWidgetQt::hasShadow() const { + const auto center = window()->geometry().center(); + return Platform::WindowsNeedShadow() + && Ui::Platform::TranslucentWindowsSupported(center); +} + void TitleWidgetQt::paintEvent(QPaintEvent *e) { auto active = isActiveWindow(); if (_activeState != active) { @@ -112,6 +140,25 @@ void TitleWidgetQt::paintEvent(QPaintEvent *e) { Painter(this).fillRect(rect(), active ? _st.bgActive : _st.bg); } +void TitleWidgetQt::updateWindowExtents() { + if (hasShadow()) { + if (!_maximizedState) { + Platform::SetWindowExtents( + window()->windowHandle(), + ShadowExtents()); + } else { + Platform::SetWindowExtents( + window()->windowHandle(), + QMargins()); + } + + _extentsSet = true; + } else if (_extentsSet) { + Platform::UnsetWindowExtents(window()->windowHandle()); + _extentsSet = false; + } +} + void TitleWidgetQt::updateControlsPosition() { const auto controlsLayout = Core::App().settings().windowControlsLayout(); const auto controlsLeft = controlsLayout.left; @@ -197,7 +244,7 @@ void TitleWidgetQt::mousePressEvent(QMouseEvent *e) { } void TitleWidgetQt::mouseDoubleClickEvent(QMouseEvent *e) { - if (window()->windowState() == Qt::WindowMaximized) { + if (_maximizedState) { window()->setWindowState(Qt::WindowNoState); } else { window()->setWindowState(Qt::WindowMaximized); @@ -205,11 +252,20 @@ void TitleWidgetQt::mouseDoubleClickEvent(QMouseEvent *e) { } bool TitleWidgetQt::eventFilter(QObject *obj, QEvent *e) { + // I tried to listen only QEvent::Move and QEvent::Resize + // but that doesn't work on Wayland + if (obj->isWidgetType() + && window() == static_cast(obj) + && Platform::IsWayland()) { + updateWindowExtents(); + } + if (e->type() == QEvent::MouseMove || e->type() == QEvent::MouseButtonPress) { if (window()->isAncestorOf(static_cast(obj))) { const auto mouseEvent = static_cast(e); - const auto edges = edgesFromPos(mouseEvent->windowPos().toPoint()); + const auto edges = edgesFromPos( + mouseEvent->windowPos().toPoint()); if (e->type() == QEvent::MouseMove && mouseEvent->buttons() == Qt::NoButton) { @@ -218,7 +274,7 @@ bool TitleWidgetQt::eventFilter(QObject *obj, QEvent *e) { if (e->type() == QEvent::MouseButtonPress && mouseEvent->button() == Qt::LeftButton - && window()->windowState() != Qt::WindowMaximized) { + && !_maximizedState) { return startResize(edges); } } @@ -226,6 +282,11 @@ bool TitleWidgetQt::eventFilter(QObject *obj, QEvent *e) { if (window() == static_cast(obj)) { restoreCursor(); } + } else if (e->type() == QEvent::Move + || e->type() == QEvent::Resize) { + if (window() == static_cast(obj)) { + updateWindowExtents(); + } } return TitleWidget::eventFilter(obj, e); @@ -240,6 +301,13 @@ void TitleWidgetQt::windowStateChanged(Qt::WindowState state) { if (_maximizedState != maximized) { _maximizedState = maximized; updateButtonsState(); + updateWindowExtents(); + } +} + +void TitleWidgetQt::visibleChanged(bool visible) { + if (visible) { + updateWindowExtents(); } } @@ -273,26 +341,48 @@ void TitleWidgetQt::updateButtonsState() { : nullptr); } +int TitleWidgetQt::getResizeArea(Qt::Edge edge) const { + if (!hasShadow()) { + return st::windowResizeArea; + } + + if (edge == Qt::LeftEdge) { + return ShadowExtents().left(); + } else if (edge == Qt::RightEdge) { + return ShadowExtents().right(); + } else if (edge == Qt::TopEdge) { + return ShadowExtents().top(); + } else if (edge == Qt::BottomEdge) { + return ShadowExtents().bottom(); + } + + return 0; +} + Qt::Edges TitleWidgetQt::edgesFromPos(const QPoint &pos) { - if (pos.x() <= st::windowResizeArea) { - if (pos.y() <= st::windowResizeArea) { + if (pos.x() <= getResizeArea(Qt::LeftEdge)) { + if (pos.y() <= getResizeArea(Qt::TopEdge)) { return Qt::LeftEdge | Qt::TopEdge; - } else if (pos.y() >= (window()->height() - st::windowResizeArea)) { + } else if (pos.y() + >= (window()->height() - getResizeArea(Qt::BottomEdge))) { return Qt::LeftEdge | Qt::BottomEdge; } return Qt::LeftEdge; - } else if (pos.x() >= (window()->width() - st::windowResizeArea)) { - if (pos.y() <= st::windowResizeArea) { + } else if (pos.x() + >= (window()->width() - getResizeArea(Qt::RightEdge))) { + if (pos.y() <= getResizeArea(Qt::TopEdge)) { return Qt::RightEdge | Qt::TopEdge; - } else if (pos.y() >= (window()->height() - st::windowResizeArea)) { + } else if (pos.y() + >= (window()->height() - getResizeArea(Qt::BottomEdge))) { return Qt::RightEdge | Qt::BottomEdge; } return Qt::RightEdge; - } else if (pos.y() <= st::windowResizeArea) { + } else if (pos.y() <= getResizeArea(Qt::TopEdge)) { return Qt::TopEdge; - } else if (pos.y() >= (window()->height() - st::windowResizeArea)) { + } else if (pos.y() + >= (window()->height() - getResizeArea(Qt::BottomEdge))) { return Qt::BottomEdge; } else { return 0; @@ -307,7 +397,7 @@ void TitleWidgetQt::restoreCursor() { } void TitleWidgetQt::updateCursor(Qt::Edges edges) { - if (!edges || window()->windowState() == Qt::WindowMaximized) { + if (!edges || _maximizedState) { restoreCursor(); return; } else if (!QGuiApplication::overrideCursor()) { diff --git a/Telegram/SourceFiles/window/window_title_qt.h b/Telegram/SourceFiles/window/window_title_qt.h index c3536587d..0d10865c3 100644 --- a/Telegram/SourceFiles/window/window_title_qt.h +++ b/Telegram/SourceFiles/window/window_title_qt.h @@ -39,6 +39,8 @@ protected: private: void windowStateChanged(Qt::WindowState state = Qt::WindowNoState); + void visibleChanged(bool visible); + void updateWindowExtents(); void updateButtonsState(); void updateControlsPosition(); void updateControlsPositionBySide( @@ -46,6 +48,8 @@ private: bool right); void toggleFramelessWindow(bool enabled); + bool hasShadow() const; + int getResizeArea(Qt::Edge edge) const; Qt::Edges edgesFromPos(const QPoint &pos); void updateCursor(Qt::Edges edges); void restoreCursor(); @@ -62,6 +66,7 @@ private: bool _activeState = false; bool _windowWasFrameless = false; bool _cursorOverriden = false; + bool _extentsSet = false; }; diff --git a/cmake b/cmake index 9b1ed3965..fb7924a6f 160000 --- a/cmake +++ b/cmake @@ -1 +1 @@ -Subproject commit 9b1ed3965b836131fe08b1090a8b5788a04066b8 +Subproject commit fb7924a6ffeeaec17ed39203f49fb72dd9eff60f diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 560040275..ea836488a 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -68,6 +68,7 @@ parts: parse-info: [usr/share/metainfo/kotatogramdesktop.appdata.xml] build-environment: - LD_LIBRARY_PATH: $SNAPCRAFT_STAGE/usr/lib + - tg_owt_DIR: $SNAPCRAFT_STAGE/tg_owt build-packages: - python - qtbase5-private-dev @@ -104,7 +105,6 @@ parts: - -DTDESKTOP_API_HASH=d524b414d21f4d37f08684c1df41ac9c - -DDESKTOP_APP_USE_PACKAGED_LAZY=ON - -DDESKTOP_APP_QTWAYLANDCLIENT_PRIVATE_HEADERS=$SNAPCRAFT_STAGE/usr/include/$SNAPCRAFT_ARCH_TRIPLET/qt5/QtWaylandClient/5.12.8 - - -DDESKTOP_APP_WEBRTC_LOCATION=$SNAPCRAFT_STAGE/webrtc/src override-pull: | snapcraftctl pull @@ -119,14 +119,6 @@ parts: - qtwayland - webrtc - patches: - source: https://github.com/desktop-app/patches.git - source-depth: 1 - plugin: dump - organize: - "*": patches/ - prime: [-./*] - telegram-patches: source: Telegram/Patches plugin: dump @@ -134,14 +126,6 @@ parts: "*": telegram_patches/ prime: [-./*] - depot-tools: - source: https://chromium.googlesource.com/chromium/tools/depot_tools.git - source-depth: 1 - plugin: dump - organize: - "*": depot_tools/ - prime: [-./*] - desktop-qt5: source: https://github.com/ubuntu/snapcraft-desktop-helpers.git source-subdir: qt @@ -360,79 +344,31 @@ parts: qmake make -j$(nproc) make INSTALL_ROOT="$SNAPCRAFT_PART_INSTALL" install - after: - - desktop-qt5 stage: [-./usr/lib] prime: [-./*] + after: + - desktop-qt5 webrtc: - plugin: nil + source: https://github.com/ilya-fedin/tg_owt.git + source-depth: 1 + source-branch: improve-packaged-build + plugin: cmake build-packages: - - curl - - python2 + - yasm + - libjpeg8-dev - libopus-dev - libssl-dev stage-packages: + - libjpeg8 - libopus0 - libssl1.1 - override-pull: | - export PATH="$SNAPCRAFT_STAGE/depot_tools:$PATH" - - mkdir webrtc - cd webrtc - cp "$SNAPCRAFT_STAGE/patches/webrtc/.gclient" . - git clone --depth=1 https://github.com/open-webrtc-toolkit/owt-deps-webrtc src - gclient sync --no-history - - applyPatch() { - cd "$SNAPCRAFT_PART_SRC/webrtc/$1" - git apply "$SNAPCRAFT_STAGE/patches/webrtc/$(basename $1).diff" - } - - applyPatch src - applyPatch src/build - applyPatch src/third_party - applyPatch src/third_party/libsrtp override-build: | - export PATH="$SNAPCRAFT_STAGE/depot_tools:$PATH" - - cd webrtc/src - - ArgumentsList=`echo \ - target_os=\"linux\" \ - treat_warnings_as_errors=false \ - is_component_build=false \ - is_debug=false \ - is_clang=false \ - proprietary_codecs=true \ - use_custom_libcxx=false \ - use_rtti=true \ - use_gold=false \ - use_sysroot=false \ - linux_use_bundled_binutils=false \ - enable_dsyms=true \ - rtc_include_tests=false \ - rtc_build_examples=false \ - rtc_build_tools=false \ - rtc_build_opus=false \ - rtc_build_ssl=false \ - rtc_ssl_root=\"/usr/include\" \ - rtc_ssl_libs=[\"ssl\",\"crypto\"] \ - rtc_builtin_ssl_root_certificates=true \ - rtc_build_ffmpeg=false \ - rtc_ffmpeg_root=\"$SNAPCRAFT_STAGE/usr/include\" \ - rtc_ffmpeg_libs=[\"avcodec\",\"swscale\",\"swresample\",\"avutil\"] \ - rtc_opus_root=\"/usr/include/opus\" \ - rtc_enable_protobuf=false` - - gn gen out/Release --args="$ArgumentsList" - - ninja -C out/Release webrtc - cd ../.. - - cp -a webrtc "$SNAPCRAFT_PART_INSTALL" - after: - - depot-tools - - ffmpeg - - patches + cmake "$SNAPCRAFT_PART_SRC" -DCMAKE_BUILD_TYPE=Release + cmake --build . -- -j$(nproc) + cp -a . "$SNAPCRAFT_PART_INSTALL" + organize: + "*": tg_owt/ prime: [-./*] + after: + - ffmpeg