1
0
mirror of https://github.com/qTox/qTox.git synced 2024-03-22 14:00:36 +08:00

Implement GTK systray icon backend

This one is deprecated, but should work much better than any other system tray icon backend we currently have, both in term of supported features and reliability. It justs needs some testing to see where we can enable it now.
This commit is contained in:
tux3 2015-02-24 23:27:08 +01:00
parent bee584bdb1
commit 8a83a6114f
No known key found for this signature in database
GPG Key ID: 7E086DD661263264
4 changed files with 148 additions and 8 deletions

View File

@ -237,6 +237,30 @@ contains(ENABLE_SYSTRAY_STATUSNOTIFIER_BACKEND, NO) {
}
}
# The systray GTK backend implements a system tray icon compatible with many systems
unix:!macx:!android {
contains(ENABLE_SYSTRAY_GTK_BACKEND, NO) {
} else {
DEFINES += ENABLE_SYSTRAY_GTK_BACKEND
INCLUDEPATH += "/usr/include/gtk-2.0"
INCLUDEPATH += "/usr/include/glib-2.0"
INCLUDEPATH += "/usr/lib/glib-2.0/include"
INCLUDEPATH += "/usr/lib/x86_64-linux-gnu/glib-2.0/include"
INCLUDEPATH += "/usr/lib/i386-linux-gnu/glib-2.0/include"
INCLUDEPATH += "/usr/lib/gtk-2.0/include"
INCLUDEPATH += "/usr/lib/x86_64-linux-gnu/gtk-2.0/include"
INCLUDEPATH += "/usr/lib/i386-linux-gnu/gtk-2.0/include"
INCLUDEPATH += "/usr/include/atk-1.0"
INCLUDEPATH += "/usr/include/gdk-pixbuf-2.0"
INCLUDEPATH += "/usr/include/cairo"
INCLUDEPATH += "/usr/include/pango-1.0"
LIBS += -lglib-2.0 -lgdk_pixbuf-2.0 -lgio-2.0 -lcairo -lgtk-x11-2.0 -lgdk-x11-2.0 -lgobject-2.0
}
}
!android {
HEADERS += \
src/friend.h \

View File

@ -37,6 +37,42 @@ SystemTrayIcon::SystemTrayIcon()
app_indicator_set_menu(unityIndicator, GTK_MENU(unityMenu));
}
#endif
#ifdef ENABLE_SYSTRAY_GTK_BACKEND
else if (desktop == "xfce" || (desktop == "kde"
&& getenv("KDE_SESSION_VERSION") == QString("4")))
{
qDebug() << "SystemTrayIcon: Using GTK backend";
backendType = SystrayBackendType::GTK;
gtk_init(nullptr, nullptr);
void (*callbackFreeImage)(guchar*, gpointer) =
[](guchar*, gpointer image)
{
delete reinterpret_cast<QImage*>(image);
};
QImage* image = new QImage(":/img/icon.png");
if (image->format() != QImage::Format_RGBA8888_Premultiplied)
*image = image->convertToFormat(QImage::Format_RGBA8888_Premultiplied);
GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data(image->bits(), GDK_COLORSPACE_RGB, image->hasAlphaChannel(),
8, image->width(), image->height(),
image->bytesPerLine(), callbackFreeImage, image);
gtkIcon = gtk_status_icon_new_from_pixbuf(pixbuf);
gtkMenu = gtk_menu_new();
void (*callbackTrigger)(GtkStatusIcon*, gpointer) =
[](GtkStatusIcon*, gpointer data)
{
((SystemTrayIcon*)data)->activated(QSystemTrayIcon::Trigger);
};
g_signal_connect(gtkIcon, "activate", G_CALLBACK(callbackTrigger), this);
void (*callbackButtonClick)(GtkStatusIcon*, GdkEvent*, gpointer) =
[](GtkStatusIcon*, GdkEvent* event, gpointer data)
{
if (event->button.button == 2)
((SystemTrayIcon*)data)->activated(QSystemTrayIcon::MiddleClick);
};
g_signal_connect(gtkIcon, "button-release-event", G_CALLBACK(callbackButtonClick), this);
}
#endif
#ifdef ENABLE_SYSTRAY_STATUSNOTIFIER_BACKEND
else if (desktop == "kde"
&& getenv("KDE_SESSION_VERSION") == QString("5"))
@ -156,6 +192,51 @@ void SystemTrayIcon::setContextMenu(QMenu* menu)
g_signal_connect(statusNotifier, "context-menu", G_CALLBACK(callbackMenu), this);
}
#endif
#ifdef ENABLE_SYSTRAY_GTK_BACKEND
else if (backendType == SystrayBackendType::GTK)
{
for (QAction* a : menu->actions())
{
QString aText = a->text().replace('&',"");
GtkWidget* item;
if (a->isSeparator())
item = gtk_menu_item_new();
else if (a->icon().isNull())
item = gtk_menu_item_new_with_label(aText.toStdString().c_str());
else
{
void (*callbackFreeImage)(guchar*, gpointer) =
[](guchar*, gpointer image)
{
delete reinterpret_cast<QImage*>(image);
};
QImage* image = new QImage(a->icon().pixmap(64, 64).toImage());
if (image->format() != QImage::Format_RGBA8888_Premultiplied)
*image = image->convertToFormat(QImage::Format_RGBA8888_Premultiplied);
GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data(image->bits(), GDK_COLORSPACE_RGB, image->hasAlphaChannel(),
8, image->width(), image->height(),
image->bytesPerLine(), callbackFreeImage, image);
item = gtk_image_menu_item_new_with_label(aText.toStdString().c_str());
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), gtk_image_new_from_pixbuf(pixbuf));
gtk_image_menu_item_set_always_show_image(GTK_IMAGE_MENU_ITEM(item),TRUE);
}
gtk_menu_shell_append(GTK_MENU_SHELL(gtkMenu), item);
void (*callback)(GtkMenu*, gpointer data) = [](GtkMenu*, gpointer a)
{
((QAction*)a)->activate(QAction::Trigger);
};
g_signal_connect(item, "activate", G_CALLBACK(callback), a);
gtk_widget_show(item);
}
void (*callbackMenu)(StatusNotifier*, gint, gint, gpointer) =
[](StatusNotifier*, gint, gint, gpointer data)
{
gtk_widget_show_all(((SystemTrayIcon*)data)->gtkMenu);
gtk_menu_popup(GTK_MENU(((SystemTrayIcon*)data)->gtkMenu), 0, 0, 0, 0, 3, gtk_get_current_event_time());
};
g_signal_connect(gtkIcon, "popup-menu", G_CALLBACK(callbackMenu), this);
}
#endif
#ifdef ENABLE_SYSTRAY_UNITY_BACKEND
else if (backendType == SystrayBackendType::Unity)
{
@ -224,6 +305,15 @@ void SystemTrayIcon::setVisible(bool newState)
status_notifier_set_status(statusNotifier, STATUS_NOTIFIER_STATUS_PASSIVE);
}
#endif
#ifdef ENABLE_SYSTRAY_GTK_BACKEND
else if (backendType == SystrayBackendType::GTK)
{
if (newState)
gtk_status_icon_set_visible(gtkIcon, true);
else
gtk_status_icon_set_visible(gtkIcon, false);
}
#endif
#ifdef ENABLE_SYSTRAY_UNITY_BACKEND
else if (backendType == SystrayBackendType::Unity)
{
@ -262,6 +352,23 @@ void SystemTrayIcon::setIcon(QIcon &&icon)
status_notifier_set_from_pixbuf(statusNotifier, STATUS_NOTIFIER_ICON, pixbuf);
}
#endif
#ifdef ENABLE_SYSTRAY_GTK_BACKEND
else if (backendType == SystrayBackendType::GTK)
{
void (*callbackFreeImage)(guchar*, gpointer) =
[](guchar*, gpointer image)
{
delete reinterpret_cast<QImage*>(image);
};
QImage* image = new QImage(icon.pixmap(64, 64).toImage());
if (image->format() != QImage::Format_RGBA8888_Premultiplied)
*image = image->convertToFormat(QImage::Format_RGBA8888_Premultiplied);
GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data(image->bits(), GDK_COLORSPACE_RGB, image->hasAlphaChannel(),
8, image->width(), image->height(),
image->bytesPerLine(), callbackFreeImage, image);
gtk_status_icon_set_from_pixbuf(gtkIcon, pixbuf);
}
#endif
#ifdef ENABLE_SYSTRAY_UNITY_BACKEND
else if (backendType == SystrayBackendType::Unity)
{

View File

@ -36,6 +36,10 @@ private:
StatusNotifier* statusNotifier;
GtkWidget* snMenu;
#endif
#ifdef ENABLE_SYSTRAY_GTK_BACKEND
GtkStatusIcon* gtkIcon;
GtkWidget* gtkMenu;
#endif
};
#endif // SYSTEMTRAYICON_H

View File

@ -30,6 +30,17 @@ extern "C" {
#define signals public
#endif
#ifdef ENABLE_SYSTRAY_GTK_BACKEND
#ifdef signals
#undef signals
#endif
extern "C" {
#include <libappindicator/app-indicator.h>
#include <gtk/gtk.h>
}
#define signals public
#endif
enum class SystrayBackendType
{
Qt,
@ -40,15 +51,9 @@ enum class SystrayBackendType
#ifdef ENABLE_SYSTRAY_STATUSNOTIFIER_BACKEND
StatusNotifier,
#endif
};
union SystrayBackend
{
QSystemTrayIcon *qt;
#ifdef ENABLE_SYSTRAY_UNITY_BACKEND
AppIndicator *unity;
#ifdef ENABLE_SYSTRAY_GTK_BACKEND
GTK,
#endif
};
#endif // SYSTEMTRAYICON_PRIVATE_H