Build fixed for QtCreator. Linux libs loading order changed.

This commit is contained in:
John Preston 2016-06-16 20:20:58 +03:00
parent 8e78cfed85
commit 7a9dfb50e1
9 changed files with 672 additions and 514 deletions

View File

@ -436,7 +436,7 @@ void MainWindow::init() {
setWindowIcon(wndIcon);
Application::instance()->installEventFilter(this);
connect(windowHandle(), SIGNAL(windowStateChanged(Qt::WindowState)), this, SLOT(stateChanged(Qt::WindowState)));
connect(windowHandle(), SIGNAL(windowStateChanged(Qt::WindowState)), this, SLOT(onStateChanged(Qt::WindowState)));
connect(windowHandle(), SIGNAL(activeChanged()), this, SLOT(checkHistoryActivation()), Qt::QueuedConnection);
QPalette p(palette());

View File

@ -0,0 +1,184 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free 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.
It 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.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "platform/linux/linux_libs.h"
namespace Platform {
namespace Libs {
namespace {
bool loadLibrary(QLibrary &lib, const char *name, int version) {
DEBUG_LOG(("Loading '%1' with version %2...").arg(QLatin1String(name)).arg(version));
lib.setFileNameAndVersion(QLatin1String(name), version);
if (lib.load()) {
DEBUG_LOG(("Loaded '%1' with version %2!").arg(QLatin1String(name)).arg(version));
return true;
}
lib.setFileNameAndVersion(QLatin1String(name), QString());
if (lib.load()) {
DEBUG_LOG(("Loaded '%1' without version!").arg(QLatin1String(name)));
return true;
}
LOG(("Could not load '%1' with version %2 :(").arg(QLatin1String(name)).arg(version));
return false;
}
bool setupGtkBase(QLibrary &lib_gtk) {
if (!load(lib_gtk, "gtk_init_check", gtk_init_check)) return false;
if (!load(lib_gtk, "gtk_menu_new", gtk_menu_new)) return false;
if (!load(lib_gtk, "gtk_menu_get_type", gtk_menu_get_type)) return false;
if (!load(lib_gtk, "gtk_menu_item_new_with_label", gtk_menu_item_new_with_label)) return false;
if (!load(lib_gtk, "gtk_menu_item_set_label", gtk_menu_item_set_label)) return false;
if (!load(lib_gtk, "gtk_menu_shell_append", gtk_menu_shell_append)) return false;
if (!load(lib_gtk, "gtk_menu_shell_get_type", gtk_menu_shell_get_type)) return false;
if (!load(lib_gtk, "gtk_widget_show", gtk_widget_show)) return false;
if (!load(lib_gtk, "gtk_widget_get_toplevel", gtk_widget_get_toplevel)) return false;
if (!load(lib_gtk, "gtk_widget_get_visible", gtk_widget_get_visible)) return false;
if (!load(lib_gtk, "gtk_widget_set_sensitive", gtk_widget_set_sensitive)) return false;
if (!load(lib_gtk, "g_type_check_instance_cast", g_type_check_instance_cast)) return false;
if (!load(lib_gtk, "g_signal_connect_data", g_signal_connect_data)) return false;
if (!load(lib_gtk, "g_object_ref_sink", g_object_ref_sink)) return false;
if (!load(lib_gtk, "g_object_unref", g_object_unref)) return false;
DEBUG_LOG(("Library gtk functions loaded!"));
if (!gtk_init_check(0, 0)) {
gtk_init_check = nullptr;
DEBUG_LOG(("Failed to gtk_init_check(0, 0)!"));
return false;
}
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;
}
} // namespace
f_gtk_init_check gtk_init_check = nullptr;
f_gtk_menu_new gtk_menu_new = nullptr;
f_gtk_menu_get_type gtk_menu_get_type = nullptr;
f_gtk_menu_item_new_with_label gtk_menu_item_new_with_label = nullptr;
f_gtk_menu_item_set_label gtk_menu_item_set_label = nullptr;
f_gtk_menu_shell_append gtk_menu_shell_append = nullptr;
f_gtk_menu_shell_get_type gtk_menu_shell_get_type = nullptr;
f_gtk_widget_show gtk_widget_show = nullptr;
f_gtk_widget_get_toplevel gtk_widget_get_toplevel = nullptr;
f_gtk_widget_get_visible gtk_widget_get_visible = nullptr;
f_gtk_widget_set_sensitive gtk_widget_set_sensitive = nullptr;
f_g_type_check_instance_cast g_type_check_instance_cast = nullptr;
f_g_signal_connect_data g_signal_connect_data = 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_gtk_status_icon_new_from_pixbuf gtk_status_icon_new_from_pixbuf = nullptr;
f_gtk_status_icon_set_from_pixbuf gtk_status_icon_set_from_pixbuf = nullptr;
f_gtk_status_icon_set_title gtk_status_icon_set_title = nullptr;
f_gtk_status_icon_set_tooltip_text gtk_status_icon_set_tooltip_text = nullptr;
f_gtk_status_icon_set_visible gtk_status_icon_set_visible = nullptr;
f_gtk_status_icon_is_embedded gtk_status_icon_is_embedded = nullptr;
f_gtk_status_icon_get_geometry gtk_status_icon_get_geometry = nullptr;
f_gtk_status_icon_position_menu gtk_status_icon_position_menu = nullptr;
f_gtk_menu_popup gtk_menu_popup = nullptr;
f_gtk_get_current_event_time gtk_get_current_event_time = nullptr;
f_g_object_ref_sink g_object_ref_sink = nullptr;
f_g_object_unref g_object_unref = nullptr;
f_g_idle_add g_idle_add = nullptr;
f_unity_launcher_entry_set_count unity_launcher_entry_set_count = nullptr;
f_unity_launcher_entry_set_count_visible unity_launcher_entry_set_count_visible = nullptr;
f_unity_launcher_entry_get_for_desktop_id unity_launcher_entry_get_for_desktop_id = nullptr;
void start() {
DEBUG_LOG(("Loading libraries"));
bool gtkLoaded = false;
bool indicatorLoaded = false;
QLibrary lib_gtk, lib_indicator;
if (loadLibrary(lib_indicator, "appindicator3", 1)) {
if (loadLibrary(lib_gtk, "gtk-3", 0)) {
gtkLoaded = setupGtkBase(lib_gtk);
indicatorLoaded = setupAppIndicator(lib_indicator);
}
}
if (!gtkLoaded || !indicatorLoaded) {
if (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);
}
}
}
// If no appindicator, try at least load gtk.
if (!gtkLoaded && !indicatorLoaded) {
if (loadLibrary(lib_gtk, "gtk-3", 0)) {
gtkLoaded = setupGtkBase(lib_gtk);
}
if (!gtkLoaded && loadLibrary(lib_gtk, "gtk-x11-2.0", 0)) {
gtkLoaded = setupGtkBase(lib_gtk);
}
}
if (gtkLoaded) {
load(lib_gtk, "gdk_init_check", gdk_init_check);
load(lib_gtk, "gdk_pixbuf_new_from_data", gdk_pixbuf_new_from_data);
load(lib_gtk, "gtk_status_icon_new_from_pixbuf", gtk_status_icon_new_from_pixbuf);
load(lib_gtk, "gtk_status_icon_set_from_pixbuf", gtk_status_icon_set_from_pixbuf);
load(lib_gtk, "gtk_status_icon_set_title", gtk_status_icon_set_title);
load(lib_gtk, "gtk_status_icon_set_tooltip_text", gtk_status_icon_set_tooltip_text);
load(lib_gtk, "gtk_status_icon_set_visible", gtk_status_icon_set_visible);
load(lib_gtk, "gtk_status_icon_is_embedded", gtk_status_icon_is_embedded);
load(lib_gtk, "gtk_status_icon_get_geometry", gtk_status_icon_get_geometry);
load(lib_gtk, "gtk_status_icon_position_menu", gtk_status_icon_position_menu);
load(lib_gtk, "gtk_menu_popup", gtk_menu_popup);
load(lib_gtk, "gtk_get_current_event_time", gtk_get_current_event_time);
load(lib_gtk, "g_idle_add", g_idle_add);
} else {
LOG(("Could not load gtk-x11-2.0!"));
}
if (QString(getenv("XDG_CURRENT_DESKTOP")).toLower() == qstr("unity")) {
QLibrary lib_unity(qstr("unity"), 9, 0);
loadLibrary(lib_unity, "unity", 9);
load(lib_unity, "unity_launcher_entry_get_for_desktop_id", unity_launcher_entry_get_for_desktop_id);
load(lib_unity, "unity_launcher_entry_set_count", unity_launcher_entry_set_count);
load(lib_unity, "unity_launcher_entry_set_count_visible", unity_launcher_entry_set_count_visible);
}
}
} // namespace Libs
} // namespace Platform

