[rkward-cvs] SF.net SVN: rkward: [937] trunk/rkward/rkward

tfry at users.sourceforge.net tfry at users.sourceforge.net
Sun Nov 26 16:04:11 UTC 2006


Revision: 937
          http://svn.sourceforge.net/rkward/?rev=937&view=rev
Author:   tfry
Date:     2006-11-26 08:04:11 -0800 (Sun, 26 Nov 2006)

Log Message:
-----------
First proof of concept implementation of R X11 window catching

Modified Paths:
--------------
    trunk/rkward/rkward/Makefile.am
    trunk/rkward/rkward/main.cpp
    trunk/rkward/rkward/rbackend/rembedinternal.cpp
    trunk/rkward/rkward/rbackend/rembedinternal.h
    trunk/rkward/rkward/rbackend/rinterface.cpp
    trunk/rkward/rkward/rbackend/rkwindowcatcher.cpp
    trunk/rkward/rkward/rbackend/rkwindowcatcher.h
    trunk/rkward/rkward/rbackend/rpackages/rkward/R/internal.R
    trunk/rkward/rkward/rbackend/rthread.cpp

Added Paths:
-----------
    trunk/rkward/rkward/rkwardapplication.cpp
    trunk/rkward/rkward/rkwardapplication.h

Modified: trunk/rkward/rkward/Makefile.am
===================================================================
--- trunk/rkward/rkward/Makefile.am	2006-11-26 13:38:54 UTC (rev 936)
+++ trunk/rkward/rkward/Makefile.am	2006-11-26 16:04:11 UTC (rev 937)
@@ -23,11 +23,11 @@
 
 rkward_bin_SOURCES = rkwatch.cpp rkward.cpp main.cpp \
 	rkglobals.cpp robjectbrowser.cpp robjectviewer.cpp \
-	khelpdlg.cpp rkconsole.cpp rkward.skel
+	khelpdlg.cpp rkconsole.cpp rkward.skel rkwardapplication.cpp
 
 noinst_HEADERS = rkwatch.h rkward.h debug.h \
 	rkglobals.h robjectbrowser.h robjectviewer.h \
-	khelpdlg.h rkconsole.h
+	khelpdlg.h rkconsole.h rkwardapplication.h
 
 rkward_bin_LDADD = $(top_builddir)/rkward/windows/libwindows.a \
 	$(top_builddir)/rkward/agents/libagents.a $(top_builddir)/rkward/dialogs/libdialogs.a \

Modified: trunk/rkward/rkward/main.cpp
===================================================================
--- trunk/rkward/rkward/main.cpp	2006-11-26 13:38:54 UTC (rev 936)
+++ trunk/rkward/rkward/main.cpp	2006-11-26 16:04:11 UTC (rev 937)
@@ -50,10 +50,6 @@
 **
 */
 
-
-
-
-
 #include <kcmdlineargs.h>
 #include <kaboutdata.h>
 #include <klocale.h>
@@ -61,6 +57,8 @@
 #include <qstring.h>
 
 #include "rkward.h"
+#include "rkwardapplication.h"
+
 #include "config.h"
 
 #include "debug.h"
@@ -103,7 +101,7 @@
 	KCmdLineArgs::init( argc, argv, &aboutData );
 	KCmdLineArgs::addCmdLineOptions( options ); // Add our own options.
 	
