mirror of
https://github.com/kotatogram/kotatogram-desktop
synced 2025-09-18 14:00:09 +00:00
Updated TDesktop sources to 2.6
This commit is contained in:
@@ -7,29 +7,35 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "platform/linux/specific_linux.h"
|
||||
|
||||
#include "platform/linux/linux_libs.h"
|
||||
#include "base/platform/base_platform_info.h"
|
||||
#include "base/platform/linux/base_xcb_utilities_linux.h"
|
||||
#include "base/platform/linux/base_linux_gtk_integration.h"
|
||||
#include "ui/platform/ui_platform_utility.h"
|
||||
#include "platform/linux/linux_desktop_environment.h"
|
||||
#include "platform/linux/linux_gtk_integration.h"
|
||||
#include "platform/linux/linux_wayland_integration.h"
|
||||
#include "base/qt_adapters.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "platform/linux/linux_desktop_environment.h"
|
||||
#include "platform/linux/file_utilities_linux.h"
|
||||
#include "platform/linux/linux_wayland_integration.h"
|
||||
#include "platform/platform_notifications_manager.h"
|
||||
#include "storage/localstorage.h"
|
||||
#include "core/crash_reports.h"
|
||||
#include "core/sandbox.h"
|
||||
#include "core/application.h"
|
||||
#include "core/core_settings.h"
|
||||
#include "core/update_checker.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "core/application.h"
|
||||
|
||||
#ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION
|
||||
#include "base/platform/linux/base_linux_xcb_utilities.h"
|
||||
#endif // !DESKTOP_APP_DISABLE_X11_INTEGRATION
|
||||
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
#include "platform/linux/linux_notification_service_watcher.h"
|
||||
#include "platform/linux/linux_gsd_media_keys.h"
|
||||
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
|
||||
#include <QtWidgets/QApplication>
|
||||
#include <QtWidgets/QDesktopWidget>
|
||||
#include <QtCore/QStandardPaths>
|
||||
#include <QtCore/QProcess>
|
||||
#include <QtCore/QVersionNumber>
|
||||
#include <QtCore/QLibraryInfo>
|
||||
#include <QtGui/QWindow>
|
||||
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
@@ -41,8 +47,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include <QtDBus/QDBusError>
|
||||
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
extern "C" {
|
||||
@@ -61,14 +65,13 @@ extern "C" {
|
||||
#include <iostream>
|
||||
|
||||
using namespace Platform;
|
||||
using Platform::File::internal::EscapeShell;
|
||||
using BaseGtkIntegration = base::Platform::GtkIntegration;
|
||||
using Platform::internal::WaylandIntegration;
|
||||
using Platform::internal::GtkIntegration;
|
||||
|
||||
namespace Platform {
|
||||
namespace {
|
||||
|
||||
constexpr auto kIgnoreGtkIncompatibility = "TDESKTOP_I_KNOW_ABOUT_GTK_INCOMPATIBILITY"_cs;
|
||||
|
||||
constexpr auto kDesktopFile = ":/misc/kotatogramdesktop.desktop"_cs;
|
||||
constexpr auto kIconName = "kotatogram"_cs;
|
||||
constexpr auto kHandlerTypeName = "x-scheme-handler/tg"_cs;
|
||||
@@ -77,11 +80,9 @@ constexpr auto kXDGDesktopPortalService = "org.freedesktop.portal.Desktop"_cs;
|
||||
constexpr auto kXDGDesktopPortalObjectPath = "/org/freedesktop/portal/desktop"_cs;
|
||||
constexpr auto kPropertiesInterface = "org.freedesktop.DBus.Properties"_cs;
|
||||
|
||||
constexpr auto kXCBFrameExtentsAtomName = "_GTK_FRAME_EXTENTS"_cs;
|
||||
|
||||
QStringList PlatformThemes;
|
||||
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
std::unique_ptr<internal::NotificationServiceWatcher> NSWInstance;
|
||||
|
||||
QStringList ListDBusActivatableNames() {
|
||||
static const auto Result = [&] {
|
||||
const auto message = QDBusMessage::createMethodCall(
|
||||
@@ -95,8 +96,8 @@ QStringList ListDBusActivatableNames() {
|
||||
|
||||
if (reply.isValid()) {
|
||||
return reply.value();
|
||||
} else {
|
||||
LOG(("App Error: %1: %2")
|
||||
} else if (reply.error().type() != QDBusError::Disconnected) {
|
||||
LOG(("ListActivatableNames Error: %1: %2")
|
||||
.arg(reply.error().name())
|
||||
.arg(reply.error().message()));
|
||||
}
|
||||
@@ -107,14 +108,14 @@ QStringList ListDBusActivatableNames() {
|
||||
return Result;
|
||||
}
|
||||
|
||||
void PortalAutostart(bool autostart, bool silent = false) {
|
||||
void PortalAutostart(bool start, bool silent = false) {
|
||||
if (cExeName().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QVariantMap options;
|
||||
options["reason"] = tr::lng_settings_auto_start(tr::now);
|
||||
options["autostart"] = autostart;
|
||||
options["autostart"] = start;
|
||||
options["commandline"] = QStringList{
|
||||
cExeName(),
|
||||
qsl("-workdir"),
|
||||
@@ -147,13 +148,14 @@ void PortalAutostart(bool autostart, bool silent = false) {
|
||||
|
||||
if (silent) {
|
||||
QDBusConnection::sessionBus().send(message);
|
||||
} else {
|
||||
const QDBusReply<void> reply = QDBusConnection::sessionBus().call(
|
||||
message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!reply.isValid()) {
|
||||
LOG(("Flatpak autostart error: %1").arg(reply.error().message()));
|
||||
}
|
||||
const QDBusError error = QDBusConnection::sessionBus().call(message);
|
||||
if (error.isValid()) {
|
||||
LOG(("Flatpak Autostart Error: %1: %2")
|
||||
.arg(error.name())
|
||||
.arg(error.message()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,11 +211,12 @@ uint FileChooserPortalVersion() {
|
||||
|
||||
if (reply.isValid()) {
|
||||
return reply.value().toUInt();
|
||||
} else {
|
||||
LOG(("Error getting FileChooser portal version: %1")
|
||||
.arg(reply.error().message()));
|
||||
}
|
||||
|
||||
LOG(("Error getting FileChooser portal version: %1: %2")
|
||||
.arg(reply.error().name())
|
||||
.arg(reply.error().message()));
|
||||
|
||||
return 0;
|
||||
}();
|
||||
|
||||
@@ -221,6 +224,32 @@ uint FileChooserPortalVersion() {
|
||||
}
|
||||
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
|
||||
QByteArray EscapeShell(const QByteArray &content) {
|
||||
auto result = QByteArray();
|
||||
|
||||
auto b = content.constData(), e = content.constEnd();
|
||||
for (auto ch = b; ch != e; ++ch) {
|
||||
if (*ch == ' ' || *ch == '"' || *ch == '\'' || *ch == '\\') {
|
||||
if (result.isEmpty()) {
|
||||
result.reserve(content.size() * 2);
|
||||
}
|
||||
if (ch > b) {
|
||||
result.append(b, ch - b);
|
||||
}
|
||||
result.append('\\');
|
||||
b = ch;
|
||||
}
|
||||
}
|
||||
if (result.isEmpty()) {
|
||||
return content;
|
||||
}
|
||||
|
||||
if (e > b) {
|
||||
result.append(b, e - b);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QString EscapeShellInLauncher(const QString &content) {
|
||||
return EscapeShell(content.toUtf8()).replace('\\', "\\\\");
|
||||
}
|
||||
@@ -228,7 +257,7 @@ QString EscapeShellInLauncher(const QString &content) {
|
||||
QString FlatpakID() {
|
||||
static const auto Result = [] {
|
||||
if (!qEnvironmentVariableIsEmpty("FLATPAK_ID")) {
|
||||
return QString::fromLatin1(qgetenv("FLATPAK_ID"));
|
||||
return qEnvironmentVariable("FLATPAK_ID");
|
||||
} else {
|
||||
return GetLauncherBasename();
|
||||
}
|
||||
@@ -322,242 +351,42 @@ bool GenerateDesktopFile(
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
bool GetImageFromClipboardSupported() {
|
||||
return (Libs::gtk_clipboard_wait_for_contents != nullptr)
|
||||
&& (Libs::gtk_clipboard_wait_for_image != nullptr)
|
||||
&& (Libs::gtk_selection_data_targets_include_image != nullptr)
|
||||
&& (Libs::gtk_selection_data_free != nullptr)
|
||||
&& (Libs::gdk_pixbuf_get_pixels != nullptr)
|
||||
&& (Libs::gdk_pixbuf_get_width != nullptr)
|
||||
&& (Libs::gdk_pixbuf_get_height != nullptr)
|
||||
&& (Libs::gdk_pixbuf_get_rowstride != nullptr)
|
||||
&& (Libs::gdk_pixbuf_get_has_alpha != nullptr)
|
||||
&& (Libs::gdk_atom_intern != nullptr);
|
||||
}
|
||||
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
void SetGtkScaleFactor() {
|
||||
const auto integration = GtkIntegration::Instance();
|
||||
const auto ratio = Core::Sandbox::Instance().devicePixelRatio();
|
||||
if (!integration || ratio > 1.) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint XCBMoveResizeFromEdges(Qt::Edges edges) {
|
||||
if (edges == (Qt::TopEdge | Qt::LeftEdge))
|
||||
return 0;
|
||||
if (edges == Qt::TopEdge)
|
||||
return 1;
|
||||
if (edges == (Qt::TopEdge | Qt::RightEdge))
|
||||
return 2;
|
||||
if (edges == Qt::RightEdge)
|
||||
return 3;
|
||||
if (edges == (Qt::RightEdge | Qt::BottomEdge))
|
||||
return 4;
|
||||
if (edges == Qt::BottomEdge)
|
||||
return 5;
|
||||
if (edges == (Qt::BottomEdge | Qt::LeftEdge))
|
||||
return 6;
|
||||
if (edges == Qt::LeftEdge)
|
||||
return 7;
|
||||
const auto scaleFactor = integration->scaleFactor().value_or(1);
|
||||
if (scaleFactor == 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
return 0;
|
||||
LOG(("GTK scale factor: %1").arg(scaleFactor));
|
||||
cSetScreenScale(style::CheckScale(scaleFactor * 100));
|
||||
}
|
||||
|
||||
bool StartXCBMoveResize(QWindow *window, int edges) {
|
||||
const auto connection = base::Platform::XCB::GetConnectionFromQt();
|
||||
if (!connection) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto root = base::Platform::XCB::GetRootWindowFromQt();
|
||||
if (!root.has_value()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto moveResizeAtom = base::Platform::XCB::GetAtom(
|
||||
connection,
|
||||
"_NET_WM_MOVERESIZE");
|
||||
|
||||
if (!moveResizeAtom.has_value()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto globalPos = QCursor::pos();
|
||||
|
||||
xcb_client_message_event_t xev;
|
||||
xev.response_type = XCB_CLIENT_MESSAGE;
|
||||
xev.type = *moveResizeAtom;
|
||||
xev.sequence = 0;
|
||||
xev.window = window->winId();
|
||||
xev.format = 32;
|
||||
xev.data.data32[0] = globalPos.x();
|
||||
xev.data.data32[1] = globalPos.y();
|
||||
xev.data.data32[2] = (edges == 16)
|
||||
? 8 // move
|
||||
: XCBMoveResizeFromEdges(Qt::Edges(edges));
|
||||
xev.data.data32[3] = XCB_BUTTON_INDEX_1;
|
||||
xev.data.data32[4] = 0;
|
||||
|
||||
xcb_ungrab_pointer(connection, XCB_CURRENT_TIME);
|
||||
xcb_send_event(
|
||||
connection,
|
||||
false,
|
||||
*root,
|
||||
XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT
|
||||
| XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY,
|
||||
reinterpret_cast<const char*>(&xev));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ShowXCBWindowMenu(QWindow *window) {
|
||||
const auto connection = base::Platform::XCB::GetConnectionFromQt();
|
||||
if (!connection) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto root = base::Platform::XCB::GetRootWindowFromQt();
|
||||
if (!root.has_value()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto showWindowMenuAtom = base::Platform::XCB::GetAtom(
|
||||
connection,
|
||||
"_GTK_SHOW_WINDOW_MENU");
|
||||
|
||||
if (!showWindowMenuAtom.has_value()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto globalPos = QCursor::pos();
|
||||
|
||||
xcb_client_message_event_t xev;
|
||||
xev.response_type = XCB_CLIENT_MESSAGE;
|
||||
xev.type = *showWindowMenuAtom;
|
||||
xev.sequence = 0;
|
||||
xev.window = window->winId();
|
||||
xev.format = 32;
|
||||
xev.data.data32[0] = 0;
|
||||
xev.data.data32[1] = globalPos.x();
|
||||
xev.data.data32[2] = globalPos.y();
|
||||
xev.data.data32[3] = 0;
|
||||
xev.data.data32[4] = 0;
|
||||
|
||||
xcb_ungrab_pointer(connection, XCB_CURRENT_TIME);
|
||||
xcb_send_event(
|
||||
connection,
|
||||
false,
|
||||
*root,
|
||||
XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT
|
||||
| XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY,
|
||||
reinterpret_cast<const char*>(&xev));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool XCBFrameExtentsSupported() {
|
||||
const auto connection = base::Platform::XCB::GetConnectionFromQt();
|
||||
if (!connection) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto frameExtentsAtom = base::Platform::XCB::GetAtom(
|
||||
connection,
|
||||
kXCBFrameExtentsAtomName.utf16());
|
||||
|
||||
if (!frameExtentsAtom.has_value()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ranges::contains(
|
||||
base::Platform::XCB::GetWMSupported(connection),
|
||||
*frameExtentsAtom);
|
||||
}
|
||||
|
||||
bool SetXCBFrameExtents(QWindow *window, const QMargins &extents) {
|
||||
const auto connection = base::Platform::XCB::GetConnectionFromQt();
|
||||
if (!connection) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto frameExtentsAtom = base::Platform::XCB::GetAtom(
|
||||
connection,
|
||||
kXCBFrameExtentsAtomName.utf16());
|
||||
|
||||
if (!frameExtentsAtom.has_value()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto extentsVector = std::vector<uint>{
|
||||
uint(extents.left()),
|
||||
uint(extents.right()),
|
||||
uint(extents.top()),
|
||||
uint(extents.bottom()),
|
||||
};
|
||||
|
||||
xcb_change_property(
|
||||
connection,
|
||||
XCB_PROP_MODE_REPLACE,
|
||||
window->winId(),
|
||||
*frameExtentsAtom,
|
||||
XCB_ATOM_CARDINAL,
|
||||
32,
|
||||
extentsVector.size(),
|
||||
extentsVector.data());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UnsetXCBFrameExtents(QWindow *window) {
|
||||
const auto connection = base::Platform::XCB::GetConnectionFromQt();
|
||||
if (!connection) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto frameExtentsAtom = base::Platform::XCB::GetAtom(
|
||||
connection,
|
||||
kXCBFrameExtentsAtomName.utf16());
|
||||
|
||||
if (!frameExtentsAtom.has_value()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
xcb_delete_property(
|
||||
connection,
|
||||
window->winId(),
|
||||
*frameExtentsAtom);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool XCBSkipTaskbarSupported() {
|
||||
const auto connection = base::Platform::XCB::GetConnectionFromQt();
|
||||
if (!connection) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto skipTaskbarAtom = base::Platform::XCB::GetAtom(
|
||||
connection,
|
||||
"_NET_WM_STATE_SKIP_TASKBAR");
|
||||
|
||||
if (!skipTaskbarAtom.has_value()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ranges::contains(
|
||||
base::Platform::XCB::GetWMSupported(connection),
|
||||
*skipTaskbarAtom);
|
||||
}
|
||||
|
||||
Window::Control GtkKeywordToWindowControl(const QString &keyword) {
|
||||
if (keyword == qstr("minimize")) {
|
||||
return Window::Control::Minimize;
|
||||
} else if (keyword == qstr("maximize")) {
|
||||
return Window::Control::Maximize;
|
||||
} else if (keyword == qstr("close")) {
|
||||
return Window::Control::Close;
|
||||
}
|
||||
|
||||
return Window::Control::Unknown;
|
||||
void DarkModeChanged() {
|
||||
Core::Sandbox::Instance().customEnterFromEventLoop([] {
|
||||
Core::App().settings().setSystemDarkMode(IsDarkMode());
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void SetWatchingMediaKeys(bool watching) {
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
static std::unique_ptr<internal::GSDMediaKeys> Instance;
|
||||
|
||||
if (watching && !Instance) {
|
||||
Instance = std::make_unique<internal::GSDMediaKeys>();
|
||||
} else if (!watching && Instance) {
|
||||
Instance = nullptr;
|
||||
}
|
||||
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
}
|
||||
|
||||
void SetApplicationIcon(const QIcon &icon) {
|
||||
QApplication::setWindowIcon(icon);
|
||||
}
|
||||
@@ -572,37 +401,6 @@ bool InSnap() {
|
||||
return Result;
|
||||
}
|
||||
|
||||
bool IsStaticBinary() {
|
||||
#ifdef DESKTOP_APP_USE_PACKAGED
|
||||
return false;
|
||||
#else // DESKTOP_APP_USE_PACKAGED
|
||||
return true;
|
||||
#endif // !DESKTOP_APP_USE_PACKAGED
|
||||
}
|
||||
|
||||
bool UseGtkIntegration() {
|
||||
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
static const auto Result = cGtkIntegration();
|
||||
|
||||
return Result;
|
||||
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsGtkIntegrationForced() {
|
||||
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
static const auto Result = [&] {
|
||||
return PlatformThemes.contains(qstr("gtk3"), Qt::CaseInsensitive)
|
||||
|| PlatformThemes.contains(qstr("gtk2"), Qt::CaseInsensitive);
|
||||
}();
|
||||
|
||||
return Result;
|
||||
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AreQtPluginsBundled() {
|
||||
#if !defined DESKTOP_APP_USE_PACKAGED || defined DESKTOP_APP_USE_PACKAGED_LAZY
|
||||
return true;
|
||||
@@ -614,18 +412,16 @@ bool AreQtPluginsBundled() {
|
||||
bool UseXDGDesktopPortal() {
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
static const auto Result = [&] {
|
||||
const auto onlyIn = AreQtPluginsBundled()
|
||||
// it is handled by Qt for flatpak and snap
|
||||
&& !InFlatpak()
|
||||
&& !InSnap();
|
||||
if (InFlatpak() || InSnap()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto envVar = qEnvironmentVariableIsSet("TDESKTOP_USE_PORTAL");
|
||||
const auto portalPresent = IsXDGDesktopPortalPresent();
|
||||
const auto neededForKde = DesktopEnvironment::IsKDE()
|
||||
&& IsXDGDesktopPortalKDEPresent();
|
||||
|
||||
return onlyIn
|
||||
&& portalPresent
|
||||
return portalPresent
|
||||
&& (neededForKde || envVar);
|
||||
}();
|
||||
|
||||
@@ -638,12 +434,7 @@ bool UseXDGDesktopPortal() {
|
||||
bool CanOpenDirectoryWithPortal() {
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
static const auto Result = [&] {
|
||||
#ifdef DESKTOP_APP_QT_PATCHED
|
||||
return FileChooserPortalVersion() >= 3;
|
||||
#else // DESKTOP_APP_QT_PATCHED
|
||||
return QLibraryInfo::version() >= QVersionNumber(5, 15, 0)
|
||||
&& FileChooserPortalVersion() >= 3;
|
||||
#endif // !DESKTOP_APP_QT_PATCHED
|
||||
}();
|
||||
|
||||
return Result;
|
||||
@@ -652,6 +443,17 @@ bool CanOpenDirectoryWithPortal() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsNotificationServiceActivatable() {
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
static const auto Result = ListDBusActivatableNames().contains(
|
||||
qsl("org.freedesktop.Notifications"));
|
||||
|
||||
return Result;
|
||||
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QString AppRuntimeDirectory() {
|
||||
static const auto Result = [&] {
|
||||
auto runtimeDir = QStandardPaths::writableLocation(
|
||||
@@ -727,64 +529,38 @@ QString GetIconName() {
|
||||
}
|
||||
|
||||
QImage GetImageFromClipboard() {
|
||||
QImage data;
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
if (!GetImageFromClipboardSupported() || !Libs::GtkClipboard()) {
|
||||
return data;
|
||||
if (const auto integration = GtkIntegration::Instance()) {
|
||||
return integration->getImageFromClipboard();
|
||||
}
|
||||
|
||||
auto gsel = Libs::gtk_clipboard_wait_for_contents(
|
||||
Libs::GtkClipboard(),
|
||||
Libs::gdk_atom_intern("TARGETS", true));
|
||||
|
||||
if (gsel) {
|
||||
if (Libs::gtk_selection_data_targets_include_image(gsel, false)) {
|
||||
auto img = Libs::gtk_clipboard_wait_for_image(
|
||||
Libs::GtkClipboard());
|
||||
|
||||
if (img) {
|
||||
data = QImage(
|
||||
Libs::gdk_pixbuf_get_pixels(img),
|
||||
Libs::gdk_pixbuf_get_width(img),
|
||||
Libs::gdk_pixbuf_get_height(img),
|
||||
Libs::gdk_pixbuf_get_rowstride(img),
|
||||
Libs::gdk_pixbuf_get_has_alpha(img)
|
||||
? QImage::Format_RGBA8888
|
||||
: QImage::Format_RGB888).copy();
|
||||
|
||||
g_object_unref(img);
|
||||
}
|
||||
}
|
||||
|
||||
Libs::gtk_selection_data_free(gsel);
|
||||
}
|
||||
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
|
||||
return data;
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<bool> IsDarkMode() {
|
||||
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
if (Libs::GtkSettingSupported() && Libs::GtkLoaded()) {
|
||||
if (Libs::gtk_check_version != nullptr
|
||||
&& !Libs::gtk_check_version(3, 0, 0)
|
||||
&& Libs::GtkSetting<gboolean>(
|
||||
"gtk-application-prefer-dark-theme")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto themeName = Libs::GtkSetting("gtk-theme-name").toLower();
|
||||
|
||||
if (themeName.contains(qsl("-dark"))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
const auto integration = BaseGtkIntegration::Instance();
|
||||
if (!integration) {
|
||||
return std::nullopt;
|
||||
}
|
||||
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
|
||||
return std::nullopt;
|
||||
if (integration->checkVersion(3, 0, 0)) {
|
||||
const auto preferDarkTheme = integration->getBoolSetting(
|
||||
qsl("gtk-application-prefer-dark-theme"));
|
||||
|
||||
if (!preferDarkTheme.has_value()) {
|
||||
return std::nullopt;
|
||||
} else if (*preferDarkTheme) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const auto themeName = integration->getStringSetting(qsl("gtk-theme-name"));
|
||||
if (!themeName.has_value()) {
|
||||
return std::nullopt;
|
||||
} else if (themeName->toLower().contains(qsl("-dark"))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AutostartSupported() {
|
||||
@@ -802,108 +578,14 @@ bool TrayIconSupported() {
|
||||
}
|
||||
|
||||
bool SkipTaskbarSupported() {
|
||||
return !IsWayland() && XCBSkipTaskbarSupported();
|
||||
}
|
||||
|
||||
bool StartSystemMove(QWindow *window) {
|
||||
if (const auto integration = WaylandIntegration::Instance()) {
|
||||
return integration->startMove(window);
|
||||
} else {
|
||||
return StartXCBMoveResize(window, 16);
|
||||
}
|
||||
}
|
||||
|
||||
bool StartSystemResize(QWindow *window, Qt::Edges edges) {
|
||||
if (const auto integration = WaylandIntegration::Instance()) {
|
||||
return integration->startResize(window, edges);
|
||||
} else {
|
||||
return StartXCBMoveResize(window, edges);
|
||||
}
|
||||
}
|
||||
|
||||
bool ShowWindowMenu(QWindow *window) {
|
||||
if (const auto integration = WaylandIntegration::Instance()) {
|
||||
return integration->showWindowMenu(window);
|
||||
} else {
|
||||
return ShowXCBWindowMenu(window);
|
||||
}
|
||||
}
|
||||
|
||||
bool SetWindowExtents(QWindow *window, const QMargins &extents) {
|
||||
if (!IsWayland()) {
|
||||
return SetXCBFrameExtents(window, extents);
|
||||
}
|
||||
#ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION
|
||||
return !IsWayland()
|
||||
&& base::Platform::XCB::IsSupportedByWM("_NET_WM_STATE_SKIP_TASKBAR");
|
||||
#endif // !DESKTOP_APP_DISABLE_X11_INTEGRATION
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UnsetWindowExtents(QWindow *window) {
|
||||
if (!IsWayland()) {
|
||||
return UnsetXCBFrameExtents(window);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WindowsNeedShadow() {
|
||||
if (!IsWayland() && XCBFrameExtentsSupported()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Window::ControlsLayout WindowControlsLayout() {
|
||||
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
if (Libs::GtkSettingSupported()
|
||||
&& Libs::GtkLoaded()
|
||||
&& Libs::gtk_check_version != nullptr
|
||||
&& !Libs::gtk_check_version(3, 12, 0)) {
|
||||
const auto decorationLayout = Libs::GtkSetting(
|
||||
"gtk-decoration-layout").split(':');
|
||||
|
||||
std::vector<Window::Control> controlsLeft;
|
||||
ranges::transform(
|
||||
decorationLayout[0].split(','),
|
||||
ranges::back_inserter(controlsLeft),
|
||||
GtkKeywordToWindowControl
|
||||
);
|
||||
|
||||
std::vector<Window::Control> controlsRight;
|
||||
if (decorationLayout.size() > 1) {
|
||||
ranges::transform(
|
||||
decorationLayout[1].split(','),
|
||||
ranges::back_inserter(controlsRight),
|
||||
GtkKeywordToWindowControl
|
||||
);
|
||||
}
|
||||
|
||||
return Window::ControlsLayout{
|
||||
.left = controlsLeft,
|
||||
.right = controlsRight
|
||||
};
|
||||
}
|
||||
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
|
||||
if (DesktopEnvironment::IsUnity()) {
|
||||
return Window::ControlsLayout{
|
||||
.left = {
|
||||
Window::Control::Close,
|
||||
Window::Control::Minimize,
|
||||
Window::Control::Maximize,
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return Window::ControlsLayout{
|
||||
.right = {
|
||||
Window::Control::Minimize,
|
||||
Window::Control::Maximize,
|
||||
Window::Control::Close,
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Platform
|
||||
|
||||
QRect psDesktopRect() {
|
||||
@@ -926,7 +608,7 @@ void psActivateProcess(uint64 pid) {
|
||||
|
||||
namespace {
|
||||
|
||||
QString getHomeDir() {
|
||||
QString GetHomeDir() {
|
||||
const auto home = QString(g_get_home_dir());
|
||||
|
||||
if (!home.isEmpty() && !home.endsWith('/')) {
|
||||
@@ -936,12 +618,39 @@ QString getHomeDir() {
|
||||
return home;
|
||||
}
|
||||
|
||||
#ifdef __HAIKU__
|
||||
void HaikuAutostart(bool start) {
|
||||
const auto home = GetHomeDir();
|
||||
if (home.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QFile file(home + "config/settings/boot/launch/telegram-desktop");
|
||||
if (start) {
|
||||
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
QTextStream out(&file);
|
||||
out
|
||||
<< "#!/bin/bash" << Qt::endl
|
||||
<< "cd /system/apps" << Qt::endl
|
||||
<< "./Telegram -autostart" << " &" << Qt::endl;
|
||||
file.close();
|
||||
file.setPermissions(file.permissions()
|
||||
| QFileDevice::ExeOwner
|
||||
| QFileDevice::ExeGroup
|
||||
| QFileDevice::ExeOther);
|
||||
}
|
||||
} else {
|
||||
file.remove();
|
||||
}
|
||||
}
|
||||
#endif // __HAIKU__
|
||||
|
||||
} // namespace
|
||||
|
||||
QString psAppDataPath() {
|
||||
// We should not use ~/.TelegramDesktop, since it's a fork.
|
||||
/*
|
||||
auto home = getHomeDir();
|
||||
auto home = GetHomeDir();
|
||||
if (!home.isEmpty()) {
|
||||
auto oldPath = home + qsl(".TelegramDesktop/");
|
||||
auto oldSettingsBase = oldPath + qsl("tdata/settings");
|
||||
@@ -980,39 +689,15 @@ int psFixPrevious() {
|
||||
namespace Platform {
|
||||
|
||||
void start() {
|
||||
PlatformThemes = QString::fromUtf8(qgetenv("QT_QPA_PLATFORMTHEME"))
|
||||
.split(':', base::QStringSkipEmptyParts);
|
||||
|
||||
LOG(("Launcher filename: %1").arg(GetLauncherFilename()));
|
||||
|
||||
qputenv("PULSE_PROP_application.name", AppName.utf8());
|
||||
qputenv("PULSE_PROP_application.icon_name", GetIconName().toLatin1());
|
||||
|
||||
// if gtk integration and qgtk3/qgtk2 platformtheme (or qgtk2 style)
|
||||
// is used at the same time, the app will crash
|
||||
if (UseGtkIntegration()
|
||||
&& !IsStaticBinary()
|
||||
&& !qEnvironmentVariableIsSet(
|
||||
kIgnoreGtkIncompatibility.utf8())) {
|
||||
g_warning(
|
||||
"Unfortunately, GTK integration "
|
||||
"conflicts with qgtk2 platformtheme and style. "
|
||||
"Therefore, QT_QPA_PLATFORMTHEME "
|
||||
"and QT_STYLE_OVERRIDE will be unset.");
|
||||
|
||||
g_message(
|
||||
"This can be ignored by setting %s environment variable "
|
||||
"to any value, however, if qgtk2 theme or style is used, "
|
||||
"this will lead to a crash.",
|
||||
kIgnoreGtkIncompatibility.utf8().constData());
|
||||
|
||||
qunsetenv("QT_QPA_PLATFORMTHEME");
|
||||
qunsetenv("QT_STYLE_OVERRIDE");
|
||||
|
||||
// Don't allow qgtk3 to init gtk earlier than us
|
||||
if (DesktopEnvironment::IsGtkBased()) {
|
||||
QApplication::setDesktopSettingsAware(false);
|
||||
}
|
||||
if (const auto integration = BaseGtkIntegration::Instance()) {
|
||||
integration->prepareEnvironment();
|
||||
} else {
|
||||
g_warning("GTK integration is disabled, some feature unavailable. ");
|
||||
}
|
||||
|
||||
#ifdef DESKTOP_APP_USE_PACKAGED_RLOTTIE
|
||||
@@ -1027,19 +712,13 @@ void start() {
|
||||
"this may lead to font issues.");
|
||||
#endif // DESKTOP_APP_USE_PACKAGED_FONTS
|
||||
|
||||
if (AreQtPluginsBundled()) {
|
||||
qputenv("QT_WAYLAND_DECORATION", "material");
|
||||
}
|
||||
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
// this can give us a chance to use
|
||||
// a proper file dialog for current session
|
||||
// Tell the user when XDP file dialog is used
|
||||
DEBUG_LOG(("Checking for XDG Desktop Portal..."));
|
||||
if (IsXDGDesktopPortalPresent()) {
|
||||
DEBUG_LOG(("XDG Desktop Portal is present!"));
|
||||
if (UseXDGDesktopPortal()) {
|
||||
LOG(("Using XDG Desktop Portal."));
|
||||
qputenv("QT_QPA_PLATFORMTHEME", "xdgdesktopportal");
|
||||
} else {
|
||||
DEBUG_LOG(("Not using XDG Desktop Portal."));
|
||||
}
|
||||
@@ -1069,8 +748,8 @@ void finish() {
|
||||
}
|
||||
|
||||
void InstallLauncher(bool force) {
|
||||
static const auto DisabledByEnv = qEnvironmentVariableIsSet(
|
||||
"TDESKTOP_DISABLE_DESKTOP_FILE_GENERATION");
|
||||
static const auto DisabledByEnv = !qEnvironmentVariableIsEmpty(
|
||||
"DESKTOPINTEGRATION");
|
||||
|
||||
// don't update desktop file for alpha version or if updater is disabled
|
||||
if ((cAlphaVersion() || Core::UpdaterDisabled() || DisabledByEnv)
|
||||
@@ -1122,7 +801,7 @@ void RegisterCustomScheme(bool force) {
|
||||
.arg(neededCommandlineBuilder);
|
||||
|
||||
auto currentAppInfo = g_app_info_get_default_for_type(
|
||||
kHandlerTypeName.utf8(),
|
||||
kHandlerTypeName.utf8().constData(),
|
||||
true);
|
||||
|
||||
if (currentAppInfo) {
|
||||
@@ -1137,7 +816,7 @@ void RegisterCustomScheme(bool force) {
|
||||
}
|
||||
|
||||
auto registeredAppInfoList = g_app_info_get_recommended_for_type(
|
||||
kHandlerTypeName.utf8());
|
||||
kHandlerTypeName.utf8().constData());
|
||||
|
||||
for (auto l = registeredAppInfoList; l != nullptr; l = l->next) {
|
||||
const auto currentRegisteredAppInfo = reinterpret_cast<GAppInfo*>(
|
||||
@@ -1160,15 +839,15 @@ void RegisterCustomScheme(bool force) {
|
||||
}
|
||||
|
||||
auto newAppInfo = g_app_info_create_from_commandline(
|
||||
neededCommandlineBuilder.toUtf8(),
|
||||
AppName.utf8(),
|
||||
neededCommandlineBuilder.toUtf8().constData(),
|
||||
AppName.utf8().constData(),
|
||||
G_APP_INFO_CREATE_SUPPORTS_URIS,
|
||||
&error);
|
||||
|
||||
if (newAppInfo) {
|
||||
g_app_info_set_as_default_for_type(
|
||||
newAppInfo,
|
||||
kHandlerTypeName.utf8(),
|
||||
kHandlerTypeName.utf8().constData(),
|
||||
&error);
|
||||
|
||||
g_object_unref(newAppInfo);
|
||||
@@ -1217,6 +896,9 @@ bool OpenSystemSettings(SystemSettingsType type) {
|
||||
} else if (DesktopEnvironment::IsMATE()) {
|
||||
add("mate-volume-control");
|
||||
}
|
||||
#ifdef __HAIKU__
|
||||
add("Media");
|
||||
#endif // __ HAIKU__
|
||||
add("pavucontrol-qt");
|
||||
add("pavucontrol");
|
||||
add("alsamixergui");
|
||||
@@ -1230,14 +912,46 @@ bool OpenSystemSettings(SystemSettingsType type) {
|
||||
namespace ThirdParty {
|
||||
|
||||
void start() {
|
||||
DEBUG_LOG(("Icon theme: %1").arg(QIcon::themeName()));
|
||||
DEBUG_LOG(("Fallback icon theme: %1").arg(QIcon::fallbackThemeName()));
|
||||
if (const auto integration = BaseGtkIntegration::Instance()) {
|
||||
integration->load();
|
||||
}
|
||||
|
||||
Libs::start();
|
||||
MainWindow::LibsLoaded();
|
||||
if (const auto integration = GtkIntegration::Instance()) {
|
||||
integration->load();
|
||||
}
|
||||
|
||||
SetGtkScaleFactor();
|
||||
|
||||
BaseGtkIntegration::Instance()->connectToSetting(
|
||||
"gtk-theme-name",
|
||||
DarkModeChanged);
|
||||
|
||||
if (BaseGtkIntegration::Instance()->checkVersion(3, 0, 0)) {
|
||||
BaseGtkIntegration::Instance()->connectToSetting(
|
||||
"gtk-application-prefer-dark-theme",
|
||||
DarkModeChanged);
|
||||
}
|
||||
|
||||
if (BaseGtkIntegration::Instance()->checkVersion(3, 12, 0)) {
|
||||
BaseGtkIntegration::Instance()->connectToSetting(
|
||||
"gtk-decoration-layout",
|
||||
Ui::Platform::NotifyTitleControlsLayoutChanged);
|
||||
}
|
||||
|
||||
// wait for interface announce to know if native window frame is supported
|
||||
if (const auto integration = WaylandIntegration::Instance()) {
|
||||
integration->waitForInterfaceAnnounce();
|
||||
}
|
||||
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
NSWInstance = std::make_unique<internal::NotificationServiceWatcher>();
|
||||
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
}
|
||||
|
||||
void finish() {
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
NSWInstance = nullptr;
|
||||
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
}
|
||||
|
||||
} // namespace ThirdParty
|
||||
@@ -1245,11 +959,18 @@ void finish() {
|
||||
} // namespace Platform
|
||||
|
||||
void psNewVersion() {
|
||||
#ifndef __HAIKU__
|
||||
Platform::InstallLauncher();
|
||||
#endif // __HAIKU__
|
||||
Platform::RegisterCustomScheme();
|
||||
}
|
||||
|
||||
void psAutoStart(bool start, bool silent) {
|
||||
#ifdef __HAIKU__
|
||||
HaikuAutostart(start);
|
||||
return;
|
||||
#endif // __HAIKU__
|
||||
|
||||
if (InFlatpak()) {
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
PortalAutostart(start, silent);
|
||||
|
Reference in New Issue
Block a user