2fbf67cb29
* NEW: Update FSF address in every source file. git-svn-id: svn://localhost/gambas/trunk@3870 867c0c6c-44f3-4631-809d-bfa615b0a4ec
631 lines
12 KiB
C++
631 lines
12 KiB
C++
/***************************************************************************
|
|
|
|
CTrayIcon.cpp
|
|
|
|
(c) 2000-2011 Benoît Minisini <gambas@users.sourceforge.net>
|
|
|
|
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.
|
|
|
|
***************************************************************************/
|
|
|
|
#define __CTRAYICON_CPP
|
|
|
|
#include <qnamespace.h>
|
|
#include <qapplication.h>
|
|
#include <qtooltip.h>
|
|
#include <qpixmap.h>
|
|
#include <qbitmap.h>
|
|
#include <qevent.h>
|
|
#include <qeventloop.h>
|
|
|
|
//Added by qt3to4:
|
|
#include <QContextMenuEvent>
|
|
#include <QWheelEvent>
|
|
#include <QMouseEvent>
|
|
|
|
#include "gambas.h"
|
|
#include "main.h"
|
|
|
|
#include "CMouse.h"
|
|
#define DO_NOT_DECLARE_EVENTS
|
|
#include "CWidget.h"
|
|
#include "CMenu.h"
|
|
#include "CWindow.h"
|
|
#include "x11.h"
|
|
#include "CTrayIcon.h"
|
|
|
|
DECLARE_METHOD(Control_ScreenX);
|
|
DECLARE_METHOD(Control_ScreenY);
|
|
DECLARE_METHOD(Control_Width);
|
|
DECLARE_METHOD(Control_Height);
|
|
|
|
DECLARE_EVENT(EVENT_MouseDown);
|
|
DECLARE_EVENT(EVENT_MouseUp);
|
|
DECLARE_EVENT(EVENT_MouseMove);
|
|
DECLARE_EVENT(EVENT_MouseWheel);
|
|
DECLARE_EVENT(EVENT_DblClick);
|
|
DECLARE_EVENT(EVENT_Enter);
|
|
DECLARE_EVENT(EVENT_Leave);
|
|
DECLARE_EVENT(EVENT_GotFocus);
|
|
DECLARE_EVENT(EVENT_LostFocus);
|
|
DECLARE_EVENT(EVENT_Menu);
|
|
|
|
static int _state;
|
|
static QList<CTRAYICON *> _list;
|
|
|
|
#include "gb.form.trayicon.h"
|
|
|
|
/** MyTrayIcon ***********************************************************/
|
|
|
|
MyTrayIcon::MyTrayIcon() : SystemTrayIcon()
|
|
{
|
|
_icon = QPixmap(_default_trayicon);
|
|
}
|
|
|
|
void MyTrayIcon::setIcon(QPixmap &icon)
|
|
{
|
|
if (icon.isNull())
|
|
_icon = QPixmap(_default_trayicon);
|
|
else
|
|
_icon = icon;
|
|
update();
|
|
}
|
|
|
|
void MyTrayIcon::paintEvent(QPaintEvent *e)
|
|
{
|
|
SystemTrayIcon::paintEvent(e);
|
|
QPainter p(this);
|
|
p.drawPixmap((width() - _icon.width()) / 2, (height() - _icon.height()) / 2, _icon);
|
|
}
|
|
|
|
|
|
static CTRAYICON *find_object(const QObject *o)
|
|
{
|
|
int i;
|
|
CTRAYICON *_object;
|
|
|
|
for (i = 0; i < _list.count(); i++)
|
|
{
|
|
_object = _list.at(i);
|
|
if (THIS->widget == o)
|
|
return THIS;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void destroy_widget(CTRAYICON *_object)
|
|
{
|
|
if (WIDGET)
|
|
{
|
|
delete WIDGET;
|
|
THIS->widget = NULL;
|
|
}
|
|
}
|
|
|
|
void CTRAYICON_close_all(void)
|
|
{
|
|
CTRAYICON *_object, *last = 0;
|
|
int i;
|
|
|
|
GB.StopAllEnum((void *)GB.FindClass("TrayIcons"));
|
|
|
|
i = 0;
|
|
for (;;)
|
|
{
|
|
if (i >= _list.count())
|
|
break;
|
|
|
|
_object = _list.at(i);
|
|
|
|
if (_object == last)
|
|
{
|
|
i++;
|
|
continue;
|
|
}
|
|
|
|
last = _object;
|
|
destroy_widget(THIS);
|
|
GB.Unref(POINTER(&_object));
|
|
}
|
|
|
|
_list.clear();
|
|
}
|
|
|
|
|
|
BEGIN_METHOD_VOID(CTRAYICON_new)
|
|
|
|
THIS->tag.type = GB_T_NULL;
|
|
_list.append(THIS);
|
|
GB.Ref(THIS);
|
|
|
|
END_METHOD
|
|
|
|
|
|
BEGIN_METHOD_VOID(CTRAYICON_free)
|
|
|
|
//qDebug("CTRAYICON_free");
|
|
|
|
_list.removeAt(_list.indexOf(THIS));
|
|
|
|
GB.StoreObject(NULL, POINTER(&THIS->icon));
|
|
GB.FreeString(&THIS->tooltip);
|
|
GB.FreeString(&THIS->popup);
|
|
GB.StoreVariant(NULL, &THIS->tag);
|
|
|
|
destroy_widget(THIS);
|
|
|
|
END_METHOD
|
|
|
|
|
|
static void define_mask(CTRAYICON *_object)
|
|
{
|
|
QPixmap *p;
|
|
|
|
if (!WIDGET)
|
|
return;
|
|
|
|
if (THIS->icon)
|
|
p = THIS->icon->pixmap;
|
|
else
|
|
p = new QPixmap(_default_trayicon);
|
|
|
|
/*WIDGET->clearMask();
|
|
if (p->hasAlpha())
|
|
WIDGET->setMask(*(p->mask()));*/
|
|
|
|
WIDGET->setIcon(*p);
|
|
//WIDGET->setPaletteBackgroundColor(QColor(255, 0, 0));
|
|
WIDGET->resize(p->width(), p->height());
|
|
|
|
if (!THIS->icon)
|
|
delete p;
|
|
|
|
#ifndef NO_X_WINDOW
|
|
// Needed, otherwise the icon does not appear in Gnome or XFCE notification area!
|
|
XSizeHints hints;
|
|
hints.flags = PMinSize;
|
|
hints.min_width = WIDGET->width();
|
|
hints.min_height = WIDGET->height();
|
|
XSetWMNormalHints(WIDGET->x11Display(), WIDGET->winId(), &hints);
|
|
#endif
|
|
}
|
|
|
|
static void define_tooltip(CTRAYICON *_object)
|
|
{
|
|
if (!WIDGET)
|
|
return;
|
|
|
|
WIDGET->setToolTip(TO_QSTRING(THIS->tooltip));
|
|
}
|
|
|
|
|
|
BEGIN_PROPERTY(CTRAYICON_picture)
|
|
|
|
if (READ_PROPERTY)
|
|
{
|
|
GB.ReturnObject(THIS->icon);
|
|
return;
|
|
}
|
|
|
|
GB.StoreObject(PROP(GB_OBJECT), POINTER(&THIS->icon));
|
|
define_mask(THIS);
|
|
|
|
END_PROPERTY
|
|
|
|
|
|
BEGIN_PROPERTY(CTRAYICON_tooltip)
|
|
|
|
if (READ_PROPERTY)
|
|
GB.ReturnString(THIS->tooltip);
|
|
else
|
|
{
|
|
GB.StoreString(PROP(GB_STRING), &(THIS->tooltip));
|
|
define_tooltip(THIS);
|
|
}
|
|
|
|
END_PROPERTY
|
|
|
|
BEGIN_PROPERTY(TrayIcon_PopupMenu)
|
|
|
|
if (READ_PROPERTY)
|
|
GB.ReturnString(THIS->popup);
|
|
else
|
|
GB.StoreString(PROP(GB_STRING), &(THIS->popup));
|
|
|
|
END_PROPERTY
|
|
|
|
|
|
BEGIN_METHOD_VOID(CTRAYICON_show)
|
|
|
|
if (!WIDGET)
|
|
{
|
|
MyTrayIcon *wid = new MyTrayIcon();
|
|
//wid->setFocusPolicy(Qt::NoFocus);
|
|
wid->installEventFilter(&CTrayIcon::manager);
|
|
|
|
THIS->widget = wid;
|
|
|
|
//QObject::connect(WIDGET, SIGNAL(embedded()), &CTrayIcon::manager, SLOT(embedded()));
|
|
//QObject::connect(WIDGET, SIGNAL(containerClosed()), &CTrayIcon::manager, SLOT(closed()));
|
|
//QObject::connect(WIDGET, SIGNAL(error(QX11EmbedWidget::Error)), &CTrayIcon::manager, SLOT(error()));
|
|
|
|
//qDebug("XEMBED: EmbedState: %d", CWINDOW_EmbedState);
|
|
define_mask(THIS);
|
|
define_tooltip(THIS);
|
|
//X11_window_dock(WIDGET->winId());
|
|
|
|
/*_state = EMBED_WAIT;
|
|
for(i = 0; i < 500; i++)
|
|
{
|
|
MAIN_process_events();
|
|
if (_state)
|
|
break;
|
|
usleep(10000);
|
|
}
|
|
|
|
if (_state != EMBED_OK)
|
|
{
|
|
GB.Error("Embedding has failed");
|
|
destroy_widget(THIS);
|
|
return;
|
|
}*/
|
|
|
|
#ifndef NO_X_WINDOW
|
|
WIDGET->addToTray();
|
|
#else
|
|
WIDGET->show();
|
|
#endif
|
|
define_mask(THIS);
|
|
define_tooltip(THIS);
|
|
}
|
|
|
|
END_METHOD
|
|
|
|
|
|
BEGIN_METHOD_VOID(CTRAYICON_hide)
|
|
|
|
destroy_widget(THIS);
|
|
|
|
END_METHOD
|
|
|
|
|
|
BEGIN_PROPERTY(CTRAYICON_visible)
|
|
|
|
if (READ_PROPERTY)
|
|
{
|
|
GB.ReturnBoolean(WIDGET != NULL);
|
|
return;
|
|
}
|
|
|
|
if (VPROP(GB_BOOLEAN))
|
|
CTRAYICON_show(_object, _param);
|
|
else
|
|
CTRAYICON_hide(_object, _param);
|
|
|
|
END_PROPERTY
|
|
|
|
|
|
BEGIN_PROPERTY(CTRAYICON_tag)
|
|
|
|
if (READ_PROPERTY)
|
|
GB.ReturnPtr(GB_T_VARIANT, &THIS->tag);
|
|
else
|
|
GB.StoreVariant(PROP(GB_VARIANT), (void *)&THIS->tag);
|
|
|
|
END_METHOD
|
|
|
|
|
|
BEGIN_METHOD_VOID(CTRAYICON_next)
|
|
|
|
int index;
|
|
|
|
index = ENUM(int);
|
|
|
|
if (index >= _list.count())
|
|
{
|
|
GB.StopEnum();
|
|
return;
|
|
}
|
|
|
|
ENUM(int) = index + 1;
|
|
|
|
GB.ReturnObject(_list.at(index));
|
|
|
|
END_METHOD
|
|
|
|
|
|
BEGIN_METHOD(CTRAYICON_get, GB_INTEGER index)
|
|
|
|
int index = (uint)VARG(index);
|
|
|
|
if (index >= _list.count())
|
|
{
|
|
GB.Error("Bad index");
|
|
return;
|
|
}
|
|
|
|
GB.ReturnObject(_list.at(index));
|
|
|
|
END_METHOD
|
|
|
|
|
|
BEGIN_PROPERTY(CTRAYICON_count)
|
|
|
|
GB.ReturnInteger(_list.count());
|
|
|
|
END_PROPERTY
|
|
|
|
BEGIN_PROPERTY(CTRAYICON_screen_x)
|
|
|
|
if (WIDGET)
|
|
Control_ScreenX(_object, _param);
|
|
else
|
|
GB.ReturnInteger(0);
|
|
|
|
END_PROPERTY
|
|
|
|
|
|
BEGIN_PROPERTY(CTRAYICON_screen_y)
|
|
|
|
if (WIDGET)
|
|
Control_ScreenY(_object, _param);
|
|
else
|
|
GB.ReturnInteger(0);
|
|
|
|
END_PROPERTY
|
|
|
|
|
|
BEGIN_PROPERTY(CTRAYICON_w)
|
|
|
|
if (WIDGET)
|
|
Control_Width(_object, _param);
|
|
else
|
|
GB.ReturnInteger(0);
|
|
|
|
END_PROPERTY
|
|
|
|
|
|
BEGIN_PROPERTY(CTRAYICON_h)
|
|
|
|
if (WIDGET)
|
|
Control_Height(_object, _param);
|
|
else
|
|
GB.ReturnInteger(0);
|
|
|
|
END_PROPERTY
|
|
|
|
|
|
|
|
|
|
GB_DESC CTrayIconsDesc[] =
|
|
{
|
|
GB_DECLARE("TrayIcons", 0), GB_NOT_CREATABLE(),
|
|
|
|
GB_STATIC_METHOD("_next", "TrayIcon", CTRAYICON_next, NULL),
|
|
GB_STATIC_METHOD("_get", "TrayIcon", CTRAYICON_get, "(Index)i"),
|
|
GB_STATIC_PROPERTY_READ("Count", "i", CTRAYICON_count),
|
|
|
|
GB_END_DECLARE
|
|
};
|
|
|
|
|
|
GB_DESC CTrayIconDesc[] =
|
|
{
|
|
GB_DECLARE("TrayIcon", sizeof(CTRAYICON)),
|
|
|
|
GB_METHOD("_new", NULL, CTRAYICON_new, NULL),
|
|
GB_METHOD("_free", NULL, CTRAYICON_free, NULL),
|
|
|
|
GB_METHOD("Show", NULL, CTRAYICON_show, NULL),
|
|
GB_METHOD("Hide", NULL, CTRAYICON_hide, NULL),
|
|
GB_METHOD("Delete", NULL, CTRAYICON_hide, NULL),
|
|
|
|
GB_PROPERTY("Picture", "Picture", CTRAYICON_picture),
|
|
GB_PROPERTY("Icon", "Picture", CTRAYICON_picture),
|
|
GB_PROPERTY("Visible", "b", CTRAYICON_visible),
|
|
|
|
GB_PROPERTY("Text", "s", CTRAYICON_tooltip),
|
|
GB_PROPERTY("PopupMenu", "s", TrayIcon_PopupMenu),
|
|
GB_PROPERTY("Tooltip", "s", CTRAYICON_tooltip),
|
|
GB_PROPERTY("Tag", "v", CTRAYICON_tag),
|
|
|
|
GB_PROPERTY_READ("ScreenX", "i", CTRAYICON_screen_x),
|
|
GB_PROPERTY_READ("ScreenY", "i", CTRAYICON_screen_y),
|
|
GB_PROPERTY_READ("Width", "i", CTRAYICON_w),
|
|
GB_PROPERTY_READ("Height", "i", CTRAYICON_h),
|
|
GB_PROPERTY_READ("W", "i", CTRAYICON_w),
|
|
GB_PROPERTY_READ("H", "i", CTRAYICON_h),
|
|
|
|
GB_EVENT("Enter", NULL, NULL, &EVENT_Enter),
|
|
GB_EVENT("GotFocus", NULL, NULL, &EVENT_GotFocus),
|
|
GB_EVENT("LostFocus", NULL, NULL, &EVENT_LostFocus),
|
|
GB_EVENT("Leave", NULL, NULL, &EVENT_Leave),
|
|
GB_EVENT("MouseDown", NULL, NULL, &EVENT_MouseDown),
|
|
GB_EVENT("MouseMove", NULL, NULL, &EVENT_MouseMove),
|
|
GB_EVENT("MouseUp", NULL, NULL, &EVENT_MouseUp),
|
|
GB_EVENT("MouseWheel", NULL, NULL, &EVENT_MouseWheel),
|
|
GB_EVENT("DblClick", NULL, NULL, &EVENT_DblClick),
|
|
GB_EVENT("Menu", NULL, NULL, &EVENT_Menu),
|
|
|
|
TRAYICON_DESCRIPTION,
|
|
|
|
GB_END_DECLARE
|
|
};
|
|
|
|
|
|
/*--- CTrayIcon -----------------------------------------------------------------------------------------*/
|
|
|
|
CTrayIcon CTrayIcon::manager;
|
|
|
|
void CTrayIcon::error(void)
|
|
{
|
|
//CWINDOW *_object = (CWINDOW *)CWidget::getReal((QObject *)sender());
|
|
//qDebug("XEMBED: CWindow::error %p -> %p", sender(), THIS);
|
|
_state = EMBED_ERROR;
|
|
}
|
|
|
|
void CTrayIcon::embedded(void)
|
|
{
|
|
//CWINDOW *_object = (CWINDOW *)CWidget::getReal((QObject *)sender());
|
|
//qDebug("XEMBED: CWindow::embedded %p -> %p", sender(), THIS);
|
|
_state = EMBED_OK;
|
|
}
|
|
|
|
void CTrayIcon::closed(void)
|
|
{
|
|
//CWINDOW *_object = (CWINDOW *)CWidget::getReal((QObject *)sender());
|
|
//qDebug("XEMBED: CWindow::closed %p -> %p", sender(), THIS);
|
|
//CWIDGET_destroy(CWidget::getReal((QObject *)sender()));
|
|
destroy_widget(find_object(sender()));
|
|
}
|
|
|
|
|
|
bool CTrayIcon::eventFilter(QObject *widget, QEvent *event)
|
|
{
|
|
CTRAYICON *_object;
|
|
int event_id;
|
|
int type = event->type();
|
|
bool original;
|
|
QPoint p;
|
|
|
|
_object = find_object(widget);
|
|
|
|
if (!_object)
|
|
goto __STANDARD;
|
|
|
|
original = event->spontaneous();
|
|
|
|
if (type == QEvent::Enter)
|
|
{
|
|
GB.Raise(THIS, EVENT_Enter, 0);
|
|
}
|
|
else if (type == QEvent::Leave)
|
|
{
|
|
GB.Raise(THIS, EVENT_Leave, 0);
|
|
}
|
|
else if (type == QEvent::FocusIn)
|
|
{
|
|
GB.Raise(THIS, EVENT_GotFocus, 0);
|
|
}
|
|
else if (type == QEvent::FocusOut)
|
|
{
|
|
GB.Raise(THIS, EVENT_LostFocus, 0);
|
|
}
|
|
else if (type == QEvent::ContextMenu)
|
|
{
|
|
if (GB.CanRaise(THIS, EVENT_Menu))
|
|
{
|
|
((QContextMenuEvent *)event)->accept();
|
|
GB.Raise(THIS, EVENT_Menu, 0);
|
|
return true;
|
|
}
|
|
if (THIS->popup)
|
|
{
|
|
void *parent = GB.Parent(THIS);
|
|
if (parent && GB.Is(parent, CLASS_Control))
|
|
{
|
|
CWINDOW *window = CWidget::getWindow((CWIDGET *)parent);
|
|
CMENU *menu = CWindow::findMenu(window, THIS->popup);
|
|
if (menu)
|
|
CMENU_popup(menu, QCursor::pos());
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
else if ((type == QEvent::MouseButtonPress)
|
|
|| (type == QEvent::MouseButtonRelease)
|
|
|| (type == QEvent::MouseMove))
|
|
{
|
|
QMouseEvent *mevent = (QMouseEvent *)event;
|
|
|
|
if (!original)
|
|
goto __DESIGN;
|
|
|
|
if (type == QEvent::MouseButtonPress)
|
|
{
|
|
event_id = EVENT_MouseDown;
|
|
}
|
|
else
|
|
{
|
|
event_id = (type == QEvent::MouseButtonRelease) ? EVENT_MouseUp : EVENT_MouseMove;
|
|
}
|
|
|
|
if (GB.CanRaise(THIS, event_id))
|
|
{
|
|
p.setX(mevent->globalX());
|
|
p.setY(mevent->globalY());
|
|
|
|
p = WIDGET->mapFromGlobal(p);
|
|
|
|
CMOUSE_clear(true);
|
|
CMOUSE_info.x = p.x();
|
|
CMOUSE_info.y = p.y();
|
|
CMOUSE_info.button = mevent->buttons();
|
|
CMOUSE_info.modifier = mevent->modifiers();
|
|
|
|
GB.Raise(THIS, event_id, 0);
|
|
|
|
CMOUSE_clear(false);
|
|
}
|
|
}
|
|
else if (type == QEvent::MouseButtonDblClick)
|
|
{
|
|
if (!original)
|
|
goto __DESIGN;
|
|
|
|
GB.Raise(THIS, EVENT_DblClick, 0);
|
|
}
|
|
else if (type == QEvent::Wheel)
|
|
{
|
|
QWheelEvent *ev = (QWheelEvent *)event;
|
|
|
|
//qDebug("Event on %p %s%s%s", widget,
|
|
// real ? "REAL " : "", design ? "DESIGN " : "", child ? "CHILD " : "");
|
|
|
|
if (!original)
|
|
goto __DESIGN;
|
|
|
|
if (GB.CanRaise(THIS, EVENT_MouseWheel))
|
|
{
|
|
p.setX(ev->x());
|
|
p.setY(ev->y());
|
|
|
|
//p = WIDGET->mapTo(QWIDGET(control), p);
|
|
|
|
CMOUSE_clear(true);
|
|
CMOUSE_info.x = p.x();
|
|
CMOUSE_info.y = p.y();
|
|
CMOUSE_info.button = ev->buttons();
|
|
CMOUSE_info.modifier = ev->modifiers();
|
|
CMOUSE_info.orientation = ev->orientation();
|
|
CMOUSE_info.delta = ev->delta();
|
|
|
|
GB.Raise(THIS, EVENT_MouseWheel, 0);
|
|
|
|
CMOUSE_clear(false);
|
|
}
|
|
}
|
|
|
|
__DESIGN:
|
|
|
|
if (!find_object(widget))
|
|
return true;
|
|
|
|
__STANDARD:
|
|
|
|
return QObject::eventFilter(widget, event); // standard event processing
|
|
}
|