gambas-source-code/gb.gtk/src/gtrayicon.cpp

567 lines
11 KiB
C++
Raw Normal View History

/***************************************************************************
gtrayicon.cpp
(c) 2004-2006 - Daniel Campos Fernández <dcamposf@gmail.com>
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 <gdk/gdkx.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#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