Source Code (Use browser search to find items of interest.)
Class Index
kdesktop'KPixmapServer (./kdebase/kdesktop/pixmapserver.h:53)
class KPixmapServer: public QWidget
{
Q_OBJECT
public:
KPixmapServer();
~KPixmapServer();
/**
* Adds a pixmap to this server. This will make it available to all
* other X clients on the current display.
*
* You must never delete a pixmap that you add()'ed. The pixmap is
* deleted when you call remove() and after all clients have stopped
* using it.
*
* You can add the same pixmap under multiple names.
*
* @param name An X11-wide unique identifier for the pixmap.
* @param pm A pointer to the pixmap.
* @param overwrite Should an pixmap with the same name be overwritten?
*/
void add(QString name, QPixmap *pm, bool overwrite=true);
/**
* Remove a pixmap from the server. This will delete the pixmap after
* all clients have stopped using it.
*
* @param name The name of the shared pixmap.
*/
void remove(QString name);
/**
* List all pixmaps currently served by this server.
*
* @return A QStringList containing all the shared pixmaps.
*/
QStringList list();
/**
* Re-set ownership of the selection providing the shared pixmap.
*
* @param name The name of the shared pixmap.
*/
void setOwner(QString name);
signals:
/**
* This signal is emitted when the selection providing the named pixmap
* is disowned. This means that said pixmap won't be served anymore by
* this server, though it can be served by another. You can re-aqcuire
* the selection by calling setOwner().
*/
void selectionCleared(QString name);
protected:
bool x11Event(XEvent *);
private:
Atom pixmap;
QMap<QString,KPixmapInode> m_Names;
QMap<Atom,KSelectionInode> m_Selections;
QMap<HANDLE,KPixmapData> m_Data;
QMap<Atom,HANDLE> m_Active;
typedef QMap<QString,KPixmapInode>::Iterator NameIterator;
typedef QMap<Atom,KSelectionInode>::Iterator SelectionIterator;
typedef QMap<HANDLE,KPixmapData>::Iterator DataIterator;
typedef QMap<Atom,HANDLE>::Iterator AtomIterator;
};
kdesktop'KPixmapServer::KPixmapServer() (./kdebase/kdesktop/pixmapserver.cc:37)
KPixmapServer::KPixmapServer()
: QWidget(0L, "shpixmap comm window")
{
kapp->installX11EventFilter(this);
pixmap = XInternAtom(qt_xdisplay(), "PIXMAP", false);
}
kdesktop'KPixmapServer::~KPixmapServer() (./kdebase/kdesktop/pixmapserver.cc:45)
KPixmapServer::~KPixmapServer()
{
SelectionIterator it;
for (it=m_Selections.begin(); it!=m_Selections.end(); it++)
XSetSelectionOwner(qt_xdisplay(), it.key(), None, CurrentTime);
DataIterator it2;
for (it2=m_Data.begin(); it2!=m_Data.end(); it2++)
delete it2.data().pixmap;
}
kdesktop'KPixmapServer::add() (./kdebase/kdesktop/pixmapserver.cc:57)
void KPixmapServer::add(QString name, QPixmap *pm, bool overwrite)
{
if (m_Names.contains(name)) {
if (overwrite)
remove(name);
else return;
}
QString str = QString("KDESHPIXMAP:%1").arg(name);
Atom sel = XInternAtom(qt_xdisplay(), str.latin1(), false);
KPixmapInode pi;
pi.handle = pm->handle();
pi.selection = sel;
m_Names[name] = pi;
KSelectionInode si;
si.name = name;
si.handle = pm->handle();
m_Selections[sel] = si;
DataIterator it = m_Data.find(pm->handle());
if (it == m_Data.end()) {
KPixmapData data;
data.pixmap = pm;
data.usecount = 0;
data.refcount = 1;
m_Data[pm->handle()] = data;
} else
it.data().refcount++;
XSetSelectionOwner(qt_xdisplay(), sel, winId(), CurrentTime);
}
kdesktop'KPixmapServer::remove() (./kdebase/kdesktop/pixmapserver.cc:91)
void KPixmapServer::remove(QString name)
{
// Remove the name
NameIterator it = m_Names.find(name);
if (it == m_Names.end())
return;
KPixmapInode pi = it.data();
m_Names.remove(it);
// Remove and disown the selection
SelectionIterator it2 = m_Selections.find(pi.selection);
assert(it2 != m_Selections.end());
m_Selections.remove(it2);
XSetSelectionOwner(qt_xdisplay(), pi.selection, None, CurrentTime);
// Decrease refcount on data
DataIterator it3 = m_Data.find(pi.handle);
assert(it3 != m_Data.end());
it3.data().refcount--;
if (!it3.data().refcount && !it3.data().usecount) {
delete it3.data().pixmap;
m_Data.remove(it3);
}
}
kdesktop'KPixmapServer::list() (./kdebase/kdesktop/pixmapserver.cc:117)
QStringList KPixmapServer::list()
{
QStringList lst;
NameIterator it;
for (it=m_Names.begin(); it!=m_Names.end(); it++)
lst += it.key();
return lst;
}
kdesktop'KPixmapServer::setOwner() (./kdebase/kdesktop/pixmapserver.cc:127)
void KPixmapServer::setOwner(QString name)
{
NameIterator it = m_Names.find(name);
if (it == m_Names.end())
return;
XSetSelectionOwner(qt_xdisplay(), it.data().selection, winId(), CurrentTime);
}
kdesktop'KPixmapServer::x11Event() (./kdebase/kdesktop/pixmapserver.cc:137)
bool KPixmapServer::x11Event(XEvent *event)
{
// Handle SelectionRequest events by which a X client can request a
// shared pixmap.
if (event->type == SelectionRequest) {
XSelectionRequestEvent *ev = &event->xselectionrequest;
// Build negative reply
XEvent reply;
reply.type = SelectionNotify;
reply.xselection.display = qt_xdisplay();
reply.xselection.requestor = ev->requestor;
reply.xselection.selection = ev->selection;
reply.xselection.target = pixmap;
reply.xselection.property = None;
reply.xselection.time = ev->time;
// Check if we know about this selection
Atom sel = ev->selection;
SelectionIterator it = m_Selections.find(sel);
if (it == m_Selections.end())
return false;
KSelectionInode si = it.data();
// Only convert to pixmap
if (ev->target != pixmap) {
XSendEvent(qt_xdisplay(), ev->requestor, false, 0, &reply);
return true;
}
// Check if there is no transaction in progress to the same property
if (m_Active.contains(ev->property)) {
XSendEvent(qt_xdisplay(), ev->requestor, false, 0, &reply);
return true;
}
// Check if the selection was not deleted
DataIterator it2 = m_Data.find(si.handle);
if (it2 == m_Data.end()) {
XSendEvent(qt_xdisplay(), ev->requestor, false, 0, &reply);
return true;
}
qDebug("PixmapServer: request for pixmap %s", si.name.latin1());
// All OK: pass the pixmap handle.
XChangeProperty(qt_xdisplay(), ev->requestor, ev->property, pixmap,
32, PropModeReplace, (unsigned char *) &si.handle, 1);
it2.data().usecount++;
m_Active[ev->property] = si.handle;
// Request PropertyNotify events for the target window
// XXX: The target window better not be handled by us!
XSelectInput(qt_xdisplay(), ev->requestor, PropertyChangeMask);
// Acknowledge to the client and return
reply.xselection.property = ev->property;
XSendEvent(qt_xdisplay(), ev->requestor, false, 0, &reply);
return true;
}
// ICCCM says that the target property is to be deleted by the
// requestor. We are notified of this by a PropertyNotify. Only then, we
// can actually delete the pixmap if it was removed.
if (event->type == PropertyNotify) {
XPropertyEvent *ev = &event->xproperty;
AtomIterator it = m_Active.find(ev->atom);
if (it == m_Active.end())
return false;
HANDLE handle = it.data();
m_Active.remove(it);
DataIterator it2 = m_Data.find(handle);
assert(it2 != m_Data.end());
it2.data().usecount--;
if (!it2.data().usecount && !it2.data().refcount) {
delete it2.data().pixmap;
m_Data.remove(it2);
}
return true;
}
// Handle SelectionClear events.
if (event->type == SelectionClear) {
XSelectionClearEvent *ev = &event->xselectionclear;
SelectionIterator it = m_Selections.find(ev->selection);
if (it == m_Selections.end())
return false;
emit selectionCleared(it.data().name);
return true;
}
// Process further
return false;
}