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:
@@ -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())
|
||||
|
@@ -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 {
|
||||
|
@@ -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() {
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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
|
||||
|
||||
};
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
@@ -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
|
||||
|
||||
|
Reference in New Issue
Block a user