-	KApplication app;
+	RKWardApplication app;
 	if (app.isRestored ()) {
 		RESTORE(RKWardMainWindow);	// well, whatever this is supposed to do -> TODO
 	} else {

Modified: trunk/rkward/rkward/rbackend/rembedinternal.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rembedinternal.cpp	2006-11-26 13:38:54 UTC (rev 936)
+++ trunk/rkward/rkward/rbackend/rembedinternal.cpp	2006-11-26 16:04:11 UTC (rev 937)
@@ -224,7 +224,6 @@
 // ############## R Standard callback overrides END ####################
 
 char *REmbedInternal::na_char_internal = new char;
-bool REmbedInternal::x11events_disabled = false;
 
 REmbedInternal::REmbedInternal () {
 }
@@ -289,8 +288,6 @@
 void REmbedInternal::processX11Events () {
 /* what we do here is walk the list of objects, that have told R, they're listening for events.
 We figure out which ones look for X11-events and tell those to do their stuff (regardless of whether events actually occurred) */
-	if (x11events_disabled) return;
-
 	extern InputHandler *R_InputHandlers;
 	InputHandler *handler = R_InputHandlers;
 	while (handler) {

Modified: trunk/rkward/rkward/rbackend/rembedinternal.h
===================================================================
--- trunk/rkward/rkward/rbackend/rembedinternal.h	2006-11-26 13:38:54 UTC (rev 936)
+++ trunk/rkward/rkward/rbackend/rembedinternal.h	2006-11-26 16:04:11 UTC (rev 937)
@@ -154,7 +154,6 @@
 /** only one instance of this class may be around. This pointer keeps the reference to it, for interfacing to from C to C++ */
 	static REmbedInternal *this_pointer;
 	static char *na_char_internal;
-	static bool x11events_disabled;
 
 /** Flags used to classify output. */
 //	static bool output_is_warning;

Modified: trunk/rkward/rkward/rbackend/rinterface.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rinterface.cpp	2006-11-26 13:38:54 UTC (rev 936)
+++ trunk/rkward/rkward/rbackend/rinterface.cpp	2006-11-26 16:04:11 UTC (rev 937)
@@ -332,14 +332,20 @@
 		// if we're still alive, quitting was cancelled
 		issueCommand (".rk.rkreply <- \"Quitting was cancelled\"", RCommand::App | RCommand::Sync, QString::null, 0, 0, request->in_chain);
 #ifndef DISABLE_RKWINDOWCATCHER
- // does not work, yet :-( R crashes.
-	} else if (call == "catchWindow") {
+ 	} else if (call == "startOpenX11") {
 		// TODO: error checking/handling (wrong parameter count/type)
-		if (request->call_length >= 3) {
+		if (request->call_length >= 2) {
 			MUTEX_LOCK;
-			window_catcher->catchWindow (request->call[1], QString (request->call[2]).toInt ());
+			window_catcher->start (QString (request->call[1]).toInt ());
 			MUTEX_UNLOCK;
 		}
+ 	} else if (call == "endOpenX11") {
+		// TODO: error checking/handling (wrong parameter count/type)
+		if (request->call_length >= 2) {
+			MUTEX_LOCK;
+			window_catcher->stop (QString (request->call[1]).toInt ());
+			MUTEX_UNLOCK;
+		}
 #endif // DISABLE_RKWINDOWCATCHER
 	} else {
 		issueCommand (".rk.rkreply <- \"Unrecognized call '" + call + "'. Ignoring\"", RCommand::App | RCommand::Sync, QString::null, 0, 0, request->in_chain);

Modified: trunk/rkward/rkward/rbackend/rkwindowcatcher.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rkwindowcatcher.cpp	2006-11-26 13:38:54 UTC (rev 936)
+++ trunk/rkward/rkward/rbackend/rkwindowcatcher.cpp	2006-11-26 16:04:11 UTC (rev 937)
@@ -19,116 +19,55 @@
 
 #ifndef DISABLE_RKWINDOWCATCHER
 
-#include <kapplication.h>
 #include <qlayout.h>
 #include <qvbox.h>
 
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <kwin.h>
+
 #include <X11/X.h>
 #include <X11/Xlib.h>
 
+#include "../rkwardapplication.h"
 #include "../windows/qxembedcopy.h"
 #include "../debug.h"
 
-static int get_parent(WId winid, Window *out_parent)
-{
-    Window root, *children=0;
-    unsigned int nchildren;
-    int st = XQueryTree(qt_xdisplay(), winid, &root, out_parent, &children, &nchildren);
-    if (st && children) 
-        XFree(children);
-    return st;
-}
-
-// function below is a slightly adapted copy from http://lists.trolltech.com/qt-interest/1999-10/msg00224.html
-// this could be tweaked a little more, since for instance we know we're only looking for toplevel windows
-Window Window_With_Name (Display *dp, Window top, const char *name, int level=10) {
-    if (level < 0) return (0);
-    Window *children, dummy;
-    unsigned int nchildren;
-    int i;
-    Window w=0;
-    char *window_name;
-
-    if (XFetchName(dp, top, &window_name)) {
-		if (QString (window_name).startsWith (name)) {
-			Window parent=0;
-			if (get_parent (top, &parent)) {
-				XFetchName (dp, parent, &window_name);
-				qDebug ("parent %x, name: %s", parent, window_name);
-			}
-			return (top);
-		}
-	}
-
-    if (!XQueryTree(dp, top, &dummy, &dummy, &children, &nchildren))
-        return(0);
-
-    for (i=0; i<nchildren; i++) {
-        w = Window_With_Name(dp, children[i], name, level-1);
-        if (w)
-            break;
-    }
-    if (children) XFree ((char *)children);
-    return(w);
-}
-
-
 RKWindowCatcher::RKWindowCatcher (QWidget *parent) : QWidget (parent) {
 }
 
 RKWindowCatcher::~RKWindowCatcher () {
 }
 
-void RKWindowCatcher::windowLost () {
-	qDebug ("lost");
-	deleteLater ();
-}
-
-void RKWindowCatcher::catchWindow (const QString &title_start, int corresponding_device_number) {
-	Window w = Window_With_Name (qt_xdisplay (), DefaultRootWindow (qt_xdisplay()), title_start.latin1 ());
-	qDebug ("Window id is: %x (root: %x)", w, DefaultRootWindow (qt_xdisplay()));
-	if (w) {
-		QWidget *test1 = new QWidget (0);
-		test1->setCaption ("1");
-		QVBoxLayout *layout = new QVBoxLayout (test1);
-		QXEmbedCopy *capture = new QXEmbedCopy (test1, 0, Qt::WDestructiveClose);
-		connect (capture, SIGNAL (embeddedWindowDestroyed ()), this, SLOT (windowLost ()));
-		capture->setProtocol (QXEmbedCopy::XPLAIN);
-		capture->embed (w);
-		capture->show ();
-		layout->addWidget (capture);
-		test1->show ();
-		QVBox *test2 = new QVBox (0);
-		test2->setCaption ("2");
-		test1->reparent (test2, QPoint (0, 0), true);
-		test2->show ();
-	}
-}
-
 void RKWindowCatcher::start (int prev_cur_device) {
 	RK_DO (qDebug ("Window Catcher activated"), RBACKEND, DL_DEBUG);
 
+	RKWardApplication::getApp ()->startWindowCreationDetection ();
 	last_cur_device = prev_cur_device;
-	new_windows.clear ();
 }
 
 void RKWindowCatcher::stop (int new_cur_device) {
 	RK_DO (qDebug ("Window Catcher deactivated"), RBACKEND, DL_DEBUG);
-/*
+
 	if (new_cur_device != last_cur_device) {
-		QString dummy = "R Graphics: Device ";
-		//dummy.append (QString::number (new_cur_device));
-		//dummy.append (" ");
-		Window w = Window_With_Name (qt_xdisplay (), qApp->desktop ()->winId (), dummy.latin1 ());
+		WId w = RKWardApplication::getApp ()->endWindowCreationDetection ();
+
 		qDebug ("Window id is: %x", w);
 		if (w) {
-			QXEmbed *capture = new QXEmbed (); // (0, 0, Qt::WDestructiveClose);
-			capture->setProtocol (QXEmbed::XPLAIN);
+			QXEmbedCopy *capture = new QXEmbedCopy (0, 0, Qt::WDestructiveClose);
+			capture->setProtocol (QXEmbedCopy::XPLAIN);
+			connect (capture, SIGNAL (embeddedWindowDestroyed ()), capture, SLOT (deleteLater ()));
+
+			KWin::WindowInfo wininfo = KWin::windowInfo (w);
+			capture->setGeometry (wininfo.frameGeometry ());
 			capture->embed (w);
+
 			capture->show ();
+		} else {
+			KMessageBox::sorry (0, i18n ("You have created a new X11 device window in R. Usually, RKWard tries to detect such windows, to take control of them, and add a menu-bar to them. This time, however, RKWard failed to detect, which window was created, and so can not embed it.\nIf you created the window on a different screen or X11 display, that is to be expected. You might want to consider changing options(\"display\"), then.\nIf you can see the X11 window on the same screen as this message, then RKWard should do better. In this case, please contact us at rkward-devel at lists.sourceforge.net with details on your setup, so we can try to fix this in future versions of RKWard."), i18n ("Could not embed R X11 window"));
 		}
 	}
-	last_cur_device = new_cur_device; */
+	last_cur_device = new_cur_device;
 }
 
 #include "rkwindowcatcher.moc"

Modified: trunk/rkward/rkward/rbackend/rkwindowcatcher.h
===================================================================
--- trunk/rkward/rkward/rbackend/rkwindowcatcher.h	2006-11-26 13:38:54 UTC (rev 936)
+++ trunk/rkward/rkward/rbackend/rkwindowcatcher.h	2006-11-26 16:04:11 UTC (rev 937)
@@ -21,7 +21,6 @@
 //#define DISABLE_RKWINDOWCATCHER
 #ifndef DISABLE_RKWINDOWCATCHER
 
-#include <qvaluelist.h>
 #include <qwidget.h>
 
 /** This class will be used to find out, when R opens a new X11-device, find out the id of that device and embed it into a QWidget.
@@ -71,13 +70,14 @@
 	
 	void start (int prev_cur_device);
 	void stop (int new_cur_device);
-	void catchWindow (const QString &title_start, int corresponding_device_number);
-public slots:
-	void windowLost ();
 private:
 	int last_cur_device;
-	QValueList<WId> new_windows;
 };
 
+/*
+class RKCatchedX11Window : public RKMDIWindow {
+};
+*/
+
 #endif //DISABLE_RKWINDOWCATCHER
 #endif

Modified: trunk/rkward/rkward/rbackend/rpackages/rkward/R/internal.R
===================================================================
--- trunk/rkward/rkward/rbackend/rpackages/rkward/R/internal.R	2006-11-26 13:38:54 UTC (rev 936)
+++ trunk/rkward/rkward/rbackend/rpackages/rkward/R/internal.R	2006-11-26 16:04:11 UTC (rev 937)
@@ -139,18 +139,16 @@
 #	.Internal (.addCondHands (c ("message", "warning", "error"), list (function (m) { .Call ("rk.do.condition", c ("m", conditionMessage (m))) }, function (w) { .Call ("rk.do.condition", c ("w", conditionMessage (w))) }, function (e) { .Call ("rk.do.condition", c ("e", conditionMessage (e))) }), globalenv (), NULL, TRUE))
 #}
 
-".rk.catch.window" <- function (title_begin, corresponding_device) {
-	.rk.do.call ("catchWindow", c (as.character (title_begin), as.character (corresponding_device)))
+# overriding x11 to get informed, when a new x11 window is opened
+"x11" <- function (...) {
+	.rk.do.call ("startOpenX11", as.character (dev.cur ()));
+
+	grDevices::X11 (...)
+
+	.rk.do.call ("endOpenX11", as.character (dev.cur ()));
 }
 
-# overriding x11 to get informed, when a new x11 window is opened
-#"x11" <- function (...) {
-#	.rk.do.call ("startOpenX11", as.character (dev.cur ()));
-#
-#	base::X11 (...)
-#
-#	.rk.do.call ("endOpenX11", as.character (dev.cur ()));
-#}
+"X11" <- x11
 
 # these functions can be used to track assignments to R objects. The main interfaces are .rk.watch.symbol (k) and .rk.unwatch.symbol (k). This works by copying the symbol to a backup environment, removing it, and replacing it by an active binding to the backup location
 ".rk.watched.symbols" <- new.env ()

Modified: trunk/rkward/rkward/rbackend/rthread.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rthread.cpp	2006-11-26 13:38:54 UTC (rev 936)
+++ trunk/rkward/rkward/rbackend/rthread.cpp	2006-11-26 16:04:11 UTC (rev 937)
@@ -323,10 +323,6 @@
 			return;
 		}
 	}
-	if (call[0] == "catchWindow") {
-		// maybe this is not needed after all, put requires some testing. For now, we disable all R X11 updates while capturing the window.
-		x11events_disabled = true;
-	}
 
 	RCommand *prev_command = current_command;
 	REvalRequest *request = new REvalRequest;
@@ -367,7 +363,6 @@
 		msleep (10);
 	}
 
-	x11events_disabled = false;
 	delete reply_stack;
 }
 

Added: trunk/rkward/rkward/rkwardapplication.cpp
===================================================================
--- trunk/rkward/rkward/rkwardapplication.cpp	                        (rev 0)
+++ trunk/rkward/rkward/rkwardapplication.cpp	2006-11-26 16:04:11 UTC (rev 937)
@@ -0,0 +1,86 @@
+/***************************************************************************
+                          rkwardapplication  -  description
+                             -------------------
+    begin                : Sun Nov 26 2006
+    copyright            : (C) 2006 by Thomas Friedrichsmeier
+    email                : tfry at users.sourceforge.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 "rkwardapplication.h"
+
+#include <X11/X.h>
+#include <X11/Xlib.h>
+
+#include <kwin.h>
+#include <netwm_def.h>
+
+#include "debug.h"
+
+//static
+RKWardApplication *RKWardApplication::rkapp = 0;
+
+RKWardApplication::RKWardApplication () : KApplication () {
+	RK_TRACE (APP);
+	RK_ASSERT (!rkapp);
+
+	rkapp = this;
+	detect_x11_creations = false;
+}
+
+RKWardApplication::~RKWardApplication () {
+	RK_TRACE (APP);
+}
+
+RKWardApplication *RKWardApplication::getApp () {
+	RK_TRACE (APP);
+	RK_ASSERT (rkapp == KApplication::kApplication ());
+	return rkapp;
+}
+
+void RKWardApplication::startWindowCreationDetection () {
+	RK_TRACE (APP);
+	RK_ASSERT (!detect_x11_creations);
+
+	created_window = 0;
+	detect_x11_creations = true;
+
+	XSelectInput (qt_xdisplay (), qt_xrootwin (), SubstructureNotifyMask);
+}
+
+WId RKWardApplication::endWindowCreationDetection () {
+	RK_TRACE (APP);
+	RK_ASSERT (detect_x11_creations);
+
+	detect_x11_creations = false;
+	XSelectInput (qt_xdisplay (), qt_xrootwin (), 0);
+	return created_window;
+}
+
+bool RKWardApplication::x11EventFilter (XEvent *e) {
+	if (detect_x11_creations) {
+		if (e->type == CreateNotify) {
+			if (e->xcreatewindow.parent == qt_xrootwin ()) {
+				KWin::WindowInfo info = KWin::windowInfo (e->xcreatewindow.window);
+				if ((info.windowType (0xFFFF) != 0) && (!info.name ().isEmpty ())) {
+					RK_ASSERT (!created_window);
+					created_window = e->xcreatewindow.window;
+					return true;
+				}
+			} else {
+				RK_ASSERT (false);
+			}
+		}
+	}
+
+	return KApplication::x11EventFilter (e);
+}
+

Added: trunk/rkward/rkward/rkwardapplication.h
===================================================================
--- trunk/rkward/rkward/rkwardapplication.h	                        (rev 0)
+++ trunk/rkward/rkward/rkwardapplication.h	2006-11-26 16:04:11 UTC (rev 937)
@@ -0,0 +1,44 @@
+/***************************************************************************
+                          rkwardapplication  -  description
+                             -------------------
+    begin                : Sun Nov 26 2006
+    copyright            : (C) 2006 by Thomas Friedrichsmeier
+    email                : tfry at users.sourceforge.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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#ifndef RKWARDAPPLICATION_H
+#define RKWARDAPPLICATION_H
+
+#include <kapplication.h>
+
+/** The purpose of subclassing KApplication as RKWardApplication, is to obtain raw access to X11 events. This is needed to detect the creation of new toplevel windows (R X11 windows). */
+
+class RKWardApplication : public KApplication {
+public:
+	RKWardApplication ();
+	~RKWardApplication ();
+
+	/** like KApplication::kApplication () (and actually, this should always return the same pointer), but without the need to cast */
+	static RKWardApplication *getApp ();
+
+	/** reimplemented from KApplication to look for CreateNotify events */
+	bool x11EventFilter (XEvent *e);
+
+	void startWindowCreationDetection ();
+	WId endWindowCreationDetection ();
+private:
+	static RKWardApplication *rkapp;
+	bool detect_x11_creations;
+	WId created_window;
+};
+
+#endif


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the rkward-tracker mailing list