2
0
mirror of https://github.com/kotatogram/kotatogram-desktop synced 2025-08-31 14:45:14 +00:00

Updated TDesktop sources to 2.3.2+d34eabd

This commit is contained in:
RadRussianRus
2020-08-28 19:30:52 +03:00
210 changed files with 6138 additions and 2505 deletions

View File

@@ -11,18 +11,22 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "platform/linux/linux_gdk_helper.h"
#include "platform/linux/linux_desktop_environment.h"
#include "platform/linux/specific_linux.h"
#include "core/application.h"
#include "mainwindow.h"
#include "boxes/abstract_box.h"
#include "storage/localstorage.h"
#include "base/platform/base_platform_file_utilities.h"
#include "base/call_delayed.h"
#include <QtCore/QProcess>
#include <QtGui/QDesktopServices>
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
#include <private/qguiapplication_p.h>
extern "C" {
#undef signals
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#define signals public
} // extern "C"
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
namespace Platform {
@@ -126,11 +130,12 @@ bool NativeSupported(Type type = Type::ReadFile) {
// or if QT_QPA_PLATFORMTHEME=(gtk2|gtk3)
// or if portals is used and operation is to open folder
// and portal doesn't support folder choosing
return Platform::UseGtkFileDialog()
&& (Platform::DesktopEnvironment::IsGtkBased()
return (Platform::DesktopEnvironment::IsGtkBased()
|| Platform::IsGtkIntegrationForced()
|| Platform::UseXDGDesktopPortal())
&& (!Platform::UseXDGDesktopPortal()
&& ((!Platform::UseXDGDesktopPortal() &&
((!Platform::InFlatpak() && !Platform::InSnap())
|| Platform::IsGtkIntegrationForced()))
|| (type == Type::ReadFolder && !Platform::CanOpenDirectoryWithPortal()))
&& Platform::internal::GdkHelperLoaded()
&& (Libs::gtk_widget_hide_on_delete != nullptr)
@@ -461,12 +466,6 @@ int GtkFileDialog::exec() {
show();
if (const auto parent = parentWidget()) {
base::call_delayed(200, parent, [=] {
parent->activateWindow();
});
}
QPointer<QDialog> guard = this;
d->exec();
if (guard.isNull())

View File

@@ -12,14 +12,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtGui/QWindow>
#include <QtWidgets/QFileDialog>
extern "C" {
#undef signals
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
#include <gtk/gtk.h>
#include <gdk/gdk.h>
typedef struct _GtkWidget GtkWidget;
typedef struct _GtkDialog GtkDialog;
typedef struct _GtkFileFilter GtkFileFilter;
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
#define signals public
} // extern "C"
namespace Platform {
namespace File {

View File

@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "platform/linux/linux_libs.h"
#include "base/platform/base_platform_info.h"
#include "platform/linux/linux_xlib_helper.h"
#include "platform/linux/linux_gdk_helper.h"
#include "platform/linux/specific_linux.h"
@@ -114,8 +115,13 @@ bool setupGtkBase(QLibrary &lib_gtk) {
// Otherwise we get segfault in Ubuntu 17.04 in gtk_init_check() call.
// See https://github.com/telegramdesktop/tdesktop/issues/3176
// See https://github.com/telegramdesktop/tdesktop/issues/3162
DEBUG_LOG(("Limit allowed GDK backends to wayland and x11"));
gdk_set_allowed_backends("wayland,x11");
if(Platform::IsWayland()) {
DEBUG_LOG(("Limit allowed GDK backends to wayland,x11"));
gdk_set_allowed_backends("wayland,x11");
} else {
DEBUG_LOG(("Limit allowed GDK backends to x11,wayland"));
gdk_set_allowed_backends("x11,wayland");
}
}
// gtk_init will reset the Xlib error handler, and that causes
@@ -245,6 +251,14 @@ f_gdk_pixbuf_get_rowstride gdk_pixbuf_get_rowstride = nullptr;
bool GtkLoaded() {
return gtkLoaded;
}
::GtkClipboard *GtkClipboard() {
if (gtk_clipboard_get != nullptr) {
return gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
}
return nullptr;
}
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
void start() {

View File

@@ -31,6 +31,7 @@ namespace Libs {
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
bool GtkLoaded();
::GtkClipboard *GtkClipboard();
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
void start();
@@ -78,16 +79,16 @@ extern f_gtk_widget_hide_on_delete gtk_widget_hide_on_delete;
typedef void (*f_gtk_widget_destroy)(GtkWidget *widget);
extern f_gtk_widget_destroy gtk_widget_destroy;
typedef GtkClipboard* (*f_gtk_clipboard_get)(GdkAtom selection);
typedef ::GtkClipboard* (*f_gtk_clipboard_get)(GdkAtom selection);
extern f_gtk_clipboard_get gtk_clipboard_get;
typedef void (*f_gtk_clipboard_store)(GtkClipboard *clipboard);
typedef void (*f_gtk_clipboard_store)(::GtkClipboard *clipboard);
extern f_gtk_clipboard_store gtk_clipboard_store;
typedef GtkSelectionData* (*f_gtk_clipboard_wait_for_contents)(GtkClipboard *clipboard, GdkAtom target);
typedef GtkSelectionData* (*f_gtk_clipboard_wait_for_contents)(::GtkClipboard *clipboard, GdkAtom target);
extern f_gtk_clipboard_wait_for_contents gtk_clipboard_wait_for_contents;
typedef GdkPixbuf* (*f_gtk_clipboard_wait_for_image)(GtkClipboard *clipboard);
typedef GdkPixbuf* (*f_gtk_clipboard_wait_for_image)(::GtkClipboard *clipboard);
extern f_gtk_clipboard_wait_for_image gtk_clipboard_wait_for_image;
typedef gboolean (*f_gtk_selection_data_targets_include_image)(const GtkSelectionData *selection_data, gboolean writable);

View File

@@ -8,10 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "platform/linux/main_window_linux.h"
#include "styles/style_window.h"
#include "platform/linux/linux_libs.h"
#include "platform/linux/specific_linux.h"
#include "platform/linux/linux_desktop_environment.h"
#include "platform/platform_notifications_manager.h"
#include "history/history.h"
#include "history/history_widget.h"
#include "history/history_inner_widget.h"
@@ -33,7 +30,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtCore/QSize>
#include <QtGui/QWindow>
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
#include <QtDBus/QDBusInterface>
#include <QtDBus/QDBusConnection>
#include <QtDBus/QDBusConnectionInterface>
@@ -42,7 +39,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtDBus/QDBusReply>
#include <QtDBus/QDBusError>
#include <QtDBus/QDBusMetaType>
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
#include <glib.h>
namespace Platform {
namespace {
@@ -229,34 +228,34 @@ QIcon TrayIconGen(int counter, bool muted) {
if (!cDisableTrayCounter()
&& counter > 0) {
QPainter p(&iconImage);
int32 layerSize = -16;
if (iconSize >= 48) {
layerSize = -32;
} else if (iconSize >= 36) {
layerSize = -24;
} else if (iconSize >= 32) {
layerSize = -20;
}
auto &bg = muted
const auto &bg = muted
? st::trayCounterBgMute
: st::trayCounterBg;
const auto &fg = st::trayCounterFg;
if (iconSize >= 22) {
auto layerSize = -16;
if (iconSize >= 48) {
layerSize = -32;
} else if (iconSize >= 36) {
layerSize = -24;
} else if (iconSize >= 32) {
layerSize = -20;
}
const auto layer = App::wnd()->iconWithCounter(
layerSize,
counter,
bg,
fg,
false);
auto &fg = st::trayCounterFg;
auto layer = App::wnd()->iconWithCounter(
layerSize,
counter,
bg,
fg,
false);
p.drawImage(
iconImage.width() - layer.width() - 1,
iconImage.height() - layer.height() - 1,
layer);
QPainter p(&iconImage);
p.drawImage(
iconImage.width() - layer.width() - 1,
iconImage.height() - layer.height() - 1,
layer);
} else {
App::wnd()->placeSmallCounter(iconImage, 16, counter, bg, QPoint(), fg);
}
}
result.addPixmap(App::pixmapFromImageInPlace(
@@ -268,10 +267,12 @@ QIcon TrayIconGen(int counter, bool muted) {
return result;
}
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
bool IsIndicatorApplication() {
// Hack for indicator-application, which doesn't handle icons sent across D-Bus:
// save the icon to a temp file and set the icon name to that filename.
// Hack for indicator-application,
// which doesn't handle icons sent across D-Bus:
// save the icon to a temp file
// and set the icon name to that filename.
static const auto Result = [] {
const auto interface = QDBusConnection::sessionBus().interface();
@@ -337,10 +338,10 @@ bool UseUnityCounter() {
return Result;
}
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
bool IsSNIAvailable() {
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
auto message = QDBusMessage::createMethodCall(
kSNIWatcherService.utf16(),
qsl("/StatusNotifierWatcher"),
@@ -360,7 +361,7 @@ bool IsSNIAvailable() {
} else if (reply.error().type() != QDBusError::ServiceUnknown) {
LOG(("SNI Error: %1").arg(reply.error().message()));
}
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
return false;
}
@@ -374,7 +375,7 @@ quint32 djbStringHash(QString string) {
return hash;
}
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
bool IsAppMenuSupported() {
const auto interface = QDBusConnection::sessionBus().interface();
@@ -438,17 +439,12 @@ void ForceDisabled(QAction *action, bool disabled) {
action->setDisabled(false);
}
}
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
} // namespace
MainWindow::MainWindow(not_null<Window::Controller*> controller)
: Window::MainWindow(controller) {
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
if (GtkClipboardSupported()) {
_gtkClipboard = Libs::gtk_clipboard_get(Libs::gdk_atom_intern("CLIPBOARD", true));
}
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
}
void MainWindow::initHook() {
@@ -460,7 +456,7 @@ void MainWindow::initHook() {
LOG(("System tray available: %1").arg(Logs::b(trayAvailable)));
Platform::SetTrayIconSupported(trayAvailable);
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
auto sniWatcher = new QDBusServiceWatcher(
kSNIWatcherService.utf16(),
QDBusConnection::sessionBus(),
@@ -504,7 +500,7 @@ void MainWindow::initHook() {
} else {
LOG(("Not using Unity launcher counter."));
}
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
updateWaylandDecorationColors();
@@ -515,11 +511,11 @@ void MainWindow::initHook() {
}
bool MainWindow::hasTrayIcon() const {
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
return trayIcon || (SNIAvailable && _sniTrayIcon);
#else
return trayIcon;
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
}
void MainWindow::psShowTrayMenu() {
@@ -527,14 +523,14 @@ void MainWindow::psShowTrayMenu() {
}
void MainWindow::psTrayMenuUpdated() {
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
if (_sniTrayIcon && trayIconMenu) {
_sniTrayIcon->setContextMenu(trayIconMenu);
}
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
}
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
void MainWindow::setSNITrayIcon(int counter, bool muted) {
const auto iconName = GetTrayIconName(counter, muted);
@@ -649,14 +645,14 @@ void MainWindow::onAppMenuOwnerChanged(
UnregisterAppMenu(winId());
}
}
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
void MainWindow::psSetupTrayIcon() {
const auto counter = Core::App().unreadBadge();
const auto muted = Core::App().unreadBadgeMuted();
if (SNIAvailable) {
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
LOG(("Using SNI tray icon."));
if (!_sniTrayIcon) {
_sniTrayIcon = new StatusNotifierItem(
@@ -669,7 +665,7 @@ void MainWindow::psSetupTrayIcon() {
attachToSNITrayIcon();
}
updateIconCounters();
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
} else {
LOG(("Using Qt tray icon."));
if (!trayIcon) {
@@ -688,13 +684,13 @@ void MainWindow::workmodeUpdated(DBIWorkMode mode) {
if (!Platform::TrayIconSupported()) {
return;
} else if (mode == dbiwmWindowOnly) {
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
if (_sniTrayIcon) {
_sniTrayIcon->setContextMenu(0);
_sniTrayIcon->deleteLater();
}
_sniTrayIcon = nullptr;
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
if (trayIcon) {
trayIcon->setContextMenu(0);
@@ -717,7 +713,7 @@ void MainWindow::updateIconCounters() {
updateWindowIcon();
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
if (UseUnityCounter()) {
const auto launcherUrl = "application://" + GetLauncherFilename();
QVariantMap dbusUnityProperties;
@@ -745,7 +741,7 @@ void MainWindow::updateIconCounters() {
if (_sniTrayIcon) {
setSNITrayIcon(counter, muted);
}
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
if (trayIcon && IsIconRegenerationNeeded(counter, muted)) {
trayIcon->setIcon(TrayIconGen(counter, muted));
@@ -753,21 +749,38 @@ void MainWindow::updateIconCounters() {
}
void MainWindow::updateWaylandDecorationColors() {
windowHandle()->setProperty("__material_decoration_backgroundColor", st::titleBgActive->c);
windowHandle()->setProperty("__material_decoration_foregroundColor", st::titleFgActive->c);
windowHandle()->setProperty("__material_decoration_backgroundInactiveColor", st::titleBg->c);
windowHandle()->setProperty("__material_decoration_foregroundInactiveColor", st::titleFg->c);
windowHandle()->setProperty(
"__material_decoration_backgroundColor",
st::titleBgActive->c);
windowHandle()->setProperty(
"__material_decoration_foregroundColor",
st::titleFgActive->c);
windowHandle()->setProperty(
"__material_decoration_backgroundInactiveColor",
st::titleBg->c);
windowHandle()->setProperty(
"__material_decoration_foregroundInactiveColor",
st::titleFg->c);
// Trigger a QtWayland client-side decoration update
windowHandle()->resize(windowHandle()->size());
}
void MainWindow::LibsLoaded() {
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
qDBusRegisterMetaType<ToolTip>();
qDBusRegisterMetaType<IconPixmap>();
qDBusRegisterMetaType<IconPixmapList>();
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
if (!qEnvironmentVariableIsSet(kDisableTrayCounter.utf8())) {
g_message(
"You can disable tray icon counter with %s "
"and make it look better if it is monochrome.",
kDisableTrayCounter.utf8().constData());
}
}
void MainWindow::initTrayMenuHook() {
@@ -775,7 +788,7 @@ void MainWindow::initTrayMenuHook() {
_trayIconMenuXEmbed->deleteOnHide(false);
}
#ifdef TDESKTOP_DISABLE_DBUS_INTEGRATION
#ifdef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
void MainWindow::createGlobalMenu() {
}
@@ -783,7 +796,7 @@ void MainWindow::createGlobalMenu() {
void MainWindow::updateGlobalMenuHook() {
}
#else // TDESKTOP_DISABLE_DBUS_INTEGRATION
#else // DESKTOP_APP_DISABLE_DBUS_INTEGRATION
void MainWindow::createGlobalMenu() {
psMainMenu = new QMenu(this);
@@ -1094,10 +1107,10 @@ void MainWindow::onVisibleChanged(bool visible) {
}
}
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
MainWindow::~MainWindow() {
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
delete _sniTrayIcon;
if (AppMenuSupported) {
@@ -1106,7 +1119,7 @@ MainWindow::~MainWindow() {
delete _mainMenuExporter;
delete psMainMenu;
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
delete _trayIconMenuXEmbed;
}

View File

@@ -11,18 +11,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/popup_menu.h"
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
#include "statusnotifieritem.h"
#include <QtCore/QTemporaryFile>
#include <QtDBus/QDBusObjectPath>
#include <dbusmenuexporter.h>
#endif
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
typedef struct _GtkClipboard GtkClipboard;
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
namespace Platform {
class MainWindow : public Window::MainWindow {
@@ -45,7 +40,7 @@ public:
public slots:
void psShowTrayMenu();
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
void onSNIOwnerChanged(
const QString &service,
const QString &oldOwner,
@@ -73,13 +68,7 @@ public slots:
void onVisibleChanged(bool visible);
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
GtkClipboard *gtkClipboard() {
return _gtkClipboard;
}
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
protected:
void initHook() override;
@@ -112,7 +101,7 @@ private:
void updateIconCounters();
void updateWaylandDecorationColors();
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
StatusNotifierItem *_sniTrayIcon = nullptr;
std::unique_ptr<QTemporaryFile> _trayIconFile = nullptr;
@@ -142,11 +131,7 @@ private:
void setSNITrayIcon(int counter, bool muted);
void attachToSNITrayIcon();
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
GtkClipboard *_gtkClipboard = nullptr;
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
};

View File

@@ -17,24 +17,33 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "main/main_session.h"
#include "lang/lang_keys.h"
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
#include <QtCore/QVersionNumber>
#include <QtDBus/QDBusConnection>
#include <QtDBus/QDBusMessage>
#include <QtDBus/QDBusReply>
#include <QtDBus/QDBusError>
#include <QtDBus/QDBusMetaType>
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
extern "C" {
#undef signals
#include <gio/gio.h>
#define signals public
} // extern "C"
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
namespace Platform {
namespace Notifications {
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
namespace {
constexpr auto kDBusTimeout = 30000;
constexpr auto kService = "org.freedesktop.Notifications"_cs;
constexpr auto kObjectPath = "/org/freedesktop/Notifications"_cs;
constexpr auto kInterface = kService;
constexpr auto kPropertiesInterface = "org.freedesktop.DBus.Properties"_cs;
constexpr auto kImageDataType = "(iiibii@ay)"_cs;
constexpr auto kNotifyArgsType = "(susssasa{sv}i)"_cs;
bool NotificationsSupported = false;
bool InhibitedNotSupported = false;
@@ -53,7 +62,11 @@ void ComputeSupported(bool wait = false) {
watcher,
&QDBusPendingCallWatcher::finished,
[=](QDBusPendingCallWatcher *call) {
QDBusPendingReply<QString, QString, QString, QString> reply = *call;
QDBusPendingReply<
QString,
QString,
QString,
QString> reply = *call;
if (reply.isValid()) {
NotificationsSupported = true;
@@ -203,7 +216,57 @@ QString GetImageKey(const QVersionNumber &specificationVersion) {
return QString();
}
} // namespace
class NotificationData {
public:
using NotificationId = Window::Notifications::Manager::NotificationId;
NotificationData(
const base::weak_ptr<Manager> &manager,
const QString &title,
const QString &subtitle,
const QString &msg,
NotificationId id,
bool hideReplyButton);
NotificationData(const NotificationData &other) = delete;
NotificationData &operator=(const NotificationData &other) = delete;
NotificationData(NotificationData &&other) = delete;
NotificationData &operator=(NotificationData &&other) = delete;
~NotificationData();
bool show();
void close();
void setImage(const QString &imagePath);
void notificationClosed(uint id, uint reason);
void actionInvoked(uint id, const QString &actionName);
void notificationReplied(uint id, const QString &text);
private:
GDBusProxy *_dbusProxy;
base::weak_ptr<Manager> _manager;
QString _title;
QString _body;
std::vector<QString> _actions;
base::flat_map<QString, GVariant*> _hints;
QString _imageKey;
QImage _image;
uint _notificationId = 0;
NotificationId _id;
static void signalEmitted(
GDBusProxy *proxy,
gchar *sender_name,
gchar *signal_name,
GVariant *parameters,
NotificationData *notificationData);
};
using Notification = std::shared_ptr<NotificationData>;
NotificationData::NotificationData(
const base::weak_ptr<Manager> &manager,
@@ -212,7 +275,15 @@ NotificationData::NotificationData(
const QString &msg,
NotificationId id,
bool hideReplyButton)
: _dbusConnection(QDBusConnection::sessionBus())
: _dbusProxy(g_dbus_proxy_new_for_bus_sync(
G_BUS_TYPE_SESSION,
G_DBUS_PROXY_FLAGS_NONE,
nullptr,
kService.utf8(),
kObjectPath.utf8(),
kInterface.utf8(),
nullptr,
nullptr))
, _manager(manager)
, _title(title)
, _imageKey(GetImageKey(ParseSpecificationVersion(
@@ -233,116 +304,134 @@ NotificationData::NotificationData(
}
if (capabilities.contains(qsl("actions"))) {
_actions << qsl("default") << QString();
_actions.push_back(qsl("default"));
_actions.push_back(QString());
_actions
<< qsl("mail-mark-read")
<< tr::lng_context_mark_read(tr::now);
_actions.push_back(qsl("mail-mark-read"));
_actions.push_back(tr::lng_context_mark_read(tr::now));
if (capabilities.contains(qsl("inline-reply")) && !hideReplyButton) {
_actions
<< qsl("inline-reply")
<< tr::lng_notification_reply(tr::now);
_dbusConnection.connect(
kService.utf16(),
kObjectPath.utf16(),
kInterface.utf16(),
qsl("NotificationReplied"),
this,
SLOT(notificationReplied(uint,QString)));
_actions.push_back(qsl("inline-reply"));
_actions.push_back(tr::lng_notification_reply(tr::now));
} else {
// icon name according to https://specifications.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html
_actions
<< qsl("mail-reply-sender")
<< tr::lng_notification_reply(tr::now);
_actions.push_back(qsl("mail-reply-sender"));
_actions.push_back(tr::lng_notification_reply(tr::now));
}
_dbusConnection.connect(
kService.utf16(),
kObjectPath.utf16(),
kInterface.utf16(),
qsl("ActionInvoked"),
this,
SLOT(actionInvoked(uint,QString)));
}
if (capabilities.contains(qsl("action-icons"))) {
_hints["action-icons"] = true;
_hints.emplace(qsl("action-icons"), g_variant_new_boolean(true));
}
// suppress system sound if telegram sound activated, otherwise use system sound
// suppress system sound if telegram sound activated,
// otherwise use system sound
if (capabilities.contains(qsl("sound"))) {
if (Core::App().settings().soundNotify()) {
_hints["suppress-sound"] = true;
_hints.emplace(
qsl("suppress-sound"),
g_variant_new_boolean(true));
} else {
// sound name according to http://0pointer.de/public/sound-naming-spec.html
_hints["sound-name"] = qsl("message-new-instant");
_hints.emplace(
qsl("sound-name"),
g_variant_new_string("message-new-instant"));
}
}
if (capabilities.contains(qsl("x-canonical-append"))) {
_hints["x-canonical-append"] = qsl("true");
_hints.emplace(
qsl("x-canonical-append"),
g_variant_new_string("true"));
}
_hints["category"] = qsl("im.received");
_hints["desktop-entry"] = GetLauncherBasename();
_hints.emplace(qsl("category"), g_variant_new_string("im.received"));
_dbusConnection.connect(
kService.utf16(),
kObjectPath.utf16(),
kInterface.utf16(),
qsl("NotificationClosed"),
this,
SLOT(notificationClosed(uint)));
_hints.emplace(
qsl("desktop-entry"),
g_variant_new_string(GetLauncherBasename().toUtf8()));
g_signal_connect(_dbusProxy, "g-signal", G_CALLBACK(signalEmitted), this);
}
NotificationData::~NotificationData() {
g_object_unref(_dbusProxy);
for (const auto &[key, value] : _hints) {
if (value) {
g_variant_unref(value);
}
}
}
bool NotificationData::show() {
GVariantBuilder actionsBuilder, hintsBuilder;
GError *error = nullptr;
g_variant_builder_init(&actionsBuilder, G_VARIANT_TYPE("as"));
for (const auto &value : _actions) {
g_variant_builder_add(
&actionsBuilder,
"s",
value.toUtf8().constData());
}
g_variant_builder_init(&hintsBuilder, G_VARIANT_TYPE("a{sv}"));
for (auto &[key, value] : _hints) {
g_variant_builder_add(
&hintsBuilder,
"{sv}",
key.toUtf8().constData(),
value);
value = nullptr;
}
const auto iconName = _imageKey.isEmpty() || !_hints.contains(_imageKey)
? GetIconName()
: QString();
auto message = QDBusMessage::createMethodCall(
kService.utf16(),
kObjectPath.utf16(),
kInterface.utf16(),
qsl("Notify"));
auto reply = g_dbus_proxy_call_sync(
_dbusProxy,
"Notify",
g_variant_new(
kNotifyArgsType.utf8(),
AppName.utf8().constData(),
0,
iconName.toUtf8().constData(),
_title.toUtf8().constData(),
_body.toUtf8().constData(),
&actionsBuilder,
&hintsBuilder,
-1),
G_DBUS_CALL_FLAGS_NONE,
kDBusTimeout,
nullptr,
&error);
message.setArguments({
AppName.utf16(),
uint(0),
iconName,
_title,
_body,
_actions,
_hints,
-1
});
const auto replyValid = !error;
const QDBusReply<uint> reply = _dbusConnection.call(
message);
if (reply.isValid()) {
_notificationId = reply.value();
if (replyValid) {
g_variant_get(reply, "(u)", &_notificationId);
g_variant_unref(reply);
} else {
LOG(("Native notification error: %1").arg(reply.error().message()));
LOG(("Native notification error: %1").arg(error->message));
g_error_free(error);
}
return reply.isValid();
return replyValid;
}
void NotificationData::close() {
auto message = QDBusMessage::createMethodCall(
kService.utf16(),
kObjectPath.utf16(),
kInterface.utf16(),
qsl("CloseNotification"));
message.setArguments({
_notificationId
});
_dbusConnection.send(message);
g_dbus_proxy_call(
_dbusProxy,
"CloseNotification",
g_variant_new("(u)", _notificationId),
G_DBUS_CALL_FLAGS_NONE,
-1,
nullptr,
nullptr,
nullptr);
}
void NotificationData::setImage(const QString &imagePath) {
@@ -350,31 +439,60 @@ void NotificationData::setImage(const QString &imagePath) {
return;
}
const auto image = QImage(imagePath)
.convertToFormat(QImage::Format_RGBA8888);
_image = QImage(imagePath).convertToFormat(QImage::Format_RGBA8888);
const QByteArray imageBytes(
(const char*)image.constBits(),
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
image.byteCount());
#else // Qt < 5.10.0
image.sizeInBytes());
#endif // Qt >= 5.10.0
const auto imageData = ImageData{
image.width(),
image.height(),
image.bytesPerLine(),
_hints.emplace(_imageKey, g_variant_new(
kImageDataType.utf8(),
_image.width(),
_image.height(),
_image.bytesPerLine(),
true,
8,
4,
imageBytes
};
_hints[_imageKey] = QVariant::fromValue(imageData);
g_variant_new_from_data(
G_VARIANT_TYPE("ay"),
_image.constBits(),
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
_image.byteCount(),
#else // Qt < 5.10.0
_image.sizeInBytes(),
#endif // Qt >= 5.10.0
true,
nullptr,
nullptr)));
}
void NotificationData::notificationClosed(uint id) {
void NotificationData::signalEmitted(
GDBusProxy *proxy,
gchar *sender_name,
gchar *signal_name,
GVariant *parameters,
NotificationData *notificationData) {
if(signal_name == qstr("ActionInvoked")) {
guint32 id;
gchar *actionName;
g_variant_get(parameters, "(us)", &id, &actionName);
notificationData->actionInvoked(id, actionName);
g_free(actionName);
}
if(signal_name == qstr("NotificationReplied")) {
guint32 id;
gchar *text;
g_variant_get(parameters, "(us)", &id, &text);
notificationData->notificationReplied(id, text);
g_free(text);
}
if(signal_name == qstr("NotificationClosed")) {
guint32 id;
guint32 reason;
g_variant_get(parameters, "(uu)", &id, &reason);
notificationData->notificationClosed(id, reason);
}
}
void NotificationData::notificationClosed(uint id, uint reason) {
if (id == _notificationId) {
const auto manager = _manager;
const auto my = _id;
@@ -415,47 +533,17 @@ void NotificationData::notificationReplied(uint id, const QString &text) {
}
}
QDBusArgument &operator<<(
QDBusArgument &argument,
const NotificationData::ImageData &imageData) {
argument.beginStructure();
argument
<< imageData.width
<< imageData.height
<< imageData.rowStride
<< imageData.hasAlpha
<< imageData.bitsPerSample
<< imageData.channels
<< imageData.data;
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(
const QDBusArgument &argument,
NotificationData::ImageData &imageData) {
argument.beginStructure();
argument
>> imageData.width
>> imageData.height
>> imageData.rowStride
>> imageData.hasAlpha
>> imageData.bitsPerSample
>> imageData.channels
>> imageData.data;
argument.endStructure();
return argument;
}
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
} // namespace
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
bool SkipAudio() {
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
if (Supported()
&& GetCapabilities().contains(qsl("inhibitions"))
&& !InhibitedNotSupported) {
return Inhibited();
}
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
return false;
}
@@ -469,18 +557,18 @@ bool SkipFlashBounce() {
}
bool Supported() {
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
return NotificationsSupported;
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
return false;
}
std::unique_ptr<Window::Notifications::Manager> Create(
Window::Notifications::System *system) {
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
GetSupported();
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
if ((Core::App().settings().nativeNotifications() && Supported())
|| Platform::IsWayland()) {
@@ -490,7 +578,7 @@ std::unique_ptr<Window::Notifications::Manager> Create(
return nullptr;
}
#ifdef TDESKTOP_DISABLE_DBUS_INTEGRATION
#ifdef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
class Manager::Private {
public:
using Type = Window::Notifications::CachedUserpics::Type;
@@ -510,7 +598,7 @@ public:
void clearFromSession(not_null<Main::Session*> session) {}
void clearNotification(NotificationId id) {}
};
#else // TDESKTOP_DISABLE_DBUS_INTEGRATION
#else // DESKTOP_APP_DISABLE_DBUS_INTEGRATION
class Manager::Private {
public:
using Type = Window::Notifications::CachedUserpics::Type;
@@ -544,8 +632,6 @@ private:
Manager::Private::Private(not_null<Manager*> manager, Type type)
: _cachedUserpics(type)
, _manager(manager) {
qDBusRegisterMetaType<NotificationData::ImageData>();
if (!Supported()) {
return;
}
@@ -699,7 +785,7 @@ void Manager::Private::clearNotification(NotificationId id) {
Manager::Private::~Private() {
clearAll();
}
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
Manager::Manager(not_null<Window::Notifications::System*> system)
: NativeManager(system)

View File

@@ -10,76 +10,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "platform/platform_notifications_manager.h"
#include "base/weak_ptr.h"
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#include <QtDBus/QDBusConnection>
#include <QtDBus/QDBusArgument>
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
namespace Platform {
namespace Notifications {
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
class NotificationData : public QObject {
Q_OBJECT
public:
using NotificationId = Window::Notifications::Manager::NotificationId;
NotificationData(
const base::weak_ptr<Manager> &manager,
const QString &title,
const QString &subtitle,
const QString &msg,
NotificationId id,
bool hideReplyButton);
NotificationData(const NotificationData &other) = delete;
NotificationData &operator=(const NotificationData &other) = delete;
NotificationData(NotificationData &&other) = delete;
NotificationData &operator=(NotificationData &&other) = delete;
bool show();
void close();
void setImage(const QString &imagePath);
struct ImageData {
int width, height, rowStride;
bool hasAlpha;
int bitsPerSample, channels;
QByteArray data;
};
private:
QDBusConnection _dbusConnection;
base::weak_ptr<Manager> _manager;
QString _title;
QString _body;
QStringList _actions;
QVariantMap _hints;
QString _imageKey;
uint _notificationId = 0;
NotificationId _id;
private slots:
void notificationClosed(uint id);
void actionInvoked(uint id, const QString &actionName);
void notificationReplied(uint id, const QString &text);
};
using Notification = std::shared_ptr<NotificationData>;
QDBusArgument &operator<<(
QDBusArgument &argument,
const NotificationData::ImageData &imageData);
const QDBusArgument &operator>>(
const QDBusArgument &argument,
NotificationData::ImageData &imageData);
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
class Manager
: public Window::Notifications::NativeManager
, public base::has_weak_ptr {
@@ -110,7 +43,3 @@ private:
} // namespace Notifications
} // namespace Platform
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
Q_DECLARE_METATYPE(Platform::Notifications::NotificationData::ImageData)
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION

View File

@@ -31,13 +31,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <private/qwaylandwindow_p.h>
#include <private/qwaylandshellsurface_p.h>
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
#include <QtDBus/QDBusInterface>
#include <QtDBus/QDBusConnection>
#include <QtDBus/QDBusMessage>
#include <QtDBus/QDBusReply>
#include <QtDBus/QDBusError>
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
#include <xcb/xcb.h>
#include <xcb/screensaver.h>
@@ -46,6 +46,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <wayland-client.h>
#endif // Qt < 5.13 && !DESKTOP_APP_QT_PATCHED
#include <glib.h>
extern "C" {
#undef signals
#include <gio/gio.h>
#define signals public
} // extern "C"
#include <sys/stat.h>
#include <sys/types.h>
#include <cstdlib>
@@ -62,9 +70,12 @@ using QtWaylandClient::QWaylandWindow;
namespace Platform {
namespace {
constexpr auto kDisableGtkIntegration = "TDESKTOP_DISABLE_GTK_INTEGRATION"_cs;
constexpr auto kIgnoreGtkIncompatibility = "TDESKTOP_I_KNOW_ABOUT_GTK_INCOMPATIBILITY"_cs;
constexpr auto kDesktopFile = ":/misc/kotatogramdesktop.desktop"_cs;
constexpr auto kSnapLauncherDir = "/var/lib/snapd/desktop/applications/"_cs;
constexpr auto kIconName = "kotatogram"_cs;
constexpr auto kHandlerTypeName = "x-scheme-handler/tg"_cs;
constexpr auto kXDGDesktopPortalService = "org.freedesktop.portal.Desktop"_cs;
constexpr auto kXDGDesktopPortalObjectPath = "/org/freedesktop/portal/desktop"_cs;
@@ -74,8 +85,12 @@ QStringList PlatformThemes;
bool IsTrayIconSupported = true;
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
void PortalAutostart(bool autostart, bool silent = false) {
if (cExeName().isEmpty()) {
return;
}
QVariantMap options;
options["reason"] = tr::lng_settings_auto_start(tr::now);
options["autostart"] = autostart;
@@ -121,7 +136,8 @@ uint FileChooserPortalVersion() {
qsl("version")
});
const QDBusReply<uint> reply = QDBusConnection::sessionBus().call(message);
const QDBusReply<uint> reply = QDBusConnection::sessionBus().call(
message);
if (reply.isValid()) {
return reply.value();
@@ -135,7 +151,7 @@ uint FileChooserPortalVersion() {
return Result;
}
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
QString FlatpakID() {
static const auto Result = [] {
@@ -176,96 +192,39 @@ QString RealExecutablePath(int argc, char *argv[]) {
: QString();
}
bool RunShellCommand(const QByteArray &command) {
auto result = system(command.constData());
bool RunShellCommand(const QString &program, const QStringList &arguments) {
const auto result = QProcess::execute(program, arguments);
const auto command = qsl("%1 %2")
.arg(program)
.arg(arguments.join(' '));
if (result) {
DEBUG_LOG(("App Error: command failed, code: %1, command (in utf8): %2").arg(result).arg(command.constData()));
DEBUG_LOG(("App Error: command failed, code: %1, command: %2")
.arg(result)
.arg(command));
return false;
}
DEBUG_LOG(("App Info: command succeeded, command (in utf8): %1").arg(command.constData()));
DEBUG_LOG(("App Info: command succeeded, command: %1")
.arg(command));
return true;
}
[[nodiscard]] bool CheckFontConfigCrash() {
return InSnap();
}
[[nodiscard]] QString FallbackFontConfigCheckPath() {
return cWorkingDir() + "tdata/fc-check";
}
#ifdef TDESKTOP_USE_FONTCONFIG_FALLBACK
[[nodiscard]] bool BadFontConfigVersion() {
if (CheckFontConfigCrash()) {
return QFile(FallbackFontConfigCheckPath()).exists();
}
QProcess process;
process.setProcessChannelMode(QProcess::MergedChannels);
process.start("fc-list", QStringList() << "--version");
process.waitForFinished();
if (process.exitCode() > 0) {
LOG(("App Error: Could not start fc-list. Process exited with code: %1.").arg(process.exitCode()));
return false;
}
QString result(process.readAllStandardOutput());
DEBUG_LOG(("Fontconfig version string: ") + result);
QVersionNumber version = QVersionNumber::fromString(result.split("version ").last());
if (version.isNull()) {
LOG(("App Error: Could not get version from fc-list output."));
return false;
}
LOG(("Fontconfig version: %1.").arg(version.toString()));
if (version < QVersionNumber::fromString("2.13")) {
if (!qEnvironmentVariableIsSet("TDESKTOP_FORCE_CUSTOM_FONTCONFIG")) {
return false;
}
}
return true;
}
void FallbackFontConfig() {
const auto custom = cWorkingDir() + "tdata/fc-custom-1.conf";
auto doFallback = [&] {
if (QFile(custom).exists()) {
LOG(("Custom FONTCONFIG_FILE: ") + custom);
qputenv("FONTCONFIG_FILE", QFile::encodeName(custom));
return true;
}
return false;
};
if (doFallback()) {
return;
}
if (BadFontConfigVersion()) {
QFile(":/fc/fc-custom.conf").copy(custom);
doFallback();
}
}
#endif // TDESKTOP_USE_FONTCONFIG_FALLBACK
bool GenerateDesktopFile(
const QString &targetPath,
const QString &args,
bool silent = false) {
if (targetPath.isEmpty() || cExeName().isEmpty()) {
return false;
}
DEBUG_LOG(("App Info: placing .desktop file to %1").arg(targetPath));
if (!QDir(targetPath).exists()) QDir().mkpath(targetPath);
const auto sourceFile = [&] {
if (InSnap()) {
return kSnapLauncherDir.utf16() + GetLauncherFilename();
} else {
return kDesktopFile.utf16();
}
}();
const auto sourceFile = kDesktopFile.utf16();
const auto targetFile = targetPath + GetLauncherFilename();
QString fileText;
@@ -324,39 +283,57 @@ 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
std::optional<crl::time> XCBLastUserInputTime() {
if (const auto native = QGuiApplication::platformNativeInterface()) {
const auto connection = reinterpret_cast<xcb_connection_t*>(
native->nativeResourceForIntegration(QByteArray("connection")));
if (!connection) {
return std::nullopt;
}
const auto screen = xcb_setup_roots_iterator(
xcb_get_setup(connection)).data;
if (!screen) {
return std::nullopt;
}
const auto cookie = xcb_screensaver_query_info(connection, screen->root);
auto info = xcb_screensaver_query_info_reply(connection, cookie, nullptr);
if (!info) {
return std::nullopt;
}
const auto idle = info->ms_since_user_input;
free(info);
return (crl::now() - static_cast<crl::time>(idle));
const auto native = QGuiApplication::platformNativeInterface();
if (!native) {
return std::nullopt;
}
return std::nullopt;
const auto connection = reinterpret_cast<xcb_connection_t*>(
native->nativeResourceForIntegration(QByteArray("connection")));
if (!connection) {
return std::nullopt;
}
const auto screen = xcb_setup_roots_iterator(xcb_get_setup(connection)).data;
if (!screen) {
return std::nullopt;
}
const auto cookie = xcb_screensaver_query_info(connection, screen->root);
auto info = xcb_screensaver_query_info_reply(
connection,
cookie,
nullptr);
if (!info) {
return std::nullopt;
}
const auto idle = info->ms_since_user_input;
free(info);
return (crl::now() - static_cast<crl::time>(idle));
}
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
std::optional<crl::time> FreedesktopDBusLastUserInputTime() {
static auto NotSupported = false;
@@ -443,7 +420,7 @@ std::optional<crl::time> MutterDBusLastUserInputTime() {
return std::nullopt;
}
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
uint XCBMoveResizeFromEdges(Qt::Edges edges) {
if (edges == (Qt::TopEdge | Qt::LeftEdge))
@@ -510,7 +487,8 @@ bool StartXCBMoveResize(QWindow *window, int edges) {
return false;
}
const auto moveResizeCookie = xcb_intern_atom(connection,
const auto moveResizeCookie = xcb_intern_atom(
connection,
0,
strlen("_NET_WM_MOVERESIZE"),
"_NET_WM_MOVERESIZE");
@@ -544,17 +522,20 @@ bool StartXCBMoveResize(QWindow *window, int edges) {
xev.data.data32[4] = 0;
xcb_ungrab_pointer(connection, XCB_CURRENT_TIME);
xcb_send_event(connection,
xcb_send_event(
connection,
false,
screen->root,
XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY,
XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT
| XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY,
reinterpret_cast<const char*>(&xev));
return true;
}
bool StartWaylandMove(QWindow *window) {
if (const auto waylandWindow = static_cast<QWaylandWindow*>(window->handle())) {
if (const auto waylandWindow = static_cast<QWaylandWindow*>(
window->handle())) {
if (const auto seat = waylandWindow->display()->lastInputDevice()) {
if (const auto shellSurface = waylandWindow->shellSurface()) {
return shellSurface->move(seat);
@@ -566,7 +547,8 @@ bool StartWaylandMove(QWindow *window) {
}
bool StartWaylandResize(QWindow *window, Qt::Edges edges) {
if (const auto waylandWindow = static_cast<QWaylandWindow*>(window->handle())) {
if (const auto waylandWindow = static_cast<QWaylandWindow*>(
window->handle())) {
if (const auto seat = waylandWindow->display()->lastInputDevice()) {
if (const auto shellSurface = waylandWindow->shellSurface()) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) || defined DESKTOP_APP_QT_PATCHED
@@ -585,6 +567,21 @@ bool StartWaylandResize(QWindow *window, Qt::Edges edges) {
return false;
}
bool ShowWaylandWindowMenu(QWindow *window) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) || defined DESKTOP_APP_QT_PATCHED
if (const auto waylandWindow = static_cast<QWaylandWindow*>(
window->handle())) {
if (const auto seat = waylandWindow->display()->lastInputDevice()) {
if (const auto shellSurface = waylandWindow->shellSurface()) {
return shellSurface->showWindowMenu(seat);
}
}
}
#endif // Qt >= 5.13 || DESKTOP_APP_QT_PATCHED
return false;
}
Window::Control GtkKeywordToWindowControl(const QString &keyword) {
if (keyword == qstr("minimize")) {
return Window::Control::Minimize;
@@ -629,7 +626,7 @@ bool IsStaticBinary() {
bool UseGtkIntegration() {
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
static const auto Result = !qEnvironmentVariableIsSet(
"TDESKTOP_DISABLE_GTK_INTEGRATION");
kDisableGtkIntegration.utf8());
return Result;
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
@@ -650,14 +647,6 @@ bool IsGtkIntegrationForced() {
return false;
}
bool UseGtkFileDialog() {
#ifdef TDESKTOP_USE_GTK_FILE_DIALOG
return true;
#else // TDESKTOP_USE_GTK_FILE_DIALOG
return false;
#endif // !TDESKTOP_USE_GTK_FILE_DIALOG
}
bool IsQtPluginsBundled() {
#ifdef DESKTOP_APP_USE_PACKAGED_LAZY
return true;
@@ -667,13 +656,13 @@ bool IsQtPluginsBundled() {
}
bool IsXDGDesktopPortalPresent() {
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
static const auto Result = QDBusInterface(
kXDGDesktopPortalService.utf16(),
kXDGDesktopPortalObjectPath.utf16()).isValid();
return Result;
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
return false;
}
@@ -693,11 +682,11 @@ bool UseXDGDesktopPortal() {
}
bool CanOpenDirectoryWithPortal() {
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) || defined DESKTOP_APP_QT_PATCHED) && !defined TDESKTOP_DISABLE_DBUS_INTEGRATION
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) || defined DESKTOP_APP_QT_PATCHED) && !defined DESKTOP_APP_DISABLE_DBUS_INTEGRATION
return FileChooserPortalVersion() >= 3;
#else // (Qt >= 5.15 || DESKTOP_APP_QT_PATCHED) && !TDESKTOP_DISABLE_DBUS_INTEGRATION
#else // (Qt >= 5.15 || DESKTOP_APP_QT_PATCHED) && !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
return false;
#endif // (Qt < 5.15 && !DESKTOP_APP_QT_PATCHED) || TDESKTOP_DISABLE_DBUS_INTEGRATION
#endif // (Qt < 5.15 && !DESKTOP_APP_QT_PATCHED) || DESKTOP_APP_DISABLE_DBUS_INTEGRATION
}
QString CurrentExecutablePath(int argc, char *argv[]) {
@@ -756,7 +745,7 @@ QString SingleInstanceLocalServerName(const QString &hash) {
QString GetLauncherBasename() {
static const auto Result = [&] {
if (InSnap()) {
if (InSnap() && !cExeName().isEmpty()) {
const auto snapNameKey =
qEnvironmentVariableIsSet("SNAP_INSTANCE_NAME")
? "SNAP_INSTANCE_NAME"
@@ -767,14 +756,17 @@ QString GetLauncherBasename() {
.arg(cExeName());
}
if (InAppImage()) {
if (InAppImage() && !cExeName().isEmpty()) {
const auto appimagePath = qsl("file://%1%2")
.arg(cExeDir())
.arg(cExeName())
.toUtf8();
char md5Hash[33] = { 0 };
hashMd5Hex(appimagePath.constData(), appimagePath.size(), md5Hash);
hashMd5Hex(
appimagePath.constData(),
appimagePath.size(),
md5Hash);
return qsl("appimagekit_%1-%2")
.arg(md5Hash)
@@ -812,39 +804,22 @@ QString GetIconName() {
return Result;
}
bool GtkClipboardSupported() {
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
return (Libs::gtk_clipboard_get != nullptr)
&& (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
return false;
}
QImage GetImageFromClipboard() {
QImage data;
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
if (!GtkClipboardSupported() || !App::wnd()->gtkClipboard()) {
if (!GetImageFromClipboardSupported() || !Libs::GtkClipboard()) {
return data;
}
auto gsel = Libs::gtk_clipboard_wait_for_contents(
App::wnd()->gtkClipboard(),
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(App::wnd()->gtkClipboard());
auto img = Libs::gtk_clipboard_wait_for_image(
Libs::GtkClipboard());
if (img) {
data = QImage(
@@ -872,7 +847,7 @@ std::optional<crl::time> LastUserInputTime() {
return XCBLastUserInputTime();
}
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
const auto freedesktopResult = FreedesktopDBusLastUserInputTime();
if (freedesktopResult.has_value()) {
return freedesktopResult;
@@ -882,7 +857,7 @@ std::optional<crl::time> LastUserInputTime() {
if (mutterResult.has_value()) {
return mutterResult;
}
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
return std::nullopt;
}
@@ -892,11 +867,14 @@ std::optional<bool> IsDarkMode() {
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")) {
&& Libs::GtkSetting<gboolean>(
"gtk-application-prefer-dark-theme")) {
return true;
}
if (Libs::GtkSetting("gtk-theme-name").toLower().endsWith(qsl("-dark"))) {
const auto themeName = Libs::GtkSetting("gtk-theme-name").toLower();
if (themeName.endsWith(qsl("-dark"))) {
return true;
}
@@ -908,7 +886,8 @@ std::optional<bool> IsDarkMode() {
}
bool AutostartSupported() {
// snap sandbox doesn't allow creating files in folders with names started with a dot
// snap sandbox doesn't allow creating files
// in folders with names started with a dot
// and doesn't provide any api to add an app to autostart
// thus, autostart isn't supported in snap
return !InSnap();
@@ -922,23 +901,6 @@ void SetTrayIconSupported(bool supported) {
IsTrayIconSupported = supported;
}
void FallbackFontConfigCheckBegin() {
if (!CheckFontConfigCrash()) {
return;
}
auto file = QFile(FallbackFontConfigCheckPath());
if (file.open(QIODevice::WriteOnly)) {
file.write("1", 1);
}
}
void FallbackFontConfigCheckEnd() {
if (!CheckFontConfigCrash()) {
return;
}
QFile(FallbackFontConfigCheckPath()).remove();
}
bool StartSystemMove(QWindow *window) {
if (IsWayland()) {
return StartWaylandMove(window);
@@ -955,13 +917,22 @@ bool StartSystemResize(QWindow *window, Qt::Edges edges) {
}
}
bool ShowWindowMenu(QWindow *window) {
if (IsWayland()) {
return ShowWaylandWindowMenu(window);
}
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(':');
const auto decorationLayout = Libs::GtkSetting(
"gtk-decoration-layout").split(':');
std::vector<Window::Control> controlsLeft;
ranges::transform(
@@ -1069,13 +1040,13 @@ void psActivateProcess(uint64 pid) {
namespace {
QString getHomeDir() {
auto home = QDir::homePath();
const auto home = QString(g_get_home_dir());
if (home != QDir::rootPath())
if (!home.isEmpty() && !home.endsWith('/')) {
return home + '/';
}
struct passwd *pw = getpwuid(getuid());
return (pw && pw->pw_dir && strlen(pw->pw_dir)) ? (QFile::decodeName(pw->pw_dir) + '/') : QString();
return home;
}
} // namespace
@@ -1127,10 +1098,6 @@ void start() {
LOG(("Launcher filename: %1").arg(GetLauncherFilename()));
#ifdef TDESKTOP_USE_FONTCONFIG_FALLBACK
FallbackFontConfig();
#endif // TDESKTOP_USE_FONTCONFIG_FALLBACK
qputenv("PULSE_PROP_application.name", AppName.utf8());
qputenv("PULSE_PROP_application.icon_name", GetIconName().toLatin1());
@@ -1139,11 +1106,54 @@ void start() {
if (UseGtkIntegration()
&& !IsStaticBinary()
&& !qEnvironmentVariableIsSet(
"TDESKTOP_I_KNOW_ABOUT_GTK_INCOMPATIBILITY")) {
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());
g_message(
"GTK integration can be disabled by setting %s to any value. "
"Keep in mind that this will lead to clipboard issues "
"and tdesktop will be unable to get settings from GTK "
"(such as decoration layout, dark mode & more).",
kDisableGtkIntegration.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 (!UseGtkIntegration()) {
g_warning(
"GTK integration was disabled on build or in runtime. "
"This will lead to clipboard issues and a lack of some features "
"(like Auto-Night Mode or system window controls layout).");
}
#ifdef DESKTOP_APP_USE_PACKAGED_RLOTTIE
g_warning(
"Application has been built with foreign rlottie, "
"animated emojis won't be colored to the selected pack.");
#endif // DESKTOP_APP_USE_PACKAGED_RLOTTIE
#ifdef DESKTOP_APP_USE_PACKAGED_FONTS
g_warning(
"Application was built without embedded fonts, "
"this may lead to font issues.");
#endif // DESKTOP_APP_USE_PACKAGED_FONTS
if(IsStaticBinary()
|| InAppImage()
|| InFlatpak()
@@ -1154,12 +1164,13 @@ void start() {
if((IsStaticBinary()
|| InAppImage()
|| InSnap()
|| UseGtkFileDialog()
|| IsQtPluginsBundled())
&& !InFlatpak()) {
// it is handled by Qt for flatpak and snap
&& !InFlatpak()
&& !InSnap()) {
LOG(("Checking for XDG Desktop Portal..."));
// this can give us a chance to use a proper file dialog for current session
// this can give us a chance to use
// a proper file dialog for current session
if (IsXDGDesktopPortalPresent()) {
LOG(("XDG Desktop Portal is present!"));
if (UseXDGDesktopPortal()) {
@@ -1177,18 +1188,12 @@ void start() {
void finish() {
}
void RegisterCustomScheme(bool force) {
#ifndef TDESKTOP_DISABLE_REGISTER_CUSTOM_SCHEME
const auto home = getHomeDir();
if (home.isEmpty() || cExeName().isEmpty())
return;
void InstallMainDesktopFile() {
static const auto DisabledByEnv = qEnvironmentVariableIsSet(
"TDESKTOP_DISABLE_DESKTOP_FILE_GENERATION");
// don't update desktop file for alpha version or if updater is disabled
if ((cAlphaVersion() || Core::UpdaterDisabled() || DisabledByEnv)
&& !force)
if (cAlphaVersion() || Core::UpdaterDisabled() || DisabledByEnv)
return;
const auto applicationsPath = QStandardPaths::writableLocation(
@@ -1196,10 +1201,8 @@ void RegisterCustomScheme(bool force) {
GenerateDesktopFile(applicationsPath, qsl("-- %u"));
const auto icons =
QStandardPaths::writableLocation(
QStandardPaths::GenericDataLocation)
+ qsl("/icons/");
const auto icons = QStandardPaths::writableLocation(
QStandardPaths::GenericDataLocation) + qsl("/icons/");
if (!QDir(icons).exists()) QDir().mkpath(icons);
@@ -1217,12 +1220,61 @@ void RegisterCustomScheme(bool force) {
}
}
RunShellCommand("update-desktop-database "
+ EscapeShell(QFile::encodeName(applicationsPath)));
RunShellCommand("update-desktop-database", {
applicationsPath
});
}
RunShellCommand("xdg-mime default "
+ GetLauncherFilename().toLatin1()
+ " x-scheme-handler/tg");
void RegisterCustomScheme(bool force) {
#ifndef TDESKTOP_DISABLE_REGISTER_CUSTOM_SCHEME
if (cExeName().isEmpty()) {
return;
}
GError *error = nullptr;
const auto actualCommandlineBuilder = qsl("%1 --")
.arg((IsStaticBinary() || InAppImage())
? cExeDir() + cExeName()
: cExeName());
const auto actualCommandline = qsl("%1 %u")
.arg(actualCommandlineBuilder);
auto currentAppInfo = g_app_info_get_default_for_type(
kHandlerTypeName.utf8(),
true);
if (currentAppInfo) {
const auto currentCommandline = QString(
g_app_info_get_commandline(currentAppInfo));
g_object_unref(currentAppInfo);
if (currentCommandline == actualCommandline) {
return;
}
}
auto newAppInfo = g_app_info_create_from_commandline(
actualCommandlineBuilder.toUtf8(),
AppName.utf8(),
G_APP_INFO_CREATE_SUPPORTS_URIS,
&error);
if (newAppInfo) {
g_app_info_set_as_default_for_type(
newAppInfo,
kHandlerTypeName.utf8(),
&error);
g_object_unref(newAppInfo);
}
if (error) {
LOG(("App Error: %1").arg(error->message));
g_error_free(error);
}
#endif // !TDESKTOP_DISABLE_REGISTER_CUSTOM_SCHEME
}
@@ -1280,6 +1332,7 @@ void finish() {
} // namespace Platform
void psNewVersion() {
Platform::InstallMainDesktopFile();
Platform::RegisterCustomScheme();
}
@@ -1288,28 +1341,14 @@ bool psShowOpenWithMenu(int x, int y, const QString &file) {
}
void psAutoStart(bool start, bool silent) {
const auto home = getHomeDir();
if (home.isEmpty() || cExeName().isEmpty())
return;
if (InFlatpak()) {
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
PortalAutostart(start, silent);
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
} else {
const auto autostart = [&] {
if (InSnap()) {
QDir realHomeDir(home);
realHomeDir.cd(qsl("../../.."));
return realHomeDir
.absoluteFilePath(qsl(".config/autostart/"));
} else {
return QStandardPaths::writableLocation(
QStandardPaths::GenericConfigLocation)
+ qsl("/autostart/");
}
}();
const auto autostart = QStandardPaths::writableLocation(
QStandardPaths::GenericConfigLocation)
+ qsl("/autostart/");
if (start) {
GenerateDesktopFile(autostart, qsl("-autostart"), silent);

View File

@@ -26,7 +26,6 @@ bool InAppImage();
bool IsStaticBinary();
bool UseGtkIntegration();
bool IsGtkIntegrationForced();
bool UseGtkFileDialog();
bool IsQtPluginsBundled();
bool IsXDGDesktopPortalPresent();
@@ -43,11 +42,8 @@ QString GetIconName();
inline void IgnoreApplicationActivationRightNow() {
}
void FallbackFontConfigCheckBegin();
void FallbackFontConfigCheckEnd();
bool GtkClipboardSupported();
void SetTrayIconSupported(bool supported);
void InstallMainDesktopFile();
} // namespace Platform