1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
|
/***************************************************************************
* Copyright (C) 2003 by liuspider *
* sharecash@163.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 of the License, or *
* (at your option) any later version. *
***************************************************************************/
#include "skimapplet.h"
#include <klocale.h>
#include <kglobal.h>
#include <kapplication.h>
#include <kdeversion.h>
#include <dcopclient.h> //only needed when KDE < 3.4.0
#define KDEGT340 (KDE::version() >= KDE_MAKE_VERSION(3,4,0))
#include <kwin.h>
#include <kdebug.h>
#include <qxembed.h>
#include <qlayout.h>
#include <qcursor.h>
#include <qtimer.h>
#ifdef Q_WS_X11
#include <X11/Xlib.h>
#endif
extern "C"
{
KDE_EXPORT KPanelApplet* init(QWidget *parent, const QString& configFile)
{
return new SkimApplet(configFile, KPanelApplet::Stretch,
KPanelApplet::Preferences, parent, "skimapplet");
}
}
SkimApplet::SkimApplet(const QString& configFile, Type type, int actions,
QWidget *parent, const char *name)
: KPanelApplet(configFile, type, actions, parent, name), DCOPObject("SkimApplet"),
m_emittedDestroyedSignal(true), m_autoHideHandle(false), m_scheduledWindow(0)
{
// kapp->dcopClient()->detach();
// kapp->dcopClient()->registerAs("kicker_skimapplet", false);
// kapp->dcopClient()->attach();
// KGlobal::locale()->insertCatalogue("skimapplet");
setBackgroundOrigin(QWidget::AncestorOrigin);
// setAlignment(KPanelApplet::Center);
// setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
QHBoxLayout * hbox = new QHBoxLayout(this, 0, 0);
hbox->setAutoAdd(true);
hbox->setAlignment(Qt::AlignCenter);
m_embedWin = new QXEmbed(this);
connect(m_embedWin, SIGNAL(embeddedWindowDestroyed()), this, SLOT(hideAll()));
m_embedWin->setBackgroundOrigin(QWidget::AncestorOrigin);
m_embedWin->setBackgroundMode(QWidget::X11ParentRelative);
//immediately after the contruction of this applet, the pluginmanager will call
//show in the parent->parentWidget(), so we have to use a timer to schedule a hide call
QTimer::singleShot(0, this, SLOT(hideAll()));
connect(kapp, SIGNAL(shutDown()), this, SLOT(shuttingDown()));
if(appletHandleDragWidget())
appletHandleDragWidget()->installEventFilter(this);
}
SkimApplet::~SkimApplet()
{
//KApplication::closingDown() always return false
notifyEmbedWindow(KApplication::closingDown());
// KGlobal::locale()->removeCatalogue("skimapplet");
}
void SkimApplet::shuttingDown()
{
notifyEmbedWindow(true);
}
void SkimApplet::notifyEmbedWindow(bool exiting)
{
if(!m_emittedDestroyedSignal)
{
m_emittedDestroyedSignal = true;
if(kapp->dcopClient()->isAttached())
{
// QErrorMessage * warningBox = QErrorMessage::qtHandler ();
// warningBox->message(QString("%d closing applet").arg(KApplication::closingDown()));
QByteArray data;
QDataStream arg(data, IO_WriteOnly);
arg << exiting;
emitDCOPSignal("appletDestroyed(bool)", data);
}
}
}
void SkimApplet::hideAll()
{
if(QWidget * w = appletHandleWidget())
w->hide();
}
void SkimApplet::resizeEvent ( QResizeEvent * e )
{
if(e->size().width() >= 0 && e->size().height() >= 0)
{
QSize contentSize = e->size();
if(QWidget * w = appletHandleWidget())
if(orientation() == Qt::Horizontal)
contentSize.setWidth(contentSize.width() - w->width());
else
contentSize.setHeight(contentSize.height() - w->height());
emit preferedSizeChanged(contentSize, (int)orientation());
{
QByteArray data;
QDataStream arg(data, IO_WriteOnly);
arg << contentSize << (int)orientation();
emitDCOPSignal("preferedSizeChanged(QSize, int)", data);
}
}
KPanelApplet::resizeEvent(e);
}
void SkimApplet::positionChange( Position p )
{
//hide the handle if required
slotLeaveEvent ();
//this function will generate resizeEvent
KPanelApplet::positionChange(p);
}
void SkimApplet::embedWindow(Q_UINT32 intw)
{
m_emittedDestroyedSignal = false;
WId wid = (WId)(intw);
KWin::WindowInfo wininfo = KWin::windowInfo(wid);
if(wininfo.valid(true))
{
m_scheduledWindow = wid;
realEmbedWindow();
}
else
kdError() << "Something is terribly WRONG: embeded window WId is not correct!!";
}
void SkimApplet::realEmbedWindow()
{
if(m_scheduledWindow)
{
KWin::WindowInfo wininfo = KWin::windowInfo(m_scheduledWindow);
if(wininfo.valid(true))
{
m_embedWin->embed(m_scheduledWindow);
#ifdef Q_WS_X11
//as the embeding window may not have be shown, so
//we map it. We can not get the corresponding qwidget
//object, so X call is used.
XMapWindow(qt_xdisplay(), m_scheduledWindow);
#endif
m_scheduledWindow = 0;
parentWidget()->parentWidget()->show();
show();
//these two calls will make sure handler is shown correctly
slotEnterEvent ();
slotLeaveEvent ();
}
}
}
void SkimApplet::setAutoHideHandle(bool b)
{
m_autoHideHandle = b;
if(QWidget * w = appletHandleWidget())
if(m_autoHideHandle)
{
w->installEventFilter(this);
w->hide();
}
else
{
w->removeEventFilter(this);
w->show();
}
}
#include <qwidgetlist.h>
QWidget * SkimApplet::containerWidget()
{
if(KDEGT340) //this is KDE 3.4
if( parentWidget() && parentWidget()->parentWidget())
return parentWidget()->parentWidget();
else
return 0;
else
{ //this is KDE 3.3
//FIXME: shall we cache the result?
QWidgetList *list = QApplication::topLevelWidgets();
QWidgetListIt it( *list ); // iterate over the widgets
QWidget * w, *ret = 0;
while ( (w=it.current()) != 0 ) { // for each top level widget...
if(!strcmp(w->name(), "Panel"))
{
ret = dynamic_cast<QWidget *>(w->child("skim_panelappletcontainer"));
break;
}
++it;
}
delete list;
return ret;
}
}
QWidget * SkimApplet::appletHandleWidget()
{
if(QWidget * w = containerWidget())
return dynamic_cast<QWidget *>(w->child(0, "AppletHandle"));
else
return 0;
}
QWidget * SkimApplet::appletHandleDragWidget()
{
if(appletHandleWidget())
return dynamic_cast<QWidget *>(appletHandleWidget()->child(0, "AppletHandleDrag"));
else
return 0;
}
bool SkimApplet::eventFilter(QObject * object, QEvent * e)
{
bool ret = false;
if(object == appletHandleWidget())
{
switch ( e->type() ) {
case QEvent::Leave:
if(m_autoHideHandle)
slotLeaveEvent ();
break;
default:
break;
}
}
else if(object == appletHandleDragWidget())
{
static QMouseEvent * lastMouseButtonPressEvent = 0;
static bool omitNextButtonPress = false;
switch ( e->type() ) {
//HACK START: this is an ungly hack to achieve emitting doubleClick signal when
// the user double click the AppletHandleDrag:
// this hack highly depends on the underlying implementation details of kicker,
// especially: in kicker/core/applethandle.cpp, AppletHandle installs an
// eventfilter to AppletHandleDrag, which filter all MouseButtonPress events of
// widget AppletHandleDrag. Thus, without this hack, no MouseButtonDblClick
// events can be generated. So here we filter all MouseButtonPress events, to
// make them go through Qt built-in handlers, which will generate DblClick
// events. However, we need to feed MouseButtonPress to AppletHandle::eventfilter
// to activate the movement of applet: if users move the mouse, then we send
// the last mouse button press event to appletHandleDragWidget, so AppletHandle
// can emit a signal to notify its parent to move the applet.
// As in void ContainerArea::startContainerMove(BaseContainer *a), ContainerArea
// would grab the mouse, so no further MouseMove event will be received by this
// filter after sending out lastMouseButtonPressEvent, until the movement is
// completed.
case QEvent::MouseMove:
if(lastMouseButtonPressEvent)
{
omitNextButtonPress = true;
QApplication::sendEvent(object, lastMouseButtonPressEvent);
ret = true;
}
break;
case QEvent::MouseButtonPress:
if(!omitNextButtonPress)
{
QMouseEvent * me = static_cast<QMouseEvent *>(e);
if(me->button() == Qt::LeftButton) //only interested in LeftButton
{
if(lastMouseButtonPressEvent)
delete lastMouseButtonPressEvent;
lastMouseButtonPressEvent = new QMouseEvent(*me);
ret = true;
}
else
omitNextButtonPress = false;
} else
omitNextButtonPress = false;
break;
//HACK END
case QEvent::MouseButtonDblClick:
{
QByteArray data;
emitDCOPSignal("doubleCliked()", data);
ret = true;
}
break;
default:
break;
}
}
return ret;
}
void SkimApplet::slotEnterEvent ()
{
if(QWidget * w = appletHandleWidget())
w->show();
}
void SkimApplet::slotLeaveEvent ()
{
QWidget * area = containerWidget();
if(m_autoHideHandle && area)
{
//if mouse is still in the area of the applet (including handle), do not hide the handle
if(!area->rect().contains(area->mapFromGlobal(QCursor::pos())))
hideAll();
}
}
int SkimApplet::heightForWidth(int width) const
{
if(m_embedWin->embeddedWinId())
return KPanelApplet::heightForWidth(width);
else
return 0;
}
int SkimApplet::widthForHeight(int height) const
{
if(m_embedWin->embeddedWinId())
return KPanelApplet::widthForHeight(height);
else
return 0;
}
void SkimApplet::action(Action a)
{
KPanelApplet::action(a);
}
#include "skimapplet.moc"
|