summaryrefslogtreecommitdiffstats
path: root/kdesktop/pixmapserver.cc
diff options
context:
space:
mode:
Diffstat (limited to 'kdesktop/pixmapserver.cc')
-rw-r--r--kdesktop/pixmapserver.cc254
1 files changed, 254 insertions, 0 deletions
diff --git a/kdesktop/pixmapserver.cc b/kdesktop/pixmapserver.cc
new file mode 100644
index 000000000..ba66ef966
--- /dev/null
+++ b/kdesktop/pixmapserver.cc
@@ -0,0 +1,254 @@
+/* vi: ts=8 sts=4 sw=4
+ *
+ * This file is part of the KDE project, module kdesktop.
+ * Copyright (C) 1999 Geert Jansen <g.t.jansen@stud.tue.nl>
+ *
+ * You can Freely distribute this program under the GNU General Public
+ * License. See the file "COPYING" for the exact licensing terms.
+ *
+ *
+ * Shared pixmap server for KDE.
+ *
+ * 5 Dec 99: Geert Jansen:
+ *
+ * Initial implementation using the X11 selection mechanism.
+ */
+
+#include <assert.h>
+
+
+#include <kapplication.h>
+#include <kdebug.h>
+
+#include <X11/X.h>
+#include <X11/Xlib.h>
+
+#include "pixmapserver.h"
+
+#ifndef None
+#define None 0L
+#endif
+
+#ifdef __GNUC__
+#define ID __PRETTY_FUNCTION__ << ": "
+#else
+#define ID "KPixmapServer: "
+#endif
+
+
+KPixmapServer::KPixmapServer()
+ : QWidget(0L, "shpixmap comm window")
+{
+ kapp->installX11EventFilter(this);
+ pixmap = XInternAtom(qt_xdisplay(), "PIXMAP", false);
+}
+
+
+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;
+}
+
+
+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);
+}
+
+
+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);
+ }
+}
+
+
+QStringList KPixmapServer::list()
+{
+ QStringList lst;
+ NameIterator it;
+ for (it=m_Names.begin(); it!=m_Names.end(); it++)
+ lst += it.key();
+ return lst;
+}
+
+
+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);
+}
+
+
+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)
+ {
+ kdDebug(1204) << ID << "illegal target\n";
+ 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))
+ {
+ kdDebug(1204) << ID << "selection is busy.\n";
+ 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())
+ {
+ kdDebug(1204) << ID << "selection has been deleted.\n";
+ XSendEvent(qt_xdisplay(), ev->requestor, false, 0, &reply);
+ return true;
+ }
+
+ kdDebug(1204) << ID << "request for " << si.name << "\n";
+
+ // 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;
+}
+
+#include "pixmapserver.moc"