/*************************************************************************** gtrayicon.cpp (c) 2004-2006 - Daniel Campos Fernández Gtkmae "GTK+ made easy" classes Realizado para la Junta de Extremadura. Consejería de Educación Ciencia y Tecnología. Proyecto gnuLinEx 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA. ***************************************************************************/ #include "widgets.h" #ifdef GDK_WINDOWING_X11 #ifndef GAMBAS_DIRECTFB #define GOT_TRAYICON #endif #endif #ifdef GOT_TRAYICON #include #include #include #endif #include "gapplication.h" #include "gmouse.h" #include "gtrayicon.h" #define SYSTEM_TRAY_REQUEST_DOCK 0 #define SYSTEM_TRAY_BEGIN_MESSAGE 1 #define SYSTEM_TRAY_CANCEL_MESSAGE 2 #define OPCODE "_NET_SYSTEM_TRAY_OPCODE" /***************************************************************************** Default picture ******************************************************************************/ #include "gb.form.trayicon.h" /***************************************************************************** Low level stuff ******************************************************************************/ #ifdef GOT_TRAYICON void XTray_RequestDock(Display *xdisplay,Window icon) { Window xmanager=None; XClientMessageEvent ev; Atom OpCodeAtom; Screen *xscreen; char buf[256]; Atom selection_atom; buf[0]=0; xscreen=DefaultScreenOfDisplay(xdisplay); sprintf(buf,"_NET_SYSTEM_TRAY_S%d",XScreenNumberOfScreen (xscreen)); selection_atom = XInternAtom (xdisplay,buf,0); XGrabServer (xdisplay); xmanager = XGetSelectionOwner (xdisplay,selection_atom); if ( xmanager != None) XSelectInput (xdisplay,xmanager,StructureNotifyMask); XUngrabServer (xdisplay); XFlush (xdisplay); /*********************************************** Dock Tray Icon ************************************************/ OpCodeAtom=XInternAtom(xdisplay,OPCODE,0); ev.type = ClientMessage; ev.window = xmanager; ev.message_type = OpCodeAtom; ev.format = 32; ev.data.l[0] = 0; ev.data.l[1] = SYSTEM_TRAY_REQUEST_DOCK; ev.data.l[2] = icon; ev.data.l[3] = 0; ev.data.l[4] = 0; XSendEvent (xdisplay,xmanager, 0, NoEventMask, (XEvent *)&ev); XSync (xdisplay, 0); } void XTray_getSize(Display *xdisplay,Window icon,unsigned int *w,unsigned int *h) { XWindowAttributes Attr; XGetWindowAttributes(xdisplay,icon,&Attr); if (w) *w=Attr.width; if (h) *h=Attr.height; } void XTray_getPosition(Display *xdisplay,Window icon,unsigned int *x,unsigned int *y) { Window rwin; Window pwin; Window *cwin; unsigned int count; XWindowAttributes Attr; Window w=icon; if (x) *x=0; if (y) *y=0; do { XQueryTree(xdisplay,w,&rwin,&pwin,&cwin,&count); if (cwin) XFree(cwin); if (pwin) { XGetWindowAttributes(xdisplay, pwin,&Attr); if (x) (*x)+=Attr.x; if (y) (*y)+=Attr.y; w=pwin; } } while (pwin); } #endif /************************************************************************* gTrayIcon **************************************************************************/ static bool tray_enterleave(GtkWidget *widget, GdkEventCrossing *e,gTrayIcon *data) { if (e->type==GDK_ENTER_NOTIFY) { if (data->onEnter) data->onEnter(data); } else { if (data->onLeave) data->onLeave(data); } return false; } static void tray_destroy (GtkWidget *object,gTrayIcon *data) { //if (data->onHide) { data->onHide=false; return; } //if (data->onDestroy) data->onDestroy(data); data->plug = NULL; //delete data; } static gboolean tray_event(GtkWidget *widget, GdkEvent *event,gTrayIcon *data) { if (!gApplication::userEvents()) return false; if (event->type==GDK_2BUTTON_PRESS) { if (data->onDoubleClick) data->onDoubleClick(data); return false; } return false; } static gboolean tray_down (GtkWidget *widget,GdkEventButton *event,gTrayIcon *data) { if (!gApplication::userEvents()) return false; if (data->onMousePress) { gMouse::validate(); gMouse::setMouse((int)event->x, (int)event->y, event->button, event->state); data->onMousePress(data); gMouse::invalidate(); } if (event->button==3) if (data->onMenu) data->onMenu(data); return false; } static gboolean tray_up (GtkWidget *widget,GdkEventButton *event,gTrayIcon *data) { if (!gApplication::userEvents()) return false; if (data->onMouseRelease) { gMouse::validate(); gMouse::setMouse((int)event->x, (int)event->y, event->button, event->state); data->onMouseRelease(data); gMouse::invalidate(); } return false; } static gboolean cb_menu(GtkWidget *widget, gTrayIcon *data) { if (!gApplication::userEvents()) return false; if (data->onMenu) data->onMenu(data); return false; } static gboolean tray_focus_In(GtkWidget *widget,GdkEventFocus *event,gTrayIcon *data) { if (!gApplication::allEvents()) return false; if (data->onFocusEnter) data->onFocusEnter(data); return false; } static gboolean tray_focus_Out(GtkWidget *widget,GdkEventFocus *event,gTrayIcon *data) { if (!gApplication::allEvents()) return false; if (data->onFocusLeave) data->onFocusLeave(data); return false; } static gboolean cb_scroll(GtkWidget *widget, GdkEventScroll *event, gTrayIcon *data) { int dt = 0; int ort = 0; if (!gApplication::userEvents()) return false; if (data->onMouseWheel) { switch (event->direction) { 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: dt=1; ort=0; break; } gMouse::validate(); gMouse::setMouse((int)event->x, (int)event->y, 0, event->state); gMouse::setWheel(dt, ort); data->onMouseWheel(data); gMouse::invalidate(); } return false; } GList *gTrayIcon::trayicons = NULL; #ifdef GOT_TRAYICON gTrayIcon::gTrayIcon() { plug=NULL; buftext=NULL; _icon = NULL; //onHide=false; onMousePress=NULL; onMouseRelease=NULL; onMenu=NULL; onFocusEnter=NULL; onFocusLeave=NULL; onDoubleClick=NULL; onEnter=NULL; onLeave=NULL; setPicture(0); trayicons = g_list_append(trayicons, (gpointer)this); } gTrayIcon::~gTrayIcon() { gPicture::assign(&_icon); if (buftext) { g_free(buftext); buftext = NULL; } if (plug) gtk_widget_destroy(plug); setVisible(false); trayicons = g_list_remove(trayicons, (gpointer)this); if (onDestroy) (*onDestroy)(this); } GdkPixbuf *gTrayIcon::getIcon() { if (_icon) return _icon->getPixbuf(); else return gdk_pixbuf_new_from_xpm_data((const char**)_default_trayicon); } void gTrayIcon::updateMask() { GdkPixbuf *icon = getIcon(); GdkPixmap *mask; int w, h; if (!plug || !icon) return; w = gdk_pixbuf_get_width(icon); h = gdk_pixbuf_get_height(icon); mask = gdk_pixmap_new(NULL, w, h, 1); gdk_pixbuf_render_threshold_alpha(icon, mask, 0, 0, 0, 0, w, h, 128); gtk_widget_shape_combine_mask(plug, mask, 0, 0); } void gTrayIcon::setPicture(gPicture *picture) { GtkWidget *icon; gPicture::assign(&_icon, picture); if (plug) { icon = gtk_bin_get_child(GTK_BIN(plug)); gtk_image_set_from_pixbuf(GTK_IMAGE(icon), getIcon()); updateMask(); } } char* gTrayIcon::toolTip() { return buftext; } void gTrayIcon::updateTooltip() { if (!plug) return; gtk_tooltips_set_tip(gApplication::tipHandle(), plug, buftext, NULL); } void gTrayIcon::setToolTip(char* vl) { if (buftext) g_free(buftext); buftext = vl && *vl ? g_strdup(vl) : NULL; updateTooltip(); } bool gTrayIcon::isVisible() { return (bool)plug; } void gTrayIcon::setVisible(bool vl) { if (vl) { GtkWidget *icon; Window win; if (!plug) { plug=gtk_plug_new(0); //XSetWindowBackgroundPixmap(gtk_plug_get_id(plug), ParentRelative); icon=gtk_image_new_from_pixbuf(getIcon()); gtk_container_add(GTK_CONTAINER(plug),icon); updateTooltip(); updateMask(); gtk_widget_show_all(plug); //gtk_widget_add_events(plug,GDK_PROXIMITY_IN_MASK); gtk_widget_add_events(plug,GDK_BUTTON_PRESS_MASK); gtk_widget_add_events(plug,GDK_BUTTON_RELEASE_MASK); gtk_widget_add_events(plug,GDK_ENTER_NOTIFY_MASK); gtk_widget_add_events(plug,GDK_LEAVE_NOTIFY_MASK); g_signal_connect(G_OBJECT(plug),"destroy",G_CALLBACK(tray_destroy),(gpointer)this); g_signal_connect(G_OBJECT(plug),"event",G_CALLBACK(tray_event),(gpointer)this); g_signal_connect(G_OBJECT(plug),"button-release-event",G_CALLBACK(tray_up),(gpointer)this); g_signal_connect(G_OBJECT(plug),"button-press-event",G_CALLBACK(tray_down),(gpointer)this); g_signal_connect(G_OBJECT(plug),"focus-in-event",G_CALLBACK(tray_focus_In),(gpointer)this); g_signal_connect(G_OBJECT(plug),"focus-out-event",G_CALLBACK(tray_focus_Out),(gpointer)this); g_signal_connect(G_OBJECT(plug),"enter-notify-event",G_CALLBACK(tray_enterleave),(gpointer)this); g_signal_connect(G_OBJECT(plug),"leave-notify-event",G_CALLBACK(tray_enterleave),(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); win=gtk_plug_get_id(GTK_PLUG(plug)); XTray_RequestDock(gdk_display,win); } } else { if (plug) { //onHide=true; gtk_widget_destroy(plug); //plug=NULL; } } } long gTrayIcon::screenX() { unsigned int ret; if (!plug) return 0; XTray_getPosition(gdk_display,gtk_plug_get_id(GTK_PLUG(plug)),&ret,NULL); return ret; } long gTrayIcon::screenY() { unsigned int ret; if (!plug) return 0; XTray_getPosition(gdk_display,gtk_plug_get_id(GTK_PLUG(plug)),NULL,&ret); return ret; } long gTrayIcon::width() { unsigned int ret; XTray_getSize(gdk_display,gtk_plug_get_id(GTK_PLUG(plug)),&ret,NULL); return ret; } long gTrayIcon::height() { unsigned int ret; XTray_getSize(gdk_display,gtk_plug_get_id(GTK_PLUG(plug)),NULL,&ret); return ret; } void gTrayIcon::exit() { gTrayIcon *icon; while((icon = get(0))) delete icon; } #else gTrayIcon::gTrayIcon() { stub("no-X11/gTrayIcon class"); } gTrayIcon::~gTrayIcon() { stub("no-X11/gTrayIcon class"); } GdkPixbuf *gTrayIcon::getIcon() { stub("no-X11/gTrayIcon class"); } void gTrayIcon::updateMask() { stub("no-X11/gTrayIcon class"); } void gTrayIcon::setPicture(gPicture *picture) { stub("no-X11/gTrayIcon class"); } char* gTrayIcon::toolTip() { stub("no-X11/gTrayIcon class"); } void gTrayIcon::setToolTip(char* vl) { stub("no-X11/gTrayIcon class"); } bool gTrayIcon::isVisible() { stub("no-X11/gTrayIcon class"); } void gTrayIcon::setVisible(bool vl) { stub("no-X11/gTrayIcon class"); } long gTrayIcon::screenX() { stub("no-X11/gTrayIcon class"); } long gTrayIcon::screenY() { stub("no-X11/gTrayIcon class"); } long gTrayIcon::width() { stub("no-X11/gTrayIcon class"); } long gTrayIcon::height() { stub("no-X11/gTrayIcon class"); } void gTrayIcon::exit() { stub("no-X11/gTrayIcon class"); } #endif