/*************************************************************************** gtrayicon.cpp (c) 2004-2006 - Daniel Campos Fernández 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 #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 }