--Boundary-00=_18BcMvs36AZZ136 Content-Type: Text/Plain; charset="iso-8859-15" Content-Transfer-Encoding: 7bit Am Saturday 21 August 2010 schrieb Aaron Lewis: > Hi Thoams , Hi Aaorn ... ;-P > void GlobalMenu::activeWindowChanged(WId wid) > { > if (!mMenu->isHidden()) { > mMenu->hide(); > } > > kDebug() << QString::number(wid,16); > QString ctxXML = mContextMap[wid]; > if (!ctxXML.isEmpty()) { > bindGlobalShortcut(ctxXML); > mXBarIfce->requestFocus(wid); > } else { > qDebug() << "Released . "; > if ( lastWid ) > mXBarIfce->releaseFocus(lastWid); > } > } > > You compile and run it , qDebug() << "Released" always prints , when > clicking on blank areas or minimized , but clicking on blank areas just > don't work .. couldn't figure out. checked whether lastWid is still correct? Afaics it's unconditionally set in windowChanged() what can happen quite often* to every kind of window (and likely even if you just deactivate a window. Also there's a good chance that you receive a windowChange on de/activation as well (since this in not the property variant), so you should rather set lastWid in activeWindowChanged() and _only_ if !ctxXML.isEmpty() (assuming this means there's a globalmenu property ont he window - see attachment. Also WId is iirc unsigned, so "-1" is no good idea, rather use "0" here) Thomas *there's probably space for optimization by connecting the signal that only fires on property changes and check whether it's actuall _your_ property before doing anything. --Boundary-00=_18BcMvs36AZZ136 Content-Type: text/x-c++src; charset="UTF-8"; name="globalmenu.cpp" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="globalmenu.cpp" /* Bespin mac-a-like GlobalMenu KDE4 Copyright (C) 2007 Thomas Luebking This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "globalmenu.h" #include "xbarclientadaptor.h" #define MSG(_FNC_) QDBusMessage::createMethodCall( "org.kde.XBar", "/XBar", "org.kde.XBar", _FNC_ ) #define XBAR_SEND( _MSG_ ) QDBusConnection::sessionBus().send( _MSG_ ) static GlobalMenu *self = 0; static const QString SERVICE_NAME = "org.kde.XBar-gtk"; static QString windowName(WId wid) { NETRootInfo rootInfo(QX11Info::display(), -1); NETWinInfo winInfo(QX11Info::display(), wid, rootInfo.rootWindow(), -1); QString name = QString::fromUtf8(winInfo.visibleIconName()); if (name.isEmpty()) { name = QString::fromUtf8(winInfo.visibleName()); } if (name.isEmpty()) { name = QString::fromUtf8(winInfo.name()); } if (name.isEmpty()) { name = "unknown"; } return name; } static QStringList topMenuList(const QString &source) { QDomDocument doc; QDomElement docElem; QDomNode rootNode; QDomNodeList topNodes; QString error; QStringList result; doc.setContent(source,false,&error); rootNode = doc.firstChild(); for (QDomElement elem = rootNode.firstChildElement(); !elem.isNull(); elem = elem.nextSiblingElement()) { if (elem.attribute("visible") != "0") { QString result_tmp = elem.attribute("label").replace("_","&"); result << result_tmp; } } return result; } GlobalMenu::GlobalMenu(QWidget *parent) : QWidget(parent), mMenu(0), mMapper(new QSignalMapper(this)) { Q_ASSERT(self == 0); self = this; lastWid = 0; QAbstractEventDispatcher::instance()->setEventFilter(x11EventFilter); mCtxAtom = XInternAtom(QX11Info::display(),"_NET_GLOBALMENU_MENU_CONTEXT",FALSE); mEvtAtom = XInternAtom(QX11Info::display(),"_NET_GLOBALMENU_MENU_EVENT",FALSE); QDBusConnection conn = QDBusConnection::connectToBus(QDBusConnection::SessionBus, "globalmenu"); mXBarIfce = new OrgKdeXBarInterface("org.kde.XBar","/XBar",conn); mMenu = new KMenu(parent); connect(mMapper,SIGNAL(mapped(const QString &)),this,SLOT(triggered(const QString &))); conn.registerService(SERVICE_NAME); new XBarClientAdaptor(this); conn.registerObject("/XBarClient", this); connect(KWindowSystem::self(),SIGNAL(activeWindowChanged(WId)), this,SLOT(activeWindowChanged(WId))); connect(KWindowSystem::self(),SIGNAL(windowChanged(WId)), this,SLOT(windowChanged(WId))); connect(KWindowSystem::self(),SIGNAL(windowAdded(WId)), this,SLOT(windowAdded(WId))); connect(KWindowSystem::self(),SIGNAL(windowRemoved(WId)), this,SLOT(windowRemoved(WId))); } GlobalMenu::~GlobalMenu() { Q_ASSERT(self); self = 0; } void GlobalMenu::activate() { // qDebug() << "Activate Now !"; kDebug(); } void GlobalMenu::deactivate() { // qDebug() << "Deactivate Now !"; kDebug(); } void GlobalMenu::hover(qlonglong key, int idx, int x, int y) { if (mMenu->isVisible()) { popup(key,idx,x,y); } } void GlobalMenu::popDown(qlonglong key) { Q_UNUSED(key); mMenu->hide(); } void GlobalMenu::popup(qlonglong key, int idx, int x, int y) { QDomDocument doc; QDomElement rootElem; idx = idx+1; if (doc.setContent(mContextMap[key],false)) { for (QDomElement elem = doc.firstChildElement().firstChildElement(); !elem.isNull(); elem = elem.nextSiblingElement()) { if (elem.attribute("visible") != "0") { idx--; } if (idx == 0) { rootElem = elem; break; } } //mMenu = new KMenu(rootElem.attribute("label"),0); mMenu->clear(); mMenu->setWindowFlags(Qt::X11BypassWindowManagerHint); buildChildMenu(mMenu,rootElem.firstChildElement("menu"),"/"+rootElem.attribute("id")); mMenu->exec(QPoint(x,y)); } } void GlobalMenu::raise(qlonglong key) { Q_UNUSED(key); kDebug(); } void GlobalMenu::windowAdded(WId wid) { kDebug() << QString::number(wid,16); XSelectInput(QX11Info::display(),wid,PropertyChangeMask); qApp->syncX(); } void GlobalMenu::windowRemoved(WId wid) { kDebug() << QString::number(wid,16); // Restore to "plasma" top menu when window closed. XBAR_SEND( MSG("unregisterMenu") << (qlonglong)wid ); } void GlobalMenu::windowChanged(WId wid) { // Ugly Implementation , Check If Menu is hidden() if (!mMenu->isHidden()) { mMenu->hide(); } updateContextMap(wid); } void GlobalMenu::activeWindowChanged(WId wid) { if (!mMenu->isHidden()) { mMenu->hide(); } // check whether we have another presently active client if ( lastWid && lastWid != wid ) mXBarIfce->releaseFocus(lastWid); // and release it // invalidate active client lastWid = 0; QString ctxXML = mContextMap[wid]; if (!ctxXML.isEmpty()) { lastWid = wid; // update active client to this one bindGlobalShortcut(ctxXML); mXBarIfce->requestFocus(wid); } } void GlobalMenu::updateContextMap(WId wid) { int list_count; char **list_return; QString ctxXML; Display *display = QX11Info::display(); Status status; XTextProperty tp; status = XGetTextProperty(display, wid, &tp, mCtxAtom); if (status) { status = XTextPropertyToStringList(&tp,&list_return,&list_count); if (status) { if (list_count) { // for ( int i = 0 ; i < list_count ; i ++ ) { // qDebug() << "Register , I is " << i; ctxXML = QString::fromUtf8(list_return[0]); // if (ctxXML != mContextMap[wid]) { // qDebug() << "Step 4"; kDebug() << ctxXML; mContextMap.insert(wid,ctxXML); mXBarIfce->registerMenu(SERVICE_NAME,wid, windowName(wid), topMenuList(ctxXML)); if (KWindowSystem::activeWindow() == wid) { mXBarIfce->requestFocus(wid); } // break; // } // } } else { ctxXML.clear(); } XFreeStringList(list_return); } } else { ctxXML.clear(); } } void GlobalMenu::buildChildMenu(KMenu *topMenu,const QDomElement &elem, const QString &prefix) { if (elem.isNull()) { return; } KAction *action; //KSelectAction *selectAction = 0; for (QDomElement itemElem = elem.firstChildElement("item"); !itemElem.isNull(); itemElem = itemElem.nextSiblingElement("item")) { if (itemElem.attribute("visible") == "0" ) { continue; } else if (itemElem.attribute("type") == "s") { topMenu->addSeparator(); } else if (!itemElem.firstChildElement("menu").isNull() ) { QString menu_tmp = itemElem.attribute("label").replace("_","&"); KMenu *childMenu = new KMenu(menu_tmp,topMenu); buildChildMenu(childMenu,itemElem.firstChildElement("menu"), QString("%1/%2").arg(prefix).arg(itemElem.attribute("id"))); topMenu->addMenu(childMenu); continue; } else if ( !itemElem.attribute("label").isEmpty() ) { QString menu_tmp = itemElem.attribute("label").replace("_","&"); action = new KAction(menu_tmp,0); mMapper->setMapping(action,QString("%1/%2").arg(prefix).arg(itemElem.attribute("id"))); connect(action,SIGNAL(triggered()),mMapper,SLOT(map())); if (itemElem.attribute("sensible") == "0") { action->setEnabled(false); } topMenu->addAction(action); } } } void GlobalMenu::triggered(const QString &id) { kDebug() << id; mMenu->hide(); WId wid = KWindowSystem::activeWindow(); char *data = id.toUtf8().append("\0").data(); QString ctxXML; Display *display = QX11Info::display(); XTextProperty tp; XStringListToTextProperty(&data,1,&tp); XSetTextProperty(display, wid, &tp, mEvtAtom); } bool GlobalMenu::processXEvent(XEvent *ev) { if (ev->type == PropertyNotify) { if (ev->xproperty.atom == mCtxAtom) { updateContextMap(ev->xproperty.window); } if (ev->xproperty.atom == mEvtAtom) { kDebug() << "Evt:" << QString::number(ev->xproperty.window) << XGetAtomName(QX11Info::display(),ev->xproperty.atom); } } return false; } bool GlobalMenu::x11EventFilter(void *message) { return self->processXEvent(static_cast(message)); } void GlobalMenu::bindGlobalShortcut(const QString &source) { QDomDocument doc; QDomElement docElem; QDomElement rootElem; QDomNodeList topNodes; QString error; QStringList result; doc.setContent(source,false,&error); rootElem = doc.firstChildElement(); for (QDomElement elem = rootElem.firstChildElement(); !elem.isNull(); elem = elem.nextSiblingElement()) { if (elem.attribute("visible") != "0") { KShortcut shortcut(elem.attribute("accel")); QString label = elem.attribute("label").replace("_","&"); KAction *action = new KAction(label,0); mMapper->setMapping(action,QString("/%1").arg(elem.attribute("id"))); connect(action,SIGNAL(triggered()),mMapper,SLOT(map())); action->setGlobalShortcut(shortcut); result << label; } } return; } #include "globalmenu.moc" --Boundary-00=_18BcMvs36AZZ136 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline >> Visit http://mail.kde.org/mailman/listinfo/kde-devel#unsub to unsubscribe << --Boundary-00=_18BcMvs36AZZ136--