mirror of https://github.com/procxx/kepka.git
Use LXQt's StatusNotifierItem implementation instead of appindicator
This commit is contained in:
parent
1b1f9d9985
commit
3b4dfa1381
|
@ -54,7 +54,7 @@ jobs:
|
|||
sudo apt-get update
|
||||
sudo apt-get install software-properties-common -y && \
|
||||
sudo apt-get install git libexif-dev liblzma-dev libz-dev libssl-dev \
|
||||
libappindicator-dev libicu-dev libdee-dev libdrm-dev dh-autoreconf \
|
||||
libgtk2.0-dev libice-dev libsm-dev libicu-dev libdrm-dev dh-autoreconf \
|
||||
autoconf automake build-essential libass-dev libfreetype6-dev \
|
||||
libgpac-dev libsdl1.2-dev libtheora-dev libtool libva-dev libvdpau-dev \
|
||||
libvorbis-dev libenchant-dev libxcb1-dev libxcb-image0-dev libxcb-shm0-dev \
|
||||
|
|
|
@ -61,3 +61,6 @@
|
|||
[submodule "Telegram/lib_qr"]
|
||||
path = Telegram/lib_qr
|
||||
url = https://github.com/desktop-app/lib_qr.git
|
||||
[submodule "Telegram/ThirdParty/libdbusmenu-qt"]
|
||||
path = Telegram/ThirdParty/libdbusmenu-qt
|
||||
url = https://github.com/desktop-app/libdbusmenu-qt.git
|
||||
|
|
|
@ -77,6 +77,14 @@ if (DESKTOP_APP_USE_PACKAGED)
|
|||
)
|
||||
endif()
|
||||
|
||||
if (LINUX AND NOT TDESKTOP_DISABLE_DBUS_INTEGRATION)
|
||||
target_link_libraries(Telegram
|
||||
PRIVATE
|
||||
desktop-app::external_statusnotifieritem
|
||||
desktop-app::external_dbusmenu_qt
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_libraries(Telegram
|
||||
PRIVATE
|
||||
tdesktop::lib_mtproto
|
||||
|
@ -1059,28 +1067,6 @@ elseif (LINUX)
|
|||
find_library(X11_LIBRARY X11)
|
||||
target_link_libraries(Telegram PRIVATE ${X11_LIBRARY})
|
||||
endif()
|
||||
|
||||
set(appindicator_packages
|
||||
ayatana-appindicator3-0.1
|
||||
ayatana-appindicator-0.1
|
||||
appindicator3-0.1
|
||||
appindicator-0.1
|
||||
)
|
||||
set(appindicator_found 0)
|
||||
foreach (package ${appindicator_packages})
|
||||
pkg_check_modules(APPIND_${package} ${package})
|
||||
if (APPIND_${package}_FOUND)
|
||||
set(appindicator_found 1)
|
||||
target_include_directories(Telegram PRIVATE "${APPIND_${package}_INCLUDE_DIRS}")
|
||||
if (${package} MATCHES "ayatana")
|
||||
target_compile_definitions(Telegram PRIVATE TDESKTOP_USE_AYATANA_INDICATORS)
|
||||
endif()
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
if (NOT ${appindicator_found})
|
||||
message(FATAL_ERROR "No libappindicator found by pkg-config.")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
|
|
@ -144,14 +144,10 @@ void MainWindow::firstShow() {
|
|||
|
||||
if (Platform::IsLinux()) {
|
||||
trayIconMenu->addAction(tr::lng_open_from_tray(tr::now), this, SLOT(showFromTray()));
|
||||
trayIconMenu->addAction(tr::lng_minimize_to_tray(tr::now), this, SLOT(minimizeToTray()));
|
||||
trayIconMenu->addAction(notificationActionText, this, SLOT(toggleDisplayNotifyFromTray()));
|
||||
trayIconMenu->addAction(tr::lng_quit_from_tray(tr::now), this, SLOT(quitFromTray()));
|
||||
} else {
|
||||
trayIconMenu->addAction(tr::lng_minimize_to_tray(tr::now), this, SLOT(minimizeToTray()));
|
||||
trayIconMenu->addAction(notificationActionText, this, SLOT(toggleDisplayNotifyFromTray()));
|
||||
trayIconMenu->addAction(tr::lng_quit_from_tray(tr::now), this, SLOT(quitFromTray()));
|
||||
}
|
||||
trayIconMenu->addAction(tr::lng_minimize_to_tray(tr::now), this, SLOT(minimizeToTray()));
|
||||
trayIconMenu->addAction(notificationActionText, this, SLOT(toggleDisplayNotifyFromTray()));
|
||||
trayIconMenu->addAction(tr::lng_quit_from_tray(tr::now), this, SLOT(quitFromTray()));
|
||||
Global::RefWorkMode().setForced(Global::WorkMode().value(), true);
|
||||
|
||||
psFirstShow();
|
||||
|
@ -564,7 +560,7 @@ void MainWindow::updateTrayMenu(bool force) {
|
|||
auto actions = iconMenu->actions();
|
||||
if (Platform::IsLinux()) {
|
||||
auto minimizeAction = actions.at(1);
|
||||
minimizeAction->setDisabled(!isVisible());
|
||||
minimizeAction->setEnabled(isVisible());
|
||||
} else {
|
||||
updateIsActive(0);
|
||||
auto active = isActive();
|
||||
|
@ -588,12 +584,6 @@ void MainWindow::updateTrayMenu(bool force) {
|
|||
: tr::lng_enable_notifications_from_tray(tr::now);
|
||||
notificationAction->setText(notificationActionText);
|
||||
|
||||
#ifndef Q_OS_WIN
|
||||
if (trayIcon && trayIcon->contextMenu() != iconMenu) {
|
||||
trayIcon->setContextMenu(iconMenu);
|
||||
}
|
||||
#endif // !Q_OS_WIN
|
||||
|
||||
psTrayMenuUpdated();
|
||||
}
|
||||
|
||||
|
|
|
@ -9,10 +9,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "platform/linux/specific_linux.h"
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
#include <QDBusInterface>
|
||||
#endif
|
||||
|
||||
namespace Platform {
|
||||
namespace DesktopEnvironment {
|
||||
namespace {
|
||||
|
@ -44,18 +40,15 @@ Type Compute() {
|
|||
return Type::Gnome;
|
||||
}
|
||||
return Type::Unity;
|
||||
} else if (list.contains("pantheon")) {
|
||||
return Type::Pantheon;
|
||||
} else if (list.contains("gnome")) {
|
||||
if (list.contains("ubuntu"))
|
||||
return Type::Ubuntu;
|
||||
|
||||
return Type::Gnome;
|
||||
} else if (list.contains("kde")) {
|
||||
if (kdeSession == qstr("5")) {
|
||||
return Type::KDE5;
|
||||
}
|
||||
return Type::KDE4;
|
||||
} else if (list.contains("mate")) {
|
||||
return Type::MATE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,6 +63,8 @@ Type Compute() {
|
|||
return Type::KDE4;
|
||||
}
|
||||
return Type::KDE3;
|
||||
} else if (desktopSession == qstr("mate")) {
|
||||
return Type::MATE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,9 +91,8 @@ Type ComputeAndLog() {
|
|||
case Type::KDE3: return "KDE3";
|
||||
case Type::KDE4: return "KDE4";
|
||||
case Type::KDE5: return "KDE5";
|
||||
case Type::Ubuntu: return "Ubuntu";
|
||||
case Type::Unity: return "Unity";
|
||||
case Type::Pantheon: return "Pantheon";
|
||||
case Type::MATE: return "MATE";
|
||||
}
|
||||
return QString::number(static_cast<int>(result));
|
||||
};
|
||||
|
@ -114,20 +108,5 @@ Type Get() {
|
|||
return result;
|
||||
}
|
||||
|
||||
bool TryQtTrayIcon() {
|
||||
return !IsPantheon();
|
||||
}
|
||||
|
||||
bool PreferAppIndicatorTrayIcon() {
|
||||
return (InSandbox() && !IsKDE())
|
||||
|| IsUnity()
|
||||
|| IsUbuntu()
|
||||
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
|| (IsGnome() && QDBusInterface("org.kde.StatusNotifierWatcher", "/").isValid());
|
||||
#else
|
||||
|| IsGnome();
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace DesktopEnvironment
|
||||
} // namespace Platform
|
||||
|
|
|
@ -16,9 +16,8 @@ enum class Type {
|
|||
KDE3,
|
||||
KDE4,
|
||||
KDE5,
|
||||
Ubuntu,
|
||||
Unity,
|
||||
Pantheon,
|
||||
MATE,
|
||||
};
|
||||
|
||||
Type Get();
|
||||
|
@ -43,20 +42,13 @@ inline bool IsKDE() {
|
|||
return IsKDE3() || IsKDE4() || IsKDE5();
|
||||
}
|
||||
|
||||
inline bool IsUbuntu() {
|
||||
return Get() == Type::Ubuntu;
|
||||
}
|
||||
|
||||
inline bool IsUnity() {
|
||||
return Get() == Type::Unity;
|
||||
}
|
||||
|
||||
inline bool IsPantheon() {
|
||||
return Get() == Type::Pantheon;
|
||||
inline bool IsMATE() {
|
||||
return Get() == Type::MATE;
|
||||
}
|
||||
|
||||
bool TryQtTrayIcon();
|
||||
bool PreferAppIndicatorTrayIcon();
|
||||
|
||||
} // namespace DesktopEnvironment
|
||||
} // namespace Platform
|
||||
|
|
|
@ -126,16 +126,6 @@ bool setupGtkBase(QLibrary &lib_gtk) {
|
|||
DEBUG_LOG(("Checked gtk with gtk_init_check!"));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool setupAppIndicator(QLibrary &lib_indicator) {
|
||||
if (!load(lib_indicator, "app_indicator_new", app_indicator_new)) return false;
|
||||
if (!load(lib_indicator, "app_indicator_set_status", app_indicator_set_status)) return false;
|
||||
if (!load(lib_indicator, "app_indicator_set_menu", app_indicator_set_menu)) return false;
|
||||
if (!load(lib_indicator, "app_indicator_set_icon_full", app_indicator_set_icon_full)) return false;
|
||||
|
||||
DEBUG_LOG(("Library appindicator functions loaded!"));
|
||||
return true;
|
||||
}
|
||||
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
|
||||
} // namespace
|
||||
|
@ -197,10 +187,6 @@ f_g_type_check_instance_cast g_type_check_instance_cast = nullptr;
|
|||
f_g_type_check_instance_is_a g_type_check_instance_is_a = nullptr;
|
||||
f_g_signal_connect_data g_signal_connect_data = nullptr;
|
||||
f_g_signal_handler_disconnect g_signal_handler_disconnect = nullptr;
|
||||
f_app_indicator_new app_indicator_new = nullptr;
|
||||
f_app_indicator_set_status app_indicator_set_status = nullptr;
|
||||
f_app_indicator_set_menu app_indicator_set_menu = nullptr;
|
||||
f_app_indicator_set_icon_full app_indicator_set_icon_full = nullptr;
|
||||
f_gdk_init_check gdk_init_check = nullptr;
|
||||
f_gdk_pixbuf_new_from_data gdk_pixbuf_new_from_data = nullptr;
|
||||
f_gdk_pixbuf_new_from_file gdk_pixbuf_new_from_file = nullptr;
|
||||
|
@ -233,33 +219,14 @@ void start() {
|
|||
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
|
||||
bool gtkLoaded = false;
|
||||
bool indicatorLoaded = false;
|
||||
bool isWayland = QGuiApplication::platformName().startsWith(qsl("wayland"), Qt::CaseInsensitive);
|
||||
QLibrary lib_gtk, lib_indicator;
|
||||
if (loadLibrary(lib_indicator, "ayatana-appindicator3", 1) || loadLibrary(lib_indicator, "appindicator3", 1)) {
|
||||
if (loadLibrary(lib_gtk, "gtk-3", 0)) {
|
||||
gtkLoaded = setupGtkBase(lib_gtk);
|
||||
indicatorLoaded = setupAppIndicator(lib_indicator);
|
||||
}
|
||||
}
|
||||
if ((!gtkLoaded || !indicatorLoaded) && !isWayland) {
|
||||
if (loadLibrary(lib_indicator, "ayatana-appindicator", 1) || loadLibrary(lib_indicator, "appindicator", 1)) {
|
||||
if (loadLibrary(lib_gtk, "gtk-x11-2.0", 0)) {
|
||||
gtkLoaded = indicatorLoaded = false;
|
||||
gtkLoaded = setupGtkBase(lib_gtk);
|
||||
indicatorLoaded = setupAppIndicator(lib_indicator);
|
||||
}
|
||||
}
|
||||
}
|
||||
QLibrary lib_gtk;
|
||||
|
||||
// If no appindicator, try at least load gtk.
|
||||
if (!gtkLoaded && !indicatorLoaded) {
|
||||
if (loadLibrary(lib_gtk, "gtk-3", 0)) {
|
||||
gtkLoaded = setupGtkBase(lib_gtk);
|
||||
}
|
||||
if (!gtkLoaded && !isWayland && loadLibrary(lib_gtk, "gtk-x11-2.0", 0)) {
|
||||
gtkLoaded = setupGtkBase(lib_gtk);
|
||||
}
|
||||
if (loadLibrary(lib_gtk, "gtk-3", 0)) {
|
||||
gtkLoaded = setupGtkBase(lib_gtk);
|
||||
}
|
||||
if (!gtkLoaded && !isWayland && loadLibrary(lib_gtk, "gtk-x11-2.0", 0)) {
|
||||
gtkLoaded = setupGtkBase(lib_gtk);
|
||||
}
|
||||
|
||||
if (gtkLoaded) {
|
||||
|
@ -287,7 +254,7 @@ void start() {
|
|||
load(lib_gtk, "gtk_button_set_label", gtk_button_set_label);
|
||||
load(lib_gtk, "gtk_button_get_type", gtk_button_get_type);
|
||||
} else {
|
||||
LOG(("Could not load gtk-x11-2.0!"));
|
||||
LOG(("Could not load gtk-3 or gtk-x11-2.0!"));
|
||||
}
|
||||
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
}
|
||||
|
|
|
@ -13,11 +13,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
extern "C" {
|
||||
#undef signals
|
||||
#ifdef TDESKTOP_USE_AYATANA_INDICATORS
|
||||
#include <libayatana-appindicator/app-indicator.h>
|
||||
#else
|
||||
#include <libappindicator/app-indicator.h>
|
||||
#endif
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk/gdk.h>
|
||||
#define signals public
|
||||
|
@ -278,18 +273,6 @@ inline gulong g_signal_connect_swapped_helper(gpointer instance, const gchar *de
|
|||
typedef void (*f_g_signal_handler_disconnect)(gpointer instance, gulong handler_id);
|
||||
extern f_g_signal_handler_disconnect g_signal_handler_disconnect;
|
||||
|
||||
typedef AppIndicator* (*f_app_indicator_new)(const gchar *id, const gchar *icon_name, AppIndicatorCategory category);
|
||||
extern f_app_indicator_new app_indicator_new;
|
||||
|
||||
typedef void (*f_app_indicator_set_status)(AppIndicator *self, AppIndicatorStatus status);
|
||||
extern f_app_indicator_set_status app_indicator_set_status;
|
||||
|
||||
typedef void (*f_app_indicator_set_menu)(AppIndicator *self, GtkMenu *menu);
|
||||
extern f_app_indicator_set_menu app_indicator_set_menu;
|
||||
|
||||
typedef void (*f_app_indicator_set_icon_full)(AppIndicator *self, const gchar *icon_name, const gchar *icon_desc);
|
||||
extern f_app_indicator_set_icon_full app_indicator_set_icon_full;
|
||||
|
||||
typedef gboolean (*f_gdk_init_check)(gint *argc, gchar ***argv);
|
||||
extern f_gdk_init_check gdk_init_check;
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "history/history.h"
|
||||
#include "mainwindow.h"
|
||||
#include "core/application.h"
|
||||
#include "core/sandbox.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "storage/localstorage.h"
|
||||
#include "facades.h"
|
||||
|
@ -22,101 +23,77 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
#include <QtDBus>
|
||||
#endif
|
||||
|
||||
#include <QtWidgets/QMenu>
|
||||
#include <QtWidgets/QAction>
|
||||
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
|
||||
namespace Platform {
|
||||
namespace {
|
||||
|
||||
bool noQtTrayIcon = false, tryAppIndicator = false;
|
||||
bool useGtkBase = false, useAppIndicator = false, useStatusIcon = false, trayIconChecked = false, useUnityCount = false;
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
AppIndicator *_trayIndicator = 0;
|
||||
GtkStatusIcon *_trayIcon = 0;
|
||||
GtkWidget *_trayMenu = 0;
|
||||
GdkPixbuf *_trayPixbuf = 0;
|
||||
QByteArray _trayPixbufData;
|
||||
QList<QPair<GtkWidget*, QObject*> > _trayItems;
|
||||
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
constexpr auto kDisableTrayCounter = "TDESKTOP_DISABLE_TRAY_COUNTER"_cs;
|
||||
constexpr auto kTrayIconName = "telegram"_cs;
|
||||
constexpr auto kPanelTrayIconName = "telegram-panel"_cs;
|
||||
constexpr auto kMutePanelTrayIconName = "telegram-mute-panel"_cs;
|
||||
constexpr auto kAttentionPanelTrayIconName = "telegram-attention-panel"_cs;
|
||||
constexpr auto kSNIWatcherService = "org.kde.StatusNotifierWatcher"_cs;
|
||||
constexpr auto kTrayIconFilename = "tdesktop-trayicon-XXXXXX.png"_cs;
|
||||
|
||||
int32 _trayIconSize = 48;
|
||||
bool _trayIconMuted = true;
|
||||
int32 _trayIconCount = 0;
|
||||
QImage _trayIconImageBack, _trayIconImage;
|
||||
QString _trayIconThemeName, _trayIconName;
|
||||
QString _desktopFile;
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
QString _dbusPath = "/";
|
||||
#endif
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
void _trayIconPopup(GtkStatusIcon *status_icon, guint button, guint32 activate_time, gpointer popup_menu) {
|
||||
Libs::gtk_menu_popup(Libs::gtk_menu_cast(popup_menu), NULL, NULL, Libs::gtk_status_icon_position_menu, status_icon, button, activate_time);
|
||||
}
|
||||
|
||||
void _trayIconActivate(GtkStatusIcon *status_icon, gpointer popup_menu) {
|
||||
if (App::wnd()->isActiveWindow() && App::wnd()->isVisible()) {
|
||||
Libs::gtk_menu_popup(Libs::gtk_menu_cast(popup_menu), NULL, NULL, Libs::gtk_status_icon_position_menu, status_icon, 0, Libs::gtk_get_current_event_time());
|
||||
} else {
|
||||
App::wnd()->showFromTray();
|
||||
}
|
||||
}
|
||||
|
||||
gboolean _trayIconResized(GtkStatusIcon *status_icon, gint size, gpointer popup_menu) {
|
||||
_trayIconSize = size;
|
||||
if (Global::started()) Notify::unreadCounterUpdated();
|
||||
return FALSE;
|
||||
}
|
||||
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
bool UseUnityCount = false;
|
||||
QString UnityCountDesktopFile;
|
||||
QString UnityCountDBusPath = "/";
|
||||
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
|
||||
#define QT_RED 0
|
||||
#define QT_GREEN 1
|
||||
#define QT_BLUE 2
|
||||
#define QT_ALPHA 3
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
#define GTK_RED 2
|
||||
#define GTK_GREEN 1
|
||||
#define GTK_BLUE 0
|
||||
#define GTK_ALPHA 3
|
||||
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
QString GetTrayIconName() {
|
||||
const auto counter = Core::App().unreadBadge();
|
||||
const auto muted = Core::App().unreadBadgeMuted();
|
||||
|
||||
QImage _trayIconImageGen(bool useSystemIcon) {
|
||||
return (counter > 0)
|
||||
? (muted
|
||||
? kMutePanelTrayIconName.utf16()
|
||||
: kAttentionPanelTrayIconName.utf16())
|
||||
: kPanelTrayIconName.utf16();
|
||||
}
|
||||
|
||||
QImage TrayIconImageGen() {
|
||||
const auto counter = Core::App().unreadBadge();
|
||||
const auto muted = Core::App().unreadBadgeMuted();
|
||||
const auto counterSlice = (counter >= 1000)
|
||||
? (1000 + (counter % 100))
|
||||
: counter;
|
||||
|
||||
QString iconThemeName = QIcon::themeName();
|
||||
QString iconName = (counter > 0)
|
||||
? (muted ? "telegram-mute-panel" : "telegram-attention-panel")
|
||||
: "telegram-panel";
|
||||
const auto iconThemeName = QIcon::themeName();
|
||||
const auto iconName = GetTrayIconName();
|
||||
|
||||
if (_trayIconImage.isNull() || _trayIconImage.width() != _trayIconSize
|
||||
|| (useSystemIcon && (iconThemeName != _trayIconThemeName
|
||||
|| iconName != _trayIconName))
|
||||
|| muted != _trayIconMuted || counterSlice != _trayIconCount) {
|
||||
if (_trayIconImage.isNull()
|
||||
|| _trayIconImage.width() != _trayIconSize
|
||||
|| iconThemeName != _trayIconThemeName
|
||||
|| iconName != _trayIconName
|
||||
|| muted != _trayIconMuted
|
||||
|| counterSlice != _trayIconCount) {
|
||||
if (_trayIconImageBack.isNull()
|
||||
|| _trayIconImageBack.width() != _trayIconSize
|
||||
|| iconThemeName != _trayIconThemeName
|
||||
|| iconName != _trayIconName) {
|
||||
_trayIconImageBack = Core::App().logo();
|
||||
|
||||
if (useSystemIcon) {
|
||||
_trayIconImageBack = QIcon::fromTheme(
|
||||
iconName,
|
||||
QIcon::fromTheme(
|
||||
"telegram",
|
||||
QIcon(QPixmap::fromImage(_trayIconImageBack)))
|
||||
).pixmap(_trayIconSize, _trayIconSize).toImage();
|
||||
}
|
||||
_trayIconImageBack = QIcon::fromTheme(
|
||||
iconName,
|
||||
QIcon::fromTheme(
|
||||
kTrayIconName.utf16(),
|
||||
QIcon(QPixmap::fromImage(_trayIconImageBack)))
|
||||
).pixmap(_trayIconSize, _trayIconSize).toImage();
|
||||
|
||||
int w = _trayIconImageBack.width(),
|
||||
auto w = _trayIconImageBack.width(),
|
||||
h = _trayIconImageBack.height();
|
||||
|
||||
if (w != _trayIconSize || h != _trayIconSize) {
|
||||
|
@ -132,8 +109,8 @@ QImage _trayIconImageGen(bool useSystemIcon) {
|
|||
|
||||
w = _trayIconImageBack.width();
|
||||
h = _trayIconImageBack.height();
|
||||
int perline = _trayIconImageBack.bytesPerLine();
|
||||
uchar *bytes = _trayIconImageBack.bits();
|
||||
const auto perline = _trayIconImageBack.bytesPerLine();
|
||||
auto *bytes = _trayIconImageBack.bits();
|
||||
|
||||
for (int32 y = 0; y < h; ++y) {
|
||||
for (int32 x = 0; x < w; ++x) {
|
||||
|
@ -189,81 +166,66 @@ QImage _trayIconImageGen(bool useSystemIcon) {
|
|||
return _trayIconImage;
|
||||
}
|
||||
|
||||
QString _trayIconImageFile() {
|
||||
const auto counter = Core::App().unreadBadge();
|
||||
const auto muted = Core::App().unreadBadgeMuted();
|
||||
const auto counterSlice = (counter >= 1000)
|
||||
? (1000 + (counter % 100))
|
||||
: counter;
|
||||
|
||||
QString iconThemeName = QIcon::themeName();
|
||||
|
||||
QString name = cWorkingDir() + qsl("tdata/ticons/icon%1_%2_%3_%4.png")
|
||||
.arg(muted ? "mute" : "")
|
||||
.arg(iconThemeName)
|
||||
.arg(_trayIconSize)
|
||||
.arg(counterSlice);
|
||||
|
||||
QFileInfo info(name);
|
||||
if (info.exists()) return name;
|
||||
|
||||
QImage img = _trayIconImageGen(false);
|
||||
if (img.save(name, "PNG")) return name;
|
||||
|
||||
QDir dir(info.absoluteDir());
|
||||
if (!dir.exists()) {
|
||||
dir.mkpath(dir.absolutePath());
|
||||
if (img.save(name, "PNG")) return name;
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
|
||||
void loadPixbuf(QImage image) {
|
||||
int w = image.width(), h = image.height(), perline = image.bytesPerLine(), s = image.byteCount();
|
||||
_trayPixbufData.resize(w * h * 4);
|
||||
uchar *result = (uchar*)_trayPixbufData.data(), *bytes = image.bits();
|
||||
for (int32 y = 0; y < h; ++y) {
|
||||
for (int32 x = 0; x < w; ++x) {
|
||||
int32 offset = (y * w + x) * 4, srcoff = y * perline + x * 4;
|
||||
result[offset + GTK_RED ] = bytes[srcoff + QT_RED ];
|
||||
result[offset + GTK_GREEN] = bytes[srcoff + QT_GREEN];
|
||||
result[offset + GTK_BLUE ] = bytes[srcoff + QT_BLUE ];
|
||||
result[offset + GTK_ALPHA] = bytes[srcoff + QT_ALPHA];
|
||||
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
static bool NeedTrayIconFile() {
|
||||
// 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 TrayIconFileNeeded = [&] {
|
||||
auto necessary = false;
|
||||
const auto session = QDBusConnection::sessionBus();
|
||||
const auto pid = session.interface()
|
||||
->servicePid(kSNIWatcherService.utf16()).value();
|
||||
const auto processName = ProcessNameByPID(QString::number(pid));
|
||||
necessary = processName.endsWith(
|
||||
qsl("indicator-application-service"));
|
||||
if (!necessary) {
|
||||
// Accessing to process name might be not allowed if the application
|
||||
// is confined, thus we can just rely on the current desktop in use
|
||||
necessary = DesktopEnvironment::IsUnity()
|
||||
|| DesktopEnvironment::IsMATE();
|
||||
}
|
||||
}
|
||||
|
||||
if (_trayPixbuf) Libs::g_object_unref(_trayPixbuf);
|
||||
_trayPixbuf = Libs::gdk_pixbuf_new_from_data(result, GDK_COLORSPACE_RGB, true, 8, w, h, w * 4, 0, 0);
|
||||
return necessary;
|
||||
}();
|
||||
return TrayIconFileNeeded;
|
||||
}
|
||||
|
||||
void _trayMenuCallback(GtkMenu *menu, gpointer data) {
|
||||
for (int32 i = 0, l = _trayItems.size(); i < l; ++i) {
|
||||
if ((void*)_trayItems.at(i).first == (void*)menu) {
|
||||
QMetaObject::invokeMethod(_trayItems.at(i).second, "triggered");
|
||||
}
|
||||
}
|
||||
static inline QString TrayIconFileTemplate() {
|
||||
static const auto TempFileTemplate = AppRuntimeDirectory()
|
||||
+ kTrayIconFilename.utf16();
|
||||
return TempFileTemplate;
|
||||
}
|
||||
|
||||
static gboolean _trayIconCheck(gpointer/* pIn*/) {
|
||||
if (useStatusIcon && !trayIconChecked) {
|
||||
if (Libs::gtk_status_icon_is_embedded(_trayIcon)) {
|
||||
trayIconChecked = true;
|
||||
cSetSupportTray(true);
|
||||
if (Global::started()) {
|
||||
Global::RefWorkMode().setForced(Global::WorkMode().value(), true);
|
||||
}
|
||||
if (App::wnd()) {
|
||||
Notify::unreadCounterUpdated();
|
||||
App::wnd()->updateTrayMenu();
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
std::unique_ptr<QTemporaryFile> TrayIconFile(
|
||||
const QPixmap &icon, QObject *parent) {
|
||||
auto ret = std::make_unique<QTemporaryFile>(
|
||||
TrayIconFileTemplate(),
|
||||
parent);
|
||||
ret->open();
|
||||
icon.save(ret.get());
|
||||
ret->close();
|
||||
return ret;
|
||||
}
|
||||
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
|
||||
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
bool IsSNIAvailable() {
|
||||
static const auto SNIAvailable = [&] {
|
||||
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
QDBusInterface systrayHost(
|
||||
kSNIWatcherService.utf16(),
|
||||
qsl("/StatusNotifierWatcher"),
|
||||
kSNIWatcherService.utf16());
|
||||
|
||||
return systrayHost.isValid()
|
||||
&& systrayHost
|
||||
.property("IsStatusNotifierHostRegistered")
|
||||
.toBool();
|
||||
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
|
||||
return false;
|
||||
}();
|
||||
|
||||
return SNIAvailable;
|
||||
}
|
||||
|
||||
quint32 djbStringHash(QString string) {
|
||||
quint32 hash = 5381;
|
||||
|
@ -278,71 +240,106 @@ quint32 djbStringHash(QString string) {
|
|||
|
||||
MainWindow::MainWindow(not_null<Window::Controller*> controller)
|
||||
: Window::MainWindow(controller) {
|
||||
connect(&_psCheckStatusIconTimer, SIGNAL(timeout()), this, SLOT(psStatusIconCheck()));
|
||||
_psCheckStatusIconTimer.setSingleShot(false);
|
||||
|
||||
connect(&_psUpdateIndicatorTimer, SIGNAL(timeout()), this, SLOT(psUpdateIndicator()));
|
||||
_psUpdateIndicatorTimer.setSingleShot(true);
|
||||
}
|
||||
|
||||
bool MainWindow::hasTrayIcon() const {
|
||||
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
return trayIcon || ((useAppIndicator || (useStatusIcon && trayIconChecked)) && (Global::WorkMode().value() != dbiwmWindowOnly));
|
||||
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
return trayIcon || _sniTrayIcon;
|
||||
#else
|
||||
return trayIcon;
|
||||
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
}
|
||||
|
||||
void MainWindow::psStatusIconCheck() {
|
||||
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
_trayIconCheck(0);
|
||||
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
if (cSupportTray() || !--_psCheckStatusIconLeft) {
|
||||
_psCheckStatusIconTimer.stop();
|
||||
return;
|
||||
}
|
||||
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
}
|
||||
|
||||
void MainWindow::psShowTrayMenu() {
|
||||
if (!IsSNIAvailable()) {
|
||||
_trayIconMenuXEmbed->popup(QCursor::pos());
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::psTrayMenuUpdated() {
|
||||
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
if (noQtTrayIcon && (useAppIndicator || useStatusIcon)) {
|
||||
const QList<QAction*> &actions = trayIconMenu->actions();
|
||||
if (_trayItems.isEmpty()) {
|
||||
DEBUG_LOG(("Creating tray menu!"));
|
||||
for (int32 i = 0, l = actions.size(); i != l; ++i) {
|
||||
GtkWidget *item = Libs::gtk_menu_item_new_with_label(actions.at(i)->text().toUtf8());
|
||||
Libs::gtk_menu_shell_append(Libs::gtk_menu_shell_cast(_trayMenu), item);
|
||||
Libs::g_signal_connect_helper(item, "activate", G_CALLBACK(_trayMenuCallback), this);
|
||||
Libs::gtk_widget_show(item);
|
||||
Libs::gtk_widget_set_sensitive(item, actions.at(i)->isEnabled());
|
||||
|
||||
_trayItems.push_back(qMakePair(item, actions.at(i)));
|
||||
}
|
||||
} else {
|
||||
DEBUG_LOG(("Updating tray menu!"));
|
||||
for (int32 i = 0, l = actions.size(); i != l; ++i) {
|
||||
if (i < _trayItems.size()) {
|
||||
Libs::gtk_menu_item_set_label(reinterpret_cast<GtkMenuItem*>(_trayItems.at(i).first), actions.at(i)->text().toUtf8());
|
||||
Libs::gtk_widget_set_sensitive(_trayItems.at(i).first, actions.at(i)->isEnabled());
|
||||
}
|
||||
}
|
||||
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
if (IsSNIAvailable()) {
|
||||
if (_sniTrayIcon && trayIconMenu) {
|
||||
_sniTrayIcon->setContextMenu(trayIconMenu);
|
||||
}
|
||||
}
|
||||
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
}
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
void MainWindow::setSNITrayIcon(
|
||||
const QIcon &icon, const QPixmap &iconPixmap) {
|
||||
if (!NeedTrayIconFile()) {
|
||||
_sniTrayIcon->setIconByPixmap(icon);
|
||||
_sniTrayIcon->setToolTipIconByPixmap(icon);
|
||||
}
|
||||
|
||||
if (qEnvironmentVariableIsSet(kDisableTrayCounter.utf8())) {
|
||||
const auto iconName = GetTrayIconName();
|
||||
_sniTrayIcon->setIconByName(iconName);
|
||||
_sniTrayIcon->setToolTipIconByName(iconName);
|
||||
} else if (NeedTrayIconFile()) {
|
||||
_trayIconFile = TrayIconFile(iconPixmap, this);
|
||||
|
||||
if (_trayIconFile) {
|
||||
_sniTrayIcon->setIconByName(_trayIconFile->fileName());
|
||||
_sniTrayIcon->setToolTipIconByName(_trayIconFile->fileName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::attachToSNITrayIcon() {
|
||||
_sniTrayIcon->setToolTipTitle(AppName.utf16());
|
||||
connect(_sniTrayIcon,
|
||||
&StatusNotifierItem::activateRequested,
|
||||
this,
|
||||
[=](const QPoint &) {
|
||||
Core::Sandbox::Instance().customEnterFromEventLoop([&] {
|
||||
handleTrayIconActication(QSystemTrayIcon::Trigger);
|
||||
});
|
||||
});
|
||||
connect(_sniTrayIcon,
|
||||
&StatusNotifierItem::secondaryActivateRequested,
|
||||
this,
|
||||
[=](const QPoint &) {
|
||||
Core::Sandbox::Instance().customEnterFromEventLoop([&] {
|
||||
handleTrayIconActication(QSystemTrayIcon::MiddleClick);
|
||||
});
|
||||
});
|
||||
updateTrayMenu();
|
||||
}
|
||||
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
|
||||
void MainWindow::psSetupTrayIcon() {
|
||||
if (noQtTrayIcon) {
|
||||
if (!cSupportTray()) return;
|
||||
const auto iconPixmap = QPixmap::fromImage(TrayIconImageGen());
|
||||
const auto icon = QIcon(iconPixmap);
|
||||
|
||||
if (IsSNIAvailable()) {
|
||||
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
LOG(("Using SNI tray icon."));
|
||||
if (!_sniTrayIcon) {
|
||||
_sniTrayIcon = new StatusNotifierItem(
|
||||
QCoreApplication::applicationName(),
|
||||
this);
|
||||
|
||||
_sniTrayIcon->setTitle(QCoreApplication::applicationName());
|
||||
setSNITrayIcon(icon, iconPixmap);
|
||||
|
||||
attachToSNITrayIcon();
|
||||
}
|
||||
updateIconCounters();
|
||||
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
} else {
|
||||
LOG(("Using Qt tray icon."));
|
||||
|
||||
if (!_trayIconMenuXEmbed) {
|
||||
_trayIconMenuXEmbed = new Ui::PopupMenu(nullptr, trayIconMenu);
|
||||
_trayIconMenuXEmbed->deleteOnHide(false);
|
||||
}
|
||||
|
||||
if (!trayIcon) {
|
||||
trayIcon = new QSystemTrayIcon(this);
|
||||
trayIcon->setIcon(QIcon(QPixmap::fromImage(_trayIconImageGen(true))));
|
||||
trayIcon->setIcon(icon);
|
||||
|
||||
attachToTrayIcon(trayIcon);
|
||||
}
|
||||
|
@ -356,14 +353,14 @@ void MainWindow::workmodeUpdated(DBIWorkMode mode) {
|
|||
if (!cSupportTray()) return;
|
||||
|
||||
if (mode == dbiwmWindowOnly) {
|
||||
if (noQtTrayIcon) {
|
||||
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
if (useAppIndicator) {
|
||||
Libs::app_indicator_set_status(_trayIndicator, APP_INDICATOR_STATUS_PASSIVE);
|
||||
} else if (useStatusIcon) {
|
||||
Libs::gtk_status_icon_set_visible(_trayIcon, false);
|
||||
if (IsSNIAvailable()) {
|
||||
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
if (_sniTrayIcon) {
|
||||
_sniTrayIcon->setContextMenu(0);
|
||||
_sniTrayIcon->deleteLater();
|
||||
}
|
||||
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
_sniTrayIcon = 0;
|
||||
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
} else {
|
||||
if (trayIcon) {
|
||||
trayIcon->setContextMenu(0);
|
||||
|
@ -372,35 +369,10 @@ void MainWindow::workmodeUpdated(DBIWorkMode mode) {
|
|||
trayIcon = 0;
|
||||
}
|
||||
} else {
|
||||
if (noQtTrayIcon) {
|
||||
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
if (useAppIndicator) {
|
||||
Libs::app_indicator_set_status(_trayIndicator, APP_INDICATOR_STATUS_ACTIVE);
|
||||
} else if (useStatusIcon) {
|
||||
Libs::gtk_status_icon_set_visible(_trayIcon, true);
|
||||
}
|
||||
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
} else {
|
||||
psSetupTrayIcon();
|
||||
}
|
||||
psSetupTrayIcon();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::psUpdateIndicator() {
|
||||
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
_psUpdateIndicatorTimer.stop();
|
||||
_psLastIndicatorUpdate = crl::now();
|
||||
QFileInfo iconFile(_trayIconImageFile());
|
||||
if (iconFile.exists()) {
|
||||
QByteArray path = QFile::encodeName(iconFile.absoluteFilePath()), name = QFile::encodeName(iconFile.fileName());
|
||||
name = name.mid(0, name.size() - 4);
|
||||
Libs::app_indicator_set_icon_full(_trayIndicator, path.constData(), name);
|
||||
} else {
|
||||
useAppIndicator = false;
|
||||
}
|
||||
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
}
|
||||
|
||||
void MainWindow::unreadCounterChangedHook() {
|
||||
setWindowTitle(titleText());
|
||||
updateIconCounters();
|
||||
|
@ -410,208 +382,91 @@ void MainWindow::updateIconCounters() {
|
|||
updateWindowIcon();
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
if (useUnityCount) {
|
||||
if (UseUnityCount) {
|
||||
const auto counter = Core::App().unreadBadge();
|
||||
QVariantMap dbusUnityProperties;
|
||||
if (counter > 0) {
|
||||
// Gnome requires that count is a 64bit integer
|
||||
dbusUnityProperties.insert("count", (qint64) ((counter > 9999) ? 9999 : (counter)));
|
||||
dbusUnityProperties.insert(
|
||||
"count",
|
||||
(qint64) ((counter > 9999)
|
||||
? 9999
|
||||
: (counter)));
|
||||
dbusUnityProperties.insert("count-visible", true);
|
||||
} else {
|
||||
dbusUnityProperties.insert("count-visible", false);
|
||||
}
|
||||
QDBusMessage signal = QDBusMessage::createSignal(_dbusPath, "com.canonical.Unity.LauncherEntry", "Update");
|
||||
signal << "application://" + _desktopFile;
|
||||
QDBusMessage signal = QDBusMessage::createSignal(
|
||||
UnityCountDBusPath,
|
||||
"com.canonical.Unity.LauncherEntry",
|
||||
"Update");
|
||||
signal << "application://" + UnityCountDesktopFile;
|
||||
signal << dbusUnityProperties;
|
||||
QDBusConnection::sessionBus().send(signal);
|
||||
}
|
||||
#endif
|
||||
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
|
||||
if (noQtTrayIcon) {
|
||||
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
if (useAppIndicator) {
|
||||
if (crl::now() > _psLastIndicatorUpdate + 1000) {
|
||||
psUpdateIndicator();
|
||||
} else if (!_psUpdateIndicatorTimer.isActive()) {
|
||||
_psUpdateIndicatorTimer.start(100);
|
||||
}
|
||||
} else if (useStatusIcon && trayIconChecked) {
|
||||
loadPixbuf(_trayIconImageGen(true));
|
||||
Libs::gtk_status_icon_set_from_pixbuf(_trayIcon, _trayPixbuf);
|
||||
const auto iconPixmap = QPixmap::fromImage(TrayIconImageGen());
|
||||
const auto icon = QIcon(iconPixmap);
|
||||
|
||||
if (IsSNIAvailable()) {
|
||||
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
if (_sniTrayIcon) {
|
||||
setSNITrayIcon(icon, iconPixmap);
|
||||
}
|
||||
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
} else if (trayIcon) {
|
||||
trayIcon->setIcon(QIcon(QPixmap::fromImage(_trayIconImageGen(true))));
|
||||
trayIcon->setIcon(icon);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::LibsLoaded() {
|
||||
noQtTrayIcon = !DesktopEnvironment::TryQtTrayIcon();
|
||||
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
tryAppIndicator = DesktopEnvironment::PreferAppIndicatorTrayIcon();
|
||||
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
qDBusRegisterMetaType<ToolTip>();
|
||||
qDBusRegisterMetaType<IconPixmap>();
|
||||
qDBusRegisterMetaType<IconPixmapList>();
|
||||
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
|
||||
LOG(("Tray Icon: Try Qt = %1, Prefer appindicator = %2").arg(Logs::b(!noQtTrayIcon)).arg(Logs::b(tryAppIndicator)));
|
||||
|
||||
if (noQtTrayIcon) cSetSupportTray(false);
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
useGtkBase = (Libs::gtk_init_check != nullptr)
|
||||
&& (Libs::gtk_menu_new != nullptr)
|
||||
&& (Libs::gtk_menu_get_type != nullptr)
|
||||
&& (Libs::gtk_menu_item_new_with_label != nullptr)
|
||||
&& (Libs::gtk_menu_item_set_label != nullptr)
|
||||
&& (Libs::gtk_menu_shell_append != nullptr)
|
||||
&& (Libs::gtk_menu_shell_get_type != nullptr)
|
||||
&& (Libs::gtk_widget_show != nullptr)
|
||||
&& (Libs::gtk_widget_get_toplevel != nullptr)
|
||||
&& (Libs::gtk_widget_get_visible != nullptr)
|
||||
&& (Libs::gtk_widget_set_sensitive != nullptr)
|
||||
&& (Libs::g_type_check_instance_cast != nullptr)
|
||||
&& (Libs::g_signal_connect_data != nullptr)
|
||||
&& (Libs::g_object_ref_sink != nullptr)
|
||||
&& (Libs::g_object_unref != nullptr);
|
||||
|
||||
useAppIndicator = useGtkBase
|
||||
&& (Libs::app_indicator_new != nullptr)
|
||||
&& (Libs::app_indicator_set_status != nullptr)
|
||||
&& (Libs::app_indicator_set_menu != nullptr)
|
||||
&& (Libs::app_indicator_set_icon_full != nullptr);
|
||||
|
||||
if (tryAppIndicator && useGtkBase && useAppIndicator) {
|
||||
noQtTrayIcon = true;
|
||||
cSetSupportTray(false);
|
||||
if (!IsSNIAvailable()) {
|
||||
_trayIconSize = 22;
|
||||
}
|
||||
|
||||
useStatusIcon = (Libs::gdk_init_check != nullptr)
|
||||
&& (Libs::gdk_pixbuf_new_from_data != nullptr)
|
||||
&& (Libs::gtk_status_icon_new_from_pixbuf != nullptr)
|
||||
&& (Libs::gtk_status_icon_set_from_pixbuf != nullptr)
|
||||
&& (Libs::gtk_status_icon_new_from_file != nullptr)
|
||||
&& (Libs::gtk_status_icon_set_from_file != nullptr)
|
||||
&& (Libs::gtk_status_icon_set_title != nullptr)
|
||||
&& (Libs::gtk_status_icon_set_tooltip_text != nullptr)
|
||||
&& (Libs::gtk_status_icon_set_visible != nullptr)
|
||||
&& (Libs::gtk_status_icon_is_embedded != nullptr)
|
||||
&& (Libs::gtk_status_icon_get_geometry != nullptr)
|
||||
&& (Libs::gtk_status_icon_position_menu != nullptr)
|
||||
&& (Libs::gtk_menu_popup != nullptr)
|
||||
&& (Libs::gtk_get_current_event_time != nullptr)
|
||||
&& (Libs::g_idle_add != nullptr);
|
||||
if (useStatusIcon) {
|
||||
DEBUG_LOG(("Status icon api loaded!"));
|
||||
}
|
||||
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
}
|
||||
|
||||
void MainWindow::psCreateTrayIcon() {
|
||||
if (!noQtTrayIcon) {
|
||||
LOG(("Tray Icon: Using Qt tray icon, available: %1").arg(Logs::b(QSystemTrayIcon::isSystemTrayAvailable())));
|
||||
cSetSupportTray(QSystemTrayIcon::isSystemTrayAvailable());
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
if (useAppIndicator) {
|
||||
DEBUG_LOG(("Trying to create AppIndicator"));
|
||||
_trayMenu = Libs::gtk_menu_new();
|
||||
if (_trayMenu) {
|
||||
DEBUG_LOG(("Created gtk menu for appindicator!"));
|
||||
QFileInfo iconFile(_trayIconImageFile());
|
||||
if (iconFile.exists()) {
|
||||
QByteArray path = QFile::encodeName(iconFile.absoluteFilePath());
|
||||
_trayIndicator = Libs::app_indicator_new("Telegram Desktop", path.constData(), APP_INDICATOR_CATEGORY_APPLICATION_STATUS);
|
||||
if (_trayIndicator) {
|
||||
LOG(("Tray Icon: Using appindicator tray icon."));
|
||||
} else {
|
||||
DEBUG_LOG(("Failed to app_indicator_new()!"));
|
||||
}
|
||||
} else {
|
||||
useAppIndicator = false;
|
||||
DEBUG_LOG(("Failed to create image file!"));
|
||||
}
|
||||
} else {
|
||||
DEBUG_LOG(("Failed to gtk_menu_new()!"));
|
||||
}
|
||||
if (_trayMenu && _trayIndicator) {
|
||||
Libs::app_indicator_set_status(_trayIndicator, APP_INDICATOR_STATUS_ACTIVE);
|
||||
Libs::app_indicator_set_menu(_trayIndicator, Libs::gtk_menu_cast(_trayMenu));
|
||||
useStatusIcon = false;
|
||||
} else {
|
||||
DEBUG_LOG(("AppIndicator failed!"));
|
||||
useAppIndicator = false;
|
||||
}
|
||||
}
|
||||
if (useStatusIcon) {
|
||||
if (Libs::gdk_init_check(0, 0)) {
|
||||
if (!_trayMenu) _trayMenu = Libs::gtk_menu_new();
|
||||
if (_trayMenu) {
|
||||
loadPixbuf(_trayIconImageGen(true));
|
||||
_trayIcon = Libs::gtk_status_icon_new_from_pixbuf(_trayPixbuf);
|
||||
if (_trayIcon) {
|
||||
LOG(("Tray Icon: Using GTK status tray icon."));
|
||||
|
||||
Libs::g_signal_connect_helper(_trayIcon, "popup-menu", GCallback(_trayIconPopup), _trayMenu);
|
||||
Libs::g_signal_connect_helper(_trayIcon, "activate", GCallback(_trayIconActivate), _trayMenu);
|
||||
Libs::g_signal_connect_helper(_trayIcon, "size-changed", GCallback(_trayIconResized), _trayMenu);
|
||||
|
||||
Libs::gtk_status_icon_set_title(_trayIcon, "Telegram Desktop");
|
||||
Libs::gtk_status_icon_set_tooltip_text(_trayIcon, "Telegram Desktop");
|
||||
Libs::gtk_status_icon_set_visible(_trayIcon, true);
|
||||
} else {
|
||||
useStatusIcon = false;
|
||||
}
|
||||
} else {
|
||||
useStatusIcon = false;
|
||||
}
|
||||
} else {
|
||||
useStatusIcon = false;
|
||||
}
|
||||
}
|
||||
if (!useStatusIcon && !useAppIndicator) {
|
||||
LOG(("Tray Icon: Not able to use any tray icon :("));
|
||||
if (_trayMenu) {
|
||||
Libs::g_object_ref_sink(_trayMenu);
|
||||
Libs::g_object_unref(_trayMenu);
|
||||
_trayMenu = nullptr;
|
||||
}
|
||||
}
|
||||
cSetSupportTray(useAppIndicator);
|
||||
if (useStatusIcon) {
|
||||
Libs::g_idle_add((GSourceFunc)_trayIconCheck, 0);
|
||||
_psCheckStatusIconTimer.start(100);
|
||||
} else {
|
||||
workmodeUpdated(Global::WorkMode().value());
|
||||
}
|
||||
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
}
|
||||
|
||||
void MainWindow::psFirstShow() {
|
||||
psCreateTrayIcon();
|
||||
const auto trayAvailable = IsSNIAvailable()
|
||||
|| QSystemTrayIcon::isSystemTrayAvailable();
|
||||
|
||||
LOG(("System tray available: %1").arg(Logs::b(trayAvailable)));
|
||||
cSetSupportTray(trayAvailable);
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
if (QDBusInterface("com.canonical.Unity", "/").isValid()) {
|
||||
std::vector<QString> possibleDesktopFiles = {
|
||||
const std::vector<QString> possibleDesktopFiles = {
|
||||
GetLauncherFilename(),
|
||||
"Telegram.desktop"
|
||||
};
|
||||
|
||||
for (auto it = possibleDesktopFiles.begin(); it != possibleDesktopFiles.end(); it++) {
|
||||
if (!QStandardPaths::locate(QStandardPaths::ApplicationsLocation, *it).isEmpty()) {
|
||||
_desktopFile = *it;
|
||||
LOG(("Found Unity Launcher entry %1!").arg(_desktopFile));
|
||||
useUnityCount = true;
|
||||
for (auto it = possibleDesktopFiles.begin();
|
||||
it != possibleDesktopFiles.end(); it++) {
|
||||
if (!QStandardPaths::locate(
|
||||
QStandardPaths::ApplicationsLocation, *it).isEmpty()) {
|
||||
UnityCountDesktopFile = *it;
|
||||
LOG(("Found Unity Launcher entry %1!")
|
||||
.arg(UnityCountDesktopFile));
|
||||
UseUnityCount = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!useUnityCount) {
|
||||
if (!UseUnityCount) {
|
||||
LOG(("Could not get Unity Launcher entry!"));
|
||||
}
|
||||
_dbusPath = "/com/canonical/unity/launcherentry/" + QString::number(djbStringHash("application://" + _desktopFile));
|
||||
UnityCountDBusPath = "/com/canonical/unity/launcherentry/"
|
||||
+ QString::number(
|
||||
djbStringHash("application://" + UnityCountDesktopFile));
|
||||
} else {
|
||||
LOG(("Not using Unity Launcher count."));
|
||||
}
|
||||
#endif
|
||||
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
|
||||
show();
|
||||
if (cWindowPos().maximized) {
|
||||
|
@ -619,13 +474,15 @@ void MainWindow::psFirstShow() {
|
|||
setWindowState(Qt::WindowMaximized);
|
||||
}
|
||||
|
||||
if ((cLaunchMode() == LaunchModeAutoStart && cStartMinimized()) || cStartInTray()) {
|
||||
if ((cLaunchMode() == LaunchModeAutoStart && cStartMinimized())
|
||||
|| cStartInTray()) {
|
||||
// If I call hide() synchronously here after show() then on Ubuntu 14.04
|
||||
// it will show a window frame with transparent window body, without content.
|
||||
// And to be able to "Show from tray" one more hide() will be required.
|
||||
crl::on_main(this, [=] {
|
||||
setWindowState(Qt::WindowMinimized);
|
||||
if (Global::WorkMode().value() == dbiwmTrayOnly || Global::WorkMode().value() == dbiwmWindowAndTray) {
|
||||
if (Global::WorkMode().value() == dbiwmTrayOnly
|
||||
|| Global::WorkMode().value() == dbiwmWindowAndTray) {
|
||||
hide();
|
||||
} else {
|
||||
show();
|
||||
|
@ -637,25 +494,11 @@ void MainWindow::psFirstShow() {
|
|||
}
|
||||
|
||||
MainWindow::~MainWindow() {
|
||||
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
if (_trayIcon) {
|
||||
Libs::g_object_unref(_trayIcon);
|
||||
_trayIcon = nullptr;
|
||||
}
|
||||
if (_trayPixbuf) {
|
||||
Libs::g_object_unref(_trayPixbuf);
|
||||
_trayPixbuf = nullptr;
|
||||
}
|
||||
if (_trayMenu) {
|
||||
Libs::g_object_ref_sink(_trayMenu);
|
||||
Libs::g_object_unref(_trayMenu);
|
||||
_trayMenu = nullptr;
|
||||
}
|
||||
if (_trayIndicator) {
|
||||
Libs::g_object_unref(_trayIndicator);
|
||||
_trayIndicator = nullptr;
|
||||
}
|
||||
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
delete _sniTrayIcon;
|
||||
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
|
||||
delete _trayIconMenuXEmbed;
|
||||
}
|
||||
|
||||
} // namespace Platform
|
||||
|
|
|
@ -9,7 +9,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "platform/platform_main_window.h"
|
||||
|
||||
#include <QtCore/QTimer>
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
#include "statusnotifieritem.h"
|
||||
#include <QtCore/QTemporaryFile>
|
||||
#endif
|
||||
|
||||
namespace Platform {
|
||||
|
||||
|
@ -21,7 +26,12 @@ public:
|
|||
|
||||
void psFirstShow();
|
||||
|
||||
virtual QImage iconWithCounter(int size, int count, style::color bg, style::color fg, bool smallIcon) = 0;
|
||||
virtual QImage iconWithCounter(
|
||||
int size,
|
||||
int count,
|
||||
style::color bg,
|
||||
style::color fg,
|
||||
bool smallIcon) = 0;
|
||||
|
||||
static void LibsLoaded();
|
||||
|
||||
|
@ -30,9 +40,6 @@ public:
|
|||
public slots:
|
||||
void psShowTrayMenu();
|
||||
|
||||
void psStatusIconCheck();
|
||||
void psUpdateIndicator();
|
||||
|
||||
protected:
|
||||
void unreadCounterChangedHook() override;
|
||||
|
||||
|
@ -46,17 +53,26 @@ protected:
|
|||
void psTrayMenuUpdated();
|
||||
void psSetupTrayIcon();
|
||||
|
||||
virtual void placeSmallCounter(QImage &img, int size, int count, style::color bg, const QPoint &shift, style::color color) = 0;
|
||||
virtual void placeSmallCounter(
|
||||
QImage &img,
|
||||
int size,
|
||||
int count,
|
||||
style::color bg,
|
||||
const QPoint &shift,
|
||||
style::color color) = 0;
|
||||
|
||||
private:
|
||||
Ui::PopupMenu *_trayIconMenuXEmbed = nullptr;
|
||||
|
||||
void updateIconCounters();
|
||||
void psCreateTrayIcon();
|
||||
|
||||
QTimer _psCheckStatusIconTimer;
|
||||
int _psCheckStatusIconLeft = 100;
|
||||
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
StatusNotifierItem *_sniTrayIcon = nullptr;
|
||||
std::unique_ptr<QTemporaryFile> _trayIconFile = nullptr;
|
||||
|
||||
QTimer _psUpdateIndicatorTimer;
|
||||
crl::time _psLastIndicatorUpdate = 0;
|
||||
void setSNITrayIcon(const QIcon &icon, const QPixmap &iconPixmap);
|
||||
void attachToSNITrayIcon();
|
||||
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ namespace {
|
|||
|
||||
constexpr auto kDesktopFile = ":/misc/telegramdesktop.desktop"_cs;
|
||||
|
||||
bool XDGDesktopPortalIsPresent = false;
|
||||
bool XDGDesktopPortalPresent = false;
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
|
||||
void SandboxAutostart(bool autostart) {
|
||||
|
@ -196,13 +196,13 @@ bool InSnap() {
|
|||
}
|
||||
|
||||
bool IsXDGDesktopPortalPresent() {
|
||||
return XDGDesktopPortalIsPresent;
|
||||
};
|
||||
return XDGDesktopPortalPresent;
|
||||
}
|
||||
|
||||
QString CurrentExecutablePath(int argc, char *argv[]) {
|
||||
QString ProcessNameByPID(const QString &pid) {
|
||||
constexpr auto kMaxPath = 1024;
|
||||
char result[kMaxPath] = { 0 };
|
||||
auto count = readlink("/proc/self/exe", result, kMaxPath);
|
||||
auto count = readlink("/proc/" + pid.toLatin1() + "/exe", result, kMaxPath);
|
||||
if (count > 0) {
|
||||
auto filename = QFile::decodeName(result);
|
||||
auto deletedPostfix = qstr(" (deleted)");
|
||||
|
@ -212,26 +212,53 @@ QString CurrentExecutablePath(int argc, char *argv[]) {
|
|||
return filename;
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString CurrentExecutablePath(int argc, char *argv[]) {
|
||||
const auto processName = ProcessNameByPID(qsl("self"));
|
||||
|
||||
// Fallback to the first command line argument.
|
||||
return argc ? QFile::decodeName(argv[0]) : QString();
|
||||
return !processName.isEmpty()
|
||||
? processName
|
||||
: argc
|
||||
? QFile::decodeName(argv[0])
|
||||
: QString();
|
||||
}
|
||||
|
||||
QString AppRuntimeDirectory() {
|
||||
static const auto RuntimeDirectory = [&] {
|
||||
auto runtimeDir = QStandardPaths::writableLocation(
|
||||
QStandardPaths::RuntimeLocation);
|
||||
|
||||
if (InSandbox()) {
|
||||
runtimeDir += qsl("/app/")
|
||||
+ QString::fromLatin1(qgetenv("FLATPAK_ID"));
|
||||
}
|
||||
|
||||
if (!QFileInfo::exists(runtimeDir)) { // non-systemd distros
|
||||
runtimeDir = QDir::tempPath();
|
||||
}
|
||||
|
||||
if (runtimeDir.isEmpty()) {
|
||||
runtimeDir = qsl("/tmp/");
|
||||
}
|
||||
|
||||
if (!runtimeDir.endsWith('/')) {
|
||||
runtimeDir += '/';
|
||||
}
|
||||
|
||||
return runtimeDir;
|
||||
}();
|
||||
|
||||
return RuntimeDirectory;
|
||||
}
|
||||
|
||||
QString SingleInstanceLocalServerName(const QString &hash) {
|
||||
const auto runtimeDir = QStandardPaths::writableLocation(
|
||||
QStandardPaths::RuntimeLocation);
|
||||
|
||||
if (InSandbox()) {
|
||||
return runtimeDir
|
||||
+ qsl("/app/")
|
||||
+ QString::fromLatin1(qgetenv("FLATPAK_ID"))
|
||||
+ '/' + hash;
|
||||
} else if (QFileInfo::exists(runtimeDir) && InSnap()) {
|
||||
return runtimeDir + '/' + hash;
|
||||
} else if (QFileInfo::exists(runtimeDir)) {
|
||||
return runtimeDir + '/' + hash + '-' + cGUIDStr();
|
||||
} else { // non-systemd distros
|
||||
return QStandardPaths::writableLocation(QStandardPaths::TempLocation)
|
||||
+ '/' + hash + '-' + cGUIDStr();
|
||||
if (InSandbox() || InSnap()) {
|
||||
return AppRuntimeDirectory() + hash;
|
||||
} else {
|
||||
return AppRuntimeDirectory() + hash + '-' + cGUIDStr();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -381,12 +408,12 @@ void start() {
|
|||
|
||||
#if !defined(TDESKTOP_DISABLE_DBUS_INTEGRATION) && defined(TDESKTOP_FORCE_GTK_FILE_DIALOG)
|
||||
LOG(("Checking for XDG Desktop Portal..."));
|
||||
XDGDesktopPortalIsPresent = QDBusInterface(
|
||||
XDGDesktopPortalPresent = QDBusInterface(
|
||||
"org.freedesktop.portal.Desktop",
|
||||
"/org/freedesktop/portal/desktop").isValid();
|
||||
|
||||
// this can give us a chance to use a proper file dialog for current session
|
||||
if(XDGDesktopPortalIsPresent) {
|
||||
if(XDGDesktopPortalPresent) {
|
||||
LOG(("XDG Desktop Portal is present!"));
|
||||
qputenv("QT_QPA_PLATFORMTHEME", "xdgdesktopportal");
|
||||
} else {
|
||||
|
@ -467,6 +494,8 @@ bool OpenSystemSettings(SystemSettingsType type) {
|
|||
add("kcmshell4 phonon");
|
||||
} else if (DesktopEnvironment::IsGnome()) {
|
||||
add("gnome-control-center sound");
|
||||
} else if (DesktopEnvironment::IsMATE()) {
|
||||
add("mate-volume-control");
|
||||
}
|
||||
add("pavucontrol-qt");
|
||||
add("pavucontrol");
|
||||
|
|
|
@ -25,8 +25,10 @@ bool InSnap();
|
|||
|
||||
bool IsXDGDesktopPortalPresent();
|
||||
|
||||
QString ProcessNameByPID(const QString &pid);
|
||||
QString CurrentExecutablePath(int argc, char *argv[]);
|
||||
|
||||
QString AppRuntimeDirectory();
|
||||
QString SingleInstanceLocalServerName(const QString &hash);
|
||||
|
||||
QString GetLauncherBasename();
|
||||
|
|
|
@ -548,6 +548,9 @@ void MainWindow::psShowTrayMenu() {
|
|||
}
|
||||
|
||||
void MainWindow::psTrayMenuUpdated() {
|
||||
if (trayIcon && trayIconMenu && trayIcon->contextMenu() != trayIconMenu) {
|
||||
trayIcon->setContextMenu(trayIconMenu);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::psSetupTrayIcon() {
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 75afa1003c1d0f6fdfa3a76ce2db689b49f86968
|
|
@ -0,0 +1,75 @@
|
|||
/* BEGIN_COMMON_COPYRIGHT_HEADER
|
||||
* (c)LGPL2+
|
||||
*
|
||||
* LXQt - a lightweight, Qt based, desktop toolset
|
||||
* https://lxqt.org
|
||||
*
|
||||
* Copyright: 2015 LXQt team
|
||||
* Authors:
|
||||
* Balázs Béla <balazsbela[at]gmail.com>
|
||||
* Paulo Lieuthier <paulolieuthier@gmail.com>
|
||||
*
|
||||
* This program or library is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
* END_COMMON_COPYRIGHT_HEADER */
|
||||
|
||||
#include "dbustypes.h"
|
||||
|
||||
// Marshall the IconPixmap data into a D-Bus argument
|
||||
QDBusArgument &operator<<(QDBusArgument &argument, const IconPixmap &icon)
|
||||
{
|
||||
argument.beginStructure();
|
||||
argument << icon.width;
|
||||
argument << icon.height;
|
||||
argument << icon.bytes;
|
||||
argument.endStructure();
|
||||
return argument;
|
||||
}
|
||||
|
||||
// Retrieve the ImageStruct data from the D-Bus argument
|
||||
const QDBusArgument &operator>>(const QDBusArgument &argument, IconPixmap &icon)
|
||||
{
|
||||
argument.beginStructure();
|
||||
argument >> icon.width;
|
||||
argument >> icon.height;
|
||||
argument >> icon.bytes;
|
||||
argument.endStructure();
|
||||
return argument;
|
||||
}
|
||||
|
||||
// Marshall the ToolTip data into a D-Bus argument
|
||||
QDBusArgument &operator<<(QDBusArgument &argument, const ToolTip &toolTip)
|
||||
{
|
||||
argument.beginStructure();
|
||||
argument << toolTip.iconName;
|
||||
argument << toolTip.iconPixmap;
|
||||
argument << toolTip.title;
|
||||
argument << toolTip.description;
|
||||
argument.endStructure();
|
||||
return argument;
|
||||
}
|
||||
|
||||
// Retrieve the ToolTip data from the D-Bus argument
|
||||
const QDBusArgument &operator>>(const QDBusArgument &argument, ToolTip &toolTip)
|
||||
{
|
||||
argument.beginStructure();
|
||||
argument >> toolTip.iconName;
|
||||
argument >> toolTip.iconPixmap;
|
||||
argument >> toolTip.title;
|
||||
argument >> toolTip.description;
|
||||
argument.endStructure();
|
||||
return argument;
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/* BEGIN_COMMON_COPYRIGHT_HEADER
|
||||
* (c)LGPL2+
|
||||
*
|
||||
* LXQt - a lightweight, Qt based, desktop toolset
|
||||
* https://lxqt.org
|
||||
*
|
||||
* Copyright: 2015 LXQt team
|
||||
* Authors:
|
||||
* Balázs Béla <balazsbela[at]gmail.com>
|
||||
* Paulo Lieuthier <paulolieuthier@gmail.com>
|
||||
*
|
||||
* This program or library is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
* END_COMMON_COPYRIGHT_HEADER */
|
||||
|
||||
#include <QDBusArgument>
|
||||
|
||||
#ifndef DBUSTYPES_H
|
||||
#define DBUSTYPES_H
|
||||
|
||||
struct IconPixmap {
|
||||
int width;
|
||||
int height;
|
||||
QByteArray bytes;
|
||||
};
|
||||
|
||||
typedef QList<IconPixmap> IconPixmapList;
|
||||
|
||||
Q_DECLARE_METATYPE(IconPixmap)
|
||||
Q_DECLARE_METATYPE(IconPixmapList)
|
||||
|
||||
struct ToolTip {
|
||||
QString iconName;
|
||||
QList<IconPixmap> iconPixmap;
|
||||
QString title;
|
||||
QString description;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(ToolTip)
|
||||
|
||||
QDBusArgument &operator<<(QDBusArgument &argument, const IconPixmap &icon);
|
||||
const QDBusArgument &operator>>(const QDBusArgument &argument, IconPixmap &icon);
|
||||
|
||||
QDBusArgument &operator<<(QDBusArgument &argument, const ToolTip &toolTip);
|
||||
const QDBusArgument &operator>>(const QDBusArgument &argument, ToolTip &toolTip);
|
||||
|
||||
#endif // DBUSTYPES_H
|
|
@ -0,0 +1,69 @@
|
|||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="org.kde.StatusNotifierItem">
|
||||
|
||||
<property name="Category" type="s" access="read"/>
|
||||
<property name="Id" type="s" access="read"/>
|
||||
<property name="Title" type="s" access="read"/>
|
||||
<property name="Status" type="s" access="read"/>
|
||||
<property name="WindowId" type="i" access="read"/>
|
||||
<property name="IconThemePath" type="s" access="read"/>
|
||||
<property name="Menu" type="o" access="read"/>
|
||||
<property name="ItemIsMenu" type="b" access="read"/>
|
||||
<property name="IconName" type="s" access="read"/>
|
||||
<property name="IconPixmap" type="a(iiay)" access="read">
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName" value="IconPixmapList"/>
|
||||
</property>
|
||||
<property name="OverlayIconName" type="s" access="read"/>
|
||||
<property name="OverlayIconPixmap" type="a(iiay)" access="read">
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName" value="IconPixmapList"/>
|
||||
</property>
|
||||
<property name="AttentionIconName" type="s" access="read"/>
|
||||
<property name="AttentionIconPixmap" type="a(iiay)" access="read">
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName" value="IconPixmapList"/>
|
||||
</property>
|
||||
<property name="AttentionMovieName" type="s" access="read"/>
|
||||
<property name="ToolTip" type="(sa(iiay)ss)" access="read">
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName" value="ToolTip"/>
|
||||
</property>
|
||||
<method name="ContextMenu">
|
||||
<arg name="x" type="i" direction="in"/>
|
||||
<arg name="y" type="i" direction="in"/>
|
||||
</method>
|
||||
|
||||
<method name="Activate">
|
||||
<arg name="x" type="i" direction="in"/>
|
||||
<arg name="y" type="i" direction="in"/>
|
||||
</method>
|
||||
|
||||
<method name="SecondaryActivate">
|
||||
<arg name="x" type="i" direction="in"/>
|
||||
<arg name="y" type="i" direction="in"/>
|
||||
</method>
|
||||
|
||||
<method name="Scroll">
|
||||
<arg name="delta" type="i" direction="in"/>
|
||||
<arg name="orientation" type="s" direction="in"/>
|
||||
</method>
|
||||
|
||||
<signal name="NewTitle">
|
||||
</signal>
|
||||
|
||||
<signal name="NewIcon">
|
||||
</signal>
|
||||
|
||||
<signal name="NewAttentionIcon">
|
||||
</signal>
|
||||
|
||||
<signal name="NewOverlayIcon">
|
||||
</signal>
|
||||
|
||||
<signal name="NewToolTip">
|
||||
</signal>
|
||||
|
||||
<signal name="NewStatus">
|
||||
<arg name="status" type="s"/>
|
||||
</signal>
|
||||
|
||||
</interface>
|
||||
</node>
|
|
@ -0,0 +1,331 @@
|
|||
/* BEGIN_COMMON_COPYRIGHT_HEADER
|
||||
* (c)LGPL2+
|
||||
*
|
||||
* LXQt - a lightweight, Qt based, desktop toolset
|
||||
* https://lxqt.org/
|
||||
*
|
||||
* Copyright: 2015 LXQt team
|
||||
* Authors:
|
||||
* Paulo Lieuthier <paulolieuthier@gmail.com>
|
||||
*
|
||||
* This program or library is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
* END_COMMON_COPYRIGHT_HEADER */
|
||||
|
||||
#include "statusnotifieritem.h"
|
||||
#include "statusnotifieritemadaptor.h"
|
||||
#include <QDBusInterface>
|
||||
#include <QDBusServiceWatcher>
|
||||
#include <dbusmenuexporter.h>
|
||||
|
||||
int StatusNotifierItem::mServiceCounter = 0;
|
||||
|
||||
StatusNotifierItem::StatusNotifierItem(QString id, QObject *parent)
|
||||
: QObject(parent),
|
||||
mAdaptor(new StatusNotifierItemAdaptor(this)),
|
||||
mService(QString::fromLatin1("org.freedesktop.StatusNotifierItem-%1-%2")
|
||||
.arg(QCoreApplication::applicationPid())
|
||||
.arg(++mServiceCounter)),
|
||||
mId(id),
|
||||
mTitle(QLatin1String("Test")),
|
||||
mStatus(QLatin1String("Active")),
|
||||
mMenu(nullptr),
|
||||
mMenuPath(QLatin1String("/NO_DBUSMENU")),
|
||||
mMenuExporter(nullptr),
|
||||
mSessionBus(QDBusConnection::connectToBus(QDBusConnection::SessionBus, mService))
|
||||
{
|
||||
// Separate DBus connection to the session bus is created, because QDbus does not provide
|
||||
// a way to register different objects for different services with the same paths.
|
||||
// For status notifiers we need different /StatusNotifierItem for each service.
|
||||
|
||||
// register service
|
||||
|
||||
mSessionBus.registerObject(QLatin1String("/StatusNotifierItem"), this);
|
||||
|
||||
registerToHost();
|
||||
|
||||
// monitor the watcher service in case the host restarts
|
||||
QDBusServiceWatcher *watcher = new QDBusServiceWatcher(QLatin1String("org.kde.StatusNotifierWatcher"),
|
||||
mSessionBus,
|
||||
QDBusServiceWatcher::WatchForOwnerChange,
|
||||
this);
|
||||
connect(watcher, &QDBusServiceWatcher::serviceOwnerChanged,
|
||||
this, &StatusNotifierItem::onServiceOwnerChanged);
|
||||
}
|
||||
|
||||
StatusNotifierItem::~StatusNotifierItem()
|
||||
{
|
||||
mSessionBus.unregisterObject(QLatin1String("/StatusNotifierItem"));
|
||||
QDBusConnection::disconnectFromBus(mService);
|
||||
}
|
||||
|
||||
void StatusNotifierItem::registerToHost()
|
||||
{
|
||||
QDBusInterface interface(QLatin1String("org.kde.StatusNotifierWatcher"),
|
||||
QLatin1String("/StatusNotifierWatcher"),
|
||||
QLatin1String("org.kde.StatusNotifierWatcher"),
|
||||
mSessionBus);
|
||||
interface.asyncCall(QLatin1String("RegisterStatusNotifierItem"), mSessionBus.baseService());
|
||||
}
|
||||
|
||||
void StatusNotifierItem::onServiceOwnerChanged(const QString& service, const QString& oldOwner,
|
||||
const QString& newOwner)
|
||||
{
|
||||
Q_UNUSED(service);
|
||||
Q_UNUSED(oldOwner);
|
||||
|
||||
if (!newOwner.isEmpty())
|
||||
registerToHost();
|
||||
}
|
||||
|
||||
void StatusNotifierItem::onMenuDestroyed()
|
||||
{
|
||||
mMenu = nullptr;
|
||||
setMenuPath(QLatin1String("/NO_DBUSMENU"));
|
||||
mMenuExporter = nullptr; //mMenu is a QObject parent of the mMenuExporter
|
||||
}
|
||||
|
||||
void StatusNotifierItem::setTitle(const QString &title)
|
||||
{
|
||||
if (mTitle == title)
|
||||
return;
|
||||
|
||||
mTitle = title;
|
||||
Q_EMIT mAdaptor->NewTitle();
|
||||
}
|
||||
|
||||
void StatusNotifierItem::setStatus(const QString &status)
|
||||
{
|
||||
if (mStatus == status)
|
||||
return;
|
||||
|
||||
mStatus = status;
|
||||
Q_EMIT mAdaptor->NewStatus(mStatus);
|
||||
}
|
||||
|
||||
void StatusNotifierItem::setMenuPath(const QString& path)
|
||||
{
|
||||
mMenuPath.setPath(path);
|
||||
}
|
||||
|
||||
void StatusNotifierItem::setIconByName(const QString &name)
|
||||
{
|
||||
if (mIconName == name)
|
||||
return;
|
||||
|
||||
mIconName = name;
|
||||
Q_EMIT mAdaptor->NewIcon();
|
||||
}
|
||||
|
||||
void StatusNotifierItem::setIconByPixmap(const QIcon &icon)
|
||||
{
|
||||
if (mIconCacheKey == icon.cacheKey())
|
||||
return;
|
||||
|
||||
mIconCacheKey = icon.cacheKey();
|
||||
mIcon = iconToPixmapList(icon);
|
||||
mIconName.clear();
|
||||
Q_EMIT mAdaptor->NewIcon();
|
||||
}
|
||||
|
||||
void StatusNotifierItem::setOverlayIconByName(const QString &name)
|
||||
{
|
||||
if (mOverlayIconName == name)
|
||||
return;
|
||||
|
||||
mOverlayIconName = name;
|
||||
Q_EMIT mAdaptor->NewOverlayIcon();
|
||||
}
|
||||
|
||||
void StatusNotifierItem::setOverlayIconByPixmap(const QIcon &icon)
|
||||
{
|
||||
if (mOverlayIconCacheKey == icon.cacheKey())
|
||||
return;
|
||||
|
||||
mOverlayIconCacheKey = icon.cacheKey();
|
||||
mOverlayIcon = iconToPixmapList(icon);
|
||||
mOverlayIconName.clear();
|
||||
Q_EMIT mAdaptor->NewOverlayIcon();
|
||||
}
|
||||
|
||||
void StatusNotifierItem::setAttentionIconByName(const QString &name)
|
||||
{
|
||||
if (mAttentionIconName == name)
|
||||
return;
|
||||
|
||||
mAttentionIconName = name;
|
||||
Q_EMIT mAdaptor->NewAttentionIcon();
|
||||
}
|
||||
|
||||
void StatusNotifierItem::setAttentionIconByPixmap(const QIcon &icon)
|
||||
{
|
||||
if (mAttentionIconCacheKey == icon.cacheKey())
|
||||
return;
|
||||
|
||||
mAttentionIconCacheKey = icon.cacheKey();
|
||||
mAttentionIcon = iconToPixmapList(icon);
|
||||
mAttentionIconName.clear();
|
||||
Q_EMIT mAdaptor->NewAttentionIcon();
|
||||
}
|
||||
|
||||
void StatusNotifierItem::setToolTipTitle(const QString &title)
|
||||
{
|
||||
if (mTooltipTitle == title)
|
||||
return;
|
||||
|
||||
mTooltipTitle = title;
|
||||
Q_EMIT mAdaptor->NewToolTip();
|
||||
}
|
||||
|
||||
void StatusNotifierItem::setToolTipSubTitle(const QString &subTitle)
|
||||
{
|
||||
if (mTooltipSubtitle == subTitle)
|
||||
return;
|
||||
|
||||
mTooltipSubtitle = subTitle;
|
||||
Q_EMIT mAdaptor->NewToolTip();
|
||||
}
|
||||
|
||||
void StatusNotifierItem::setToolTipIconByName(const QString &name)
|
||||
{
|
||||
if (mTooltipIconName == name)
|
||||
return;
|
||||
|
||||
mTooltipIconName = name;
|
||||
Q_EMIT mAdaptor->NewToolTip();
|
||||
}
|
||||
|
||||
void StatusNotifierItem::setToolTipIconByPixmap(const QIcon &icon)
|
||||
{
|
||||
if (mTooltipIconCacheKey == icon.cacheKey())
|
||||
return;
|
||||
|
||||
mTooltipIconCacheKey = icon.cacheKey();
|
||||
mTooltipIcon = iconToPixmapList(icon);
|
||||
mTooltipIconName.clear();
|
||||
Q_EMIT mAdaptor->NewToolTip();
|
||||
}
|
||||
|
||||
void StatusNotifierItem::setContextMenu(QMenu* menu)
|
||||
{
|
||||
if (mMenu == menu)
|
||||
return;
|
||||
|
||||
if (nullptr != mMenu)
|
||||
{
|
||||
disconnect(mMenu, &QObject::destroyed, this, &StatusNotifierItem::onMenuDestroyed);
|
||||
}
|
||||
mMenu = menu;
|
||||
|
||||
if (nullptr != mMenu)
|
||||
setMenuPath(QLatin1String("/MenuBar"));
|
||||
else
|
||||
setMenuPath(QLatin1String("/NO_DBUSMENU"));
|
||||
|
||||
//Note: we need to destroy menu exporter before creating new one -> to free the DBus object path for new menu
|
||||
delete mMenuExporter;
|
||||
if (nullptr != mMenu)
|
||||
{
|
||||
connect(mMenu, &QObject::destroyed, this, &StatusNotifierItem::onMenuDestroyed);
|
||||
mMenuExporter = new DBusMenuExporter{this->menu().path(), mMenu, mSessionBus};
|
||||
}
|
||||
}
|
||||
|
||||
void StatusNotifierItem::Activate(int x, int y)
|
||||
{
|
||||
if (mStatus == QLatin1String("NeedsAttention"))
|
||||
mStatus = QLatin1String("Active");
|
||||
|
||||
Q_EMIT activateRequested(QPoint(x, y));
|
||||
}
|
||||
|
||||
void StatusNotifierItem::SecondaryActivate(int x, int y)
|
||||
{
|
||||
if (mStatus == QLatin1String("NeedsAttention"))
|
||||
mStatus = QLatin1String("Active");
|
||||
|
||||
Q_EMIT secondaryActivateRequested(QPoint(x, y));
|
||||
}
|
||||
|
||||
void StatusNotifierItem::ContextMenu(int x, int y)
|
||||
{
|
||||
if (mMenu)
|
||||
{
|
||||
if (mMenu->isVisible())
|
||||
mMenu->popup(QPoint(x, y));
|
||||
else
|
||||
mMenu->hide();
|
||||
}
|
||||
}
|
||||
|
||||
void StatusNotifierItem::Scroll(int delta, const QString &orientation)
|
||||
{
|
||||
Qt::Orientation orient = Qt::Vertical;
|
||||
if (orientation.toLower() == QLatin1String("horizontal"))
|
||||
orient = Qt::Horizontal;
|
||||
|
||||
Q_EMIT scrollRequested(delta, orient);
|
||||
}
|
||||
|
||||
void StatusNotifierItem::showMessage(const QString& title, const QString& msg,
|
||||
const QString& iconName, int secs)
|
||||
{
|
||||
QDBusInterface interface(QLatin1String("org.freedesktop.Notifications"), QLatin1String("/org/freedesktop/Notifications"),
|
||||
QLatin1String("org.freedesktop.Notifications"), mSessionBus);
|
||||
interface.call(QLatin1String("Notify"), mTitle, (uint) 0, iconName, title,
|
||||
msg, QStringList(), QVariantMap(), secs);
|
||||
}
|
||||
|
||||
IconPixmapList StatusNotifierItem::iconToPixmapList(const QIcon& icon)
|
||||
{
|
||||
IconPixmapList pixmapList;
|
||||
|
||||
// long live KDE!
|
||||
const QList<QSize> sizes = icon.availableSizes();
|
||||
for (const QSize &size : sizes)
|
||||
{
|
||||
QImage image = icon.pixmap(size).toImage();
|
||||
|
||||
IconPixmap pix;
|
||||
pix.height = image.height();
|
||||
pix.width = image.width();
|
||||
|
||||
if (image.format() != QImage::Format_ARGB32)
|
||||
image = image.convertToFormat(QImage::Format_ARGB32);
|
||||
|
||||
pix.bytes = QByteArray((char *) image.bits(),
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
|
||||
image.byteCount());
|
||||
#else
|
||||
image.sizeInBytes());
|
||||
#endif
|
||||
|
||||
// swap to network byte order if we are little endian
|
||||
if (QSysInfo::ByteOrder == QSysInfo::LittleEndian)
|
||||
{
|
||||
quint32 *uintBuf = (quint32 *) pix.bytes.data();
|
||||
for (uint i = 0; i < pix.bytes.size() / sizeof(quint32); ++i)
|
||||
{
|
||||
*uintBuf = qToBigEndian(*uintBuf);
|
||||
++uintBuf;
|
||||
}
|
||||
}
|
||||
|
||||
pixmapList.append(pix);
|
||||
}
|
||||
|
||||
return pixmapList;
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
/* BEGIN_COMMON_COPYRIGHT_HEADER
|
||||
* (c)LGPL2+
|
||||
*
|
||||
* LXQt - a lightweight, Qt based, desktop toolset
|
||||
* https://lxqt.org/
|
||||
*
|
||||
* Copyright: 2015 LXQt team
|
||||
* Authors:
|
||||
* Paulo Lieuthier <paulolieuthier@gmail.com>
|
||||
*
|
||||
* This program or library is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
* END_COMMON_COPYRIGHT_HEADER */
|
||||
|
||||
|
||||
#ifndef STATUS_NOTIFIER_ITEM_H
|
||||
#define STATUS_NOTIFIER_ITEM_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QIcon>
|
||||
#include <QMenu>
|
||||
#include <QDBusConnection>
|
||||
|
||||
#include "dbustypes.h"
|
||||
|
||||
class StatusNotifierItemAdaptor;
|
||||
class DBusMenuExporter;
|
||||
|
||||
class StatusNotifierItem : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString Title READ title)
|
||||
Q_PROPERTY(QString Id READ id)
|
||||
Q_PROPERTY(QString Status READ status)
|
||||
Q_PROPERTY(QDBusObjectPath Menu READ menu)
|
||||
|
||||
Q_PROPERTY(QString IconName READ iconName)
|
||||
Q_PROPERTY(IconPixmapList IconPixmap READ iconPixmap)
|
||||
|
||||
Q_PROPERTY(QString OverlayIconName READ overlayIconName)
|
||||
Q_PROPERTY(IconPixmapList OverlayIconPixmap READ overlayIconPixmap)
|
||||
|
||||
Q_PROPERTY(QString AttentionIconName READ attentionIconName)
|
||||
Q_PROPERTY(IconPixmapList AttentionIconPixmap READ attentionIconPixmap)
|
||||
|
||||
Q_PROPERTY(ToolTip ToolTip READ toolTip)
|
||||
|
||||
public:
|
||||
StatusNotifierItem(QString id, QObject *parent = nullptr);
|
||||
~StatusNotifierItem() override;
|
||||
|
||||
QString id() const
|
||||
{ return mId; }
|
||||
|
||||
QString title() const
|
||||
{ return mTitle; }
|
||||
void setTitle(const QString &title);
|
||||
|
||||
QString status() const
|
||||
{ return mStatus; }
|
||||
void setStatus(const QString &status);
|
||||
|
||||
QDBusObjectPath menu() const
|
||||
{ return mMenuPath; }
|
||||
void setMenuPath(const QString &path);
|
||||
|
||||
QString iconName() const
|
||||
{ return mIconName; }
|
||||
void setIconByName(const QString &name);
|
||||
|
||||
IconPixmapList iconPixmap() const
|
||||
{ return mIcon; }
|
||||
void setIconByPixmap(const QIcon &icon);
|
||||
|
||||
QString overlayIconName() const
|
||||
{ return mOverlayIconName; }
|
||||
void setOverlayIconByName(const QString &name);
|
||||
|
||||
IconPixmapList overlayIconPixmap() const
|
||||
{ return mOverlayIcon; }
|
||||
void setOverlayIconByPixmap(const QIcon &icon);
|
||||
|
||||
QString attentionIconName() const
|
||||
{ return mAttentionIconName; }
|
||||
void setAttentionIconByName(const QString &name);
|
||||
|
||||
IconPixmapList attentionIconPixmap() const
|
||||
{ return mAttentionIcon; }
|
||||
void setAttentionIconByPixmap(const QIcon &icon);
|
||||
|
||||
QString toolTipTitle() const
|
||||
{ return mTooltipTitle; }
|
||||
void setToolTipTitle(const QString &title);
|
||||
|
||||
QString toolTipSubTitle() const
|
||||
{ return mTooltipSubtitle; }
|
||||
void setToolTipSubTitle(const QString &subTitle);
|
||||
|
||||
QString toolTipIconName() const
|
||||
{ return mTooltipIconName; }
|
||||
void setToolTipIconByName(const QString &name);
|
||||
|
||||
IconPixmapList toolTipIconPixmap() const
|
||||
{ return mTooltipIcon; }
|
||||
void setToolTipIconByPixmap(const QIcon &icon);
|
||||
|
||||
ToolTip toolTip() const
|
||||
{
|
||||
ToolTip tt;
|
||||
tt.title = mTooltipTitle;
|
||||
tt.description = mTooltipSubtitle;
|
||||
tt.iconName = mTooltipIconName;
|
||||
tt.iconPixmap = mTooltipIcon;
|
||||
return tt;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \Note: we don't take ownership for the \param menu
|
||||
*/
|
||||
void setContextMenu(QMenu *menu);
|
||||
|
||||
public Q_SLOTS:
|
||||
void Activate(int x, int y);
|
||||
void SecondaryActivate(int x, int y);
|
||||
void ContextMenu(int x, int y);
|
||||
void Scroll(int delta, const QString &orientation);
|
||||
|
||||
void showMessage(const QString &title, const QString &msg, const QString &iconName, int secs);
|
||||
|
||||
private:
|
||||
void registerToHost();
|
||||
IconPixmapList iconToPixmapList(const QIcon &icon);
|
||||
|
||||
private Q_SLOTS:
|
||||
void onServiceOwnerChanged(const QString &service, const QString &oldOwner,
|
||||
const QString &newOwner);
|
||||
void onMenuDestroyed();
|
||||
|
||||
Q_SIGNALS:
|
||||
void activateRequested(const QPoint &pos);
|
||||
void secondaryActivateRequested(const QPoint &pos);
|
||||
void scrollRequested(int delta, Qt::Orientation orientation);
|
||||
|
||||
private:
|
||||
StatusNotifierItemAdaptor *mAdaptor;
|
||||
|
||||
QString mService;
|
||||
QString mId;
|
||||
QString mTitle;
|
||||
QString mStatus;
|
||||
|
||||
// icons
|
||||
QString mIconName, mOverlayIconName, mAttentionIconName;
|
||||
IconPixmapList mIcon, mOverlayIcon, mAttentionIcon;
|
||||
qint64 mIconCacheKey, mOverlayIconCacheKey, mAttentionIconCacheKey;
|
||||
|
||||
// tooltip
|
||||
QString mTooltipTitle, mTooltipSubtitle, mTooltipIconName;
|
||||
IconPixmapList mTooltipIcon;
|
||||
qint64 mTooltipIconCacheKey;
|
||||
|
||||
// menu
|
||||
QMenu *mMenu;
|
||||
QDBusObjectPath mMenuPath;
|
||||
DBusMenuExporter *mMenuExporter;
|
||||
QDBusConnection mSessionBus;
|
||||
|
||||
static int mServiceCounter;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -8,7 +8,7 @@ option(TDESKTOP_FORCE_GTK_FILE_DIALOG "Force using GTK file dialog (Linux only).
|
|||
option(TDESKTOP_DISABLE_REGISTER_CUSTOM_SCHEME "Disable automatic 'tg://' URL scheme handler registration." ${DESKTOP_APP_USE_PACKAGED})
|
||||
option(TDESKTOP_DISABLE_NETWORK_PROXY "Disable all code for working through Socks5 or MTProxy." OFF)
|
||||
option(TDESKTOP_DISABLE_DESKTOP_FILE_GENERATION "Disable automatic '.desktop' file generation (Linux only)." ${DESKTOP_APP_USE_PACKAGED})
|
||||
option(TDESKTOP_DISABLE_GTK_INTEGRATION "Disable all code for GTK integration (Linux only)." OFF)
|
||||
option(TDESKTOP_DISABLE_GTK_INTEGRATION "Disable all code for GTK integration (Linux only)." ON)
|
||||
option(TDESKTOP_DISABLE_DBUS_INTEGRATION "Disable all code for D-Bus integration (Linux only)." OFF)
|
||||
option(TDESKTOP_USE_PACKAGED_TGVOIP "Find libtgvoip using CMake instead of bundled one." ${DESKTOP_APP_USE_PACKAGED})
|
||||
option(TDESKTOP_API_TEST "Use test API credentials." OFF)
|
||||
|
@ -48,8 +48,8 @@ if (NOT DESKTOP_APP_SPECIAL_TARGET STREQUAL "")
|
|||
set(TDESKTOP_FORCE_GTK_FILE_DIALOG ON)
|
||||
endif()
|
||||
|
||||
if (TDESKTOP_FORCE_GTK_FILE_DIALOG AND TDESKTOP_DISABLE_GTK_INTEGRATION)
|
||||
message(FATAL_ERROR "Option TDESKTOP_FORCE_GTK_FILE_DIALOG conflicts with option TDESKTOP_DISABLE_GTK_INTEGRATION.")
|
||||
if (TDESKTOP_FORCE_GTK_FILE_DIALOG)
|
||||
set(TDESKTOP_DISABLE_GTK_INTEGRATION OFF)
|
||||
endif()
|
||||
|
||||
if (DESKTOP_APP_DISABLE_SPELLCHECK)
|
||||
|
|
|
@ -14,7 +14,7 @@ You will need GCC 8 installed. To install them and all the required dependencies
|
|||
|
||||
sudo apt-get install software-properties-common -y && \
|
||||
sudo apt-get install git libexif-dev liblzma-dev libz-dev libssl-dev \
|
||||
libappindicator-dev libicu-dev libdee-dev libdrm-dev dh-autoreconf \
|
||||
libgtk2.0-dev libice-dev libsm-dev libicu-dev libdrm-dev dh-autoreconf \
|
||||
autoconf automake build-essential libass-dev libfreetype6-dev \
|
||||
libgpac-dev libsdl1.2-dev libtheora-dev libtool libva-dev libvdpau-dev \
|
||||
libvorbis-dev libenchant-dev libxcb1-dev libxcb-image0-dev libxcb-shm0-dev \
|
||||
|
|
|
@ -52,15 +52,13 @@ parts:
|
|||
- g++-8
|
||||
- qtbase5-private-dev
|
||||
- libmapbox-variant-dev
|
||||
- libmsgsl-dev
|
||||
- libayatana-appindicator3-dev
|
||||
- libgtk-3-dev
|
||||
- libasound2-dev
|
||||
- libavcodec-dev
|
||||
- libavformat-dev
|
||||
- libavutil-dev
|
||||
- libswscale-dev
|
||||
- libswresample-dev
|
||||
- libdbusmenu-qt5-dev
|
||||
- liblz4-dev
|
||||
- liblzma-dev
|
||||
- libminizip-dev
|
||||
|
@ -71,13 +69,13 @@ parts:
|
|||
- zlib1g-dev
|
||||
stage-packages:
|
||||
- qt5-image-formats-plugins
|
||||
- libayatana-appindicator3-1
|
||||
- libasound2
|
||||
- libavcodec57
|
||||
- libavformat57
|
||||
- libavutil55
|
||||
- libswscale4
|
||||
- libswresample2
|
||||
- libdbusmenu-qt5-2
|
||||
- liblz4-1
|
||||
- liblzma5
|
||||
- libminizip1
|
||||
|
@ -116,6 +114,7 @@ parts:
|
|||
- cmake
|
||||
- desktop-qt5
|
||||
- enchant
|
||||
- gsl
|
||||
- range-v3
|
||||
- xxhash
|
||||
|
||||
|
@ -205,6 +204,15 @@ parts:
|
|||
- --enable-relocatable
|
||||
prime: [-./bin/*]
|
||||
|
||||
gsl:
|
||||
source: https://github.com/microsoft/GSL.git
|
||||
source-depth: 1
|
||||
source-tag: v2.1.0
|
||||
plugin: cmake
|
||||
configflags:
|
||||
- -DGSL_TEST=OFF
|
||||
prime: [-./*]
|
||||
|
||||
range-v3:
|
||||
source: https://github.com/ericniebler/range-v3.git
|
||||
source-depth: 1
|
||||
|
|
Loading…
Reference in New Issue