06d751bb0b
[GB.GTK] * OPT: Replace all dynamic event callback functions (one by object) by unique global functions. * BUG: Do nothing when setting a control font with the same font. [GB.GTK3] * OPT: Replace all dynamic event callback functions (one by object) by unique global functions. * BUG: Do nothing when setting a control font with the same font.
283 lines
6.2 KiB
C++
283 lines
6.2 KiB
C++
/***************************************************************************
|
|
|
|
gtrayicon.cpp
|
|
|
|
(c) 2004-2006 - Daniel Campos Fernández <dcamposf@gmail.com>
|
|
|
|
This program 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 2, or (at your option)
|
|
any later version.
|
|
|
|
This program 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 this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
MA 02110-1301, USA.
|
|
|
|
***************************************************************************/
|
|
|
|
#include "widgets.h"
|
|
|
|
#include <unistd.h>
|
|
#ifndef GTK3
|
|
#include "x11.h"
|
|
#endif
|
|
#include "gapplication.h"
|
|
#include "gmouse.h"
|
|
#include "gtrayicon.h"
|
|
|
|
#include "gb.form.trayicon.h"
|
|
|
|
int gTrayIcon::_visible_count = 0;
|
|
|
|
/*************************************************************************
|
|
|
|
gTrayIcon
|
|
|
|
**************************************************************************/
|
|
|
|
static gboolean cb_button_press(GtkStatusIcon *plug, GdkEventButton *event, gTrayIcon *data)
|
|
{
|
|
if (gApplication::loopLevel() > data->loopLevel()) return false;
|
|
|
|
gApplication::updateLastEventTime();
|
|
|
|
gMouse::validate();
|
|
gMouse::setMouse((int)event->x, (int)event->y, (int)event->x_root, (int)event->y_root, event->button, event->state);
|
|
if (event->type == GDK_BUTTON_PRESS)
|
|
CB_trayicon_click(data, event->button);
|
|
/*else if (event->type == GDK_2BUTTON_PRESS)
|
|
data->onDoubleClick(data);*/
|
|
gMouse::invalidate();
|
|
|
|
/*if (event->button == 3)
|
|
if (data->onMenu)
|
|
data->onMenu(data);*/
|
|
|
|
return false;
|
|
}
|
|
|
|
static gboolean cb_menu(GtkStatusIcon *plug, guint button, guint activate_time, gTrayIcon *data)
|
|
{
|
|
if (gApplication::loopLevel() > data->loopLevel()) return false;
|
|
|
|
gApplication::updateLastEventTime();
|
|
|
|
CB_trayicon_menu(data);
|
|
|
|
return false;
|
|
}
|
|
|
|
static gboolean cb_scroll(GtkStatusIcon *plug, GdkEventScroll *event, gTrayIcon *data)
|
|
{
|
|
GdkScrollDirection dir;
|
|
int dt = 0;
|
|
int ort = 0;
|
|
|
|
if (gApplication::loopLevel() > data->loopLevel()) return false;
|
|
|
|
gApplication::updateLastEventTime();
|
|
|
|
dir = event->direction;
|
|
|
|
#ifdef GTK3
|
|
if (dir == GDK_SCROLL_SMOOTH)
|
|
return false;
|
|
/*{
|
|
gdouble dx = 0, dy = 0;
|
|
gdk_event_get_scroll_deltas((GdkEvent *)event, &dx, &dy);
|
|
if (fabs(dy) > fabs(dx))
|
|
dir = (dy < 0) ? GDK_SCROLL_UP : GDK_SCROLL_DOWN;
|
|
else
|
|
dir = (dx < 0) ? GDK_SCROLL_LEFT : GDK_SCROLL_RIGHT;
|
|
}*/
|
|
#endif
|
|
|
|
switch (dir)
|
|
{
|
|
case GDK_SCROLL_UP: dt=1; ort=1; break;
|
|
case GDK_SCROLL_DOWN: dt=-1; ort=1; break;
|
|
case GDK_SCROLL_LEFT: dt=-1; ort=0; break;
|
|
case GDK_SCROLL_RIGHT: default: dt=1; ort=0; break;
|
|
}
|
|
|
|
gMouse::validate();
|
|
gMouse::setMouse((int)event->x, (int)event->y, (int)event->x_root, (int)event->y_root, 0, event->state);
|
|
gMouse::setWheel(dt, ort);
|
|
CB_trayicon_scroll(data);
|
|
gMouse::invalidate();
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
GList *gTrayIcon::trayicons = NULL;
|
|
gPicture *gTrayIcon::_default_icon = NULL;
|
|
|
|
gTrayIcon::gTrayIcon()
|
|
{
|
|
plug = NULL;
|
|
_tooltip = NULL;
|
|
_icon = NULL;
|
|
_loopLevel = 0;
|
|
|
|
trayicons = g_list_append(trayicons, (gpointer)this);
|
|
}
|
|
|
|
gTrayIcon::~gTrayIcon()
|
|
{
|
|
setVisible(false);
|
|
|
|
gPicture::assign(&_icon);
|
|
|
|
if (_tooltip)
|
|
{
|
|
g_free(_tooltip);
|
|
_tooltip = NULL;
|
|
}
|
|
|
|
trayicons = g_list_remove(trayicons, (gpointer)this);
|
|
|
|
if (!trayicons && _default_icon)
|
|
{
|
|
delete _default_icon;
|
|
_default_icon = NULL;
|
|
}
|
|
|
|
CB_trayicon_destroy(this);
|
|
}
|
|
|
|
gPicture *gTrayIcon::defaultIcon()
|
|
{
|
|
if (!_default_icon)
|
|
{
|
|
GdkPixbuf *img = gdk_pixbuf_new_from_data(_default_trayicon_data, GDK_COLORSPACE_RGB, TRUE, 8,
|
|
DEFAULT_TRAYICON_WIDTH, DEFAULT_TRAYICON_HEIGHT,
|
|
DEFAULT_TRAYICON_WIDTH * sizeof(int), NULL, NULL);
|
|
_default_icon = new gPicture(img);
|
|
}
|
|
|
|
return _default_icon;
|
|
}
|
|
|
|
void gTrayIcon::updatePicture()
|
|
{
|
|
GdkPixbuf *pixbuf;
|
|
|
|
if (!plug)
|
|
return;
|
|
|
|
if (_icon)
|
|
pixbuf = _icon->getPixbuf();
|
|
else
|
|
pixbuf = defaultIcon()->getPixbuf();
|
|
|
|
gtk_status_icon_set_from_pixbuf(plug, pixbuf);
|
|
|
|
_iconw = gdk_pixbuf_get_width(pixbuf);
|
|
_iconh = gdk_pixbuf_get_height(pixbuf);
|
|
}
|
|
|
|
void gTrayIcon::setPicture(gPicture *picture)
|
|
{
|
|
gPicture::assign(&_icon, picture);
|
|
updatePicture();
|
|
}
|
|
|
|
void gTrayIcon::updateTooltip()
|
|
{
|
|
if (!plug)
|
|
return;
|
|
|
|
gtk_status_icon_set_tooltip_text(plug, _tooltip);
|
|
}
|
|
|
|
void gTrayIcon::setTooltip(char* vl)
|
|
{
|
|
if (_tooltip)
|
|
g_free(_tooltip);
|
|
|
|
_tooltip = vl && *vl ? g_strdup(vl) : NULL;
|
|
updateTooltip();
|
|
}
|
|
|
|
bool gTrayIcon::isVisible()
|
|
{
|
|
return (bool)plug;
|
|
}
|
|
|
|
static void hide_icon(GtkStatusIcon *plug)
|
|
{
|
|
gtk_status_icon_set_visible(plug, FALSE);
|
|
g_object_unref(plug);
|
|
}
|
|
|
|
void gTrayIcon::setVisible(bool vl)
|
|
{
|
|
if (vl)
|
|
{
|
|
if (!plug)
|
|
{
|
|
_loopLevel = gApplication::loopLevel() + 1;
|
|
|
|
plug = gtk_status_icon_new();
|
|
|
|
updatePicture();
|
|
updateTooltip();
|
|
|
|
#ifdef GDK_WINDOWING_X11
|
|
#ifdef GTK3
|
|
PLATFORM.Desktop.ShowTrayIcon(plug, _iconw, _iconh);
|
|
#else
|
|
// Needed, otherwise the icon does not appear in Gnome or XFCE notification area!
|
|
XSizeHints hints;
|
|
hints.flags = PMinSize;
|
|
hints.min_width = _iconw;
|
|
hints.min_height = _iconh;
|
|
XSetWMNormalHints(gdk_x11_display_get_xdisplay(gdk_display_get_default()), gtk_status_icon_get_x11_window_id(plug), &hints);
|
|
#endif
|
|
#endif
|
|
|
|
gtk_status_icon_set_visible(plug, TRUE);
|
|
|
|
g_signal_connect(G_OBJECT(plug), "button-press-event", G_CALLBACK(cb_button_press), (gpointer)this);
|
|
g_signal_connect(G_OBJECT(plug), "popup-menu", G_CALLBACK(cb_menu), (gpointer)this);
|
|
g_signal_connect(G_OBJECT(plug), "scroll-event", G_CALLBACK(cb_scroll), (gpointer)this);
|
|
|
|
_visible_count++;
|
|
|
|
usleep(10000); // BUG: Embedding too fast sometimes fails with GTK+
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (plug)
|
|
{
|
|
GB.Post((void (*)())hide_icon, (intptr_t)plug);
|
|
plug = NULL;
|
|
_visible_count--;
|
|
}
|
|
}
|
|
}
|
|
|
|
void gTrayIcon::exit()
|
|
{
|
|
gTrayIcon *icon;
|
|
|
|
while((icon = get(0)))
|
|
delete icon;
|
|
}
|
|
|
|
bool gTrayIcon::hasSystemTray()
|
|
{
|
|
#ifdef GTK3
|
|
return PLATFORM.Desktop.HasSystemTray();
|
|
#else
|
|
return X11_get_system_tray() != 0;
|
|
#endif
|
|
}
|