mirror of https://github.com/qTox/qTox.git
8 changed files with 4 additions and 568 deletions
@ -1,335 +0,0 @@
@@ -1,335 +0,0 @@
|
||||
/*
|
||||
Copyright © 2015-2019 by The qTox Project Contributors |
||||
|
||||
This file is part of qTox, a Qt-based graphical interface for Tox. |
||||
|
||||
qTox is libre software: you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation, either version 3 of the License, or |
||||
(at your option) any later version. |
||||
|
||||
qTox 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 General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License |
||||
along with qTox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
|
||||
#include "systemtrayicon.h" |
||||
#include "src/persistence/settings.h" |
||||
#include <QDebug> |
||||
#include <QFile> |
||||
#include <QMenu> |
||||
#include <QString> |
||||
#include <QSystemTrayIcon> |
||||
|
||||
SystemTrayIcon::SystemTrayIcon() |
||||
{ |
||||
QString desktop = getenv("XDG_CURRENT_DESKTOP"); |
||||
if (desktop.isEmpty()) |
||||
desktop = getenv("DESKTOP_SESSION"); |
||||
desktop = desktop.toLower(); |
||||
if (false) |
||||
; |
||||
#ifdef ENABLE_SYSTRAY_UNITY_BACKEND |
||||
else if (desktop == "unity") { |
||||
qDebug() << "Using Unity backend"; |
||||
gtk_init(nullptr, nullptr); |
||||
QString settingsDir = Settings::getInstance().getSettingsDirPath(); |
||||
QFile iconFile(settingsDir + "/icon.png"); |
||||
if (iconFile.open(QIODevice::Truncate | QIODevice::WriteOnly)) { |
||||
QFile resIconFile(":/img/icon.png"); |
||||
if (resIconFile.open(QIODevice::ReadOnly)) |
||||
iconFile.write(resIconFile.readAll()); |
||||
resIconFile.close(); |
||||
iconFile.close(); |
||||
} |
||||
backendType = SystrayBackendType::Unity; |
||||
unityMenu = gtk_menu_new(); |
||||
const std::string settingsDirString = settingsDir.toStdString(); |
||||
unityIndicator = |
||||
app_indicator_new_with_path("qTox", "icon", APP_INDICATOR_CATEGORY_APPLICATION_STATUS, |
||||
settingsDirString.c_str()); |
||||
app_indicator_set_menu(unityIndicator, GTK_MENU(unityMenu)); |
||||
} |
||||
#endif |
||||
#ifdef ENABLE_SYSTRAY_GTK_BACKEND |
||||
else if (desktop == "xfce" || desktop.contains("gnome") || desktop == "mate" |
||||
|| desktop == "x-cinnamon") { |
||||
qDebug() << "Using GTK backend"; |
||||
backendType = SystrayBackendType::GTK; |
||||
gtk_init(nullptr, nullptr); |
||||
|
||||
gtkIcon = gtk_status_icon_new(); |
||||
|
||||
gtkMenu = gtk_menu_new(); |
||||
|
||||
void (*callbackTrigger)(GtkStatusIcon*, gpointer) = [](GtkStatusIcon*, gpointer data) { |
||||
static_cast<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) |
||||
static_cast<SystemTrayIcon*>(data)->activated(QSystemTrayIcon::MiddleClick); |
||||
}; |
||||
g_signal_connect(gtkIcon, "button-release-event", G_CALLBACK(callbackButtonClick), this); |
||||
} |
||||
#endif |
||||
else { |
||||
qDebug() << "Using the Qt backend"; |
||||
qtIcon = new QSystemTrayIcon; |
||||
backendType = SystrayBackendType::Qt; |
||||
connect(qtIcon, &QSystemTrayIcon::activated, this, &SystemTrayIcon::activated); |
||||
} |
||||
} |
||||
|
||||
SystemTrayIcon::~SystemTrayIcon() |
||||
{ |
||||
qDebug() << "Deleting SystemTrayIcon"; |
||||
delete qtIcon; |
||||
} |
||||
|
||||
QString SystemTrayIcon::extractIconToFile(QIcon icon, QString name) |
||||
{ |
||||
QString iconPath; |
||||
(void)icon; |
||||
(void)name; |
||||
#ifdef ENABLE_SYSTRAY_UNITY_BACKEND |
||||
iconPath = Settings::getInstance().getSettingsDirPath() + "/" + name + ".png"; |
||||
QSize iconSize = icon.actualSize(QSize{64, 64}); |
||||
icon.pixmap(iconSize).save(iconPath); |
||||
#endif |
||||
return iconPath; |
||||
} |
||||
|
||||
#if defined(ENABLE_SYSTRAY_GTK_BACKEND) || defined(ENABLE_SYSTRAY_STATUSNOTIFIER_BACKEND) |
||||
GdkPixbuf* SystemTrayIcon::convertQIconToPixbuf(const QIcon& icon) |
||||
{ |
||||
void (*callbackFreeImage)(guchar*, gpointer) = [](guchar* image_bytes, gpointer) { |
||||
delete[] image_bytes; |
||||
}; |
||||
QImage image = icon.pixmap(64, 64).toImage(); |
||||
if (image.format() != QImage::Format_RGBA8888_Premultiplied) |
||||
image = image.convertToFormat(QImage::Format_RGBA8888_Premultiplied); |
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) |
||||
guchar* image_bytes = new guchar[image.sizeInBytes()]; |
||||
memcpy(image_bytes, image.bits(), image.sizeInBytes()); |
||||
#else |
||||
guchar* image_bytes = new guchar[image.byteCount()]; |
||||
memcpy(image_bytes, image.bits(), image.byteCount()); |
||||
#endif |
||||
return gdk_pixbuf_new_from_data(image_bytes, GDK_COLORSPACE_RGB, image.hasAlphaChannel(), 8, |
||||
image.width(), image.height(), image.bytesPerLine(), |
||||
callbackFreeImage, nullptr); |
||||
} |
||||
#endif |
||||
|
||||
void SystemTrayIcon::setContextMenu(QMenu* menu) |
||||
{ |
||||
if (false) |
||||
; |
||||
#ifdef ENABLE_SYSTRAY_STATUSNOTIFIER_BACKEND |
||||
else if (backendType == SystrayBackendType::StatusNotifier) { |
||||
void (*callbackClick)(StatusNotifier*, gint, gint, gpointer) = [](StatusNotifier*, gint, |
||||
gint, gpointer data) { |
||||
static_cast<SystemTrayIcon*>(data)->activated(QSystemTrayIcon::Trigger); |
||||
}; |
||||
g_signal_connect(statusNotifier, "activate", G_CALLBACK(callbackClick), this); |
||||
void (*callbackMiddleClick)(StatusNotifier*, gint, gint, |
||||
gpointer) = [](StatusNotifier*, gint, gint, gpointer data) { |
||||
static_cast<SystemTrayIcon*>(data)->activated(QSystemTrayIcon::MiddleClick); |
||||
}; |
||||
g_signal_connect(statusNotifier, "secondary_activate", G_CALLBACK(callbackMiddleClick), this); |
||||
|
||||
for (QAction* a : menu->actions()) { |
||||
const std::string aText = a->text().replace('&', "").toStdString(); |
||||
GtkWidget* item; |
||||
if (a->isSeparator()) |
||||
item = gtk_menu_item_new(); |
||||
else if (a->icon().isNull()) |
||||
item = gtk_menu_item_new_with_label(aText.c_str()); |
||||
else { |
||||
GdkPixbuf* pixbuf = convertQIconToPixbuf(a->icon()); |
||||
item = gtk_image_menu_item_new_with_label(aText.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); |
||||
g_object_unref(pixbuf); |
||||
} |
||||
gtk_menu_shell_append(GTK_MENU_SHELL(snMenu), 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(static_cast<SystemTrayIcon*>(data)->snMenu); |
||||
gtk_menu_popup(GTK_MENU(static_cast<SystemTrayIcon*>(data)->snMenu), 0, 0, 0, 0, 3, |
||||
gtk_get_current_event_time()); |
||||
}; |
||||
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()) { |
||||
const std::string aText = a->text().replace('&', "").toStdString(); |
||||
GtkWidget* item; |
||||
if (a->isSeparator()) |
||||
item = gtk_menu_item_new(); |
||||
else if (a->icon().isNull()) |
||||
item = gtk_menu_item_new_with_label(aText.c_str()); |
||||
else { |
||||
GdkPixbuf* pixbuf = convertQIconToPixbuf(a->icon()); |
||||
item = gtk_image_menu_item_new_with_label(aText.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); |
||||
g_object_unref(pixbuf); |
||||
} |
||||
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)(GtkMenu*, gint, gint, gpointer) = [](GtkMenu*, gint, gint, gpointer data) { |
||||
gtk_widget_show_all(static_cast<SystemTrayIcon*>(data)->gtkMenu); |
||||
gtk_menu_popup(GTK_MENU(static_cast<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) { |
||||
for (QAction* a : menu->actions()) { |
||||
const std::string aText = a->text().replace('&', "").toStdString(); |
||||
GtkWidget* item; |
||||
if (a->isSeparator()) |
||||
item = gtk_menu_item_new(); |
||||
else if (a->icon().isNull()) |
||||
item = gtk_menu_item_new_with_label(aText.c_str()); |
||||
else { |
||||
const std::string iconPath = |
||||
extractIconToFile(a->icon(), "iconmenu" + a->icon().name()).toStdString(); |
||||
GtkWidget* image = gtk_image_new_from_file(iconPath.c_str()); |
||||
item = gtk_image_menu_item_new_with_label(aText.c_str()); |
||||
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image); |
||||
gtk_image_menu_item_set_always_show_image(GTK_IMAGE_MENU_ITEM(item), TRUE); |
||||
} |
||||
gtk_menu_shell_append(GTK_MENU_SHELL(unityMenu), item); |
||||
void (*callback)(GtkMenu*, gpointer data) = [](GtkMenu*, gpointer a) { |
||||
static_cast<QAction*>(a)->activate(QAction::Trigger); |
||||
}; |
||||
g_signal_connect(item, "activate", G_CALLBACK(callback), a); |
||||
gtk_widget_show(item); |
||||
} |
||||
app_indicator_set_menu(unityIndicator, GTK_MENU(unityMenu)); |
||||
DbusmenuServer* menuServer; |
||||
DbusmenuMenuitem* rootMenuItem; |
||||
g_object_get(unityIndicator, "dbus-menu-server", &menuServer, nullptr); |
||||
g_object_get(menuServer, "root-node", &rootMenuItem, nullptr); |
||||
void (*callback)(DbusmenuMenuitem*, gpointer) = [](DbusmenuMenuitem*, gpointer data) { |
||||
static_cast<SystemTrayIcon*>(data)->activated(QSystemTrayIcon::Unknown); |
||||
}; |
||||
g_signal_connect(rootMenuItem, "about-to-show", G_CALLBACK(callback), this); |
||||
} |
||||
#endif |
||||
else if (backendType == SystrayBackendType::Qt) { |
||||
qtIcon->setContextMenu(menu); |
||||
} |
||||
} |
||||
|
||||
void SystemTrayIcon::show() |
||||
{ |
||||
setVisible(true); |
||||
} |
||||
|
||||
void SystemTrayIcon::hide() |
||||
{ |
||||
setVisible(false); |
||||
} |
||||
|
||||
void SystemTrayIcon::setVisible(bool newState) |
||||
{ |
||||
if (false) |
||||
; |
||||
#ifdef ENABLE_SYSTRAY_STATUSNOTIFIER_BACKEND |
||||
else if (backendType == SystrayBackendType::StatusNotifier) { |
||||
if (newState) |
||||
status_notifier_set_status(statusNotifier, STATUS_NOTIFIER_STATUS_ACTIVE); |
||||
else |
||||
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) { |
||||
if (newState) |
||||
app_indicator_set_status(unityIndicator, APP_INDICATOR_STATUS_ACTIVE); |
||||
else |
||||
app_indicator_set_status(unityIndicator, APP_INDICATOR_STATUS_PASSIVE); |
||||
} |
||||
#endif |
||||
else if (backendType == SystrayBackendType::Qt) { |
||||
if (newState) |
||||
qtIcon->show(); |
||||
else |
||||
qtIcon->hide(); |
||||
} |
||||
} |
||||
|
||||
void SystemTrayIcon::setIcon(QIcon& icon) |
||||
{ |
||||
if (false) |
||||
; |
||||
#ifdef ENABLE_SYSTRAY_STATUSNOTIFIER_BACKEND |
||||
else if (backendType == SystrayBackendType::StatusNotifier) { |
||||
GdkPixbuf* pixbuf = convertQIconToPixbuf(icon); |
||||
status_notifier_set_from_pixbuf(statusNotifier, STATUS_NOTIFIER_ICON, pixbuf); |
||||
g_object_unref(pixbuf); |
||||
} |
||||
#endif |
||||
#ifdef ENABLE_SYSTRAY_GTK_BACKEND |
||||
else if (backendType == SystrayBackendType::GTK) { |
||||
GdkPixbuf* pixbuf = convertQIconToPixbuf(icon); |
||||
gtk_status_icon_set_from_pixbuf(gtkIcon, pixbuf); |
||||
g_object_unref(pixbuf); |
||||
} |
||||
#endif |
||||
#ifdef ENABLE_SYSTRAY_UNITY_BACKEND |
||||
else if (backendType == SystrayBackendType::Unity) { |
||||
// Alternate file names or appindicator will not reload the icon
|
||||
if (app_indicator_get_icon(unityIndicator) == QString("icon2")) { |
||||
extractIconToFile(icon, "icon"); |
||||
app_indicator_set_icon_full(unityIndicator, "icon", "qtox"); |
||||
} else { |
||||
extractIconToFile(icon, "icon2"); |
||||
app_indicator_set_icon_full(unityIndicator, "icon2", "qtox"); |
||||
} |
||||
} |
||||
#endif |
||||
else if (backendType == SystrayBackendType::Qt) { |
||||
qtIcon->setIcon(icon); |
||||
} |
||||
} |
||||
|
||||
SystrayBackendType SystemTrayIcon::backend() const |
||||
{ |
||||
return backendType; |
||||
} |
||||
@ -1,70 +0,0 @@
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
Copyright © 2015-2019 by The qTox Project Contributors |
||||
|
||||
This file is part of qTox, a Qt-based graphical interface for Tox. |
||||
|
||||
qTox is libre software: you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation, either version 3 of the License, or |
||||
(at your option) any later version. |
||||
|
||||
qTox 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 General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License |
||||
along with qTox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
|
||||
#ifndef SYSTEMTRAYICON_H |
||||
#define SYSTEMTRAYICON_H |
||||
|
||||
#include "systemtrayicon_private.h" |
||||
#include <QObject> |
||||
|
||||
class QSystemTrayIcon; |
||||
class QMenu; |
||||
|
||||
class SystemTrayIcon : public QObject |
||||
{ |
||||
Q_OBJECT |
||||
public: |
||||
SystemTrayIcon(); |
||||
~SystemTrayIcon(); |
||||
void setContextMenu(QMenu* menu); |
||||
void show(); |
||||
void hide(); |
||||
void setVisible(bool); |
||||
void setIcon(QIcon& icon); |
||||
SystrayBackendType backend() const; |
||||
|
||||
signals: |
||||
void activated(QSystemTrayIcon::ActivationReason); |
||||
|
||||
private: |
||||
QString extractIconToFile(QIcon icon, QString name = "icon"); |
||||
#if defined(ENABLE_SYSTRAY_GTK_BACKEND) || defined(ENABLE_SYSTRAY_STATUSNOTIFIER_BACKEND) |
||||
static GdkPixbuf* convertQIconToPixbuf(const QIcon& icon); |
||||
#endif |
||||
|
||||
private: |
||||
SystrayBackendType backendType; |
||||
QSystemTrayIcon* qtIcon = nullptr; |
||||
|
||||
#ifdef ENABLE_SYSTRAY_UNITY_BACKEND |
||||
AppIndicator* unityIndicator; |
||||
GtkWidget* unityMenu; |
||||
#endif |
||||
#ifdef ENABLE_SYSTRAY_STATUSNOTIFIER_BACKEND |
||||
StatusNotifier* statusNotifier; |
||||
GtkWidget* snMenu; |
||||
#endif |
||||
#ifdef ENABLE_SYSTRAY_GTK_BACKEND |
||||
GtkStatusIcon* gtkIcon; |
||||
GtkWidget* gtkMenu; |
||||
#endif |
||||
}; |
||||
|
||||
#endif // SYSTEMTRAYICON_H
|
||||
@ -1,71 +0,0 @@
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
Copyright © 2015-2019 by The qTox Project Contributors |
||||
|
||||
This file is part of qTox, a Qt-based graphical interface for Tox. |
||||
|
||||
qTox is libre software: you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation, either version 3 of the License, or |
||||
(at your option) any later version. |
||||
|
||||
qTox 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 General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License |
||||
along with qTox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
|
||||
#ifndef SYSTEMTRAYICON_PRIVATE_H |
||||
#define SYSTEMTRAYICON_PRIVATE_H |
||||
|
||||
#include <QSystemTrayIcon> |
||||
|
||||
#ifdef ENABLE_SYSTRAY_STATUSNOTIFIER_BACKEND |
||||
#ifdef signals |
||||
#undef signals |
||||
#endif |
||||
extern "C" { |
||||
#include "src/platform/statusnotifier/statusnotifier.h" |
||||
#include <gdk-pixbuf/gdk-pixbuf.h> |
||||
#include <gio/gio.h> |
||||
#include <glib-object.h> |
||||
#include <glib.h> |
||||
#include <gtk/gtk.h> |
||||
} |
||||
#define signals public |
||||
#endif |
||||
|
||||
#ifdef ENABLE_SYSTRAY_UNITY_BACKEND |
||||
#ifdef signals |
||||
#undef signals |
||||
#endif |
||||
extern "C" { |
||||
#include <gtk/gtk.h> |
||||
#include <libappindicator/app-indicator.h> |
||||
#include <libdbusmenu-glib/server.h> |
||||
} |
||||
#define signals public |
||||
#endif |
||||
|
||||
#ifdef ENABLE_SYSTRAY_GTK_BACKEND |
||||
#ifdef signals |
||||
#undef signals |
||||
#endif |
||||
extern "C" { |
||||
#include <gtk/gtk.h> |
||||
} |
||||
#define signals public |
||||
#endif |
||||
|
||||
enum class SystrayBackendType |
||||
{ |
||||
Qt, |
||||
Unity, |
||||
StatusNotifier, |
||||
GTK |
||||
}; |
||||
|
||||
#endif // SYSTEMTRAYICON_PRIVATE_H
|
||||
Loading…
Reference in new issue