View File

@ -0,0 +1,174 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free 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.
It 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.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
extern "C" {
#undef signals
#include <libappindicator/app-indicator.h>
#include <gtk/gtk.h>
#define signals public
} // extern "C"
#include <unity/unity/unity.h>
namespace Platform {
namespace Libs {
void start();
template <typename Function>
bool load(QLibrary &lib, const char *name, Function &func) {
func = nullptr;
if (!lib.isLoaded()) {
return false;
}
func = reinterpret_cast<Function>(lib.resolve(name));
if (func) {
return true;
}
LOG(("Error: failed to load '%1' function!").arg(name));
return false;
}
typedef gboolean (*f_gtk_init_check)(int *argc, char ***argv);
extern f_gtk_init_check gtk_init_check;
typedef GtkWidget* (*f_gtk_menu_new)(void);
extern f_gtk_menu_new gtk_menu_new;
typedef GType (*f_gtk_menu_get_type)(void) G_GNUC_CONST;
extern f_gtk_menu_get_type gtk_menu_get_type;
typedef GtkWidget* (*f_gtk_menu_item_new_with_label)(const gchar *label);
extern f_gtk_menu_item_new_with_label gtk_menu_item_new_with_label;
typedef void (*f_gtk_menu_item_set_label)(GtkMenuItem *menu_item, const gchar *label);
extern f_gtk_menu_item_set_label gtk_menu_item_set_label;
typedef void (*f_gtk_menu_shell_append)(GtkMenuShell *menu_shell, GtkWidget *child);
extern f_gtk_menu_shell_append gtk_menu_shell_append;
typedef GType (*f_gtk_menu_shell_get_type)(void) G_GNUC_CONST;
extern f_gtk_menu_shell_get_type gtk_menu_shell_get_type;
typedef void (*f_gtk_widget_show)(GtkWidget *widget);
extern f_gtk_widget_show gtk_widget_show;
typedef GtkWidget* (*f_gtk_widget_get_toplevel)(GtkWidget *widget);
extern f_gtk_widget_get_toplevel gtk_widget_get_toplevel;
typedef gboolean (*f_gtk_widget_get_visible)(GtkWidget *widget);
extern f_gtk_widget_get_visible gtk_widget_get_visible;
typedef void (*f_gtk_widget_set_sensitive)(GtkWidget *widget, gboolean sensitive);
extern f_gtk_widget_set_sensitive gtk_widget_set_sensitive;
typedef GTypeInstance* (*f_g_type_check_instance_cast)(GTypeInstance *instance, GType iface_type);
extern f_g_type_check_instance_cast g_type_check_instance_cast;
template <typename Result, typename Object>
inline Result *g_type_cic_helper(Object *instance, GType iface_type) {
return reinterpret_cast<Result*>(g_type_check_instance_cast(reinterpret_cast<GTypeInstance*>(instance), iface_type));
}
template <typename Object>
inline GtkMenu *gtk_menu_cast(Object *obj) {
return g_type_cic_helper<GtkMenu, Object>(obj, gtk_menu_get_type());
}
template <typename Object>
inline GtkMenuShell *gtk_menu_shell_cast(Object *obj) {
return g_type_cic_helper<GtkMenuShell, Object>(obj, gtk_menu_get_type());
}
typedef gulong (*f_g_signal_connect_data)(gpointer instance, const gchar *detailed_signal, GCallback c_handler, gpointer data, GClosureNotify destroy_data, GConnectFlags connect_flags);
extern f_g_signal_connect_data g_signal_connect_data;
inline gulong g_signal_connect_helper(gpointer instance, const gchar *detailed_signal, GCallback c_handler, gpointer data) {
return g_signal_connect_data(instance, detailed_signal, c_handler, data, NULL, (GConnectFlags)0);
}
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;
typedef GdkPixbuf* (*f_gdk_pixbuf_new_from_data)(const guchar *data, GdkColorspace colorspace, gboolean has_alpha, int bits_per_sample, int width, int height, int rowstride, GdkPixbufDestroyNotify destroy_fn, gpointer destroy_fn_data);
extern f_gdk_pixbuf_new_from_data gdk_pixbuf_new_from_data;
typedef GtkStatusIcon* (*f_gtk_status_icon_new_from_pixbuf)(GdkPixbuf *pixbuf);
extern f_gtk_status_icon_new_from_pixbuf gtk_status_icon_new_from_pixbuf;
typedef void (*f_gtk_status_icon_set_from_pixbuf)(GtkStatusIcon *status_icon, GdkPixbuf *pixbuf);
extern f_gtk_status_icon_set_from_pixbuf gtk_status_icon_set_from_pixbuf;
typedef void (*f_gtk_status_icon_set_title)(GtkStatusIcon *status_icon, const gchar *title);
extern f_gtk_status_icon_set_title gtk_status_icon_set_title;
typedef void (*f_gtk_status_icon_set_tooltip_text)(GtkStatusIcon *status_icon, const gchar *title);
extern f_gtk_status_icon_set_tooltip_text gtk_status_icon_set_tooltip_text;
typedef void (*f_gtk_status_icon_set_visible)(GtkStatusIcon *status_icon, gboolean visible);
extern f_gtk_status_icon_set_visible gtk_status_icon_set_visible;
typedef gboolean (*f_gtk_status_icon_is_embedded)(GtkStatusIcon *status_icon);
extern f_gtk_status_icon_is_embedded gtk_status_icon_is_embedded;
typedef gboolean (*f_gtk_status_icon_get_geometry)(GtkStatusIcon *status_icon, GdkScreen **screen, GdkRectangle *area, GtkOrientation *orientation);
extern f_gtk_status_icon_get_geometry gtk_status_icon_get_geometry;
typedef void (*f_gtk_status_icon_position_menu)(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data);
extern f_gtk_status_icon_position_menu gtk_status_icon_position_menu;
typedef void (*f_gtk_menu_popup)(GtkMenu *menu, GtkWidget *parent_menu_shell, GtkWidget *parent_menu_item, GtkMenuPositionFunc func, gpointer data, guint button, guint32 activate_time);
extern f_gtk_menu_popup gtk_menu_popup;
typedef guint32 (*f_gtk_get_current_event_time)(void);
extern f_gtk_get_current_event_time gtk_get_current_event_time;
typedef gpointer (*f_g_object_ref_sink)(gpointer object);
extern f_g_object_ref_sink g_object_ref_sink;
typedef void (*f_g_object_unref)(gpointer object);
extern f_g_object_unref g_object_unref;
typedef guint (*f_g_idle_add)(GSourceFunc function, gpointer data);
extern f_g_idle_add g_idle_add;
typedef void (*f_unity_launcher_entry_set_count)(UnityLauncherEntry* self, gint64 value);
extern f_unity_launcher_entry_set_count unity_launcher_entry_set_count;
typedef void (*f_unity_launcher_entry_set_count_visible)(UnityLauncherEntry* self, gboolean value);
extern f_unity_launcher_entry_set_count_visible unity_launcher_entry_set_count_visible;
typedef UnityLauncherEntry* (*f_unity_launcher_entry_get_for_desktop_id)(const gchar* desktop_id);
extern f_unity_launcher_entry_get_for_desktop_id unity_launcher_entry_get_for_desktop_id;
} // namespace Libs
} // namespace Platform

