mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Switch MainWindow to Ui::RpWindow
This commit is contained in:
parent
4ef2d3b957
commit
1ebf27bfa1
29 changed files with 116 additions and 1933 deletions
|
@ -873,7 +873,6 @@ PRIVATE
|
||||||
platform/linux/notifications_manager_linux.h
|
platform/linux/notifications_manager_linux.h
|
||||||
platform/linux/specific_linux.cpp
|
platform/linux/specific_linux.cpp
|
||||||
platform/linux/specific_linux.h
|
platform/linux/specific_linux.h
|
||||||
platform/linux/window_title_linux.h
|
|
||||||
platform/mac/file_utilities_mac.mm
|
platform/mac/file_utilities_mac.mm
|
||||||
platform/mac/file_utilities_mac.h
|
platform/mac/file_utilities_mac.h
|
||||||
platform/mac/launcher_mac.mm
|
platform/mac/launcher_mac.mm
|
||||||
|
@ -888,7 +887,6 @@ PRIVATE
|
||||||
platform/mac/specific_mac_p.mm
|
platform/mac/specific_mac_p.mm
|
||||||
platform/mac/specific_mac_p.h
|
platform/mac/specific_mac_p.h
|
||||||
platform/mac/window_title_mac.mm
|
platform/mac/window_title_mac.mm
|
||||||
platform/mac/window_title_mac.h
|
|
||||||
platform/mac/touchbar/items/mac_formatter_item.h
|
platform/mac/touchbar/items/mac_formatter_item.h
|
||||||
platform/mac/touchbar/items/mac_formatter_item.mm
|
platform/mac/touchbar/items/mac_formatter_item.mm
|
||||||
platform/mac/touchbar/items/mac_pinned_chats_item.h
|
platform/mac/touchbar/items/mac_pinned_chats_item.h
|
||||||
|
@ -919,8 +917,6 @@ PRIVATE
|
||||||
platform/win/notifications_manager_win.h
|
platform/win/notifications_manager_win.h
|
||||||
platform/win/specific_win.cpp
|
platform/win/specific_win.cpp
|
||||||
platform/win/specific_win.h
|
platform/win/specific_win.h
|
||||||
platform/win/window_title_win.cpp
|
|
||||||
platform/win/window_title_win.h
|
|
||||||
platform/win/windows_app_user_model_id.cpp
|
platform/win/windows_app_user_model_id.cpp
|
||||||
platform/win/windows_app_user_model_id.h
|
platform/win/windows_app_user_model_id.h
|
||||||
platform/win/windows_dlls.cpp
|
platform/win/windows_dlls.cpp
|
||||||
|
@ -1099,9 +1095,6 @@ PRIVATE
|
||||||
window/window_session_controller.h
|
window/window_session_controller.h
|
||||||
window/window_slide_animation.cpp
|
window/window_slide_animation.cpp
|
||||||
window/window_slide_animation.h
|
window/window_slide_animation.h
|
||||||
window/window_title_qt.cpp
|
|
||||||
window/window_title_qt.h
|
|
||||||
window/window_title.h
|
|
||||||
window/window_top_bar_wrap.h
|
window/window_top_bar_wrap.h
|
||||||
window/themes/window_theme.cpp
|
window/themes/window_theme.cpp
|
||||||
window/themes/window_theme.h
|
window/themes/window_theme.h
|
||||||
|
@ -1140,13 +1133,6 @@ PRIVATE
|
||||||
stdafx.h
|
stdafx.h
|
||||||
)
|
)
|
||||||
|
|
||||||
if (NOT LINUX)
|
|
||||||
remove_target_sources(Telegram ${src_loc}
|
|
||||||
window/window_title_qt.cpp
|
|
||||||
window/window_title_qt.h
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (DESKTOP_APP_DISABLE_DBUS_INTEGRATION)
|
if (DESKTOP_APP_DISABLE_DBUS_INTEGRATION)
|
||||||
remove_target_sources(Telegram ${src_loc}
|
remove_target_sources(Telegram ${src_loc}
|
||||||
platform/linux/linux_xdp_file_dialog.cpp
|
platform/linux/linux_xdp_file_dialog.cpp
|
||||||
|
|
|
@ -269,7 +269,7 @@ void Application::run() {
|
||||||
|
|
||||||
const auto currentGeometry = _window->widget()->geometry();
|
const auto currentGeometry = _window->widget()->geometry();
|
||||||
_mediaView = std::make_unique<Media::View::OverlayWidget>();
|
_mediaView = std::make_unique<Media::View::OverlayWidget>();
|
||||||
_window->widget()->setGeometry(currentGeometry);
|
_window->widget()->Ui::RpWidget::setGeometry(currentGeometry);
|
||||||
|
|
||||||
DEBUG_LOG(("Application Info: showing."));
|
DEBUG_LOG(("Application Info: showing."));
|
||||||
_window->finishFirstShow();
|
_window->finishFirstShow();
|
||||||
|
|
|
@ -41,7 +41,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "settings/settings_intro.h"
|
#include "settings/settings_intro.h"
|
||||||
#include "platform/platform_notifications_manager.h"
|
#include "platform/platform_notifications_manager.h"
|
||||||
#include "base/platform/base_platform_info.h"
|
#include "base/platform/base_platform_info.h"
|
||||||
#include "ui/platform/ui_platform_utility.h"
|
|
||||||
#include "base/call_delayed.h"
|
#include "base/call_delayed.h"
|
||||||
#include "base/variant.h"
|
#include "base/variant.h"
|
||||||
#include "window/notifications_manager.h"
|
#include "window/notifications_manager.h"
|
||||||
|
@ -115,12 +114,7 @@ MainWindow::MainWindow(not_null<Window::Controller*> controller)
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
setAttribute(Qt::WA_NoSystemBackground);
|
setAttribute(Qt::WA_NoSystemBackground);
|
||||||
|
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||||
if (Ui::Platform::WindowExtentsSupported()) {
|
|
||||||
setAttribute(Qt::WA_TranslucentBackground);
|
|
||||||
} else {
|
|
||||||
setAttribute(Qt::WA_OpaquePaintEvent);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::initHook() {
|
void MainWindow::initHook() {
|
||||||
|
@ -226,10 +220,8 @@ void MainWindow::applyInitialWorkMode() {
|
||||||
|
|
||||||
void MainWindow::finishFirstShow() {
|
void MainWindow::finishFirstShow() {
|
||||||
createTrayIconMenu();
|
createTrayIconMenu();
|
||||||
initShadows();
|
|
||||||
applyInitialWorkMode();
|
applyInitialWorkMode();
|
||||||
createGlobalMenu();
|
createGlobalMenu();
|
||||||
firstShadowsUpdate();
|
|
||||||
|
|
||||||
windowDeactivateEvents(
|
windowDeactivateEvents(
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
|
@ -419,7 +411,7 @@ void MainWindow::showMainMenu() {
|
||||||
|
|
||||||
ensureLayerCreated();
|
ensureLayerCreated();
|
||||||
_layer->showMainMenu(
|
_layer->showMainMenu(
|
||||||
object_ptr<Window::MainMenu>(this, sessionController()),
|
object_ptr<Window::MainMenu>(body(), sessionController()),
|
||||||
anim::type::normal);
|
anim::type::normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,128 +21,73 @@ using namespace KWayland::Client;
|
||||||
namespace Platform {
|
namespace Platform {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
class WaylandIntegration::Private : public QObject {
|
struct WaylandIntegration::Private {
|
||||||
public:
|
std::unique_ptr<ConnectionThread> connection;
|
||||||
Private();
|
Registry registry;
|
||||||
|
std::unique_ptr<XdgExporter> xdgExporter;
|
||||||
[[nodiscard]] Registry ®istry() {
|
std::unique_ptr<PlasmaShell> plasmaShell;
|
||||||
return _registry;
|
std::unique_ptr<AppMenuManager> appMenuManager;
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] XdgExporter *xdgExporter() {
|
|
||||||
return _xdgExporter.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] PlasmaShell *plasmaShell() {
|
|
||||||
return _plasmaShell.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] AppMenuManager *appMenuManager() {
|
|
||||||
return _appMenuManager.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] QEventLoop &interfacesLoop() {
|
|
||||||
return _interfacesLoop;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] bool interfacesAnnounced() const {
|
|
||||||
return _interfacesAnnounced;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
ConnectionThread _connection;
|
|
||||||
ConnectionThread *_applicationConnection = nullptr;
|
|
||||||
Registry _registry;
|
|
||||||
Registry _applicationRegistry;
|
|
||||||
std::unique_ptr<XdgExporter> _xdgExporter;
|
|
||||||
std::unique_ptr<PlasmaShell> _plasmaShell;
|
|
||||||
std::unique_ptr<AppMenuManager> _appMenuManager;
|
|
||||||
QEventLoop _interfacesLoop;
|
|
||||||
bool _interfacesAnnounced = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
WaylandIntegration::Private::Private()
|
|
||||||
: _applicationConnection(ConnectionThread::fromApplication(this)) {
|
|
||||||
_applicationRegistry.create(_applicationConnection);
|
|
||||||
_applicationRegistry.setup();
|
|
||||||
|
|
||||||
connect(
|
|
||||||
_applicationConnection,
|
|
||||||
&ConnectionThread::connectionDied,
|
|
||||||
&_applicationRegistry,
|
|
||||||
&Registry::destroy);
|
|
||||||
|
|
||||||
connect(&_connection, &ConnectionThread::connected, [=] {
|
|
||||||
LOG(("Successfully connected to Wayland server at socket: %1")
|
|
||||||
.arg(_connection.socketName()));
|
|
||||||
|
|
||||||
_registry.create(&_connection);
|
|
||||||
_registry.setup();
|
|
||||||
});
|
|
||||||
|
|
||||||
connect(
|
|
||||||
&_connection,
|
|
||||||
&ConnectionThread::connectionDied,
|
|
||||||
&_registry,
|
|
||||||
&Registry::destroy);
|
|
||||||
|
|
||||||
connect(&_registry, &Registry::interfacesAnnounced, [=] {
|
|
||||||
_interfacesAnnounced = true;
|
|
||||||
if (_interfacesLoop.isRunning()) {
|
|
||||||
_interfacesLoop.quit();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
connect(
|
|
||||||
&_applicationRegistry,
|
|
||||||
&Registry::exporterUnstableV2Announced,
|
|
||||||
[=](uint name, uint version) {
|
|
||||||
_xdgExporter = std::unique_ptr<XdgExporter>{
|
|
||||||
_applicationRegistry.createXdgExporter(name, version),
|
|
||||||
};
|
|
||||||
|
|
||||||
connect(
|
|
||||||
_applicationConnection,
|
|
||||||
&ConnectionThread::connectionDied,
|
|
||||||
_xdgExporter.get(),
|
|
||||||
&XdgExporter::destroy);
|
|
||||||
});
|
|
||||||
|
|
||||||
connect(
|
|
||||||
&_applicationRegistry,
|
|
||||||
&Registry::plasmaShellAnnounced,
|
|
||||||
[=](uint name, uint version) {
|
|
||||||
_plasmaShell = std::unique_ptr<PlasmaShell>{
|
|
||||||
_applicationRegistry.createPlasmaShell(name, version),
|
|
||||||
};
|
|
||||||
|
|
||||||
connect(
|
|
||||||
_applicationConnection,
|
|
||||||
&ConnectionThread::connectionDied,
|
|
||||||
_plasmaShell.get(),
|
|
||||||
&PlasmaShell::destroy);
|
|
||||||
});
|
|
||||||
|
|
||||||
connect(
|
|
||||||
&_applicationRegistry,
|
|
||||||
&Registry::appMenuAnnounced,
|
|
||||||
[=](uint name, uint version) {
|
|
||||||
_appMenuManager = std::unique_ptr<AppMenuManager>{
|
|
||||||
_applicationRegistry.createAppMenuManager(name, version),
|
|
||||||
};
|
|
||||||
|
|
||||||
connect(
|
|
||||||
_applicationConnection,
|
|
||||||
&ConnectionThread::connectionDied,
|
|
||||||
_appMenuManager.get(),
|
|
||||||
&AppMenuManager::destroy);
|
|
||||||
});
|
|
||||||
|
|
||||||
_connection.initConnection();
|
|
||||||
}
|
|
||||||
|
|
||||||
WaylandIntegration::WaylandIntegration()
|
WaylandIntegration::WaylandIntegration()
|
||||||
: _private(std::make_unique<Private>()) {
|
: _private(std::make_unique<Private>()) {
|
||||||
|
_private->connection = std::unique_ptr<ConnectionThread>{
|
||||||
|
ConnectionThread::fromApplication(),
|
||||||
|
};
|
||||||
|
|
||||||
|
_private->registry.create(_private->connection.get());
|
||||||
|
_private->registry.setup();
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
_private->connection.get(),
|
||||||
|
&ConnectionThread::connectionDied,
|
||||||
|
&_private->registry,
|
||||||
|
&Registry::destroy);
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
&_private->registry,
|
||||||
|
&Registry::exporterUnstableV2Announced,
|
||||||
|
[=](uint name, uint version) {
|
||||||
|
_private->xdgExporter = std::unique_ptr<XdgExporter>{
|
||||||
|
_private->registry.createXdgExporter(name, version),
|
||||||
|
};
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
_private->connection.get(),
|
||||||
|
&ConnectionThread::connectionDied,
|
||||||
|
_private->xdgExporter.get(),
|
||||||
|
&XdgExporter::destroy);
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
&_private->registry,
|
||||||
|
&Registry::plasmaShellAnnounced,
|
||||||
|
[=](uint name, uint version) {
|
||||||
|
_private->plasmaShell = std::unique_ptr<PlasmaShell>{
|
||||||
|
_private->registry.createPlasmaShell(name, version),
|
||||||
|
};
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
_private->connection.get(),
|
||||||
|
&ConnectionThread::connectionDied,
|
||||||
|
_private->plasmaShell.get(),
|
||||||
|
&PlasmaShell::destroy);
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
&_private->registry,
|
||||||
|
&Registry::appMenuAnnounced,
|
||||||
|
[=](uint name, uint version) {
|
||||||
|
_private->appMenuManager = std::unique_ptr<AppMenuManager>{
|
||||||
|
_private->registry.createAppMenuManager(name, version),
|
||||||
|
};
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
_private->connection.get(),
|
||||||
|
&ConnectionThread::connectionDied,
|
||||||
|
_private->appMenuManager.get(),
|
||||||
|
&AppMenuManager::destroy);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
WaylandIntegration::~WaylandIntegration() = default;
|
WaylandIntegration::~WaylandIntegration() = default;
|
||||||
|
@ -153,20 +98,8 @@ WaylandIntegration *WaylandIntegration::Instance() {
|
||||||
return &instance;
|
return &instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaylandIntegration::waitForInterfaceAnnounce() {
|
|
||||||
Expects(!_private->interfacesLoop().isRunning());
|
|
||||||
if (!_private->interfacesAnnounced()) {
|
|
||||||
_private->interfacesLoop().exec();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WaylandIntegration::supportsXdgDecoration() {
|
|
||||||
return _private->registry().hasInterface(
|
|
||||||
Registry::Interface::XdgDecorationUnstableV1);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString WaylandIntegration::nativeHandle(QWindow *window) {
|
QString WaylandIntegration::nativeHandle(QWindow *window) {
|
||||||
if (const auto exporter = _private->xdgExporter()) {
|
if (const auto exporter = _private->xdgExporter.get()) {
|
||||||
if (const auto surface = Surface::fromWindow(window)) {
|
if (const auto surface = Surface::fromWindow(window)) {
|
||||||
if (const auto exported = exporter->exportTopLevel(
|
if (const auto exported = exporter->exportTopLevel(
|
||||||
surface,
|
surface,
|
||||||
|
@ -186,11 +119,11 @@ QString WaylandIntegration::nativeHandle(QWindow *window) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WaylandIntegration::skipTaskbarSupported() {
|
bool WaylandIntegration::skipTaskbarSupported() {
|
||||||
return _private->plasmaShell();
|
return _private->plasmaShell != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaylandIntegration::skipTaskbar(QWindow *window, bool skip) {
|
void WaylandIntegration::skipTaskbar(QWindow *window, bool skip) {
|
||||||
const auto shell = _private->plasmaShell();
|
const auto shell = _private->plasmaShell.get();
|
||||||
if (!shell) {
|
if (!shell) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -212,7 +145,7 @@ void WaylandIntegration::registerAppMenu(
|
||||||
QWindow *window,
|
QWindow *window,
|
||||||
const QString &serviceName,
|
const QString &serviceName,
|
||||||
const QString &objectPath) {
|
const QString &objectPath) {
|
||||||
const auto manager = _private->appMenuManager();
|
const auto manager = _private->appMenuManager.get();
|
||||||
if (!manager) {
|
if (!manager) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,7 @@ namespace internal {
|
||||||
class WaylandIntegration {
|
class WaylandIntegration {
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] static WaylandIntegration *Instance();
|
[[nodiscard]] static WaylandIntegration *Instance();
|
||||||
void waitForInterfaceAnnounce();
|
|
||||||
[[nodiscard]] bool supportsXdgDecoration();
|
|
||||||
[[nodiscard]] QString nativeHandle(QWindow *window);
|
[[nodiscard]] QString nativeHandle(QWindow *window);
|
||||||
[[nodiscard]] bool skipTaskbarSupported();
|
[[nodiscard]] bool skipTaskbarSupported();
|
||||||
void skipTaskbar(QWindow *window, bool skip);
|
void skipTaskbar(QWindow *window, bool skip);
|
||||||
|
@ -27,7 +26,7 @@ private:
|
||||||
WaylandIntegration();
|
WaylandIntegration();
|
||||||
~WaylandIntegration();
|
~WaylandIntegration();
|
||||||
|
|
||||||
class Private;
|
struct Private;
|
||||||
const std::unique_ptr<Private> _private;
|
const std::unique_ptr<Private> _private;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
namespace Platform {
|
namespace Platform {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
class WaylandIntegration::Private {
|
struct WaylandIntegration::Private {
|
||||||
};
|
};
|
||||||
|
|
||||||
WaylandIntegration::WaylandIntegration() {
|
WaylandIntegration::WaylandIntegration() {
|
||||||
|
@ -26,13 +26,6 @@ WaylandIntegration *WaylandIntegration::Instance() {
|
||||||
return &instance;
|
return &instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaylandIntegration::waitForInterfaceAnnounce() {
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WaylandIntegration::supportsXdgDecoration() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString WaylandIntegration::nativeHandle(QWindow *window) {
|
QString WaylandIntegration::nativeHandle(QWindow *window) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -971,7 +971,6 @@ void MainWindow::workmodeUpdated(Core::Settings::WorkMode mode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::unreadCounterChangedHook() {
|
void MainWindow::unreadCounterChangedHook() {
|
||||||
setWindowTitle(titleText());
|
|
||||||
updateIconCounters();
|
updateIconCounters();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "base/platform/base_platform_info.h"
|
#include "base/platform/base_platform_info.h"
|
||||||
#include "base/platform/linux/base_linux_glibmm_helper.h"
|
#include "base/platform/linux/base_linux_glibmm_helper.h"
|
||||||
#include "base/platform/linux/base_linux_gtk_integration.h"
|
#include "base/platform/linux/base_linux_gtk_integration.h"
|
||||||
|
#include "ui/platform/linux/ui_linux_wayland_integration.h"
|
||||||
#include "platform/linux/linux_desktop_environment.h"
|
#include "platform/linux/linux_desktop_environment.h"
|
||||||
#include "platform/linux/linux_gtk_integration.h"
|
#include "platform/linux/linux_gtk_integration.h"
|
||||||
#include "platform/linux/linux_wayland_integration.h"
|
#include "platform/linux/linux_wayland_integration.h"
|
||||||
|
@ -60,6 +61,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
using namespace Platform;
|
using namespace Platform;
|
||||||
using BaseGtkIntegration = base::Platform::GtkIntegration;
|
using BaseGtkIntegration = base::Platform::GtkIntegration;
|
||||||
|
using UiWaylandIntegration = Ui::Platform::WaylandIntegration;
|
||||||
using Platform::internal::WaylandIntegration;
|
using Platform::internal::WaylandIntegration;
|
||||||
using Platform::internal::GtkIntegration;
|
using Platform::internal::GtkIntegration;
|
||||||
|
|
||||||
|
@ -799,7 +801,7 @@ void start() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait for interface announce to know if native window frame is supported
|
// wait for interface announce to know if native window frame is supported
|
||||||
if (const auto integration = WaylandIntegration::Instance()) {
|
if (const auto integration = UiWaylandIntegration::Instance()) {
|
||||||
integration->waitForInterfaceAnnounce();
|
integration->waitForInterfaceAnnounce();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,47 +0,0 @@
|
||||||
/*
|
|
||||||
This file is part of Telegram Desktop,
|
|
||||||
the official desktop application for the Telegram messaging service.
|
|
||||||
|
|
||||||
For license and copyright information please follow this link:
|
|
||||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "platform/platform_window_title.h"
|
|
||||||
#include "platform/linux/linux_wayland_integration.h"
|
|
||||||
#include "base/object_ptr.h"
|
|
||||||
|
|
||||||
namespace Window {
|
|
||||||
namespace Theme {
|
|
||||||
|
|
||||||
int DefaultPreviewTitleHeight();
|
|
||||||
void DefaultPreviewWindowFramePaint(QImage &preview, const style::palette &palette, QRect body, int outerWidth);
|
|
||||||
|
|
||||||
} // namespace Theme
|
|
||||||
} // namespace Window
|
|
||||||
|
|
||||||
namespace Platform {
|
|
||||||
|
|
||||||
inline bool AllowNativeWindowFrameToggle() {
|
|
||||||
const auto waylandIntegration = internal::WaylandIntegration::Instance();
|
|
||||||
return !waylandIntegration
|
|
||||||
|| waylandIntegration->supportsXdgDecoration();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline object_ptr<Window::TitleWidget> CreateTitleWidget(QWidget *parent) {
|
|
||||||
return object_ptr<Window::TitleWidgetQt>(parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool NativeTitleRequiresShadow() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int PreviewTitleHeight() {
|
|
||||||
return Window::Theme::DefaultPreviewTitleHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void PreviewWindowFramePaint(QImage &preview, const style::palette &palette, QRect body, int outerWidth) {
|
|
||||||
return Window::Theme::DefaultPreviewWindowFramePaint(preview, palette, body, outerWidth);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Platform
|
|
|
@ -62,7 +62,6 @@ protected:
|
||||||
void handleActiveChangedHook() override;
|
void handleActiveChangedHook() override;
|
||||||
void stateChangedHook(Qt::WindowState state) override;
|
void stateChangedHook(Qt::WindowState state) override;
|
||||||
void initHook() override;
|
void initHook() override;
|
||||||
void titleVisibilityChangedHook() override;
|
|
||||||
void unreadCounterChangedHook() override;
|
void unreadCounterChangedHook() override;
|
||||||
|
|
||||||
bool hasTrayIcon() const override {
|
bool hasTrayIcon() const override {
|
||||||
|
@ -80,9 +79,6 @@ protected:
|
||||||
void psSetupTrayIcon();
|
void psSetupTrayIcon();
|
||||||
virtual void placeSmallCounter(QImage &img, int size, int count, style::color bg, const QPoint &shift, style::color color) = 0;
|
virtual void placeSmallCounter(QImage &img, int size, int count, style::color bg, const QPoint &shift, style::color color) = 0;
|
||||||
|
|
||||||
QTimer psUpdatedPositionTimer;
|
|
||||||
|
|
||||||
void initShadows() override;
|
|
||||||
void closeWithoutDestroy() override;
|
void closeWithoutDestroy() override;
|
||||||
void createGlobalMenu() override;
|
void createGlobalMenu() override;
|
||||||
|
|
||||||
|
@ -90,7 +86,6 @@ private:
|
||||||
friend class Private;
|
friend class Private;
|
||||||
|
|
||||||
void hideAndDeactivate();
|
void hideAndDeactivate();
|
||||||
void updateTitleCounter();
|
|
||||||
void updateIconCounters();
|
void updateIconCounters();
|
||||||
[[nodiscard]] QIcon generateIconForTray(int counter, bool muted) const;
|
[[nodiscard]] QIcon generateIconForTray(int counter, bool muted) const;
|
||||||
|
|
||||||
|
|
|
@ -53,9 +53,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
- (void) darkModeChanged:(NSNotification *)aNotification;
|
- (void) darkModeChanged:(NSNotification *)aNotification;
|
||||||
- (void) screenIsLocked:(NSNotification *)aNotification;
|
- (void) screenIsLocked:(NSNotification *)aNotification;
|
||||||
- (void) screenIsUnlocked:(NSNotification *)aNotification;
|
- (void) screenIsUnlocked:(NSNotification *)aNotification;
|
||||||
- (void) windowWillEnterFullScreen:(NSNotification *)aNotification;
|
|
||||||
- (void) windowWillExitFullScreen:(NSNotification *)aNotification;
|
|
||||||
- (void) windowDidExitFullScreen:(NSNotification *)aNotification;
|
|
||||||
|
|
||||||
@end // @interface MainWindowObserver
|
@end // @interface MainWindowObserver
|
||||||
|
|
||||||
|
@ -67,43 +64,6 @@ namespace {
|
||||||
// fullscreen mode, after that we'll hide the window no matter what.
|
// fullscreen mode, after that we'll hide the window no matter what.
|
||||||
constexpr auto kHideAfterFullscreenTimeoutMs = 3000;
|
constexpr auto kHideAfterFullscreenTimeoutMs = 3000;
|
||||||
|
|
||||||
id FindClassInSubviews(NSView *parent, NSString *className) {
|
|
||||||
for (NSView *child in [parent subviews]) {
|
|
||||||
if ([child isKindOfClass:NSClassFromString(className)]) {
|
|
||||||
return child;
|
|
||||||
} else if (id inchild = FindClassInSubviews(child, className)) {
|
|
||||||
return inchild;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef OS_MAC_OLD
|
|
||||||
|
|
||||||
class LayerCreationChecker : public QObject {
|
|
||||||
public:
|
|
||||||
LayerCreationChecker(NSView * __weak view, Fn<void()> callback)
|
|
||||||
: _weakView(view)
|
|
||||||
, _callback(std::move(callback)) {
|
|
||||||
QCoreApplication::instance()->installEventFilter(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool eventFilter(QObject *object, QEvent *event) override {
|
|
||||||
if (!_weakView || [_weakView layer] != nullptr) {
|
|
||||||
_callback();
|
|
||||||
}
|
|
||||||
return QObject::eventFilter(object, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
NSView * __weak _weakView = nil;
|
|
||||||
Fn<void()> _callback;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // OS_MAC_OLD
|
|
||||||
|
|
||||||
[[nodiscard]] QImage TrayIconBack(bool darkMode) {
|
[[nodiscard]] QImage TrayIconBack(bool darkMode) {
|
||||||
static const auto WithColor = [](QColor color) {
|
static const auto WithColor = [](QColor color) {
|
||||||
return st::macTrayIcon.instance(color, 100);
|
return st::macTrayIcon.instance(color, 100);
|
||||||
|
@ -127,38 +87,16 @@ public:
|
||||||
not_null<Window::Controller*> controller,
|
not_null<Window::Controller*> controller,
|
||||||
rpl::producer<bool> canApplyMarkdown);
|
rpl::producer<bool> canApplyMarkdown);
|
||||||
void setWindowBadge(const QString &str);
|
void setWindowBadge(const QString &str);
|
||||||
void setWindowTitle(const QString &str);
|
|
||||||
void updateNativeTitle();
|
|
||||||
|
|
||||||
void enableShadow(WId winId);
|
|
||||||
|
|
||||||
void willEnterFullScreen();
|
|
||||||
void willExitFullScreen();
|
|
||||||
void didExitFullScreen();
|
|
||||||
|
|
||||||
bool clipboardHasText();
|
bool clipboardHasText();
|
||||||
~Private();
|
~Private();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void initCustomTitle();
|
|
||||||
void refreshWeakTitleReferences();
|
|
||||||
void enforceCorrectStyleMask();
|
|
||||||
|
|
||||||
not_null<MainWindow*> _public;
|
not_null<MainWindow*> _public;
|
||||||
friend class MainWindow;
|
friend class MainWindow;
|
||||||
|
|
||||||
#ifdef OS_MAC_OLD
|
|
||||||
NSWindow *_nativeWindow = nil;
|
|
||||||
NSView *_nativeView = nil;
|
|
||||||
#else // OS_MAC_OLD
|
|
||||||
NSWindow * __weak _nativeWindow = nil;
|
NSWindow * __weak _nativeWindow = nil;
|
||||||
NSView * __weak _nativeView = nil;
|
NSView * __weak _nativeView = nil;
|
||||||
id __weak _nativeTitleWrapWeak = nil;
|
|
||||||
id __weak _nativeTitleWeak = nil;
|
|
||||||
std::unique_ptr<LayerCreationChecker> _layerCreationChecker;
|
|
||||||
#endif // !OS_MAC_OLD
|
|
||||||
bool _useNativeTitle = false;
|
|
||||||
bool _inFullScreen = false;
|
|
||||||
|
|
||||||
MainWindowObserver *_observer = nullptr;
|
MainWindowObserver *_observer = nullptr;
|
||||||
NSPasteboard *_generalPasteboard = nullptr;
|
NSPasteboard *_generalPasteboard = nullptr;
|
||||||
|
@ -198,18 +136,6 @@ private:
|
||||||
Core::App().setScreenIsLocked(false);
|
Core::App().setScreenIsLocked(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) windowWillEnterFullScreen:(NSNotification *)aNotification {
|
|
||||||
_private->willEnterFullScreen();
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) windowWillExitFullScreen:(NSNotification *)aNotification {
|
|
||||||
_private->willExitFullScreen();
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) windowDidExitFullScreen:(NSNotification *)aNotification {
|
|
||||||
_private->didExitFullScreen();
|
|
||||||
}
|
|
||||||
|
|
||||||
@end // @implementation MainWindowObserver
|
@end // @implementation MainWindowObserver
|
||||||
|
|
||||||
namespace Platform {
|
namespace Platform {
|
||||||
|
@ -256,15 +182,12 @@ void MainWindow::Private::setWindowBadge(const QString &str) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::Private::setWindowTitle(const QString &str) {
|
|
||||||
_public->setWindowTitle(str);
|
|
||||||
updateNativeTitle();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::Private::setNativeWindow(NSWindow *window, NSView *view) {
|
void MainWindow::Private::setNativeWindow(NSWindow *window, NSView *view) {
|
||||||
_nativeWindow = window;
|
_nativeWindow = window;
|
||||||
_nativeView = view;
|
_nativeView = view;
|
||||||
initCustomTitle();
|
auto inner = [_nativeWindow contentLayoutRect];
|
||||||
|
auto full = [_nativeView frame];
|
||||||
|
_public->_customTitleHeight = qMax(qRound(full.size.height - inner.size.height), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::Private::initTouchBar(
|
void MainWindow::Private::initTouchBar(
|
||||||
|
@ -288,119 +211,6 @@ void MainWindow::Private::initTouchBar(
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::Private::initCustomTitle() {
|
|
||||||
#ifndef OS_MAC_OLD
|
|
||||||
if (![_nativeWindow respondsToSelector:@selector(contentLayoutRect)]
|
|
||||||
|| ![_nativeWindow respondsToSelector:@selector(setTitlebarAppearsTransparent:)]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
[_nativeWindow setTitlebarAppearsTransparent:YES];
|
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:_observer selector:@selector(windowWillEnterFullScreen:) name:NSWindowWillEnterFullScreenNotification object:_nativeWindow];
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:_observer selector:@selector(windowWillExitFullScreen:) name:NSWindowWillExitFullScreenNotification object:_nativeWindow];
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:_observer selector:@selector(windowDidExitFullScreen:) name:NSWindowDidExitFullScreenNotification object:_nativeWindow];
|
|
||||||
|
|
||||||
// Qt has bug with layer-backed widgets containing QOpenGLWidgets.
|
|
||||||
// See https://bugreports.qt.io/browse/QTBUG-64494
|
|
||||||
// Emulate custom title instead (code below).
|
|
||||||
//
|
|
||||||
// Tried to backport a fix, testing.
|
|
||||||
[_nativeWindow setStyleMask:[_nativeWindow styleMask] | NSFullSizeContentViewWindowMask];
|
|
||||||
auto inner = [_nativeWindow contentLayoutRect];
|
|
||||||
auto full = [_nativeView frame];
|
|
||||||
_public->_customTitleHeight = qMax(qRound(full.size.height - inner.size.height), 0);
|
|
||||||
|
|
||||||
// Qt still has some bug with layer-backed widgets containing QOpenGLWidgets.
|
|
||||||
// See https://github.com/telegramdesktop/tdesktop/issues/4150
|
|
||||||
// Tried to workaround it by catching the first moment we have CALayer created
|
|
||||||
// and explicitly setting contentsScale to window->backingScaleFactor there.
|
|
||||||
_layerCreationChecker = std::make_unique<LayerCreationChecker>(_nativeView, [=] {
|
|
||||||
if (_nativeView && _nativeWindow) {
|
|
||||||
if (CALayer *layer = [_nativeView layer]) {
|
|
||||||
LOG(("Window Info: Setting layer scale factor to: %1").arg([_nativeWindow backingScaleFactor]));
|
|
||||||
[layer setContentsScale: [_nativeWindow backingScaleFactor]];
|
|
||||||
_layerCreationChecker = nullptr;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_layerCreationChecker = nullptr;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Disabled for now.
|
|
||||||
//_useNativeTitle = true;
|
|
||||||
//setWindowTitle(qsl("Telegram"));
|
|
||||||
#endif // !OS_MAC_OLD
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::Private::refreshWeakTitleReferences() {
|
|
||||||
if (!_nativeWindow) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef OS_MAC_OLD
|
|
||||||
@autoreleasepool {
|
|
||||||
|
|
||||||
if (NSView *parent = [[_nativeWindow contentView] superview]) {
|
|
||||||
if (id titleWrap = FindClassInSubviews(parent, Q2NSString(strTitleWrapClass()))) {
|
|
||||||
if ([titleWrap respondsToSelector:@selector(setBackgroundColor:)]) {
|
|
||||||
if (id title = FindClassInSubviews(titleWrap, Q2NSString(strTitleClass()))) {
|
|
||||||
if ([title respondsToSelector:@selector(setAttributedStringValue:)]) {
|
|
||||||
_nativeTitleWrapWeak = titleWrap;
|
|
||||||
_nativeTitleWeak = title;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif // !OS_MAC_OLD
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::Private::updateNativeTitle() {
|
|
||||||
if (!_useNativeTitle) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#ifndef OS_MAC_OLD
|
|
||||||
if (!_nativeTitleWrapWeak || !_nativeTitleWeak) {
|
|
||||||
refreshWeakTitleReferences();
|
|
||||||
}
|
|
||||||
if (_nativeTitleWrapWeak && _nativeTitleWeak) {
|
|
||||||
@autoreleasepool {
|
|
||||||
|
|
||||||
auto convertColor = [](QColor color) {
|
|
||||||
return [NSColor colorWithDeviceRed:color.redF() green:color.greenF() blue:color.blueF() alpha:color.alphaF()];
|
|
||||||
};
|
|
||||||
auto adjustFg = [](const style::color &st) {
|
|
||||||
// Weird thing with NSTextField taking NSAttributedString with
|
|
||||||
// NSForegroundColorAttributeName set to colorWithDeviceRed:green:blue
|
|
||||||
// with components all equal to 128 - it ignores it and prints black text!
|
|
||||||
auto color = st->c;
|
|
||||||
return (color.red() == 128 && color.green() == 128 && color.blue() == 128)
|
|
||||||
? QColor(129, 129, 129, color.alpha())
|
|
||||||
: color;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto active = _public->isActiveWindow();
|
|
||||||
auto bgColor = (active ? st::titleBgActive : st::titleBg)->c;
|
|
||||||
auto fgColor = adjustFg(active ? st::titleFgActive : st::titleFg);
|
|
||||||
|
|
||||||
auto bgConverted = convertColor(bgColor);
|
|
||||||
auto fgConverted = convertColor(fgColor);
|
|
||||||
[_nativeTitleWrapWeak setBackgroundColor:bgConverted];
|
|
||||||
|
|
||||||
auto title = Q2NSString(_public->windowTitle());
|
|
||||||
NSDictionary *attributes = _inFullScreen
|
|
||||||
? nil
|
|
||||||
: [NSDictionary dictionaryWithObjectsAndKeys: fgConverted, NSForegroundColorAttributeName, bgConverted, NSBackgroundColorAttributeName, nil];
|
|
||||||
NSAttributedString *string = [[NSAttributedString alloc] initWithString:title attributes:attributes];
|
|
||||||
[_nativeTitleWeak setAttributedStringValue:string];
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif // !OS_MAC_OLD
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MainWindow::Private::clipboardHasText() {
|
bool MainWindow::Private::clipboardHasText() {
|
||||||
auto currentChangeCount = static_cast<int>([_generalPasteboard changeCount]);
|
auto currentChangeCount = static_cast<int>([_generalPasteboard changeCount]);
|
||||||
if (_generalPasteboardChangeCount != currentChangeCount) {
|
if (_generalPasteboardChangeCount != currentChangeCount) {
|
||||||
|
@ -410,32 +220,6 @@ bool MainWindow::Private::clipboardHasText() {
|
||||||
return _generalPasteboardHasText;
|
return _generalPasteboardHasText;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::Private::willEnterFullScreen() {
|
|
||||||
_inFullScreen = true;
|
|
||||||
_public->setTitleVisible(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::Private::willExitFullScreen() {
|
|
||||||
_inFullScreen = false;
|
|
||||||
_public->setTitleVisible(true);
|
|
||||||
enforceCorrectStyleMask();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::Private::didExitFullScreen() {
|
|
||||||
enforceCorrectStyleMask();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::Private::enforceCorrectStyleMask() {
|
|
||||||
if (_nativeWindow && _public->_customTitleHeight > 0) {
|
|
||||||
[_nativeWindow setStyleMask:[_nativeWindow styleMask] | NSFullSizeContentViewWindowMask];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::Private::enableShadow(WId winId) {
|
|
||||||
// [[(NSView*)winId window] setStyleMask:NSBorderlessWindowMask];
|
|
||||||
// [[(NSView*)winId window] setHasShadow:YES];
|
|
||||||
}
|
|
||||||
|
|
||||||
MainWindow::Private::~Private() {
|
MainWindow::Private::~Private() {
|
||||||
[_observer release];
|
[_observer release];
|
||||||
}
|
}
|
||||||
|
@ -449,11 +233,6 @@ MainWindow::MainWindow(not_null<Window::Controller*> controller)
|
||||||
#endif // !OS_MAC_OLD
|
#endif // !OS_MAC_OLD
|
||||||
|
|
||||||
_hideAfterFullScreenTimer.setCallback([this] { hideAndDeactivate(); });
|
_hideAfterFullScreenTimer.setCallback([this] { hideAndDeactivate(); });
|
||||||
|
|
||||||
style::PaletteChanged(
|
|
||||||
) | rpl::start_with_next([=] {
|
|
||||||
_private->updateNativeTitle();
|
|
||||||
}, lifetime());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::closeWithoutDestroy() {
|
void MainWindow::closeWithoutDestroy() {
|
||||||
|
@ -475,8 +254,6 @@ void MainWindow::stateChangedHook(Qt::WindowState state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::handleActiveChangedHook() {
|
void MainWindow::handleActiveChangedHook() {
|
||||||
InvokeQueued(this, [this] { _private->updateNativeTitle(); });
|
|
||||||
|
|
||||||
// On macOS just remove trayIcon menu if the window is not active.
|
// On macOS just remove trayIcon menu if the window is not active.
|
||||||
// So we will activate the window on click instead of showing the menu.
|
// So we will activate the window on click instead of showing the menu.
|
||||||
if (isActiveForTrayMenu()) {
|
if (isActiveForTrayMenu()) {
|
||||||
|
@ -506,10 +283,6 @@ void MainWindow::initHook() {
|
||||||
void MainWindow::updateWindowIcon() {
|
void MainWindow::updateWindowIcon() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::titleVisibilityChangedHook() {
|
|
||||||
updateTitleCounter();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::hideAndDeactivate() {
|
void MainWindow::hideAndDeactivate() {
|
||||||
hide();
|
hide();
|
||||||
}
|
}
|
||||||
|
@ -591,12 +364,7 @@ void _placeCounter(QImage &img, int size, int count, style::color bg, style::col
|
||||||
img.setDevicePixelRatio(savedRatio);
|
img.setDevicePixelRatio(savedRatio);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::updateTitleCounter() {
|
|
||||||
_private->setWindowTitle(titleVisible() ? QString() : titleText());
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::unreadCounterChangedHook() {
|
void MainWindow::unreadCounterChangedHook() {
|
||||||
updateTitleCounter();
|
|
||||||
updateIconCounters();
|
updateIconCounters();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -649,10 +417,6 @@ QIcon MainWindow::generateIconForTray(int counter, bool muted) const {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::initShadows() {
|
|
||||||
_private->enableShadow(winId());
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::createGlobalMenu() {
|
void MainWindow::createGlobalMenu() {
|
||||||
const auto ensureWindowShown = [=] {
|
const auto ensureWindowShown = [=] {
|
||||||
if (isHidden()) {
|
if (isHidden()) {
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
/*
|
|
||||||
This file is part of Telegram Desktop,
|
|
||||||
the official desktop application for the Telegram messaging service.
|
|
||||||
|
|
||||||
For license and copyright information please follow this link:
|
|
||||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "platform/platform_window_title.h"
|
|
||||||
|
|
||||||
namespace Ui {
|
|
||||||
class PlainShadow;
|
|
||||||
} // namespace Ui
|
|
||||||
|
|
||||||
namespace Platform {
|
|
||||||
|
|
||||||
class MainWindow;
|
|
||||||
|
|
||||||
class TitleWidget : public Window::TitleWidget {
|
|
||||||
public:
|
|
||||||
TitleWidget(MainWindow *parent, int height);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void paintEvent(QPaintEvent *e) override;
|
|
||||||
void resizeEvent(QResizeEvent *e) override;
|
|
||||||
void mouseDoubleClickEvent(QMouseEvent *e) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
object_ptr<Ui::PlainShadow> _shadow;
|
|
||||||
QFont _font;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
inline bool AllowNativeWindowFrameToggle() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
object_ptr<Window::TitleWidget> CreateTitleWidget(QWidget *parent);
|
|
||||||
|
|
||||||
inline bool NativeTitleRequiresShadow() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int PreviewTitleHeight();
|
|
||||||
void PreviewWindowFramePaint(QImage &preview, const style::palette &palette, QRect body, int outerWidth);
|
|
||||||
|
|
||||||
} // namespace Platform
|
|
|
@ -5,83 +5,18 @@ the official desktop application for the Telegram messaging service.
|
||||||
For license and copyright information please follow this link:
|
For license and copyright information please follow this link:
|
||||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#include "platform/mac/window_title_mac.h"
|
#include "platform/platform_window_title.h"
|
||||||
|
|
||||||
#include "mainwindow.h"
|
|
||||||
#include "ui/widgets/shadow.h"
|
|
||||||
#include "ui/image/image_prepare.h"
|
#include "ui/image/image_prepare.h"
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
#include "styles/style_window.h"
|
#include "styles/style_window.h"
|
||||||
#include "styles/style_media_view.h"
|
#include "styles/style_media_view.h"
|
||||||
#include "platform/platform_main_window.h"
|
|
||||||
#include "window/window_controller.h"
|
#include "window/window_controller.h"
|
||||||
|
|
||||||
#include <Cocoa/Cocoa.h>
|
#include <Cocoa/Cocoa.h>
|
||||||
#include <CoreFoundation/CFURL.h>
|
|
||||||
|
|
||||||
namespace Platform {
|
namespace Platform {
|
||||||
|
|
||||||
TitleWidget::TitleWidget(MainWindow *parent, int height)
|
|
||||||
: Window::TitleWidget(parent)
|
|
||||||
, _shadow(this, st::titleShadow) {
|
|
||||||
setAttribute(Qt::WA_OpaquePaintEvent);
|
|
||||||
resize(width(), height);
|
|
||||||
|
|
||||||
#ifndef OS_MAC_OLD
|
|
||||||
QStringList families = { qsl(".SF NS Text"), qsl("Helvetica Neue") };
|
|
||||||
for (auto family : families) {
|
|
||||||
_font.setFamily(family);
|
|
||||||
if (QFontInfo(_font).family() == _font.family()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif // OS_MAC_OLD
|
|
||||||
|
|
||||||
if (QFontInfo(_font).family() == _font.family()) {
|
|
||||||
_font.setPixelSize((height * 15) / 24);
|
|
||||||
} else {
|
|
||||||
_font = st::normalFont;
|
|
||||||
}
|
|
||||||
|
|
||||||
Core::App().unreadBadgeChanges(
|
|
||||||
) | rpl::start_with_next([=] {
|
|
||||||
update();
|
|
||||||
}, lifetime());
|
|
||||||
}
|
|
||||||
|
|
||||||
void TitleWidget::paintEvent(QPaintEvent *e) {
|
|
||||||
Painter p(this);
|
|
||||||
|
|
||||||
auto active = isActiveWindow();
|
|
||||||
p.fillRect(rect(), active ? st::titleBgActive : st::titleBg);
|
|
||||||
|
|
||||||
p.setFont(_font);
|
|
||||||
p.setPen(active ? st::titleFgActive : st::titleFg);
|
|
||||||
p.drawText(rect(), static_cast<MainWindow*>(parentWidget())->titleText(), style::al_center);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TitleWidget::resizeEvent(QResizeEvent *e) {
|
|
||||||
_shadow->setGeometry(0, height() - st::lineWidth, width(), st::lineWidth);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TitleWidget::mouseDoubleClickEvent(QMouseEvent *e) {
|
|
||||||
auto window = parentWidget();
|
|
||||||
if (window->windowState() == Qt::WindowMaximized) {
|
|
||||||
window->setWindowState(Qt::WindowNoState);
|
|
||||||
} else {
|
|
||||||
window->setWindowState(Qt::WindowMaximized);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object_ptr<Window::TitleWidget> CreateTitleWidget(QWidget *parent) {
|
|
||||||
if (auto window = qobject_cast<Platform::MainWindow*>(parent)) {
|
|
||||||
if (auto height = window->getCustomTitleHeight()) {
|
|
||||||
return object_ptr<TitleWidget>(window, height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return { nullptr };
|
|
||||||
}
|
|
||||||
|
|
||||||
// All the window decorations preview is done without taking cScale() into
|
// All the window decorations preview is done without taking cScale() into
|
||||||
// account, with 100% scale and without "px" dimensions, because thats
|
// account, with 100% scale and without "px" dimensions, because thats
|
||||||
// how it will look in real launched macOS app.
|
// how it will look in real launched macOS app.
|
||||||
|
|
|
@ -7,16 +7,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "window/window_title.h"
|
|
||||||
#include "window/window_title_qt.h"
|
|
||||||
#include "window/themes/window_theme_preview.h"
|
#include "window/themes/window_theme_preview.h"
|
||||||
#include "base/object_ptr.h"
|
#include "base/platform/base_platform_info.h"
|
||||||
|
|
||||||
namespace Platform {
|
namespace Platform {
|
||||||
|
|
||||||
bool AllowNativeWindowFrameToggle();
|
inline bool NativeTitleRequiresShadow() {
|
||||||
object_ptr<Window::TitleWidget> CreateTitleWidget(QWidget *parent);
|
return Platform::IsWindows();
|
||||||
bool NativeTitleRequiresShadow();
|
}
|
||||||
|
|
||||||
int PreviewTitleHeight();
|
int PreviewTitleHeight();
|
||||||
void PreviewWindowFramePaint(QImage &preview, const style::palette &palette, QRect body, int outerWidth);
|
void PreviewWindowFramePaint(QImage &preview, const style::palette &palette, QRect body, int outerWidth);
|
||||||
|
@ -25,28 +23,10 @@ void PreviewWindowFramePaint(QImage &preview, const style::palette &palette, QRe
|
||||||
|
|
||||||
// Platform dependent implementations.
|
// Platform dependent implementations.
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
#ifndef Q_OS_MAC
|
||||||
#include "platform/mac/window_title_mac.h"
|
|
||||||
#elif defined Q_OS_WIN // Q_OS_MAC
|
|
||||||
#include "platform/win/window_title_win.h"
|
|
||||||
#elif defined Q_OS_UNIX // Q_OS_MAC || Q_OS_WIN
|
|
||||||
#include "platform/linux/window_title_linux.h"
|
|
||||||
#else // Q_OS_MAC || Q_OS_WIN || Q_OS_UNIX
|
|
||||||
|
|
||||||
namespace Platform {
|
namespace Platform {
|
||||||
|
|
||||||
inline bool AllowNativeWindowFrameToggle() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline object_ptr<Window::TitleWidget> CreateTitleWidget(QWidget *parent) {
|
|
||||||
return object_ptr<Window::TitleWidgetQt>(parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool NativeTitleRequiresShadow() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int PreviewTitleHeight() {
|
inline int PreviewTitleHeight() {
|
||||||
return Window::Theme::DefaultPreviewTitleHeight();
|
return Window::Theme::DefaultPreviewTitleHeight();
|
||||||
}
|
}
|
||||||
|
@ -57,4 +37,4 @@ inline void PreviewWindowFramePaint(QImage &preview, const style::palette &palet
|
||||||
|
|
||||||
} // namespace Platform
|
} // namespace Platform
|
||||||
|
|
||||||
#endif // Q_OS_MAC || Q_OS_WIN || Q_OS_UNIX
|
#endif // !Q_OS_MAC
|
||||||
|
|
|
@ -43,8 +43,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
HICON qt_pixmapToWinHICON(const QPixmap &);
|
HICON qt_pixmapToWinHICON(const QPixmap &);
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(QMargins);
|
|
||||||
|
|
||||||
namespace ViewManagement = ABI::Windows::UI::ViewManagement;
|
namespace ViewManagement = ABI::Windows::UI::ViewManagement;
|
||||||
|
|
||||||
namespace Platform {
|
namespace Platform {
|
||||||
|
@ -122,12 +120,6 @@ MainWindow::MainWindow(not_null<Window::Controller*> controller)
|
||||||
if (!kTaskbarCreatedMsgId) {
|
if (!kTaskbarCreatedMsgId) {
|
||||||
kTaskbarCreatedMsgId = RegisterWindowMessage(L"TaskbarButtonCreated");
|
kTaskbarCreatedMsgId = RegisterWindowMessage(L"TaskbarButtonCreated");
|
||||||
}
|
}
|
||||||
style::PaletteChanged(
|
|
||||||
) | rpl::start_with_next([=] {
|
|
||||||
if (_shadow) {
|
|
||||||
_shadow->setColor(st::windowShadowFg->c);
|
|
||||||
}
|
|
||||||
}, lifetime());
|
|
||||||
setupNativeWindowFrame();
|
setupNativeWindowFrame();
|
||||||
|
|
||||||
using namespace rpl::mappers;
|
using namespace rpl::mappers;
|
||||||
|
@ -163,15 +155,7 @@ void MainWindow::setupNativeWindowFrame() {
|
||||||
std::move(nativeFrame),
|
std::move(nativeFrame),
|
||||||
std::move(nightMode)
|
std::move(nightMode)
|
||||||
) | rpl::skip(1) | rpl::start_with_next([=](bool native, bool night) {
|
) | rpl::skip(1) | rpl::start_with_next([=](bool native, bool night) {
|
||||||
const auto nativeChanged = (_wasNativeFrame != native);
|
|
||||||
if (nativeChanged) {
|
|
||||||
_wasNativeFrame = native;
|
|
||||||
initShadows();
|
|
||||||
}
|
|
||||||
validateWindowTheme(native, night);
|
validateWindowTheme(native, night);
|
||||||
if (nativeChanged) {
|
|
||||||
fixMaximizedWindow();
|
|
||||||
}
|
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,23 +170,12 @@ void MainWindow::TaskbarCreated() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::shadowsUpdate(
|
|
||||||
Ui::Platform::WindowShadow::Changes changes,
|
|
||||||
WINDOWPOS *position) {
|
|
||||||
if (_shadow) {
|
|
||||||
_shadow->update(changes, position);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::shadowsActivate() {
|
void MainWindow::shadowsActivate() {
|
||||||
_hasActiveFrame = true;
|
_hasActiveFrame = true;
|
||||||
// _shadow->setColor(_shActive);
|
|
||||||
shadowsUpdate(Ui::Platform::WindowShadow::Change::Activate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::shadowsDeactivate() {
|
void MainWindow::shadowsDeactivate() {
|
||||||
_hasActiveFrame = false;
|
_hasActiveFrame = false;
|
||||||
// _shadow->setColor(_shInactive);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::psShowTrayMenu() {
|
void MainWindow::psShowTrayMenu() {
|
||||||
|
@ -327,7 +300,7 @@ bool MainWindow::initSizeFromSystem() {
|
||||||
if (!screen) {
|
if (!screen) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
setGeometry(screen->availableGeometry());
|
Ui::RpWidget::setGeometry(screen->availableGeometry());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,7 +329,6 @@ bool MainWindow::isActiveForTrayMenu() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::unreadCounterChangedHook() {
|
void MainWindow::unreadCounterChangedHook() {
|
||||||
setWindowTitle(titleText());
|
|
||||||
updateIconCounters();
|
updateIconCounters();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -437,147 +409,9 @@ void MainWindow::initHook() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
psInitSysMenu();
|
validateWindowTheme(
|
||||||
}
|
Core::App().settings().nativeWindowFrame(),
|
||||||
|
Window::Theme::IsNightMode());
|
||||||
void MainWindow::initShadows() {
|
|
||||||
if (Core::App().settings().nativeWindowFrame()) {
|
|
||||||
_shadow.reset();
|
|
||||||
} else {
|
|
||||||
_shadow.emplace(this, st::windowShadowFg->c);
|
|
||||||
}
|
|
||||||
updateCustomMargins();
|
|
||||||
firstShadowsUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::firstShadowsUpdate() {
|
|
||||||
using Change = Ui::Platform::WindowShadow::Change;
|
|
||||||
if ((windowState() & (Qt::WindowMinimized | Qt::WindowMaximized))
|
|
||||||
|| isHidden()) {
|
|
||||||
shadowsUpdate(Change::Hidden);
|
|
||||||
} else {
|
|
||||||
shadowsUpdate(Change::Moved | Change::Resized | Change::Shown);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::stateChangedHook(Qt::WindowState state) {
|
|
||||||
updateSystemMenu(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::psInitSysMenu() {
|
|
||||||
Qt::WindowStates states = windowState();
|
|
||||||
ps_menu = GetSystemMenu(ps_hWnd, FALSE);
|
|
||||||
updateSystemMenu(windowHandle()->windowState());
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::updateSystemMenu(Qt::WindowState state) {
|
|
||||||
if (!ps_menu) return;
|
|
||||||
|
|
||||||
int menuToDisable = SC_RESTORE;
|
|
||||||
if (state == Qt::WindowMaximized) {
|
|
||||||
menuToDisable = SC_MAXIMIZE;
|
|
||||||
} else if (state == Qt::WindowMinimized) {
|
|
||||||
menuToDisable = SC_MINIMIZE;
|
|
||||||
}
|
|
||||||
int itemCount = GetMenuItemCount(ps_menu);
|
|
||||||
for (int i = 0; i < itemCount; ++i) {
|
|
||||||
MENUITEMINFO itemInfo = { 0 };
|
|
||||||
itemInfo.cbSize = sizeof(itemInfo);
|
|
||||||
itemInfo.fMask = MIIM_TYPE | MIIM_STATE | MIIM_ID;
|
|
||||||
if (GetMenuItemInfo(ps_menu, i, TRUE, &itemInfo)) {
|
|
||||||
if (itemInfo.fType & MFT_SEPARATOR) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (itemInfo.wID && !(itemInfo.fState & MFS_DEFAULT)) {
|
|
||||||
UINT fOldState = itemInfo.fState, fState = itemInfo.fState & ~MFS_DISABLED;
|
|
||||||
if (itemInfo.wID == SC_CLOSE) {
|
|
||||||
fState |= MFS_DEFAULT;
|
|
||||||
} else if (itemInfo.wID == menuToDisable || (itemInfo.wID != SC_MINIMIZE && itemInfo.wID != SC_MAXIMIZE && itemInfo.wID != SC_RESTORE)) {
|
|
||||||
fState |= MFS_DISABLED;
|
|
||||||
}
|
|
||||||
itemInfo.fMask = MIIM_STATE;
|
|
||||||
itemInfo.fState = fState;
|
|
||||||
if (!SetMenuItemInfo(ps_menu, i, TRUE, &itemInfo)) {
|
|
||||||
DEBUG_LOG(("PS Error: could not set state %1 to menu item %2, old state %3, error %4").arg(fState).arg(itemInfo.wID).arg(fOldState).arg(GetLastError()));
|
|
||||||
DestroyMenu(ps_menu);
|
|
||||||
ps_menu = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
DEBUG_LOG(("PS Error: could not get state, menu item %1 of %2, error %3").arg(i).arg(itemCount).arg(GetLastError()));
|
|
||||||
DestroyMenu(ps_menu);
|
|
||||||
ps_menu = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::updateCustomMargins() {
|
|
||||||
if (!ps_hWnd || _inUpdateMargins) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_inUpdateMargins = true;
|
|
||||||
|
|
||||||
const auto margins = computeCustomMargins();
|
|
||||||
if (const auto native = QGuiApplication::platformNativeInterface()) {
|
|
||||||
native->setWindowProperty(
|
|
||||||
windowHandle()->handle(),
|
|
||||||
qsl("WindowsCustomMargins"),
|
|
||||||
QVariant::fromValue<QMargins>(margins));
|
|
||||||
}
|
|
||||||
if (!_themeInited) {
|
|
||||||
_themeInited = true;
|
|
||||||
validateWindowTheme(
|
|
||||||
Core::App().settings().nativeWindowFrame(),
|
|
||||||
Window::Theme::IsNightMode());
|
|
||||||
}
|
|
||||||
_inUpdateMargins = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QMargins MainWindow::computeCustomMargins() {
|
|
||||||
if (Core::App().settings().nativeWindowFrame()) {
|
|
||||||
_deltaLeft = _deltaTop = _deltaRight = _deltaBottom = 0;
|
|
||||||
return QMargins();
|
|
||||||
}
|
|
||||||
auto r = RECT();
|
|
||||||
GetClientRect(ps_hWnd, &r);
|
|
||||||
|
|
||||||
auto a = r;
|
|
||||||
const auto style = GetWindowLongPtr(ps_hWnd, GWL_STYLE);
|
|
||||||
const auto styleEx = GetWindowLongPtr(ps_hWnd, GWL_EXSTYLE);
|
|
||||||
AdjustWindowRectEx(&a, style, false, styleEx);
|
|
||||||
auto margins = QMargins(a.left - r.left, a.top - r.top, r.right - a.right, r.bottom - a.bottom);
|
|
||||||
if (style & WS_MAXIMIZE) {
|
|
||||||
RECT w, m;
|
|
||||||
GetWindowRect(ps_hWnd, &w);
|
|
||||||
m = w;
|
|
||||||
|
|
||||||
HMONITOR hMonitor = MonitorFromRect(&w, MONITOR_DEFAULTTONEAREST);
|
|
||||||
if (hMonitor) {
|
|
||||||
MONITORINFO mi;
|
|
||||||
mi.cbSize = sizeof(mi);
|
|
||||||
GetMonitorInfo(hMonitor, &mi);
|
|
||||||
m = mi.rcWork;
|
|
||||||
}
|
|
||||||
|
|
||||||
_deltaLeft = w.left - m.left;
|
|
||||||
_deltaTop = w.top - m.top;
|
|
||||||
_deltaRight = m.right - w.right;
|
|
||||||
_deltaBottom = m.bottom - w.bottom;
|
|
||||||
|
|
||||||
margins.setLeft(margins.left() - _deltaLeft);
|
|
||||||
margins.setRight(margins.right() - _deltaRight);
|
|
||||||
margins.setBottom(margins.bottom() - _deltaBottom);
|
|
||||||
margins.setTop(margins.top() - _deltaTop);
|
|
||||||
} else if (_deltaLeft != 0 || _deltaTop != 0 || _deltaRight != 0 || _deltaBottom != 0) {
|
|
||||||
RECT w;
|
|
||||||
GetWindowRect(ps_hWnd, &w);
|
|
||||||
SetWindowPos(ps_hWnd, 0, 0, 0, w.right - w.left - _deltaLeft - _deltaRight, w.bottom - w.top - _deltaBottom - _deltaTop, SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREPOSITION);
|
|
||||||
_deltaLeft = _deltaTop = _deltaRight = _deltaBottom = 0;
|
|
||||||
}
|
|
||||||
return margins;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::validateWindowTheme(bool native, bool night) {
|
void MainWindow::validateWindowTheme(bool native, bool night) {
|
||||||
|
@ -673,25 +507,6 @@ void MainWindow::validateWindowTheme(bool native, bool night) {
|
||||||
SendMessage(ps_hWnd, WM_NCACTIVATE, _hasActiveFrame ? 1 : 0, 0);
|
SendMessage(ps_hWnd, WM_NCACTIVATE, _hasActiveFrame ? 1 : 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::fixMaximizedWindow() {
|
|
||||||
auto r = RECT();
|
|
||||||
GetClientRect(ps_hWnd, &r);
|
|
||||||
const auto style = GetWindowLongPtr(ps_hWnd, GWL_STYLE);
|
|
||||||
const auto styleEx = GetWindowLongPtr(ps_hWnd, GWL_EXSTYLE);
|
|
||||||
AdjustWindowRectEx(&r, style, false, styleEx);
|
|
||||||
if (style & WS_MAXIMIZE) {
|
|
||||||
auto w = RECT();
|
|
||||||
GetWindowRect(ps_hWnd, &w);
|
|
||||||
if (const auto hMonitor = MonitorFromRect(&w, MONITOR_DEFAULTTONEAREST)) {
|
|
||||||
MONITORINFO mi;
|
|
||||||
mi.cbSize = sizeof(mi);
|
|
||||||
GetMonitorInfo(hMonitor, &mi);
|
|
||||||
const auto m = mi.rcWork;
|
|
||||||
SetWindowPos(ps_hWnd, 0, 0, 0, m.right - m.left - _deltaLeft - _deltaRight, m.bottom - m.top - _deltaTop - _deltaBottom, SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREPOSITION);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::showFromTrayMenu() {
|
void MainWindow::showFromTrayMenu() {
|
||||||
// If we try to activate() window before the trayIconMenu is hidden,
|
// If we try to activate() window before the trayIconMenu is hidden,
|
||||||
// then the window will be shown in semi-active state (Qt bug).
|
// then the window will be shown in semi-active state (Qt bug).
|
||||||
|
@ -707,10 +522,6 @@ HWND MainWindow::psHwnd() const {
|
||||||
return ps_hWnd;
|
return ps_hWnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
HMENU MainWindow::psMenu() const {
|
|
||||||
return ps_menu;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::psDestroyIcons() {
|
void MainWindow::psDestroyIcons() {
|
||||||
if (ps_iconBig) {
|
if (ps_iconBig) {
|
||||||
DestroyIcon(ps_iconBig);
|
DestroyIcon(ps_iconBig);
|
||||||
|
@ -735,7 +546,6 @@ MainWindow::~MainWindow() {
|
||||||
taskbarList.Reset();
|
taskbarList.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ps_menu) DestroyMenu(ps_menu);
|
|
||||||
psDestroyIcons();
|
psDestroyIcons();
|
||||||
if (ps_tbHider_hWnd) DestroyWindow(ps_tbHider_hWnd);
|
if (ps_tbHider_hWnd) DestroyWindow(ps_tbHider_hWnd);
|
||||||
|
|
||||||
|
|
|
@ -8,12 +8,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "platform/platform_main_window.h"
|
#include "platform/platform_main_window.h"
|
||||||
#include "ui/platform/win/ui_window_shadow_win.h"
|
|
||||||
#include "base/platform/win/base_windows_h.h"
|
#include "base/platform/win/base_windows_h.h"
|
||||||
#include "base/flags.h"
|
#include "base/flags.h"
|
||||||
|
|
||||||
#include <QtCore/QTimer>
|
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class PopupMenu;
|
class PopupMenu;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
@ -27,11 +24,6 @@ public:
|
||||||
void showFromTrayMenu() override;
|
void showFromTrayMenu() override;
|
||||||
|
|
||||||
HWND psHwnd() const;
|
HWND psHwnd() const;
|
||||||
HMENU psMenu() const;
|
|
||||||
|
|
||||||
void psInitSysMenu();
|
|
||||||
void updateSystemMenu(Qt::WindowState state);
|
|
||||||
void updateCustomMargins();
|
|
||||||
|
|
||||||
void updateWindowIcon() override;
|
void updateWindowIcon() override;
|
||||||
bool isActiveForTrayMenu() override;
|
bool isActiveForTrayMenu() override;
|
||||||
|
@ -46,16 +38,6 @@ public:
|
||||||
// Custom shadows.
|
// Custom shadows.
|
||||||
void shadowsActivate();
|
void shadowsActivate();
|
||||||
void shadowsDeactivate();
|
void shadowsDeactivate();
|
||||||
void shadowsUpdate(
|
|
||||||
Ui::Platform::WindowShadow::Changes changes,
|
|
||||||
WINDOWPOS *position = nullptr);
|
|
||||||
|
|
||||||
int deltaLeft() const {
|
|
||||||
return _deltaLeft;
|
|
||||||
}
|
|
||||||
int deltaTop() const {
|
|
||||||
return _deltaTop;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] bool hasTabletView() const;
|
[[nodiscard]] bool hasTabletView() const;
|
||||||
|
|
||||||
|
@ -68,10 +50,6 @@ protected:
|
||||||
int32 screenNameChecksum(const QString &name) const override;
|
int32 screenNameChecksum(const QString &name) const override;
|
||||||
void unreadCounterChangedHook() override;
|
void unreadCounterChangedHook() override;
|
||||||
|
|
||||||
void initShadows() override;
|
|
||||||
void firstShadowsUpdate() override;
|
|
||||||
void stateChangedHook(Qt::WindowState state) override;
|
|
||||||
|
|
||||||
bool hasTrayIcon() const override {
|
bool hasTrayIcon() const override {
|
||||||
return trayIcon;
|
return trayIcon;
|
||||||
}
|
}
|
||||||
|
@ -91,25 +69,16 @@ protected:
|
||||||
|
|
||||||
QRect computeDesktopRect() const override;
|
QRect computeDesktopRect() const override;
|
||||||
|
|
||||||
QTimer psUpdatedPositionTimer;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Private;
|
struct Private;
|
||||||
|
|
||||||
void setupNativeWindowFrame();
|
void setupNativeWindowFrame();
|
||||||
void updateIconCounters();
|
void updateIconCounters();
|
||||||
QMargins computeCustomMargins();
|
|
||||||
void validateWindowTheme(bool native, bool night);
|
void validateWindowTheme(bool native, bool night);
|
||||||
void psDestroyIcons();
|
void psDestroyIcons();
|
||||||
void fixMaximizedWindow();
|
|
||||||
|
|
||||||
const std::unique_ptr<Private> _private;
|
const std::unique_ptr<Private> _private;
|
||||||
|
|
||||||
std::optional<Ui::Platform::WindowShadow> _shadow;
|
|
||||||
|
|
||||||
bool _themeInited = false;
|
|
||||||
bool _inUpdateMargins = false;
|
|
||||||
bool _wasNativeFrame = false;
|
|
||||||
bool _hasActiveFrame = false;
|
bool _hasActiveFrame = false;
|
||||||
|
|
||||||
// Workarounds for activation from tray icon.
|
// Workarounds for activation from tray icon.
|
||||||
|
@ -118,16 +87,10 @@ private:
|
||||||
|
|
||||||
HWND ps_hWnd = nullptr;
|
HWND ps_hWnd = nullptr;
|
||||||
HWND ps_tbHider_hWnd = nullptr;
|
HWND ps_tbHider_hWnd = nullptr;
|
||||||
HMENU ps_menu = nullptr;
|
|
||||||
HICON ps_iconBig = nullptr;
|
HICON ps_iconBig = nullptr;
|
||||||
HICON ps_iconSmall = nullptr;
|
HICON ps_iconSmall = nullptr;
|
||||||
HICON ps_iconOverlay = nullptr;
|
HICON ps_iconOverlay = nullptr;
|
||||||
|
|
||||||
int _deltaLeft = 0;
|
|
||||||
int _deltaTop = 0;
|
|
||||||
int _deltaRight = 0;
|
|
||||||
int _deltaBottom = 0;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Platform
|
} // namespace Platform
|
||||||
|
|
|
@ -1,136 +0,0 @@
|
||||||
/*
|
|
||||||
This file is part of Telegram Desktop,
|
|
||||||
the official desktop application for the Telegram messaging service.
|
|
||||||
|
|
||||||
For license and copyright information please follow this link:
|
|
||||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|
||||||
*/
|
|
||||||
#include "platform/win/window_title_win.h"
|
|
||||||
|
|
||||||
#include "ui/widgets/buttons.h"
|
|
||||||
#include "ui/widgets/shadow.h"
|
|
||||||
#include "styles/style_window.h"
|
|
||||||
|
|
||||||
#include <QtGui/QWindow>
|
|
||||||
|
|
||||||
namespace Platform {
|
|
||||||
|
|
||||||
TitleWidget::TitleWidget(QWidget *parent)
|
|
||||||
: Window::TitleWidget(parent)
|
|
||||||
, _st(st::defaultWindowTitle)
|
|
||||||
, _minimize(this, _st.minimize)
|
|
||||||
, _maximizeRestore(this, _st.maximize)
|
|
||||||
, _close(this, _st.close)
|
|
||||||
, _shadow(this, st::titleShadow)
|
|
||||||
, _maximizedState(parent->window()->windowState() & Qt::WindowMaximized) {
|
|
||||||
_minimize->setClickedCallback([=] {
|
|
||||||
window()->setWindowState(
|
|
||||||
window()->windowState() | Qt::WindowMinimized);
|
|
||||||
_minimize->clearState();
|
|
||||||
});
|
|
||||||
_minimize->setPointerCursor(false);
|
|
||||||
_maximizeRestore->setClickedCallback([=] {
|
|
||||||
window()->setWindowState(_maximizedState
|
|
||||||
? Qt::WindowNoState
|
|
||||||
: Qt::WindowMaximized);
|
|
||||||
_maximizeRestore->clearState();
|
|
||||||
});
|
|
||||||
_maximizeRestore->setPointerCursor(false);
|
|
||||||
_close->setClickedCallback([=] {
|
|
||||||
window()->close();
|
|
||||||
_close->clearState();
|
|
||||||
});
|
|
||||||
_close->setPointerCursor(false);
|
|
||||||
|
|
||||||
setAttribute(Qt::WA_OpaquePaintEvent);
|
|
||||||
resize(width(), _st.height);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TitleWidget::init() {
|
|
||||||
connect(
|
|
||||||
window()->windowHandle(),
|
|
||||||
&QWindow::windowStateChanged,
|
|
||||||
this,
|
|
||||||
[=](Qt::WindowState state) { windowStateChanged(state); });
|
|
||||||
_maximizedState = (window()->windowState() & Qt::WindowMaximized);
|
|
||||||
_activeState = isActiveWindow();
|
|
||||||
updateButtonsState();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TitleWidget::paintEvent(QPaintEvent *e) {
|
|
||||||
auto active = isActiveWindow();
|
|
||||||
if (_activeState != active) {
|
|
||||||
_activeState = active;
|
|
||||||
updateButtonsState();
|
|
||||||
}
|
|
||||||
Painter(this).fillRect(rect(), active ? _st.bgActive : _st.bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TitleWidget::updateControlsPosition() {
|
|
||||||
auto right = 0;
|
|
||||||
_close->moveToRight(right, 0); right += _close->width();
|
|
||||||
_maximizeRestore->moveToRight(right, 0); right += _maximizeRestore->width();
|
|
||||||
_minimize->moveToRight(right, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TitleWidget::resizeEvent(QResizeEvent *e) {
|
|
||||||
updateControlsPosition();
|
|
||||||
_shadow->setGeometry(0, height() - st::lineWidth, width(), st::lineWidth);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TitleWidget::windowStateChanged(Qt::WindowState state) {
|
|
||||||
if (state == Qt::WindowMinimized) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto maximized = (state == Qt::WindowMaximized);
|
|
||||||
if (_maximizedState != maximized) {
|
|
||||||
_maximizedState = maximized;
|
|
||||||
updateButtonsState();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TitleWidget::updateButtonsState() {
|
|
||||||
_minimize->setIconOverride(_activeState
|
|
||||||
? &_st.minimizeIconActive
|
|
||||||
: nullptr,
|
|
||||||
_activeState
|
|
||||||
? &_st.minimizeIconActiveOver
|
|
||||||
: nullptr);
|
|
||||||
if (_maximizedState) {
|
|
||||||
_maximizeRestore->setIconOverride(
|
|
||||||
_activeState
|
|
||||||
? &_st.restoreIconActive : &_st.restoreIcon,
|
|
||||||
_activeState
|
|
||||||
? &_st.restoreIconActiveOver
|
|
||||||
: &_st.restoreIconOver);
|
|
||||||
} else {
|
|
||||||
_maximizeRestore->setIconOverride(_activeState
|
|
||||||
? &_st.maximizeIconActive
|
|
||||||
: nullptr,
|
|
||||||
_activeState
|
|
||||||
? &_st.maximizeIconActiveOver
|
|
||||||
: nullptr);
|
|
||||||
}
|
|
||||||
_close->setIconOverride(_activeState
|
|
||||||
? &_st.closeIconActive
|
|
||||||
: nullptr,
|
|
||||||
_activeState
|
|
||||||
? &_st.closeIconActiveOver
|
|
||||||
: nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
Window::HitTestResult TitleWidget::hitTest(const QPoint &p) const {
|
|
||||||
if (false
|
|
||||||
|| (_minimize->geometry().contains(p))
|
|
||||||
|| (_maximizeRestore->geometry().contains(p))
|
|
||||||
|| (_close->geometry().contains(p))
|
|
||||||
) {
|
|
||||||
return Window::HitTestResult::SysButton;
|
|
||||||
} else if (rect().contains(p)) {
|
|
||||||
return Window::HitTestResult::Caption;
|
|
||||||
}
|
|
||||||
return Window::HitTestResult::None;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Platform
|
|
|
@ -1,82 +0,0 @@
|
||||||
/*
|
|
||||||
This file is part of Telegram Desktop,
|
|
||||||
the official desktop application for the Telegram messaging service.
|
|
||||||
|
|
||||||
For license and copyright information please follow this link:
|
|
||||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "platform/platform_window_title.h"
|
|
||||||
#include "base/object_ptr.h"
|
|
||||||
|
|
||||||
namespace style {
|
|
||||||
struct WindowTitle;
|
|
||||||
} // namespace style
|
|
||||||
|
|
||||||
namespace Ui {
|
|
||||||
class IconButton;
|
|
||||||
class PlainShadow;
|
|
||||||
} // namespace Ui
|
|
||||||
|
|
||||||
namespace Window {
|
|
||||||
namespace Theme {
|
|
||||||
|
|
||||||
int DefaultPreviewTitleHeight();
|
|
||||||
void DefaultPreviewWindowFramePaint(QImage &preview, const style::palette &palette, QRect body, int outerWidth);
|
|
||||||
|
|
||||||
} // namespace Theme
|
|
||||||
} // namespace Window
|
|
||||||
|
|
||||||
namespace Platform {
|
|
||||||
|
|
||||||
class TitleWidget : public Window::TitleWidget {
|
|
||||||
public:
|
|
||||||
TitleWidget(QWidget *parent);
|
|
||||||
|
|
||||||
void init() override;
|
|
||||||
|
|
||||||
[[nodiscard]] Window::HitTestResult hitTest(
|
|
||||||
const QPoint &p) const override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void paintEvent(QPaintEvent *e) override;
|
|
||||||
void resizeEvent(QResizeEvent *e) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void windowStateChanged(Qt::WindowState state = Qt::WindowNoState);
|
|
||||||
void updateButtonsState();
|
|
||||||
void updateControlsPosition();
|
|
||||||
|
|
||||||
const style::WindowTitle &_st;
|
|
||||||
object_ptr<Ui::IconButton> _minimize;
|
|
||||||
object_ptr<Ui::IconButton> _maximizeRestore;
|
|
||||||
object_ptr<Ui::IconButton> _close;
|
|
||||||
object_ptr<Ui::PlainShadow> _shadow;
|
|
||||||
|
|
||||||
bool _maximizedState = false;
|
|
||||||
bool _activeState = false;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
inline bool AllowNativeWindowFrameToggle() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline object_ptr<Window::TitleWidget> CreateTitleWidget(QWidget *parent) {
|
|
||||||
return object_ptr<TitleWidget>(parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool NativeTitleRequiresShadow() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int PreviewTitleHeight() {
|
|
||||||
return Window::Theme::DefaultPreviewTitleHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void PreviewWindowFramePaint(QImage &preview, const style::palette &palette, QRect body, int outerWidth) {
|
|
||||||
return Window::Theme::DefaultPreviewWindowFramePaint(preview, palette, body, outerWidth);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Platform
|
|
|
@ -63,7 +63,6 @@ SafeIniter::SafeIniter() {
|
||||||
LOAD_SYMBOL(LibPropSys, PSStringFromPropertyKey);
|
LOAD_SYMBOL(LibPropSys, PSStringFromPropertyKey);
|
||||||
|
|
||||||
const auto LibDwmApi = LoadLibrary(L"dwmapi.dll");
|
const auto LibDwmApi = LoadLibrary(L"dwmapi.dll");
|
||||||
LOAD_SYMBOL(LibDwmApi, DwmIsCompositionEnabled);
|
|
||||||
LOAD_SYMBOL(LibDwmApi, DwmSetWindowAttribute);
|
LOAD_SYMBOL(LibDwmApi, DwmSetWindowAttribute);
|
||||||
|
|
||||||
const auto LibPsApi = LoadLibrary(L"psapi.dll");
|
const auto LibPsApi = LoadLibrary(L"psapi.dll");
|
||||||
|
|
|
@ -96,8 +96,6 @@ inline HRESULT(__stdcall *PSStringFromPropertyKey)(
|
||||||
|
|
||||||
// DWMAPI.DLL
|
// DWMAPI.DLL
|
||||||
|
|
||||||
inline HRESULT(__stdcall *DwmIsCompositionEnabled)(
|
|
||||||
_Out_ BOOL* pfEnabled);
|
|
||||||
inline HRESULT(__stdcall *DwmSetWindowAttribute)(
|
inline HRESULT(__stdcall *DwmSetWindowAttribute)(
|
||||||
HWND hwnd,
|
HWND hwnd,
|
||||||
DWORD dwAttribute,
|
DWORD dwAttribute,
|
||||||
|
|
|
@ -7,12 +7,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#include "platform/win/windows_event_filter.h"
|
#include "platform/win/windows_event_filter.h"
|
||||||
|
|
||||||
#include "platform/win/windows_dlls.h"
|
|
||||||
#include "platform/win/specific_win.h"
|
#include "platform/win/specific_win.h"
|
||||||
#include "core/sandbox.h"
|
#include "core/sandbox.h"
|
||||||
#include "core/core_settings.h"
|
#include "core/core_settings.h"
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
#include "ui/inactive_press.h"
|
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "app.h"
|
#include "app.h"
|
||||||
|
|
||||||
|
@ -23,67 +21,6 @@ namespace {
|
||||||
|
|
||||||
EventFilter *instance = nullptr;
|
EventFilter *instance = nullptr;
|
||||||
|
|
||||||
int menuShown = 0, menuHidden = 0;
|
|
||||||
|
|
||||||
bool IsCompositionEnabled() {
|
|
||||||
if (!Dlls::DwmIsCompositionEnabled) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
auto result = BOOL(FALSE);
|
|
||||||
const auto success = (Dlls::DwmIsCompositionEnabled(&result) == S_OK);
|
|
||||||
return success && result;
|
|
||||||
}
|
|
||||||
|
|
||||||
HWND FindTaskbarWindow(LPRECT rcMon = nullptr) {
|
|
||||||
HWND hTaskbar = nullptr;
|
|
||||||
RECT rcTaskbar, rcMatch;
|
|
||||||
|
|
||||||
while ((hTaskbar = FindWindowEx(
|
|
||||||
nullptr,
|
|
||||||
hTaskbar,
|
|
||||||
L"Shell_TrayWnd",
|
|
||||||
nullptr)) != nullptr) {
|
|
||||||
if (!rcMon) {
|
|
||||||
break; // OK, return first found
|
|
||||||
}
|
|
||||||
if (GetWindowRect(hTaskbar, &rcTaskbar)
|
|
||||||
&& IntersectRect(&rcMatch, &rcTaskbar, rcMon)) {
|
|
||||||
break; // OK, taskbar match monitor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return hTaskbar;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsTaskbarAutoHidden(LPRECT rcMon = nullptr, PUINT pEdge = nullptr) {
|
|
||||||
HWND hTaskbar = FindTaskbarWindow(rcMon);
|
|
||||||
if (!hTaskbar) {
|
|
||||||
if (pEdge) {
|
|
||||||
*pEdge = (UINT)-1;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
APPBARDATA state = {sizeof(state), hTaskbar};
|
|
||||||
APPBARDATA pos = {sizeof(pos), hTaskbar};
|
|
||||||
|
|
||||||
LRESULT lState = SHAppBarMessage(ABM_GETSTATE, &state);
|
|
||||||
bool bAutoHidden = (lState & ABS_AUTOHIDE);
|
|
||||||
|
|
||||||
if (SHAppBarMessage(ABM_GETTASKBARPOS, &pos)) {
|
|
||||||
if (pEdge) {
|
|
||||||
*pEdge = pos.uEdge;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LOG(("Failed to get taskbar pos"));
|
|
||||||
if (pEdge) {
|
|
||||||
*pEdge = ABE_BOTTOM;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return bAutoHidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
EventFilter *EventFilter::CreateInstance(not_null<MainWindow*> window) {
|
EventFilter *EventFilter::CreateInstance(not_null<MainWindow*> window) {
|
||||||
|
@ -125,108 +62,18 @@ bool EventFilter::nativeEventFilter(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EventFilter::customWindowFrameEvent(
|
|
||||||
HWND hWnd,
|
|
||||||
UINT msg,
|
|
||||||
WPARAM wParam,
|
|
||||||
LPARAM lParam,
|
|
||||||
LRESULT *result) {
|
|
||||||
switch (msg) {
|
|
||||||
case WM_NCPAINT: {
|
|
||||||
if (QSysInfo::WindowsVersion >= QSysInfo::WV_WINDOWS8) return false;
|
|
||||||
if (result) *result = 0;
|
|
||||||
} return true;
|
|
||||||
|
|
||||||
case WM_NCCALCSIZE: {
|
|
||||||
WINDOWPLACEMENT wp;
|
|
||||||
wp.length = sizeof(WINDOWPLACEMENT);
|
|
||||||
if (GetWindowPlacement(hWnd, &wp) && wp.showCmd == SW_SHOWMAXIMIZED) {
|
|
||||||
LPNCCALCSIZE_PARAMS params = (LPNCCALCSIZE_PARAMS)lParam;
|
|
||||||
LPRECT r = (wParam == TRUE) ? ¶ms->rgrc[0] : (LPRECT)lParam;
|
|
||||||
HMONITOR hMonitor = MonitorFromPoint({ (r->left + r->right) / 2, (r->top + r->bottom) / 2 }, MONITOR_DEFAULTTONEAREST);
|
|
||||||
if (hMonitor) {
|
|
||||||
MONITORINFO mi;
|
|
||||||
mi.cbSize = sizeof(mi);
|
|
||||||
if (GetMonitorInfo(hMonitor, &mi)) {
|
|
||||||
*r = mi.rcWork;
|
|
||||||
UINT uEdge = (UINT)-1;
|
|
||||||
if (IsTaskbarAutoHidden(&mi.rcMonitor, &uEdge)) {
|
|
||||||
switch (uEdge) {
|
|
||||||
case ABE_LEFT: r->left += 1; break;
|
|
||||||
case ABE_RIGHT: r->right -= 1; break;
|
|
||||||
case ABE_TOP: r->top += 1; break;
|
|
||||||
case ABE_BOTTOM: r->bottom -= 1; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (result) *result = 0;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
case WM_NCACTIVATE: {
|
|
||||||
if (IsCompositionEnabled()) {
|
|
||||||
const auto res = DefWindowProc(hWnd, msg, wParam, -1);
|
|
||||||
if (result) *result = res;
|
|
||||||
} else {
|
|
||||||
// Thanks https://github.com/melak47/BorderlessWindow
|
|
||||||
if (result) *result = 1;
|
|
||||||
}
|
|
||||||
} return true;
|
|
||||||
|
|
||||||
case WM_NCHITTEST: {
|
|
||||||
if (!result) return false;
|
|
||||||
|
|
||||||
POINTS p = MAKEPOINTS(lParam);
|
|
||||||
RECT r;
|
|
||||||
GetWindowRect(hWnd, &r);
|
|
||||||
auto res = _window->hitTest(QPoint(p.x - r.left + _window->deltaLeft(), p.y - r.top + _window->deltaTop()));
|
|
||||||
switch (res) {
|
|
||||||
case Window::HitTestResult::Client:
|
|
||||||
case Window::HitTestResult::SysButton: *result = HTCLIENT; break;
|
|
||||||
case Window::HitTestResult::Caption: *result = HTCAPTION; break;
|
|
||||||
case Window::HitTestResult::Top: *result = HTTOP; break;
|
|
||||||
case Window::HitTestResult::TopRight: *result = HTTOPRIGHT; break;
|
|
||||||
case Window::HitTestResult::Right: *result = HTRIGHT; break;
|
|
||||||
case Window::HitTestResult::BottomRight: *result = HTBOTTOMRIGHT; break;
|
|
||||||
case Window::HitTestResult::Bottom: *result = HTBOTTOM; break;
|
|
||||||
case Window::HitTestResult::BottomLeft: *result = HTBOTTOMLEFT; break;
|
|
||||||
case Window::HitTestResult::Left: *result = HTLEFT; break;
|
|
||||||
case Window::HitTestResult::TopLeft: *result = HTTOPLEFT; break;
|
|
||||||
case Window::HitTestResult::None:
|
|
||||||
default: *result = HTTRANSPARENT; break;
|
|
||||||
};
|
|
||||||
} return true;
|
|
||||||
|
|
||||||
case WM_NCRBUTTONUP: {
|
|
||||||
SendMessage(hWnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam);
|
|
||||||
} return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EventFilter::mainWindowEvent(
|
bool EventFilter::mainWindowEvent(
|
||||||
HWND hWnd,
|
HWND hWnd,
|
||||||
UINT msg,
|
UINT msg,
|
||||||
WPARAM wParam,
|
WPARAM wParam,
|
||||||
LPARAM lParam,
|
LPARAM lParam,
|
||||||
LRESULT *result) {
|
LRESULT *result) {
|
||||||
using Change = Ui::Platform::WindowShadow::Change;
|
|
||||||
|
|
||||||
if (const auto tbCreatedMsgId = Platform::MainWindow::TaskbarCreatedMsgId()) {
|
if (const auto tbCreatedMsgId = Platform::MainWindow::TaskbarCreatedMsgId()) {
|
||||||
if (msg == tbCreatedMsgId) {
|
if (msg == tbCreatedMsgId) {
|
||||||
Platform::MainWindow::TaskbarCreated();
|
Platform::MainWindow::TaskbarCreated();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Core::App().settings().nativeWindowFrame()) {
|
|
||||||
if (customWindowFrameEvent(hWnd, msg, wParam, lParam, result)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (msg) {
|
switch (msg) {
|
||||||
|
|
||||||
case WM_TIMECHANGE: {
|
case WM_TIMECHANGE: {
|
||||||
|
@ -246,91 +93,25 @@ bool EventFilter::mainWindowEvent(
|
||||||
} return false;
|
} return false;
|
||||||
|
|
||||||
case WM_ACTIVATE: {
|
case WM_ACTIVATE: {
|
||||||
if (LOWORD(wParam) == WA_CLICKACTIVE) {
|
|
||||||
Ui::MarkInactivePress(_window, true);
|
|
||||||
}
|
|
||||||
if (LOWORD(wParam) != WA_INACTIVE) {
|
if (LOWORD(wParam) != WA_INACTIVE) {
|
||||||
_window->shadowsActivate();
|
_window->shadowsActivate();
|
||||||
} else {
|
} else {
|
||||||
_window->shadowsDeactivate();
|
_window->shadowsDeactivate();
|
||||||
}
|
}
|
||||||
_window->update();
|
|
||||||
} return false;
|
|
||||||
|
|
||||||
case WM_WINDOWPOSCHANGING:
|
|
||||||
case WM_WINDOWPOSCHANGED: {
|
|
||||||
WINDOWPLACEMENT wp;
|
|
||||||
wp.length = sizeof(WINDOWPLACEMENT);
|
|
||||||
if (_window->hasTabletView()
|
|
||||||
|| (GetWindowPlacement(hWnd, &wp)
|
|
||||||
&& (wp.showCmd == SW_SHOWMAXIMIZED
|
|
||||||
|| wp.showCmd == SW_SHOWMINIMIZED))) {
|
|
||||||
_window->shadowsUpdate(Change::Hidden);
|
|
||||||
} else {
|
|
||||||
_window->shadowsUpdate(Change::Moved | Change::Resized, (WINDOWPOS*)lParam);
|
|
||||||
}
|
|
||||||
} return false;
|
} return false;
|
||||||
|
|
||||||
case WM_SIZE: {
|
case WM_SIZE: {
|
||||||
if (wParam == SIZE_MAXIMIZED || wParam == SIZE_RESTORED || wParam == SIZE_MINIMIZED) {
|
if (wParam == SIZE_MAXIMIZED || wParam == SIZE_RESTORED || wParam == SIZE_MINIMIZED) {
|
||||||
if (wParam != SIZE_RESTORED || _window->windowState() != Qt::WindowNoState) {
|
if (wParam == SIZE_RESTORED && _window->windowState() == Qt::WindowNoState) {
|
||||||
Qt::WindowState state = Qt::WindowNoState;
|
|
||||||
if (wParam == SIZE_MAXIMIZED) {
|
|
||||||
state = Qt::WindowMaximized;
|
|
||||||
} else if (wParam == SIZE_MINIMIZED) {
|
|
||||||
state = Qt::WindowMinimized;
|
|
||||||
}
|
|
||||||
_window->windowHandle()->windowStateChanged(state);
|
|
||||||
} else {
|
|
||||||
_window->positionUpdated();
|
_window->positionUpdated();
|
||||||
}
|
}
|
||||||
_window->updateCustomMargins();
|
|
||||||
const auto changes = (wParam == SIZE_MINIMIZED || wParam == SIZE_MAXIMIZED) ? Change::Hidden : (Change::Resized | Change::Shown);
|
|
||||||
_window->shadowsUpdate(changes);
|
|
||||||
}
|
}
|
||||||
} return false;
|
} return false;
|
||||||
|
|
||||||
case WM_SHOWWINDOW: {
|
|
||||||
LONG style = GetWindowLongPtr(hWnd, GWL_STYLE);
|
|
||||||
const auto changes = Change::Resized | ((wParam && !(style & (WS_MAXIMIZE | WS_MINIMIZE))) ? Change::Shown : Change::Hidden);
|
|
||||||
_window->shadowsUpdate(changes);
|
|
||||||
} return false;
|
|
||||||
|
|
||||||
case WM_MOVE: {
|
case WM_MOVE: {
|
||||||
_window->shadowsUpdate(Change::Moved);
|
|
||||||
_window->positionUpdated();
|
_window->positionUpdated();
|
||||||
} return false;
|
} return false;
|
||||||
|
|
||||||
case WM_SYSCOMMAND: {
|
|
||||||
if (wParam == SC_MOUSEMENU) {
|
|
||||||
POINTS p = MAKEPOINTS(lParam);
|
|
||||||
_window->updateSystemMenu(_window->windowHandle()->windowState());
|
|
||||||
TrackPopupMenu(_window->psMenu(), TPM_LEFTALIGN | TPM_TOPALIGN | TPM_LEFTBUTTON, p.x, p.y, 0, hWnd, 0);
|
|
||||||
}
|
|
||||||
} return false;
|
|
||||||
|
|
||||||
case WM_COMMAND: {
|
|
||||||
if (HIWORD(wParam)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int cmd = LOWORD(wParam);
|
|
||||||
switch (cmd) {
|
|
||||||
case SC_CLOSE:
|
|
||||||
_window->close();
|
|
||||||
return true;
|
|
||||||
case SC_MINIMIZE:
|
|
||||||
_window->setWindowState(
|
|
||||||
_window->windowState() | Qt::WindowMinimized);
|
|
||||||
return true;
|
|
||||||
case SC_MAXIMIZE:
|
|
||||||
_window->setWindowState(Qt::WindowMaximized);
|
|
||||||
return true;
|
|
||||||
case SC_RESTORE:
|
|
||||||
_window->setWindowState(Qt::WindowNoState);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} return true;
|
|
||||||
|
|
||||||
case WM_SETTINGCHANGE: {
|
case WM_SETTINGCHANGE: {
|
||||||
Core::App().settings().setSystemDarkMode(Platform::IsDarkMode());
|
Core::App().settings().setSystemDarkMode(Platform::IsDarkMode());
|
||||||
} return false;
|
} return false;
|
||||||
|
|
|
@ -26,13 +26,6 @@ public:
|
||||||
private:
|
private:
|
||||||
explicit EventFilter(not_null<MainWindow*> window);
|
explicit EventFilter(not_null<MainWindow*> window);
|
||||||
|
|
||||||
bool customWindowFrameEvent(
|
|
||||||
HWND hWnd,
|
|
||||||
UINT msg,
|
|
||||||
WPARAM wParam,
|
|
||||||
LPARAM lParam,
|
|
||||||
LRESULT *result);
|
|
||||||
|
|
||||||
not_null<MainWindow*> _window;
|
not_null<MainWindow*> _window;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -22,7 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "boxes/about_box.h"
|
#include "boxes/about_box.h"
|
||||||
#include "boxes/confirm_box.h"
|
#include "boxes/confirm_box.h"
|
||||||
#include "platform/platform_specific.h"
|
#include "platform/platform_specific.h"
|
||||||
#include "platform/platform_window_title.h"
|
#include "ui/platform/ui_platform_window.h"
|
||||||
#include "base/platform/base_platform_info.h"
|
#include "base/platform/base_platform_info.h"
|
||||||
#include "window/window_controller.h"
|
#include "window/window_controller.h"
|
||||||
#include "window/window_session_controller.h"
|
#include "window/window_session_controller.h"
|
||||||
|
@ -406,7 +406,7 @@ void SetupSystemIntegrationContent(
|
||||||
}, taskbar->lifetime());
|
}, taskbar->lifetime());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Platform::AllowNativeWindowFrameToggle()) {
|
if (Ui::Platform::NativeWindowFrameSupported()) {
|
||||||
const auto nativeFrame = addCheckbox(
|
const auto nativeFrame = addCheckbox(
|
||||||
tr::lng_settings_native_frame(),
|
tr::lng_settings_native_frame(),
|
||||||
Core::App().settings().nativeWindowFrame());
|
Core::App().settings().nativeWindowFrame());
|
||||||
|
|
|
@ -9,9 +9,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "storage/localstorage.h"
|
#include "storage/localstorage.h"
|
||||||
#include "platform/platform_specific.h"
|
#include "platform/platform_specific.h"
|
||||||
|
#include "ui/platform/ui_platform_window.h"
|
||||||
#include "platform/platform_window_title.h"
|
#include "platform/platform_window_title.h"
|
||||||
#include "base/platform/base_platform_info.h"
|
#include "base/platform/base_platform_info.h"
|
||||||
#include "ui/platform/ui_platform_utility.h"
|
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
#include "window/window_session_controller.h"
|
#include "window/window_session_controller.h"
|
||||||
#include "window/window_lock_widgets.h"
|
#include "window/window_lock_widgets.h"
|
||||||
|
@ -161,9 +161,8 @@ QIcon CreateIcon(Main::Session *session) {
|
||||||
MainWindow::MainWindow(not_null<Controller*> controller)
|
MainWindow::MainWindow(not_null<Controller*> controller)
|
||||||
: _controller(controller)
|
: _controller(controller)
|
||||||
, _positionUpdatedTimer([=] { savePosition(); })
|
, _positionUpdatedTimer([=] { savePosition(); })
|
||||||
, _outdated(CreateOutdatedBar(this))
|
, _outdated(CreateOutdatedBar(body()))
|
||||||
, _body(this)
|
, _body(body()) {
|
||||||
, _titleText(qsl("Telegram")) {
|
|
||||||
style::PaletteChanged(
|
style::PaletteChanged(
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
updatePalette();
|
updatePalette();
|
||||||
|
@ -266,8 +265,6 @@ QRect MainWindow::desktopRect() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::init() {
|
void MainWindow::init() {
|
||||||
Expects(!windowHandle());
|
|
||||||
|
|
||||||
createWinId();
|
createWinId();
|
||||||
|
|
||||||
initHook();
|
initHook();
|
||||||
|
@ -293,7 +290,7 @@ void MainWindow::init() {
|
||||||
|
|
||||||
updatePalette();
|
updatePalette();
|
||||||
|
|
||||||
if (Platform::AllowNativeWindowFrameToggle()) {
|
if (Ui::Platform::NativeWindowFrameSupported()) {
|
||||||
Core::App().settings().nativeWindowFrameChanges(
|
Core::App().settings().nativeWindowFrameChanges(
|
||||||
) | rpl::start_with_next([=](bool native) {
|
) | rpl::start_with_next([=](bool native) {
|
||||||
refreshTitleWidget();
|
refreshTitleWidget();
|
||||||
|
@ -308,7 +305,6 @@ void MainWindow::init() {
|
||||||
|
|
||||||
void MainWindow::handleStateChanged(Qt::WindowState state) {
|
void MainWindow::handleStateChanged(Qt::WindowState state) {
|
||||||
stateChangedHook(state);
|
stateChangedHook(state);
|
||||||
updateShadowSize();
|
|
||||||
updateControlsGeometry();
|
updateControlsGeometry();
|
||||||
if (state == Qt::WindowMinimized) {
|
if (state == Qt::WindowMinimized) {
|
||||||
controller().updateIsActiveBlur();
|
controller().updateIsActiveBlur();
|
||||||
|
@ -381,27 +377,6 @@ void MainWindow::updatePalette() {
|
||||||
setPalette(p);
|
setPalette(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
HitTestResult MainWindow::hitTest(const QPoint &p) const {
|
|
||||||
auto titleResult = _title ? _title->hitTest(p - _title->geometry().topLeft()) : Window::HitTestResult::None;
|
|
||||||
if (titleResult != Window::HitTestResult::None) {
|
|
||||||
return titleResult;
|
|
||||||
} else if (rect().contains(p)) {
|
|
||||||
return Window::HitTestResult::Client;
|
|
||||||
}
|
|
||||||
return Window::HitTestResult::None;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MainWindow::hasShadow() const {
|
|
||||||
const auto center = geometry().center();
|
|
||||||
return Ui::Platform::WindowExtentsSupported()
|
|
||||||
&& Ui::Platform::TranslucentWindowsSupported(center)
|
|
||||||
&& _title;
|
|
||||||
}
|
|
||||||
|
|
||||||
QRect MainWindow::inner() const {
|
|
||||||
return rect().marginsRemoved(_padding);
|
|
||||||
}
|
|
||||||
|
|
||||||
int MainWindow::computeMinWidth() const {
|
int MainWindow::computeMinWidth() const {
|
||||||
auto result = st::windowMinWidth;
|
auto result = st::windowMinWidth;
|
||||||
if (const auto session = _controller->sessionController()) {
|
if (const auto session = _controller->sessionController()) {
|
||||||
|
@ -412,38 +387,32 @@ int MainWindow::computeMinWidth() const {
|
||||||
if (_rightColumn) {
|
if (_rightColumn) {
|
||||||
result += _rightColumn->width();
|
result += _rightColumn->width();
|
||||||
}
|
}
|
||||||
return result + _padding.left() + _padding.right();
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int MainWindow::computeMinHeight() const {
|
int MainWindow::computeMinHeight() const {
|
||||||
const auto title = _title ? _title->height() : 0;
|
|
||||||
const auto outdated = [&] {
|
const auto outdated = [&] {
|
||||||
if (!_outdated) {
|
if (!_outdated) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
_outdated->resizeToWidth(st::windowMinWidth - _padding.left() - _padding.right());
|
_outdated->resizeToWidth(st::windowMinWidth);
|
||||||
return _outdated->height();
|
return _outdated->height();
|
||||||
}();
|
}();
|
||||||
return title + outdated + st::windowMinHeight + _padding.top() + _padding.bottom();
|
return outdated + st::windowMinHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::refreshTitleWidget() {
|
void MainWindow::refreshTitleWidget() {
|
||||||
if (Platform::AllowNativeWindowFrameToggle()
|
if (Ui::Platform::NativeWindowFrameSupported()
|
||||||
&& Core::App().settings().nativeWindowFrame()) {
|
&& Core::App().settings().nativeWindowFrame()) {
|
||||||
_title.destroy();
|
setNativeFrame(true);
|
||||||
if (Platform::NativeTitleRequiresShadow()) {
|
if (Platform::NativeTitleRequiresShadow()) {
|
||||||
_titleShadow.create(this);
|
_titleShadow.create(this);
|
||||||
_titleShadow->show();
|
_titleShadow->show();
|
||||||
}
|
}
|
||||||
} else if ((_title = Platform::CreateTitleWidget(this))) {
|
} else {
|
||||||
_title->show();
|
setNativeFrame(false);
|
||||||
_title->init();
|
|
||||||
_titleShadow.destroy();
|
_titleShadow.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto withShadow = hasShadow();
|
|
||||||
windowHandle()->setFlag(Qt::NoDropShadowWindowHint, withShadow);
|
|
||||||
setAttribute(Qt::WA_OpaquePaintEvent, !withShadow);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::updateMinimumSize() {
|
void MainWindow::updateMinimumSize() {
|
||||||
|
@ -451,21 +420,13 @@ void MainWindow::updateMinimumSize() {
|
||||||
setMinimumHeight(computeMinHeight());
|
setMinimumHeight(computeMinHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::updateShadowSize() {
|
|
||||||
_padding = hasShadow() && !isMaximized()
|
|
||||||
? st::callShadow.extend
|
|
||||||
: style::margins();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::recountGeometryConstraints() {
|
void MainWindow::recountGeometryConstraints() {
|
||||||
updateShadowSize();
|
|
||||||
updateMinimumSize();
|
updateMinimumSize();
|
||||||
updateControlsGeometry();
|
updateControlsGeometry();
|
||||||
fixOrder();
|
fixOrder();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::initSize() {
|
void MainWindow::initSize() {
|
||||||
updateShadowSize();
|
|
||||||
updateMinimumSize();
|
updateMinimumSize();
|
||||||
|
|
||||||
if (initSizeFromSystem()) {
|
if (initSizeFromSystem()) {
|
||||||
|
@ -565,7 +526,6 @@ void MainWindow::initSize() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
geometry += _padding;
|
|
||||||
DEBUG_LOG(("Window Pos: Setting first %1, %2, %3, %4").arg(geometry.x()).arg(geometry.y()).arg(geometry.width()).arg(geometry.height()));
|
DEBUG_LOG(("Window Pos: Setting first %1, %2, %3, %4").arg(geometry.x()).arg(geometry.y()).arg(geometry.width()).arg(geometry.height()));
|
||||||
setGeometry(geometry);
|
setGeometry(geometry);
|
||||||
}
|
}
|
||||||
|
@ -574,18 +534,6 @@ void MainWindow::positionUpdated() {
|
||||||
_positionUpdatedTimer.callOnce(kSaveWindowPositionTimeout);
|
_positionUpdatedTimer.callOnce(kSaveWindowPositionTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MainWindow::titleVisible() const {
|
|
||||||
return _title && !_title->isHidden();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::setTitleVisible(bool visible) {
|
|
||||||
if (_title && (_title->isHidden() == visible)) {
|
|
||||||
_title->setVisible(visible);
|
|
||||||
updateControlsGeometry();
|
|
||||||
}
|
|
||||||
titleVisibilityChangedHook();
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 MainWindow::screenNameChecksum(const QString &name) const {
|
int32 MainWindow::screenNameChecksum(const QString &name) const {
|
||||||
const auto bytes = name.toUtf8();
|
const auto bytes = name.toUtf8();
|
||||||
return base::crc32(bytes.constData(), bytes.size());
|
return base::crc32(bytes.constData(), bytes.size());
|
||||||
|
@ -605,15 +553,7 @@ void MainWindow::attachToTrayIcon(not_null<QSystemTrayIcon*> icon) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::paintEvent(QPaintEvent *e) {
|
|
||||||
if (hasShadow() && !isMaximized()) {
|
|
||||||
QPainter p(this);
|
|
||||||
Ui::Shadow::paint(p, inner(), width(), st::callShadow);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::resizeEvent(QResizeEvent *e) {
|
void MainWindow::resizeEvent(QResizeEvent *e) {
|
||||||
updateShadowSize();
|
|
||||||
updateControlsGeometry();
|
updateControlsGeometry();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -626,14 +566,10 @@ void MainWindow::leaveEventHook(QEvent *e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::updateControlsGeometry() {
|
void MainWindow::updateControlsGeometry() {
|
||||||
const auto inner = this->inner();
|
const auto inner = body()->rect();
|
||||||
auto bodyLeft = inner.x();
|
auto bodyLeft = inner.x();
|
||||||
auto bodyTop = inner.y();
|
auto bodyTop = inner.y();
|
||||||
auto bodyWidth = inner.width();
|
auto bodyWidth = inner.width();
|
||||||
if (_title && !_title->isHidden()) {
|
|
||||||
_title->setGeometry(inner.x(), bodyTop, inner.width(), _title->height());
|
|
||||||
bodyTop += _title->height();
|
|
||||||
}
|
|
||||||
if (_titleShadow) {
|
if (_titleShadow) {
|
||||||
_titleShadow->setGeometry(inner.x(), bodyTop, inner.width(), st::lineWidth);
|
_titleShadow->setGeometry(inner.x(), bodyTop, inner.width(), st::lineWidth);
|
||||||
}
|
}
|
||||||
|
@ -656,7 +592,7 @@ void MainWindow::updateUnreadCounter() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto counter = Core::App().unreadBadge();
|
const auto counter = Core::App().unreadBadge();
|
||||||
_titleText = (counter > 0) ? qsl("Telegram (%1)").arg(counter) : qsl("Telegram");
|
setTitle((counter > 0) ? qsl("Telegram (%1)").arg(counter) : qsl("Telegram"));
|
||||||
|
|
||||||
unreadCounterChangedHook();
|
unreadCounterChangedHook();
|
||||||
}
|
}
|
||||||
|
@ -683,7 +619,7 @@ void MainWindow::savePosition(Qt::WindowState state) {
|
||||||
realPosition.maximized = 1;
|
realPosition.maximized = 1;
|
||||||
DEBUG_LOG(("Window Pos: Saving maximized position."));
|
DEBUG_LOG(("Window Pos: Saving maximized position."));
|
||||||
} else {
|
} else {
|
||||||
auto r = geometry().marginsRemoved(_padding);
|
auto r = body()->mapToGlobal(body()->rect());
|
||||||
realPosition.x = r.x();
|
realPosition.x = r.x();
|
||||||
realPosition.y = r.y();
|
realPosition.y = r.y();
|
||||||
realPosition.w = r.width() - (_rightColumn ? _rightColumn->width() : 0);
|
realPosition.w = r.width() - (_rightColumn ? _rightColumn->width() : 0);
|
||||||
|
@ -774,7 +710,7 @@ void MainWindow::showRightColumn(object_ptr<TWidget> widget) {
|
||||||
const auto wasRightWidth = _rightColumn ? _rightColumn->width() : 0;
|
const auto wasRightWidth = _rightColumn ? _rightColumn->width() : 0;
|
||||||
_rightColumn = std::move(widget);
|
_rightColumn = std::move(widget);
|
||||||
if (_rightColumn) {
|
if (_rightColumn) {
|
||||||
_rightColumn->setParent(this);
|
_rightColumn->setParent(body());
|
||||||
_rightColumn->show();
|
_rightColumn->show();
|
||||||
_rightColumn->setFocus();
|
_rightColumn->setFocus();
|
||||||
} else {
|
} else {
|
||||||
|
@ -799,12 +735,12 @@ void MainWindow::showRightColumn(object_ptr<TWidget> widget) {
|
||||||
|
|
||||||
int MainWindow::maximalExtendBy() const {
|
int MainWindow::maximalExtendBy() const {
|
||||||
auto desktop = QDesktopWidget().availableGeometry(this);
|
auto desktop = QDesktopWidget().availableGeometry(this);
|
||||||
return std::max(desktop.width() - inner().width(), 0);
|
return std::max(desktop.width() - body()->width(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MainWindow::canExtendNoMove(int extendBy) const {
|
bool MainWindow::canExtendNoMove(int extendBy) const {
|
||||||
auto desktop = QDesktopWidget().availableGeometry(this);
|
auto desktop = QDesktopWidget().availableGeometry(this);
|
||||||
auto inner = geometry().marginsRemoved(_padding);
|
auto inner = body()->mapToGlobal(body()->rect());
|
||||||
auto innerRight = (inner.x() + inner.width() + extendBy);
|
auto innerRight = (inner.x() + inner.width() + extendBy);
|
||||||
auto desktopRight = (desktop.x() + desktop.width());
|
auto desktopRight = (desktop.x() + desktop.width());
|
||||||
return innerRight <= desktopRight;
|
return innerRight <= desktopRight;
|
||||||
|
@ -812,7 +748,7 @@ bool MainWindow::canExtendNoMove(int extendBy) const {
|
||||||
|
|
||||||
int MainWindow::tryToExtendWidthBy(int addToWidth) {
|
int MainWindow::tryToExtendWidthBy(int addToWidth) {
|
||||||
auto desktop = QDesktopWidget().availableGeometry(this);
|
auto desktop = QDesktopWidget().availableGeometry(this);
|
||||||
auto inner = geometry();
|
auto inner = body()->mapToGlobal(body()->rect());
|
||||||
accumulate_min(
|
accumulate_min(
|
||||||
addToWidth,
|
addToWidth,
|
||||||
std::max(desktop.width() - inner.width(), 0));
|
std::max(desktop.width() - inner.width(), 0));
|
||||||
|
@ -821,7 +757,7 @@ int MainWindow::tryToExtendWidthBy(int addToWidth) {
|
||||||
inner.x(),
|
inner.x(),
|
||||||
desktop.x() + desktop.width() - newWidth);
|
desktop.x() + desktop.width() - newWidth);
|
||||||
if (inner.x() != newLeft || inner.width() != newWidth) {
|
if (inner.x() != newLeft || inner.width() != newWidth) {
|
||||||
setGeometry(newLeft, inner.y(), newWidth, inner.height());
|
setGeometry(QRect(newLeft, inner.y(), newWidth, inner.height()));
|
||||||
} else {
|
} else {
|
||||||
updateControlsGeometry();
|
updateControlsGeometry();
|
||||||
}
|
}
|
||||||
|
@ -841,8 +777,6 @@ void MainWindow::launchDrag(
|
||||||
}
|
}
|
||||||
|
|
||||||
MainWindow::~MainWindow() {
|
MainWindow::~MainWindow() {
|
||||||
_title.destroy();
|
|
||||||
|
|
||||||
// Otherwise:
|
// Otherwise:
|
||||||
// ~QWidget
|
// ~QWidget
|
||||||
// QWidgetPrivate::close_helper
|
// QWidgetPrivate::close_helper
|
||||||
|
|
|
@ -7,8 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "window/window_title.h"
|
#include "ui/widgets/rp_window.h"
|
||||||
#include "ui/rp_widget.h"
|
|
||||||
#include "base/timer.h"
|
#include "base/timer.h"
|
||||||
#include "base/object_ptr.h"
|
#include "base/object_ptr.h"
|
||||||
#include "core/core_settings.h"
|
#include "core/core_settings.h"
|
||||||
|
@ -37,7 +36,7 @@ QImage LoadLogoNoMargin();
|
||||||
QIcon CreateIcon(Main::Session *session = nullptr);
|
QIcon CreateIcon(Main::Session *session = nullptr);
|
||||||
void ConvertIconToBlack(QImage &image);
|
void ConvertIconToBlack(QImage &image);
|
||||||
|
|
||||||
class MainWindow : public Ui::RpWidget {
|
class MainWindow : public Ui::RpWindow {
|
||||||
public:
|
public:
|
||||||
explicit MainWindow(not_null<Controller*> controller);
|
explicit MainWindow(not_null<Controller*> controller);
|
||||||
virtual ~MainWindow();
|
virtual ~MainWindow();
|
||||||
|
@ -60,7 +59,6 @@ public:
|
||||||
[[nodiscard]] QRect desktopRect() const;
|
[[nodiscard]] QRect desktopRect() const;
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
[[nodiscard]] HitTestResult hitTest(const QPoint &p) const;
|
|
||||||
|
|
||||||
void updateIsActive();
|
void updateIsActive();
|
||||||
|
|
||||||
|
@ -77,12 +75,6 @@ public:
|
||||||
}
|
}
|
||||||
void positionUpdated();
|
void positionUpdated();
|
||||||
|
|
||||||
bool titleVisible() const;
|
|
||||||
void setTitleVisible(bool visible);
|
|
||||||
QString titleText() const {
|
|
||||||
return _titleText;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reActivateWindow();
|
void reActivateWindow();
|
||||||
|
|
||||||
void showRightColumn(object_ptr<TWidget> widget);
|
void showRightColumn(object_ptr<TWidget> widget);
|
||||||
|
@ -112,22 +104,18 @@ public:
|
||||||
|
|
||||||
void clearWidgets();
|
void clearWidgets();
|
||||||
|
|
||||||
QRect inner() const;
|
|
||||||
int computeMinWidth() const;
|
int computeMinWidth() const;
|
||||||
int computeMinHeight() const;
|
int computeMinHeight() const;
|
||||||
|
|
||||||
void recountGeometryConstraints();
|
void recountGeometryConstraints();
|
||||||
virtual void updateControlsGeometry();
|
virtual void updateControlsGeometry();
|
||||||
|
|
||||||
bool hasShadow() const;
|
|
||||||
|
|
||||||
bool minimizeToTray();
|
bool minimizeToTray();
|
||||||
void updateGlobalMenu() {
|
void updateGlobalMenu() {
|
||||||
updateGlobalMenuHook();
|
updateGlobalMenuHook();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void paintEvent(QPaintEvent *e) override;
|
|
||||||
void resizeEvent(QResizeEvent *e) override;
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
void leaveEventHook(QEvent *e) override;
|
void leaveEventHook(QEvent *e) override;
|
||||||
|
|
||||||
|
@ -154,9 +142,6 @@ protected:
|
||||||
virtual void stateChangedHook(Qt::WindowState state) {
|
virtual void stateChangedHook(Qt::WindowState state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void titleVisibilityChangedHook() {
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void unreadCounterChangedHook() {
|
virtual void unreadCounterChangedHook() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,10 +165,6 @@ protected:
|
||||||
|
|
||||||
virtual void createGlobalMenu() {
|
virtual void createGlobalMenu() {
|
||||||
}
|
}
|
||||||
virtual void initShadows() {
|
|
||||||
}
|
|
||||||
virtual void firstShadowsUpdate() {
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool initSizeFromSystem() {
|
virtual bool initSizeFromSystem() {
|
||||||
return false;
|
return false;
|
||||||
|
@ -203,7 +184,6 @@ protected:
|
||||||
private:
|
private:
|
||||||
void refreshTitleWidget();
|
void refreshTitleWidget();
|
||||||
void updateMinimumSize();
|
void updateMinimumSize();
|
||||||
void updateShadowSize();
|
|
||||||
void updatePalette();
|
void updatePalette();
|
||||||
void initSize();
|
void initSize();
|
||||||
|
|
||||||
|
@ -214,7 +194,6 @@ private:
|
||||||
base::Timer _positionUpdatedTimer;
|
base::Timer _positionUpdatedTimer;
|
||||||
bool _positionInited = false;
|
bool _positionInited = false;
|
||||||
|
|
||||||
object_ptr<TitleWidget> _title = { nullptr };
|
|
||||||
object_ptr<Ui::PlainShadow> _titleShadow = { nullptr };
|
object_ptr<Ui::PlainShadow> _titleShadow = { nullptr };
|
||||||
object_ptr<Ui::RpWidget> _outdated;
|
object_ptr<Ui::RpWidget> _outdated;
|
||||||
object_ptr<Ui::RpWidget> _body;
|
object_ptr<Ui::RpWidget> _body;
|
||||||
|
@ -222,8 +201,6 @@ private:
|
||||||
|
|
||||||
QIcon _icon;
|
QIcon _icon;
|
||||||
bool _usingSupportIcon = false;
|
bool _usingSupportIcon = false;
|
||||||
QString _titleText;
|
|
||||||
style::margins _padding;
|
|
||||||
|
|
||||||
bool _isActive = false;
|
bool _isActive = false;
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
#include "core/click_handler_types.h"
|
#include "core/click_handler_types.h"
|
||||||
#include "export/export_manager.h"
|
#include "export/export_manager.h"
|
||||||
|
#include "ui/platform/ui_platform_window.h"
|
||||||
#include "platform/platform_window_title.h"
|
#include "platform/platform_window_title.h"
|
||||||
#include "main/main_account.h"
|
#include "main/main_account.h"
|
||||||
#include "main/main_domain.h"
|
#include "main/main_domain.h"
|
||||||
|
@ -267,7 +268,7 @@ void Controller::showSettings() {
|
||||||
|
|
||||||
int Controller::verticalShadowTop() const {
|
int Controller::verticalShadowTop() const {
|
||||||
return (Platform::NativeTitleRequiresShadow()
|
return (Platform::NativeTitleRequiresShadow()
|
||||||
&& Platform::AllowNativeWindowFrameToggle()
|
&& Ui::Platform::NativeWindowFrameSupported()
|
||||||
&& Core::App().settings().nativeWindowFrame())
|
&& Core::App().settings().nativeWindowFrame())
|
||||||
? st::lineWidth
|
? st::lineWidth
|
||||||
: 0;
|
: 0;
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
/*
|
|
||||||
This file is part of Telegram Desktop,
|
|
||||||
the official desktop application for the Telegram messaging service.
|
|
||||||
|
|
||||||
For license and copyright information please follow this link:
|
|
||||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "ui/rp_widget.h"
|
|
||||||
|
|
||||||
namespace Window {
|
|
||||||
|
|
||||||
enum class HitTestResult {
|
|
||||||
None = 0,
|
|
||||||
Client,
|
|
||||||
SysButton,
|
|
||||||
Caption,
|
|
||||||
Top,
|
|
||||||
TopRight,
|
|
||||||
Right,
|
|
||||||
BottomRight,
|
|
||||||
Bottom,
|
|
||||||
BottomLeft,
|
|
||||||
Left,
|
|
||||||
TopLeft,
|
|
||||||
};
|
|
||||||
|
|
||||||
class TitleWidget : public Ui::RpWidget {
|
|
||||||
public:
|
|
||||||
using RpWidget::RpWidget;
|
|
||||||
|
|
||||||
virtual void init() {
|
|
||||||
}
|
|
||||||
virtual HitTestResult hitTest(const QPoint &p) const {
|
|
||||||
return HitTestResult::None;
|
|
||||||
}
|
|
||||||
virtual QRect iconRect() const {
|
|
||||||
return QRect();
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Window
|
|
|
@ -1,417 +0,0 @@
|
||||||
/*
|
|
||||||
This file is part of Telegram Desktop,
|
|
||||||
the official desktop application for the Telegram messaging service.
|
|
||||||
|
|
||||||
For license and copyright information please follow this link:
|
|
||||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|
||||||
*/
|
|
||||||
#include "window/window_title_qt.h"
|
|
||||||
|
|
||||||
#include "ui/platform/ui_platform_utility.h"
|
|
||||||
#include "ui/widgets/buttons.h"
|
|
||||||
#include "ui/widgets/shadow.h"
|
|
||||||
#include "styles/style_widgets.h"
|
|
||||||
#include "styles/style_window.h"
|
|
||||||
|
|
||||||
#include <QtCore/QCoreApplication>
|
|
||||||
#include <QtGui/QGuiApplication>
|
|
||||||
#include <QtGui/QWindow>
|
|
||||||
|
|
||||||
namespace Window {
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
[[nodiscard]] style::margins ShadowExtents() {
|
|
||||||
return st::callShadow.extend;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void RemoveDuplicates(std::vector<T> &v) {
|
|
||||||
auto end = v.end();
|
|
||||||
for (auto it = v.begin(); it != end; ++it) {
|
|
||||||
end = std::remove(it + 1, end, *it);
|
|
||||||
}
|
|
||||||
|
|
||||||
v.erase(end, v.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
TitleWidgetQt::TitleWidgetQt(QWidget *parent)
|
|
||||||
: TitleWidget(parent)
|
|
||||||
, _st(st::defaultWindowTitle)
|
|
||||||
, _minimize(this, _st.minimize)
|
|
||||||
, _maximizeRestore(this, _st.maximize)
|
|
||||||
, _close(this, _st.close)
|
|
||||||
, _shadow(this, st::titleShadow)
|
|
||||||
, _maximizedState(parent->window()->windowState() & Qt::WindowMaximized) {
|
|
||||||
_minimize->setClickedCallback([=] {
|
|
||||||
window()->setWindowState(
|
|
||||||
window()->windowState() | Qt::WindowMinimized);
|
|
||||||
_minimize->clearState();
|
|
||||||
});
|
|
||||||
_minimize->setPointerCursor(false);
|
|
||||||
_maximizeRestore->setClickedCallback([=] {
|
|
||||||
window()->setWindowState(_maximizedState
|
|
||||||
? Qt::WindowNoState
|
|
||||||
: Qt::WindowMaximized);
|
|
||||||
_maximizeRestore->clearState();
|
|
||||||
});
|
|
||||||
_maximizeRestore->setPointerCursor(false);
|
|
||||||
_close->setClickedCallback([=] {
|
|
||||||
window()->close();
|
|
||||||
_close->clearState();
|
|
||||||
});
|
|
||||||
_close->setPointerCursor(false);
|
|
||||||
|
|
||||||
Ui::Platform::TitleControlsLayoutChanged(
|
|
||||||
) | rpl::start_with_next([=] {
|
|
||||||
updateControlsPosition();
|
|
||||||
}, lifetime());
|
|
||||||
|
|
||||||
QCoreApplication::instance()->installEventFilter(this);
|
|
||||||
|
|
||||||
_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) {
|
|
||||||
Ui::Platform::UnsetWindowExtents(window()->windowHandle());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TitleWidgetQt::init() {
|
|
||||||
connect(
|
|
||||||
window()->windowHandle(),
|
|
||||||
&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 Ui::Platform::WindowExtentsSupported()
|
|
||||||
&& Ui::Platform::TranslucentWindowsSupported(center);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ui::IconButton *TitleWidgetQt::controlWidget(Control control) const {
|
|
||||||
switch (control) {
|
|
||||||
case Control::Minimize: return _minimize;
|
|
||||||
case Control::Maximize: return _maximizeRestore;
|
|
||||||
case Control::Close: return _close;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TitleWidgetQt::paintEvent(QPaintEvent *e) {
|
|
||||||
auto active = isActiveWindow();
|
|
||||||
if (_activeState != active) {
|
|
||||||
_activeState = active;
|
|
||||||
updateButtonsState();
|
|
||||||
}
|
|
||||||
Painter(this).fillRect(rect(), active ? _st.bgActive : _st.bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TitleWidgetQt::toggleFramelessWindow(bool enabled) {
|
|
||||||
window()->windowHandle()->setFlag(Qt::FramelessWindowHint, enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TitleWidgetQt::updateWindowExtents() {
|
|
||||||
if (hasShadow()) {
|
|
||||||
Ui::Platform::SetWindowExtents(
|
|
||||||
window()->windowHandle(),
|
|
||||||
resizeArea());
|
|
||||||
|
|
||||||
_extentsSet = true;
|
|
||||||
} else if (_extentsSet) {
|
|
||||||
Ui::Platform::UnsetWindowExtents(window()->windowHandle());
|
|
||||||
_extentsSet = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TitleWidgetQt::updateControlsPosition() {
|
|
||||||
const auto controlsLayout = Ui::Platform::TitleControlsLayout();
|
|
||||||
const auto controlsLeft = controlsLayout.left;
|
|
||||||
const auto controlsRight = controlsLayout.right;
|
|
||||||
|
|
||||||
const auto controlPresent = [&](Control control) {
|
|
||||||
return ranges::contains(controlsLeft, control)
|
|
||||||
|| ranges::contains(controlsRight, control);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (controlPresent(Control::Minimize)) {
|
|
||||||
_minimize->show();
|
|
||||||
} else {
|
|
||||||
_minimize->hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (controlPresent(Control::Maximize)) {
|
|
||||||
_maximizeRestore->show();
|
|
||||||
} else {
|
|
||||||
_maximizeRestore->hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (controlPresent(Control::Close)) {
|
|
||||||
_close->show();
|
|
||||||
} else {
|
|
||||||
_close->hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
updateControlsPositionBySide(controlsLeft, false);
|
|
||||||
updateControlsPositionBySide(controlsRight, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TitleWidgetQt::updateControlsPositionBySide(
|
|
||||||
const std::vector<Control> &controls,
|
|
||||||
bool right) {
|
|
||||||
auto preparedControls = right
|
|
||||||
? (ranges::views::reverse(controls) | ranges::to_vector)
|
|
||||||
: controls;
|
|
||||||
|
|
||||||
RemoveDuplicates(preparedControls);
|
|
||||||
|
|
||||||
auto position = 0;
|
|
||||||
for (const auto &control : preparedControls) {
|
|
||||||
const auto widget = controlWidget(control);
|
|
||||||
if (!widget) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (right) {
|
|
||||||
widget->moveToRight(position, 0);
|
|
||||||
} else {
|
|
||||||
widget->moveToLeft(position, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
position += widget->width();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TitleWidgetQt::resizeEvent(QResizeEvent *e) {
|
|
||||||
updateControlsPosition();
|
|
||||||
_shadow->setGeometry(0, height() - st::lineWidth, width(), st::lineWidth);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TitleWidgetQt::mousePressEvent(QMouseEvent *e) {
|
|
||||||
if (e->button() == Qt::LeftButton) {
|
|
||||||
_mousePressed = true;
|
|
||||||
} else if (e->button() == Qt::RightButton) {
|
|
||||||
Ui::Platform::ShowWindowMenu(window()->windowHandle());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TitleWidgetQt::mouseReleaseEvent(QMouseEvent *e) {
|
|
||||||
if (e->button() == Qt::LeftButton) {
|
|
||||||
_mousePressed = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TitleWidgetQt::mouseMoveEvent(QMouseEvent *e) {
|
|
||||||
if (_mousePressed) {
|
|
||||||
window()->windowHandle()->startSystemMove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TitleWidgetQt::mouseDoubleClickEvent(QMouseEvent *e) {
|
|
||||||
if (_maximizedState) {
|
|
||||||
window()->setWindowState(Qt::WindowNoState);
|
|
||||||
} else {
|
|
||||||
window()->setWindowState(Qt::WindowMaximized);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TitleWidgetQt::eventFilter(QObject *obj, QEvent *e) {
|
|
||||||
if (e->type() == QEvent::MouseMove
|
|
||||||
|| e->type() == QEvent::MouseButtonPress) {
|
|
||||||
if (obj->isWidgetType()
|
|
||||||
&& window()->isAncestorOf(static_cast<QWidget*>(obj))) {
|
|
||||||
const auto mouseEvent = static_cast<QMouseEvent*>(e);
|
|
||||||
const auto currentPoint = mouseEvent->windowPos().toPoint();
|
|
||||||
const auto edges = edgesFromPos(currentPoint);
|
|
||||||
|
|
||||||
if (e->type() == QEvent::MouseMove
|
|
||||||
&& mouseEvent->buttons() == Qt::NoButton) {
|
|
||||||
if (_mousePressed) {
|
|
||||||
_mousePressed = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
updateCursor(edges);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e->type() == QEvent::MouseButtonPress
|
|
||||||
&& mouseEvent->button() == Qt::LeftButton
|
|
||||||
&& edges) {
|
|
||||||
return window()->windowHandle()->startSystemResize(edges);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (e->type() == QEvent::Leave) {
|
|
||||||
if (obj->isWidgetType() && window() == static_cast<QWidget*>(obj)) {
|
|
||||||
restoreCursor();
|
|
||||||
}
|
|
||||||
} else if (e->type() == QEvent::Move
|
|
||||||
|| e->type() == QEvent::Resize) {
|
|
||||||
if (obj->isWidgetType() && window() == static_cast<QWidget*>(obj)) {
|
|
||||||
updateWindowExtents();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return TitleWidget::eventFilter(obj, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TitleWidgetQt::windowStateChanged(Qt::WindowState state) {
|
|
||||||
if (state == Qt::WindowMinimized) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto maximized = (state == Qt::WindowMaximized);
|
|
||||||
if (_maximizedState != maximized) {
|
|
||||||
_maximizedState = maximized;
|
|
||||||
updateButtonsState();
|
|
||||||
updateWindowExtents();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TitleWidgetQt::visibleChanged(bool visible) {
|
|
||||||
if (visible) {
|
|
||||||
updateWindowExtents();
|
|
||||||
|
|
||||||
// workaround a bug in Qt 5.12, works ok in Qt 5.15
|
|
||||||
// https://github.com/telegramdesktop/tdesktop/issues/10119
|
|
||||||
if (!_windowWasFrameless) {
|
|
||||||
toggleFramelessWindow(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TitleWidgetQt::updateButtonsState() {
|
|
||||||
_minimize->setIconOverride(_activeState
|
|
||||||
? &_st.minimizeIconActive
|
|
||||||
: nullptr,
|
|
||||||
_activeState
|
|
||||||
? &_st.minimizeIconActiveOver
|
|
||||||
: nullptr);
|
|
||||||
if (_maximizedState) {
|
|
||||||
_maximizeRestore->setIconOverride(
|
|
||||||
_activeState
|
|
||||||
? &_st.restoreIconActive : &_st.restoreIcon,
|
|
||||||
_activeState
|
|
||||||
? &_st.restoreIconActiveOver
|
|
||||||
: &_st.restoreIconOver);
|
|
||||||
} else {
|
|
||||||
_maximizeRestore->setIconOverride(_activeState
|
|
||||||
? &_st.maximizeIconActive
|
|
||||||
: nullptr,
|
|
||||||
_activeState
|
|
||||||
? &_st.maximizeIconActiveOver
|
|
||||||
: nullptr);
|
|
||||||
}
|
|
||||||
_close->setIconOverride(_activeState
|
|
||||||
? &_st.closeIconActive
|
|
||||||
: nullptr,
|
|
||||||
_activeState
|
|
||||||
? &_st.closeIconActiveOver
|
|
||||||
: nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
QMargins TitleWidgetQt::resizeArea() const {
|
|
||||||
if (_maximizedState) {
|
|
||||||
return QMargins();
|
|
||||||
} else if (!hasShadow()) {
|
|
||||||
return QMargins(
|
|
||||||
st::windowResizeArea,
|
|
||||||
st::windowResizeArea,
|
|
||||||
st::windowResizeArea,
|
|
||||||
st::windowResizeArea);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ShadowExtents();
|
|
||||||
}
|
|
||||||
|
|
||||||
Qt::Edges TitleWidgetQt::edgesFromPos(const QPoint &pos) const {
|
|
||||||
const auto area = resizeArea();
|
|
||||||
|
|
||||||
if (area.isNull()) {
|
|
||||||
return Qt::Edges();
|
|
||||||
} else if (pos.x() <= area.left()) {
|
|
||||||
if (pos.y() <= area.top()) {
|
|
||||||
return Qt::LeftEdge | Qt::TopEdge;
|
|
||||||
} else if (pos.y() >= (window()->height() - area.bottom())) {
|
|
||||||
return Qt::LeftEdge | Qt::BottomEdge;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Qt::LeftEdge;
|
|
||||||
} else if (pos.x() >= (window()->width() - area.right())) {
|
|
||||||
if (pos.y() <= area.top()) {
|
|
||||||
return Qt::RightEdge | Qt::TopEdge;
|
|
||||||
} else if (pos.y() >= (window()->height() - area.bottom())) {
|
|
||||||
return Qt::RightEdge | Qt::BottomEdge;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Qt::RightEdge;
|
|
||||||
} else if (pos.y() <= area.top()) {
|
|
||||||
return Qt::TopEdge;
|
|
||||||
} else if (pos.y() >= (window()->height() - area.bottom())) {
|
|
||||||
return Qt::BottomEdge;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Qt::Edges();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TitleWidgetQt::updateCursor(Qt::Edges edges) {
|
|
||||||
if (!edges) {
|
|
||||||
restoreCursor();
|
|
||||||
return;
|
|
||||||
} else if (!QGuiApplication::overrideCursor()) {
|
|
||||||
_cursorOverriden = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_cursorOverriden) {
|
|
||||||
_cursorOverriden = true;
|
|
||||||
QGuiApplication::setOverrideCursor(QCursor());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (((edges & Qt::LeftEdge) && (edges & Qt::TopEdge))
|
|
||||||
|| ((edges & Qt::RightEdge) && (edges & Qt::BottomEdge))) {
|
|
||||||
QGuiApplication::changeOverrideCursor(QCursor(Qt::SizeFDiagCursor));
|
|
||||||
} else if (((edges & Qt::LeftEdge) && (edges & Qt::BottomEdge))
|
|
||||||
|| ((edges & Qt::RightEdge) && (edges & Qt::TopEdge))) {
|
|
||||||
QGuiApplication::changeOverrideCursor(QCursor(Qt::SizeBDiagCursor));
|
|
||||||
} else if ((edges & Qt::LeftEdge) || (edges & Qt::RightEdge)) {
|
|
||||||
QGuiApplication::changeOverrideCursor(QCursor(Qt::SizeHorCursor));
|
|
||||||
} else if ((edges & Qt::TopEdge) || (edges & Qt::BottomEdge)) {
|
|
||||||
QGuiApplication::changeOverrideCursor(QCursor(Qt::SizeVerCursor));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TitleWidgetQt::restoreCursor() {
|
|
||||||
if (_cursorOverriden) {
|
|
||||||
_cursorOverriden = false;
|
|
||||||
QGuiApplication::restoreOverrideCursor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Window
|
|
|
@ -1,77 +0,0 @@
|
||||||
/*
|
|
||||||
This file is part of Telegram Desktop,
|
|
||||||
the official desktop application for the Telegram messaging service.
|
|
||||||
|
|
||||||
For license and copyright information please follow this link:
|
|
||||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "window/window_title.h"
|
|
||||||
#include "ui/platform/ui_platform_window_title.h"
|
|
||||||
#include "base/object_ptr.h"
|
|
||||||
|
|
||||||
namespace style {
|
|
||||||
struct WindowTitle;
|
|
||||||
} // namespace style
|
|
||||||
|
|
||||||
namespace Ui {
|
|
||||||
class IconButton;
|
|
||||||
class PlainShadow;
|
|
||||||
} // namespace Ui
|
|
||||||
|
|
||||||
namespace Window {
|
|
||||||
|
|
||||||
class TitleWidgetQt : public TitleWidget {
|
|
||||||
public:
|
|
||||||
using Control = Ui::Platform::TitleControls::Control;
|
|
||||||
|
|
||||||
TitleWidgetQt(QWidget *parent);
|
|
||||||
~TitleWidgetQt();
|
|
||||||
|
|
||||||
void init() override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void paintEvent(QPaintEvent *e) override;
|
|
||||||
void resizeEvent(QResizeEvent *e) override;
|
|
||||||
void mousePressEvent(QMouseEvent *e) override;
|
|
||||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
|
||||||
void mouseMoveEvent(QMouseEvent *e) override;
|
|
||||||
void mouseDoubleClickEvent(QMouseEvent *e) override;
|
|
||||||
|
|
||||||
bool eventFilter(QObject *obj, QEvent *e) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void windowStateChanged(Qt::WindowState state = Qt::WindowNoState);
|
|
||||||
void visibleChanged(bool visible);
|
|
||||||
void updateWindowExtents();
|
|
||||||
void updateButtonsState();
|
|
||||||
void updateControlsPosition();
|
|
||||||
void updateControlsPositionBySide(
|
|
||||||
const std::vector<Control> &controls,
|
|
||||||
bool right);
|
|
||||||
|
|
||||||
void toggleFramelessWindow(bool enabled);
|
|
||||||
bool hasShadow() const;
|
|
||||||
Ui::IconButton *controlWidget(Control control) const;
|
|
||||||
QMargins resizeArea() const;
|
|
||||||
Qt::Edges edgesFromPos(const QPoint &pos) const;
|
|
||||||
void updateCursor(Qt::Edges edges);
|
|
||||||
void restoreCursor();
|
|
||||||
|
|
||||||
const style::WindowTitle &_st;
|
|
||||||
object_ptr<Ui::IconButton> _minimize;
|
|
||||||
object_ptr<Ui::IconButton> _maximizeRestore;
|
|
||||||
object_ptr<Ui::IconButton> _close;
|
|
||||||
object_ptr<Ui::PlainShadow> _shadow;
|
|
||||||
|
|
||||||
bool _maximizedState = false;
|
|
||||||
bool _activeState = false;
|
|
||||||
bool _windowWasFrameless = false;
|
|
||||||
bool _cursorOverriden = false;
|
|
||||||
bool _extentsSet = false;
|
|
||||||
bool _mousePressed = false;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Window
|
|
Loading…
Add table
Reference in a new issue