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;
}