View File

@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "stdafx.h"
#include "platform/linux/main_window_linux.h"
#include "platform/linux/linux_libs.h"
#include "mainwindow.h"
#include "application.h"
#include "lang.h"
@ -29,10 +30,165 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
namespace Platform {
namespace {
bool noQtTrayIcon = false, tryAppIndicator = false;
bool useGtkBase = false, useAppIndicator = false, useStatusIcon = false, trayIconChecked = false, useUnityCount = false;
AppIndicator *_trayIndicator = 0;
GtkStatusIcon *_trayIcon = 0;
GtkWidget *_trayMenu = 0;
GdkPixbuf *_trayPixbuf = 0;
QByteArray _trayPixbufData;
QList<QPair<GtkWidget*, QObject*> > _trayItems;
int32 _trayIconSize = 22;
bool _trayIconMuted = true;
int32 _trayIconCount = 0;
QImage _trayIconImageBack, _trayIconImage;
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 (App::wnd()) App::wnd()->psUpdateCounter();
return FALSE;
}
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
#define QT_RED 3
#define QT_GREEN 2
#define QT_BLUE 1
#define QT_ALPHA 0
#else
#define QT_RED 0
#define QT_GREEN 1
#define QT_BLUE 2
#define QT_ALPHA 3
#endif
#define GTK_RED 2
#define GTK_GREEN 1
#define GTK_BLUE 0
#define GTK_ALPHA 3
QImage _trayIconImageGen() {
int32 counter = App::histories().unreadBadge(), counterSlice = (counter >= 1000) ? (1000 + (counter % 100)) : counter;
bool muted = App::histories().unreadOnlyMuted();
if (_trayIconImage.isNull() || _trayIconImage.width() != _trayIconSize || muted != _trayIconMuted || counterSlice != _trayIconCount) {
if (_trayIconImageBack.isNull() || _trayIconImageBack.width() != _trayIconSize) {
_trayIconImageBack = App::wnd()->iconLarge().scaled(_trayIconSize, _trayIconSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
_trayIconImageBack = _trayIconImageBack.convertToFormat(QImage::Format_ARGB32);
int w = _trayIconImageBack.width(), h = _trayIconImageBack.height(), perline = _trayIconImageBack.bytesPerLine();
uchar *bytes = _trayIconImageBack.bits();
for (int32 y = 0; y < h; ++y) {
for (int32 x = 0; x < w; ++x) {
int32 srcoff = y * perline + x * 4;
bytes[srcoff + QT_RED ] = qMax(bytes[srcoff + QT_RED ], uchar(224));
bytes[srcoff + QT_GREEN] = qMax(bytes[srcoff + QT_GREEN], uchar(165));
bytes[srcoff + QT_BLUE ] = qMax(bytes[srcoff + QT_BLUE ], uchar(44));
}
}
}
_trayIconImage = _trayIconImageBack;
if (counter > 0) {
QPainter p(&_trayIconImage);
int32 layerSize = -16;
if (_trayIconSize >= 48) {
layerSize = -32;
} else if (_trayIconSize >= 36) {
layerSize = -24;
} else if (_trayIconSize >= 32) {
layerSize = -20;
}
QImage layer = App::wnd()->iconWithCounter(layerSize, counter, (muted ? st::counterMuteBG : st::counterBG), false);
p.drawImage(_trayIconImage.width() - layer.width() - 1, _trayIconImage.height() - layer.height() - 1, layer);
}
}
return _trayIconImage;
}
QString _trayIconImageFile() {
int32 counter = App::histories().unreadBadge(), counterSlice = (counter >= 1000) ? (1000 + (counter % 100)) : counter;
bool muted = App::histories().unreadOnlyMuted();
QString name = cWorkingDir() + qsl("tdata/ticons/ico%1_%2_%3.png").arg(muted ? "mute" : "").arg(_trayIconSize).arg(counterSlice);
QFileInfo info(name);
if (info.exists()) return name;
QImage img = _trayIconImageGen();
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();
}
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];
}
}
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);
}
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 gboolean _trayIconCheck(gpointer/* pIn*/) {
if (useStatusIcon && !trayIconChecked) {
if (Libs::gtk_status_icon_is_embedded(_trayIcon)) {
trayIconChecked = true;
cSetSupportTray(true);
if (App::wnd()) {
App::wnd()->psUpdateWorkmode();
App::wnd()->psUpdateCounter();
App::wnd()->updateTrayMenu();
}
}
}
return FALSE;
}
UnityLauncherEntry *_psUnityLauncherEntry = nullptr;
} // namespace
MainWindow::MainWindow() : QMainWindow(),
posInited(false), trayIcon(0), trayIconMenu(0), icon256(qsl(":/gui/art/icon256.png")), iconbig256(icon256), wndIcon(QIcon::fromTheme("telegram", QIcon(QPixmap::fromImage(icon256, Qt::ColorOnly)))), _psCheckStatusIconLeft(100), _psLastIndicatorUpdate(0) {
MainWindow::MainWindow()
: icon256(qsl(":/gui/art/icon256.png"))
, iconbig256(icon256)
, wndIcon(QIcon::fromTheme("telegram", QIcon(QPixmap::fromImage(icon256, Qt::ColorOnly)))) {
connect(&_psCheckStatusIconTimer, SIGNAL(timeout()), this, SLOT(psStatusIconCheck()));
_psCheckStatusIconTimer.setSingleShot(false);
@ -64,11 +220,11 @@ void MainWindow::psTrayMenuUpdated() {
if (_trayItems.isEmpty()) {
DEBUG_LOG(("Creating tray menu!"));
for (int32 i = 0, l = actions.size(); i != l; ++i) {
GtkWidget *item = ps_gtk_menu_item_new_with_label(actions.at(i)->text().toUtf8());
ps_gtk_menu_shell_append(PS_GTK_MENU_SHELL(_trayMenu), item);
ps_g_signal_connect(item, "activate", G_CALLBACK(_trayMenuCallback), this);
ps_gtk_widget_show(item);
ps_gtk_widget_set_sensitive(item, actions.at(i)->isEnabled());
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)));
}
@ -76,8 +232,8 @@ void MainWindow::psTrayMenuUpdated() {
DEBUG_LOG(("Updating tray menu!"));
for (int32 i = 0, l = actions.size(); i != l; ++i) {
if (i < _trayItems.size()) {
ps_gtk_menu_item_set_label(reinterpret_cast<GtkMenuItem*>(_trayItems.at(i).first), actions.at(i)->text().toUtf8());
ps_gtk_widget_set_sensitive(_trayItems.at(i).first, actions.at(i)->isEnabled());
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());
}
}
}
@ -113,9 +269,9 @@ void MainWindow::psUpdateWorkmode() {
if (cWorkMode() == dbiwmWindowOnly) {
if (noQtTrayIcon) {
if (useAppIndicator) {
ps_app_indicator_set_status(_trayIndicator, APP_INDICATOR_STATUS_PASSIVE);
Libs::app_indicator_set_status(_trayIndicator, APP_INDICATOR_STATUS_PASSIVE);
} else if (useStatusIcon) {
ps_gtk_status_icon_set_visible(_trayIcon, false);
Libs::gtk_status_icon_set_visible(_trayIcon, false);
}
} else {
if (trayIcon) {
@ -127,9 +283,9 @@ void MainWindow::psUpdateWorkmode() {
} else {
if (noQtTrayIcon) {
if (useAppIndicator) {
ps_app_indicator_set_status(_trayIndicator, APP_INDICATOR_STATUS_ACTIVE);
Libs::app_indicator_set_status(_trayIndicator, APP_INDICATOR_STATUS_ACTIVE);
} else if (useStatusIcon) {
ps_gtk_status_icon_set_visible(_trayIcon, true);
Libs::gtk_status_icon_set_visible(_trayIcon, true);
}
} else {
psSetupTrayIcon();
@ -144,7 +300,7 @@ void MainWindow::psUpdateIndicator() {
if (f.exists()) {
QByteArray path = QFile::encodeName(f.absoluteFilePath()), name = QFile::encodeName(f.fileName());
name = name.mid(0, name.size() - 4);
ps_app_indicator_set_icon_full(_trayIndicator, path.constData(), name);
Libs::app_indicator_set_icon_full(_trayIndicator, path.constData(), name);
} else {
useAppIndicator = false;
}
@ -158,10 +314,10 @@ void MainWindow::psUpdateCounter() {
setWindowTitle((counter > 0) ? qsl("Telegram (%1)").arg(counter) : qsl("Telegram"));
if (_psUnityLauncherEntry) {
if (counter > 0) {
ps_unity_launcher_entry_set_count(_psUnityLauncherEntry, (counter > 9999) ? 9999 : counter);
ps_unity_launcher_entry_set_count_visible(_psUnityLauncherEntry, TRUE);
Libs::unity_launcher_entry_set_count(_psUnityLauncherEntry, (counter > 9999) ? 9999 : counter);
Libs::unity_launcher_entry_set_count_visible(_psUnityLauncherEntry, TRUE);
} else {
ps_unity_launcher_entry_set_count_visible(_psUnityLauncherEntry, FALSE);
Libs::unity_launcher_entry_set_count_visible(_psUnityLauncherEntry, FALSE);
}
}
@ -174,7 +330,7 @@ void MainWindow::psUpdateCounter() {
}
} else if (useStatusIcon && trayIconChecked) {
loadPixbuf(_trayIconImageGen());
ps_gtk_status_icon_set_from_pixbuf(_trayIcon, _trayPixbuf);
Libs::gtk_status_icon_set_from_pixbuf(_trayIcon, _trayPixbuf);
}
} else if (trayIcon) {
int32 counter = App::histories().unreadBadge();
@ -188,6 +344,65 @@ void MainWindow::psUpdateCounter() {
}
}
void MainWindow::LibsLoaded() {
QString cdesktop = QString(getenv("XDG_CURRENT_DESKTOP")).toLower();
noQtTrayIcon = (cdesktop == qstr("pantheon")) || (cdesktop == qstr("gnome"));
tryAppIndicator = (cdesktop == qstr("xfce"));
if (noQtTrayIcon) cSetSupportTray(false);
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);
}
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_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!"));
}
useUnityCount = (Libs::unity_launcher_entry_get_for_desktop_id != nullptr)
&& (Libs::unity_launcher_entry_set_count != nullptr)
&& (Libs::unity_launcher_entry_set_count_visible != nullptr);
if (useUnityCount) {
DEBUG_LOG(("Unity count api loaded!"));
}
}
void MainWindow::psUpdateDelegate() {
}
@ -228,10 +443,6 @@ void MainWindow::psInitSize() {
void MainWindow::psInitFrameless() {
psUpdatedPositionTimer.setSingleShot(true);
connect(&psUpdatedPositionTimer, SIGNAL(timeout()), this, SLOT(psSavePosition()));
if (frameless) {
//setWindowFlags(Qt::FramelessWindowHint);
}
}
void MainWindow::psSavePosition(Qt::WindowState state) {
@ -289,13 +500,13 @@ void MainWindow::psCreateTrayIcon() {
if (useAppIndicator) {
DEBUG_LOG(("Trying to create AppIndicator"));
_trayMenu = ps_gtk_menu_new();
_trayMenu = Libs::gtk_menu_new();
if (_trayMenu) {
DEBUG_LOG(("Created gtk menu for appindicator!"));
QFileInfo f(_trayIconImageFile());
if (f.exists()) {
QByteArray path = QFile::encodeName(f.absoluteFilePath());
_trayIndicator = ps_app_indicator_new("Telegram Desktop", path.constData(), APP_INDICATOR_CATEGORY_APPLICATION_STATUS);
_trayIndicator = Libs::app_indicator_new("Telegram Desktop", path.constData(), APP_INDICATOR_CATEGORY_APPLICATION_STATUS);
if (_trayIndicator) {
DEBUG_LOG(("Created appindicator!"));
} else {
@ -309,8 +520,8 @@ void MainWindow::psCreateTrayIcon() {
DEBUG_LOG(("Failed to gtk_menu_new()!"));
}
if (_trayMenu && _trayIndicator) {
ps_app_indicator_set_status(_trayIndicator, APP_INDICATOR_STATUS_ACTIVE);
ps_app_indicator_set_menu(_trayIndicator, PS_GTK_MENU(_trayMenu));
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!"));
@ -318,19 +529,19 @@ void MainWindow::psCreateTrayIcon() {
}
}
if (useStatusIcon) {
if (ps_gdk_init_check(0, 0)) {
if (!_trayMenu) _trayMenu = ps_gtk_menu_new();
if (Libs::gdk_init_check(0, 0)) {
if (!_trayMenu) _trayMenu = Libs::gtk_menu_new();
if (_trayMenu) {
loadPixbuf(_trayIconImageGen());
_trayIcon = ps_gtk_status_icon_new_from_pixbuf(_trayPixbuf);
_trayIcon = Libs::gtk_status_icon_new_from_pixbuf(_trayPixbuf);
if (_trayIcon) {
ps_g_signal_connect(_trayIcon, "popup-menu", GCallback(_trayIconPopup), _trayMenu);
ps_g_signal_connect(_trayIcon, "activate", GCallback(_trayIconActivate), _trayMenu);
ps_g_signal_connect(_trayIcon, "size-changed", GCallback(_trayIconResized), _trayMenu);
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);
ps_gtk_status_icon_set_title(_trayIcon, "Telegram Desktop");
ps_gtk_status_icon_set_tooltip_text(_trayIcon, "Telegram Desktop");
ps_gtk_status_icon_set_visible(_trayIcon, true);
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;
}
@ -343,14 +554,14 @@ void MainWindow::psCreateTrayIcon() {
}
if (!useStatusIcon && !useAppIndicator) {
if (_trayMenu) {
ps_g_object_ref_sink(_trayMenu);
ps_g_object_unref(_trayMenu);
Libs::g_object_ref_sink(_trayMenu);
Libs::g_object_unref(_trayMenu);
_trayMenu = 0;
}
}
cSetSupportTray(useAppIndicator);
if (useStatusIcon) {
ps_g_idle_add((GSourceFunc)_trayIconCheck, 0);
Libs::g_idle_add((GSourceFunc)_trayIconCheck, 0);
_psCheckStatusIconTimer.start(100);
} else {
psUpdateWorkmode();
@ -361,11 +572,11 @@ void MainWindow::psFirstShow() {
psCreateTrayIcon();
if (useUnityCount) {
_psUnityLauncherEntry = ps_unity_launcher_entry_get_for_desktop_id("telegramdesktop.desktop");
_psUnityLauncherEntry = Libs::unity_launcher_entry_get_for_desktop_id("telegramdesktop.desktop");
if (_psUnityLauncherEntry) {
LOG(("Found Unity Launcher entry telegramdesktop.desktop!"));
} else {
_psUnityLauncherEntry = ps_unity_launcher_entry_get_for_desktop_id("Telegram.desktop");
_psUnityLauncherEntry = Libs::unity_launcher_entry_get_for_desktop_id("Telegram.desktop");
if (_psUnityLauncherEntry) {
LOG(("Found Unity Launcher entry Telegram.desktop!"));
} else {
@ -376,8 +587,6 @@ void MainWindow::psFirstShow() {
LOG(("Not using Unity Launcher count."));
}
finished = false;
psUpdateMargins();
bool showShadows = true;
@ -419,21 +628,32 @@ void MainWindow::psUpdateMargins() {
void MainWindow::psFlash() {
}
void MainWindow::psActivateNotify(NotifyWindow *w) {
}
void MainWindow::psClearNotifies(PeerId peerId) {
}
void MainWindow::psNotifyShown(NotifyWindow *w) {
}
void MainWindow::psPlatformNotify(HistoryItem *item, int32 fwdCount) {
}
MainWindow::~MainWindow() {
if (_trayIcon) {
ps_g_object_unref(_trayIcon);
_trayIcon = 0;
Libs::g_object_unref(_trayIcon);
_trayIcon = nullptr;
}
if (_trayPixbuf) {
ps_g_object_unref(_trayPixbuf);
_trayPixbuf = 0;
Libs::g_object_unref(_trayPixbuf);
_trayPixbuf = nullptr;
}
if (_trayMenu) {
ps_g_object_ref_sink(_trayMenu);
ps_g_object_unref(_trayMenu);
_trayMenu = 0;
Libs::g_object_ref_sink(_trayMenu);
Libs::g_object_unref(_trayMenu);
_trayMenu = nullptr;
}
finished = true;
}
} // namespace Platform

View File

@ -71,6 +71,8 @@ public:
virtual QImage iconWithCounter(int size, int count, style::color bg, bool smallIcon) = 0;
static void LibsLoaded();
~MainWindow();
public slots:
@ -86,9 +88,9 @@ protected:
bool psHasTrayIcon() const;
bool posInited;
QSystemTrayIcon *trayIcon;
QMenu *trayIconMenu;
bool posInited = false;
QSystemTrayIcon *trayIcon = nullptr;
QMenu *trayIconMenu = nullptr;
QImage icon256, iconbig256;
QIcon wndIcon;
@ -101,10 +103,10 @@ private:
void psCreateTrayIcon();
QTimer _psCheckStatusIconTimer;
int _psCheckStatusIconLeft;
int _psCheckStatusIconLeft = 100;
QTimer _psUpdateIndicatorTimer;
uint64 _psLastIndicatorUpdate;
uint64 _psLastIndicatorUpdate = 0;
};
} // namespace Platform

View File

@ -18,6 +18,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "stdafx.h"
#include "pspecific.h"
#include "platform/linux/linux_libs.h"
#include "lang.h"
#include "application.h"
#include "mainwidget.h"
@ -33,14 +34,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include <iostream>
extern "C" {
#undef signals
#include <libappindicator/app-indicator.h>
#include <gtk/gtk.h>
#define signals public
} // extern "C"
#include <unity/unity/unity.h>
using namespace Platform;
namespace {
QByteArray escapeShell(const QByteArray &str) {
@ -66,422 +60,6 @@ namespace {
return result;
}
bool frameless = true;
bool finished = true;
bool noQtTrayIcon = false, noTryUnity = false, tryAppIndicator = false;
bool useGtkBase = false, useAppIndicator = false, useStatusIcon = false, trayIconChecked = false, useUnityCount = false;
AppIndicator *_trayIndicator = 0;
GtkStatusIcon *_trayIcon = 0;
GtkWidget *_trayMenu = 0;
GdkPixbuf *_trayPixbuf = 0;
QByteArray _trayPixbufData;
QList<QPair<GtkWidget*, QObject*> > _trayItems;
int32 _trayIconSize = 22;
bool _trayIconMuted = true;
int32 _trayIconCount = 0;
QImage _trayIconImageBack, _trayIconImage;
typedef gboolean (*f_gtk_init_check)(int *argc, char ***argv);
f_gtk_init_check ps_gtk_init_check = 0;
typedef GtkWidget* (*f_gtk_menu_new)(void);
f_gtk_menu_new ps_gtk_menu_new = 0;
typedef GType (*f_gtk_menu_get_type)(void) G_GNUC_CONST;
f_gtk_menu_get_type ps_gtk_menu_get_type = 0;
typedef GtkWidget* (*f_gtk_menu_item_new_with_label)(const gchar *label);
f_gtk_menu_item_new_with_label ps_gtk_menu_item_new_with_label = 0;
typedef void (*f_gtk_menu_item_set_label)(GtkMenuItem *menu_item, const gchar *label);
f_gtk_menu_item_set_label ps_gtk_menu_item_set_label = 0;
typedef void (*f_gtk_menu_shell_append)(GtkMenuShell *menu_shell, GtkWidget *child);
f_gtk_menu_shell_append ps_gtk_menu_shell_append = 0;
typedef GType (*f_gtk_menu_shell_get_type)(void) G_GNUC_CONST;
f_gtk_menu_shell_get_type ps_gtk_menu_shell_get_type = 0;
typedef void (*f_gtk_widget_show)(GtkWidget *widget);
f_gtk_widget_show ps_gtk_widget_show = 0;
typedef GtkWidget* (*f_gtk_widget_get_toplevel)(GtkWidget *widget);
f_gtk_widget_get_toplevel ps_gtk_widget_get_toplevel = 0;
typedef gboolean (*f_gtk_widget_get_visible)(GtkWidget *widget);
f_gtk_widget_get_visible ps_gtk_widget_get_visible = 0;
typedef void (*f_gtk_widget_set_sensitive)(GtkWidget *widget, gboolean sensitive);
f_gtk_widget_set_sensitive ps_gtk_widget_set_sensitive = 0;
typedef GTypeInstance* (*f_g_type_check_instance_cast)(GTypeInstance *instance, GType iface_type);
f_g_type_check_instance_cast ps_g_type_check_instance_cast = 0;
#define _PS_G_TYPE_CIC(ip, gt, ct) ((ct*)ps_g_type_check_instance_cast((GTypeInstance*) ip, gt))
#define PS_G_TYPE_CHECK_INSTANCE_CAST(instance, g_type, c_type) (_PS_G_TYPE_CIC((instance), (g_type), c_type))
#define PS_GTK_TYPE_MENU (ps_gtk_menu_get_type())
#define PS_GTK_MENU(obj) (PS_G_TYPE_CHECK_INSTANCE_CAST((obj), PS_GTK_TYPE_MENU, GtkMenu))
#define PS_GTK_TYPE_MENU_SHELL (ps_gtk_menu_shell_get_type())
#define PS_GTK_MENU_SHELL(obj) (PS_G_TYPE_CHECK_INSTANCE_CAST((obj), PS_GTK_TYPE_MENU_SHELL, GtkMenuShell))
typedef gulong (*f_g_signal_connect_data)(gpointer instance, const gchar *detailed_signal, GCallback c_handler, gpointer data, GClosureNotify destroy_data, GConnectFlags connect_flags);
f_g_signal_connect_data ps_g_signal_connect_data = 0;
#define ps_g_signal_connect(instance, detailed_signal, c_handler, data) ps_g_signal_connect_data((instance), (detailed_signal), (c_handler), (data), NULL, (GConnectFlags)0)
typedef AppIndicator* (*f_app_indicator_new)(const gchar *id, const gchar *icon_name, AppIndicatorCategory category);
f_app_indicator_new ps_app_indicator_new = 0;
typedef void (*f_app_indicator_set_status)(AppIndicator *self, AppIndicatorStatus status);
f_app_indicator_set_status ps_app_indicator_set_status = 0;
typedef void (*f_app_indicator_set_menu)(AppIndicator *self, GtkMenu *menu);
f_app_indicator_set_menu ps_app_indicator_set_menu = 0;
typedef void (*f_app_indicator_set_icon_full)(AppIndicator *self, const gchar *icon_name, const gchar *icon_desc);
f_app_indicator_set_icon_full ps_app_indicator_set_icon_full = 0;
typedef gboolean (*f_gdk_init_check)(gint *argc, gchar ***argv);
f_gdk_init_check ps_gdk_init_check = 0;
typedef GdkPixbuf* (*f_gdk_pixbuf_new_from_data)(const guchar *data, GdkColorspace colorspace, gboolean has_alpha, int bits_per_sample, int width, int height, int rowstride, GdkPixbufDestroyNotify destroy_fn, gpointer destroy_fn_data);
f_gdk_pixbuf_new_from_data ps_gdk_pixbuf_new_from_data = 0;
typedef GtkStatusIcon* (*f_gtk_status_icon_new_from_pixbuf)(GdkPixbuf *pixbuf);
f_gtk_status_icon_new_from_pixbuf ps_gtk_status_icon_new_from_pixbuf = 0;
typedef void (*f_gtk_status_icon_set_from_pixbuf)(GtkStatusIcon *status_icon, GdkPixbuf *pixbuf);
f_gtk_status_icon_set_from_pixbuf ps_gtk_status_icon_set_from_pixbuf = 0;
typedef void (*f_gtk_status_icon_set_title)(GtkStatusIcon *status_icon, const gchar *title);
f_gtk_status_icon_set_title ps_gtk_status_icon_set_title = 0;
typedef void (*f_gtk_status_icon_set_tooltip_text)(GtkStatusIcon *status_icon, const gchar *title);
f_gtk_status_icon_set_tooltip_text ps_gtk_status_icon_set_tooltip_text = 0;
typedef void (*f_gtk_status_icon_set_visible)(GtkStatusIcon *status_icon, gboolean visible);
f_gtk_status_icon_set_visible ps_gtk_status_icon_set_visible = 0;
typedef gboolean (*f_gtk_status_icon_is_embedded)(GtkStatusIcon *status_icon);
f_gtk_status_icon_is_embedded ps_gtk_status_icon_is_embedded = 0;
typedef gboolean (*f_gtk_status_icon_get_geometry)(GtkStatusIcon *status_icon, GdkScreen **screen, GdkRectangle *area, GtkOrientation *orientation);
f_gtk_status_icon_get_geometry ps_gtk_status_icon_get_geometry = 0;
typedef void (*f_gtk_status_icon_position_menu)(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data);
f_gtk_status_icon_position_menu ps_gtk_status_icon_position_menu = 0;
typedef void (*f_gtk_menu_popup)(GtkMenu *menu, GtkWidget *parent_menu_shell, GtkWidget *parent_menu_item, GtkMenuPositionFunc func, gpointer data, guint button, guint32 activate_time);
f_gtk_menu_popup ps_gtk_menu_popup = 0;
typedef guint32 (*f_gtk_get_current_event_time)(void);
f_gtk_get_current_event_time ps_gtk_get_current_event_time = 0;
typedef gpointer (*f_g_object_ref_sink)(gpointer object);
f_g_object_ref_sink ps_g_object_ref_sink = 0;
typedef void (*f_g_object_unref)(gpointer object);
f_g_object_unref ps_g_object_unref = 0;
typedef guint (*f_g_idle_add)(GSourceFunc function, gpointer data);
f_g_idle_add ps_g_idle_add = 0;
typedef void (*f_unity_launcher_entry_set_count)(UnityLauncherEntry* self, gint64 value);
f_unity_launcher_entry_set_count ps_unity_launcher_entry_set_count = 0;
typedef void (*f_unity_launcher_entry_set_count_visible)(UnityLauncherEntry* self, gboolean value);
f_unity_launcher_entry_set_count_visible ps_unity_launcher_entry_set_count_visible = 0;
typedef UnityLauncherEntry* (*f_unity_launcher_entry_get_for_desktop_id)(const gchar* desktop_id);
f_unity_launcher_entry_get_for_desktop_id ps_unity_launcher_entry_get_for_desktop_id = 0;
template <typename TFunction>
bool loadFunction(QLibrary &lib, const char *name, TFunction &func) {
if (!lib.isLoaded()) return false;
func = (TFunction)lib.resolve(name);
if (func) {
return true;
} else {
LOG(("Error: failed to load '%1' function!").arg(name));
return false;
}
}
void _trayIconPopup(GtkStatusIcon *status_icon, guint button, guint32 activate_time, gpointer popup_menu) {
ps_gtk_menu_popup(PS_GTK_MENU(popup_menu), NULL, NULL, ps_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()) {
ps_gtk_menu_popup(PS_GTK_MENU(popup_menu), NULL, NULL, ps_gtk_status_icon_position_menu, status_icon, 0, ps_gtk_get_current_event_time());
} else {
App::wnd()->showFromTray();
}
}
gboolean _trayIconResized(GtkStatusIcon *status_icon, gint size, gpointer popup_menu) {
_trayIconSize = size;
if (App::wnd()) App::wnd()->psUpdateCounter();
return FALSE;
}
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
#define QT_RED 3
#define QT_GREEN 2
#define QT_BLUE 1
#define QT_ALPHA 0
#else
#define QT_RED 0
#define QT_GREEN 1
#define QT_BLUE 2
#define QT_ALPHA 3
#endif
#define GTK_RED 2
#define GTK_GREEN 1
#define GTK_BLUE 0
#define GTK_ALPHA 3
QImage _trayIconImageGen() {
int32 counter = App::histories().unreadBadge(), counterSlice = (counter >= 1000) ? (1000 + (counter % 100)) : counter;
bool muted = App::histories().unreadOnlyMuted();
if (_trayIconImage.isNull() || _trayIconImage.width() != _trayIconSize || muted != _trayIconMuted || counterSlice != _trayIconCount) {
if (_trayIconImageBack.isNull() || _trayIconImageBack.width() != _trayIconSize) {
_trayIconImageBack = App::wnd()->iconLarge().scaled(_trayIconSize, _trayIconSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
_trayIconImageBack = _trayIconImageBack.convertToFormat(QImage::Format_ARGB32);
int w = _trayIconImageBack.width(), h = _trayIconImageBack.height(), perline = _trayIconImageBack.bytesPerLine();
uchar *bytes = _trayIconImageBack.bits();
for (int32 y = 0; y < h; ++y) {
for (int32 x = 0; x < w; ++x) {
int32 srcoff = y * perline + x * 4;
bytes[srcoff + QT_RED ] = qMax(bytes[srcoff + QT_RED ], uchar(224));
bytes[srcoff + QT_GREEN] = qMax(bytes[srcoff + QT_GREEN], uchar(165));
bytes[srcoff + QT_BLUE ] = qMax(bytes[srcoff + QT_BLUE ], uchar(44));
}
}
}
_trayIconImage = _trayIconImageBack;
if (counter > 0) {
QPainter p(&_trayIconImage);
int32 layerSize = -16;
if (_trayIconSize >= 48) {
layerSize = -32;
} else if (_trayIconSize >= 36) {
layerSize = -24;
} else if (_trayIconSize >= 32) {
layerSize = -20;
}
QImage layer = App::wnd()->iconWithCounter(layerSize, counter, (muted ? st::counterMuteBG : st::counterBG), false);
p.drawImage(_trayIconImage.width() - layer.width() - 1, _trayIconImage.height() - layer.height() - 1, layer);
}
}
return _trayIconImage;
}
QString _trayIconImageFile() {
int32 counter = App::histories().unreadBadge(), counterSlice = (counter >= 1000) ? (1000 + (counter % 100)) : counter;
bool muted = App::histories().unreadOnlyMuted();
QString name = cWorkingDir() + qsl("tdata/ticons/ico%1_%2_%3.png").arg(muted ? "mute" : "").arg(_trayIconSize).arg(counterSlice);
QFileInfo info(name);
if (info.exists()) return name;
QImage img = _trayIconImageGen();
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();
}
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];
}
}
if (_trayPixbuf) ps_g_object_unref(_trayPixbuf);
_trayPixbuf = ps_gdk_pixbuf_new_from_data(result, GDK_COLORSPACE_RGB, true, 8, w, h, w * 4, 0, 0);
}
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 gboolean _trayIconCheck(gpointer/* pIn*/) {
if (useStatusIcon && !trayIconChecked) {
if (ps_gtk_status_icon_is_embedded(_trayIcon)) {
trayIconChecked = true;
cSetSupportTray(true);
if (App::wnd()) {
App::wnd()->psUpdateWorkmode();
App::wnd()->psUpdateCounter();
App::wnd()->updateTrayMenu();
}
}
}
return FALSE;
}
bool loadLibrary(QLibrary &lib, const char *name, int version) {
DEBUG_LOG(("Loading '%1' with version %2...").arg(QLatin1String(name)).arg(version));
lib.setFileNameAndVersion(QLatin1String(name), version);
if (lib.load()) {
DEBUG_LOG(("Loaded '%1' with version %2!").arg(QLatin1String(name)).arg(version));
return true;
}
lib.setFileNameAndVersion(QLatin1String(name), QString());
if (lib.load()) {
DEBUG_LOG(("Loaded '%1' without version!").arg(QLatin1String(name)));
return true;
}
LOG(("Could not load '%1' with version %2 :(").arg(QLatin1String(name)).arg(version));
return false;
}
void setupGtkBase(QLibrary &lib_gtk) {
if (!loadFunction(lib_gtk, "gtk_init_check", ps_gtk_init_check)) return;
if (!loadFunction(lib_gtk, "gtk_menu_new", ps_gtk_menu_new)) return;
if (!loadFunction(lib_gtk, "gtk_menu_get_type", ps_gtk_menu_get_type)) return;
if (!loadFunction(lib_gtk, "gtk_menu_item_new_with_label", ps_gtk_menu_item_new_with_label)) return;
if (!loadFunction(lib_gtk, "gtk_menu_item_set_label", ps_gtk_menu_item_set_label)) return;
if (!loadFunction(lib_gtk, "gtk_menu_shell_append", ps_gtk_menu_shell_append)) return;
if (!loadFunction(lib_gtk, "gtk_menu_shell_get_type", ps_gtk_menu_shell_get_type)) return;
if (!loadFunction(lib_gtk, "gtk_widget_show", ps_gtk_widget_show)) return;
if (!loadFunction(lib_gtk, "gtk_widget_get_toplevel", ps_gtk_widget_get_toplevel)) return;
if (!loadFunction(lib_gtk, "gtk_widget_get_visible", ps_gtk_widget_get_visible)) return;
if (!loadFunction(lib_gtk, "gtk_widget_set_sensitive", ps_gtk_widget_set_sensitive)) return;
if (!loadFunction(lib_gtk, "g_type_check_instance_cast", ps_g_type_check_instance_cast)) return;
if (!loadFunction(lib_gtk, "g_signal_connect_data", ps_g_signal_connect_data)) return;
if (!loadFunction(lib_gtk, "g_object_ref_sink", ps_g_object_ref_sink)) return;
if (!loadFunction(lib_gtk, "g_object_unref", ps_g_object_unref)) return;
DEBUG_LOG(("Library gtk functions loaded!"));
if (ps_gtk_init_check(0, 0)) {
DEBUG_LOG(("Checked gtk with gtk_init_check!"));
useGtkBase = true;
} else {
DEBUG_LOG(("Failed to gtk_init_check(0, 0)!"));
}
}
void setupAppIndicator(QLibrary &lib_indicator) {
if (!loadFunction(lib_indicator, "app_indicator_new", ps_app_indicator_new)) return;
if (!loadFunction(lib_indicator, "app_indicator_set_status", ps_app_indicator_set_status)) return;
if (!loadFunction(lib_indicator, "app_indicator_set_menu", ps_app_indicator_set_menu)) return;
if (!loadFunction(lib_indicator, "app_indicator_set_icon_full", ps_app_indicator_set_icon_full)) return;
useAppIndicator = true;
DEBUG_LOG(("Library appindicator functions loaded!"));
}
void setupGtk() {
QLibrary lib_gtk, lib_indicator;
if (!noQtTrayIcon && !tryAppIndicator) {
if (!noTryUnity) {
if (loadLibrary(lib_gtk, "gtk-3", 0)) {
setupGtkBase(lib_gtk);
}
if (!useGtkBase) {
if (loadLibrary(lib_gtk, "gtk-x11-2.0", 0)) {
setupGtkBase(lib_gtk);
}
}
if (!useGtkBase) {
noTryUnity = true;
}
}
return;
}
if (loadLibrary(lib_indicator, "appindicator3", 1)) {
if (loadLibrary(lib_gtk, "gtk-3", 0)) {
setupGtkBase(lib_gtk);
setupAppIndicator(lib_indicator);
}
}
if (!useGtkBase || !useAppIndicator) {
if (loadLibrary(lib_indicator, "appindicator", 1)) {
if (loadLibrary(lib_gtk, "gtk-x11-2.0", 0)) {
useGtkBase = useAppIndicator = false;
setupGtkBase(lib_gtk);
setupAppIndicator(lib_indicator);
}
}
}
if (tryAppIndicator) {
if (useGtkBase && useAppIndicator) {
noQtTrayIcon = true;
cSetSupportTray(false);
}
return;
}
if (!useGtkBase && lib_gtk.isLoaded()) {
LOG(("Could not load appindicator, trying to load gtk..."));
setupGtkBase(lib_gtk);
}
if (!useGtkBase) {
useAppIndicator = false;
LOG(("Could not load gtk-x11-2.0!"));
return;
}
if (!loadFunction(lib_gtk, "gdk_init_check", ps_gdk_init_check)) return;
if (!loadFunction(lib_gtk, "gdk_pixbuf_new_from_data", ps_gdk_pixbuf_new_from_data)) return;
if (!loadFunction(lib_gtk, "gtk_status_icon_new_from_pixbuf", ps_gtk_status_icon_new_from_pixbuf)) return;
if (!loadFunction(lib_gtk, "gtk_status_icon_set_from_pixbuf", ps_gtk_status_icon_set_from_pixbuf)) return;
if (!loadFunction(lib_gtk, "gtk_status_icon_set_title", ps_gtk_status_icon_set_title)) return;
if (!loadFunction(lib_gtk, "gtk_status_icon_set_tooltip_text", ps_gtk_status_icon_set_tooltip_text)) return;
if (!loadFunction(lib_gtk, "gtk_status_icon_set_visible", ps_gtk_status_icon_set_visible)) return;
if (!loadFunction(lib_gtk, "gtk_status_icon_is_embedded", ps_gtk_status_icon_is_embedded)) return;
if (!loadFunction(lib_gtk, "gtk_status_icon_get_geometry", ps_gtk_status_icon_get_geometry)) return;
if (!loadFunction(lib_gtk, "gtk_status_icon_position_menu", ps_gtk_status_icon_position_menu)) return;
if (!loadFunction(lib_gtk, "gtk_menu_popup", ps_gtk_menu_popup)) return;
if (!loadFunction(lib_gtk, "gtk_get_current_event_time", ps_gtk_get_current_event_time)) return;
if (!loadFunction(lib_gtk, "g_idle_add", ps_g_idle_add)) return;
useStatusIcon = true;
DEBUG_LOG(("Status icon api loaded!"));
}
void setupUnity() {
if (noTryUnity) return;
QLibrary lib_unity(qstr("unity"), 9, 0);
if (!loadLibrary(lib_unity, "unity", 9)) return;
if (!loadFunction(lib_unity, "unity_launcher_entry_get_for_desktop_id", ps_unity_launcher_entry_get_for_desktop_id)) return;
if (!loadFunction(lib_unity, "unity_launcher_entry_set_count", ps_unity_launcher_entry_set_count)) return;
if (!loadFunction(lib_unity, "unity_launcher_entry_set_count_visible", ps_unity_launcher_entry_set_count_visible)) return;
useUnityCount = true;
DEBUG_LOG(("Unity count api loaded!"));
}
class _PsEventFilter : public QAbstractNativeEventFilter {
public:
_PsEventFilter() {
@ -495,8 +73,6 @@ namespace {
}
};
_PsEventFilter *_psEventFilter = 0;
UnityLauncherEntry *_psUnityLauncherEntry = 0;
};
namespace {
@ -521,18 +97,6 @@ void psBringToBack(QWidget *w) {
w->hide();
}
void PsMainWindow::psActivateNotify(NotifyWindow *w) {
}
void PsMainWindow::psClearNotifies(PeerId peerId) {
}
void PsMainWindow::psNotifyShown(NotifyWindow *w) {
}
void PsMainWindow::psPlatformNotify(HistoryItem *item, int32 fwdCount) {
}
QAbstractNativeEventFilter *psNativeEventFilter() {
delete _psEventFilter;
_psEventFilter = new _PsEventFilter();
@ -842,16 +406,8 @@ void finish() {
namespace ThirdParty {
void start() {
QString cdesktop = QString(getenv("XDG_CURRENT_DESKTOP")).toLower();
noQtTrayIcon = (cdesktop == qstr("pantheon")) || (cdesktop == qstr("gnome"));
tryAppIndicator = (cdesktop == qstr("xfce"));
noTryUnity = (cdesktop != qstr("unity"));
if (noQtTrayIcon) cSetSupportTray(false);
DEBUG_LOG(("Loading libraries"));
setupGtk();
setupUnity();
Libs::start();
MainWindow::LibsLoaded();
}
void finish() {

View File

@ -80,14 +80,14 @@ TitleWidget::TitleWidget(MainWindow *window) : TWidget(window)
) {
showUpdateBtn();
}
stateChanged();
onWindowStateChanged();
connect(&_back, SIGNAL(clicked()), window, SLOT(hideSettings()));
connect(&_cancel, SIGNAL(clicked()), this, SIGNAL(hiderClicked()));
connect(&_settings, SIGNAL(clicked()), window, SLOT(showSettings()));
connect(&_contacts, SIGNAL(clicked()), this, SLOT(onContacts()));
connect(&_about, SIGNAL(clicked()), this, SLOT(onAbout()));
connect(wnd->windowHandle(), SIGNAL(windowStateChanged(Qt::WindowState)), this, SLOT(stateChanged(Qt::WindowState)));
connect(wnd->windowHandle(), SIGNAL(windowStateChanged(Qt::WindowState)), this, SLOT(onWindowStateChanged(Qt::WindowState)));
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
Sandbox::connect(SIGNAL(updateReady()), this, SLOT(showUpdateBtn()));
@ -308,7 +308,7 @@ void TitleWidget::mouseDoubleClickEvent(QMouseEvent *e) {
}
}
void TitleWidget::stateChanged(Qt::WindowState state) {
void TitleWidget::onWindowStateChanged(Qt::WindowState state) {
if (state == Qt::WindowMinimized) return;
maximizedChanged(state == Qt::WindowMaximized);
}

View File

@ -67,7 +67,7 @@ public:
public slots:
void stateChanged(Qt::WindowState state = Qt::WindowNoState);
void onWindowStateChanged(Qt::WindowState state = Qt::WindowNoState);
void showUpdateBtn();
void onContacts();
void onAbout();

View File

@ -19,8 +19,6 @@ CONFIG(release, debug|release) {
macx {
QMAKE_INFO_PLIST = ./SourceFiles/Telegram.plist
OBJECTIVE_SOURCES += ./SourceFiles/pspecific_mac_p.mm
OBJECTIVE_HEADERS += ./SourceFiles/pspecific_mac_p.h
QMAKE_LFLAGS += -framework Cocoa
}
@ -160,6 +158,8 @@ SOURCES += \
./SourceFiles/mtproto/scheme_auto.cpp \
./SourceFiles/mtproto/session.cpp \
./SourceFiles/overview/overview_layout.cpp \
./SourceFiles/platform/linux/linux_libs.cpp \
./SourceFiles/platform/linux/main_window_linux.cpp \
./SourceFiles/profile/profile_actions_widget.cpp \
./SourceFiles/profile/profile_block_widget.cpp \
./SourceFiles/profile/profile_cover_drop_area.cpp \
@ -206,6 +206,7 @@ SOURCES += \
./SourceFiles/ui/images.cpp \
./SourceFiles/ui/scrollarea.cpp \
./SourceFiles/ui/twidget.cpp \
./SourceFiles/window/main_window.cpp \
./SourceFiles/window/section_widget.cpp \
./SourceFiles/window/slide_animation.cpp \
./SourceFiles/window/top_bar_widget.cpp
@ -312,6 +313,9 @@ HEADERS += \
./SourceFiles/mtproto/scheme_auto.h \
./SourceFiles/mtproto/session.h \
./SourceFiles/overview/overview_layout.h \
./SourceFiles/platform/platform_main_window.h \
./SourceFiles/platform/linux/linux_libs.h \
./SourceFiles/platform/linux/main_window_linux.h \
./SourceFiles/profile/profile_actions_widget.h \
./SourceFiles/profile/profile_block_widget.h \
./SourceFiles/profile/profile_cover_drop_area.h \
@ -359,6 +363,7 @@ HEADERS += \
./SourceFiles/ui/images.h \
./SourceFiles/ui/scrollarea.h \
./SourceFiles/ui/twidget.h \
./SourceFiles/window/main_window.h \
./SourceFiles/window/section_memento.h \
./SourceFiles/window/section_widget.h \
./SourceFiles/window/slide_animation.h \
@ -366,16 +371,27 @@ HEADERS += \
win32 {
SOURCES += \
./SourceFiles/pspecific_win.cpp
./SourceFiles/pspecific_win.cpp \
./SourceFiles/platform/win/windows_app_user_model_id.cpp \
./SourceFiles/platform/win/windows_dlls.cpp \
./SourceFiles/platform/win/windows_event_filter.cpp \
./SourceFiles/platform/win/windows_toasts.cpp
HEADERS += \
./SourceFiles/pspecific_win.h
./SourceFiles/pspecific_win.h \
./SourceFiles/platform/win/windows_app_user_model_id.h \
./SourceFiles/platform/win/windows_dlls.h \
./SourceFiles/platform/win/windows_event_filter.h \
./SourceFiles/platform/win/windows_toasts.h
}
winrt {
SOURCES += \
./SourceFiles/pspecific_winrt.cpp
./SourceFiles/pspecific_winrt.cpp \
./SourceFiles/platform/winrt/main_window_winrt.cpp
HEADERS += \
./SourceFiles/pspecific_winrt.h
./SourceFiles/pspecific_winrt.h \
./Sourcefiles/platform/winrt/main_window_winrt.h
}
macx {
@ -383,6 +399,12 @@ SOURCES += \
./SourceFiles/pspecific_mac.cpp
HEADERS += \
./SourceFiles/pspecific_mac.h
OBJECTIVE_SOURCES += \
./SourceFiles/pspecific_mac_p.mm \
./SourceFiles/platform/mac/main_window_mac.mm
HEADERS += \
./SourceFiles/pspecific_mac_p.h \
./SourceFiles/platform/mac/main_window_mac.h
}
SOURCES += \