summaryrefslogtreecommitdiffstats
path: root/nsplugins/viewer
diff options
context:
space:
mode:
Diffstat (limited to 'nsplugins/viewer')
-rw-r--r--nsplugins/viewer/Makefile.am11
-rw-r--r--nsplugins/viewer/NSPluginClassIface.h83
-rw-r--r--nsplugins/viewer/glibevents.cpp43
-rw-r--r--nsplugins/viewer/glibevents.h41
-rw-r--r--nsplugins/viewer/kxt.cpp629
-rw-r--r--nsplugins/viewer/kxt.h99
-rw-r--r--nsplugins/viewer/nsplugin.cpp1980
-rw-r--r--nsplugins/viewer/nsplugin.h339
-rw-r--r--nsplugins/viewer/qxteventloop.cpp472
-rw-r--r--nsplugins/viewer/qxteventloop.h80
-rw-r--r--nsplugins/viewer/resolve.h46
-rw-r--r--nsplugins/viewer/viewer.cpp312
12 files changed, 4135 insertions, 0 deletions
diff --git a/nsplugins/viewer/Makefile.am b/nsplugins/viewer/Makefile.am
new file mode 100644
index 000000000..12a0301b9
--- /dev/null
+++ b/nsplugins/viewer/Makefile.am
@@ -0,0 +1,11 @@
+INCLUDES = -I$(top_srcdir)/nsplugins -I$(top_builddir)/nsplugins $(all_includes) `pkg-config --cflags glib-2.0`
+METASOURCES = AUTO
+
+bin_PROGRAMS = nspluginviewer
+
+nspluginviewer_SOURCES = NSPluginCallbackIface.stub NSPluginClassIface.skel \
+ nsplugin.cpp viewer.cpp kxt.cpp qxteventloop.cpp glibevents.cpp
+nspluginviewer_LDFLAGS = $(all_libraries) $(KDE_RPATH) -export-dynamic `pkg-config --libs glib-2.0`
+nspluginviewer_LDADD = $(LIB_KIO) $(LIB_KPARTS) -lXt
+
+NSPluginCallbackIface_DIR = $(srcdir)/..
diff --git a/nsplugins/viewer/NSPluginClassIface.h b/nsplugins/viewer/NSPluginClassIface.h
new file mode 100644
index 000000000..20fd6ed03
--- /dev/null
+++ b/nsplugins/viewer/NSPluginClassIface.h
@@ -0,0 +1,83 @@
+/*
+
+ Copyright (c) 2000 Matthias Hoelzer-Kluepfel <[email protected]>
+ Stefan Schimanski <[email protected]>
+
+ 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.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+*/
+
+
+
+#ifndef __NSPluginClassIface_h__
+#define __NSPluginClassIface_h__
+
+
+#include <qstringlist.h>
+#include <qcstring.h>
+#include <dcopobject.h>
+#include <dcopref.h>
+
+
+class NSPluginViewerIface : virtual public DCOPObject
+{
+ K_DCOP
+
+k_dcop:
+ virtual void shutdown() = 0;
+ virtual DCOPRef newClass(QString plugin) = 0;
+};
+
+
+class NSPluginClassIface : virtual public DCOPObject
+{
+ K_DCOP
+
+k_dcop:
+
+ virtual DCOPRef newInstance(QString url, QString mimeType, Q_INT8 embed,
+ QStringList argn, QStringList argv,
+ QString appId, QString callbackId, Q_INT8 reload,
+ Q_INT8 doPost, QByteArray postData, Q_UINT32 xembed) = 0;
+ virtual QString getMIMEDescription() = 0;
+
+};
+
+
+class NSPluginInstanceIface : virtual public DCOPObject
+{
+ K_DCOP
+
+k_dcop:
+
+ virtual void shutdown() = 0;
+
+ virtual int winId() = 0;
+
+ virtual int setWindow(Q_INT8 remove=0) = 0;
+
+ virtual void resizePlugin(Q_INT32 w, Q_INT32 h) = 0;
+
+ virtual void javascriptResult(Q_INT32 id, QString result) = 0;
+
+ virtual void displayPlugin() = 0;
+
+ virtual void gotFocusIn() = 0;
+ virtual void gotFocusOut() = 0;
+};
+
+
+#endif
+
diff --git a/nsplugins/viewer/glibevents.cpp b/nsplugins/viewer/glibevents.cpp
new file mode 100644
index 000000000..b1012675b
--- /dev/null
+++ b/nsplugins/viewer/glibevents.cpp
@@ -0,0 +1,43 @@
+/*
+ Copyright (c) 2007 Lubos Lunak <[email protected]>
+
+ 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.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+*/
+
+#include "glibevents.h"
+
+#include <qapplication.h>
+
+GlibEvents::GlibEvents()
+ {
+ g_main_context_ref( g_main_context_default());
+ connect( &timer, SIGNAL( timeout()), SLOT( process()));
+ // TODO Poll for now
+ timer.start( 10 );
+ }
+
+GlibEvents::~GlibEvents()
+ {
+ g_main_context_unref( g_main_context_default());
+ }
+
+void GlibEvents::process()
+ {
+ while( g_main_context_pending( g_main_context_default()))
+ g_main_context_iteration( g_main_context_default(), false );
+ }
+
+#include "glibevents.moc"
diff --git a/nsplugins/viewer/glibevents.h b/nsplugins/viewer/glibevents.h
new file mode 100644
index 000000000..8a890807b
--- /dev/null
+++ b/nsplugins/viewer/glibevents.h
@@ -0,0 +1,41 @@
+/*
+ Copyright (c) 2007 Lubos Lunak <[email protected]>
+
+ 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.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+*/
+
+#ifndef GLIBEVENTS_H
+#define GLIBEVENTS_H
+
+#include <qwidget.h>
+#include <qtimer.h>
+
+#include <glib.h>
+
+class GlibEvents
+ : public QWidget
+ {
+ Q_OBJECT
+ public:
+ GlibEvents();
+ virtual ~GlibEvents();
+ private slots:
+ void process();
+ private:
+ QTimer timer;
+ };
+
+#endif
diff --git a/nsplugins/viewer/kxt.cpp b/nsplugins/viewer/kxt.cpp
new file mode 100644
index 000000000..7f2e04b54
--- /dev/null
+++ b/nsplugins/viewer/kxt.cpp
@@ -0,0 +1,629 @@
+/*
+
+ kxt.cpp - Xt enabled Qt classed (derived from Qt Extension QXt)
+
+ Copyright (c) 2000,2001 Stefan Schimanski <[email protected]>
+
+ 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.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+*/
+
+/****************************************************************************
+**
+** Implementation of Qt extension classes for Xt/Motif support.
+**
+** Created : 980107
+**
+** Copyright (C) 1992-2000 Troll Tech AS. All rights reserved.
+**
+** This file is part of the Qt GUI Toolkit.
+**
+** This file may be distributed under the terms of the Q Public License
+** as defined by Troll Tech AS of Norway and appearing in the file
+** LICENSE.QPL included in the packaging of this file.
+**
+** Licensees holding valid Qt Professional Edition licenses may use this
+** file in accordance with the Qt Professional Edition License Agreement
+** provided with the Qt Professional Edition.
+**
+** See http://www.trolltech.com/pricing.html or email [email protected] for
+** information about the Professional Edition licensing, or see
+** http://www.trolltech.com/qpl/ for QPL licensing information.
+**
+*****************************************************************************/
+
+#include <qglobal.h>
+#if QT_VERSION < 0x030100
+
+#include <kapplication.h>
+#include <qwidget.h>
+#include <qobjectlist.h>
+#include <qwidgetlist.h>
+#include <kdebug.h>
+#include <qtimer.h>
+
+#include "kxt.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <limits.h>
+
+#include <X11/Xlib.h>
+#include <X11/Intrinsic.h>
+#include <X11/IntrinsicP.h> // for XtCreateWindow
+#include <X11/Shell.h>
+#include <X11/StringDefs.h>
+#include <X11/Xutil.h>
+#include <X11/Xos.h>
+
+const int XKeyPress = KeyPress;
+const int XKeyRelease = KeyRelease;
+#undef KeyPress
+#undef KeyRelease
+
+extern Atom qt_wm_state;
+
+//#define HAVE_MOTIF
+#ifdef HAVE_MOTIF
+#include <Xm/Xm.h>
+#endif
+
+typedef void (*SameAsXtTimerCallbackProc)(void*,void*);
+typedef void (*IntervalSetter)(int);
+typedef void (*ForeignEventProc)(XEvent*);
+
+extern XtEventDispatchProc
+ qt_np_cascade_event_handler[LASTEvent]; // defined in qnpsupport.cpp
+void qt_reset_color_avail(); // defined in qcolor_x11.cpp
+int qt_activate_timers(); // defined in qapplication_x11.cpp
+timeval *qt_wait_timer(); // defined in qapplication_x11.cpp
+void qt_x11SendPostedEvents(); // defined in qapplication_x11.cpp
+int qt_event_handler( XEvent* event ); // defined in qnpsupport.cpp
+extern int qt_np_count; // defined in qnpsupport.cpp
+void qt_np_timeout( void* p, void* id ); // defined in qnpsupport.cpp
+void qt_np_add_timeoutcb(
+ SameAsXtTimerCallbackProc cb ); // defined in qnpsupport.cpp
+void qt_np_remove_timeoutcb(
+ SameAsXtTimerCallbackProc cb ); // defined in qnpsupport.cpp
+void qt_np_add_timer_setter(
+ IntervalSetter is ); // defined in qnpsupport.cpp
+void qt_np_remove_timer_setter(
+ IntervalSetter is ); // defined in qnpsupport.cpp
+extern XtIntervalId qt_np_timerid; // defined in qnpsupport.cpp
+extern void (*qt_np_leave_cb)
+ (XLeaveWindowEvent*); // defined in qnpsupport.cpp
+void qt_np_add_event_proc(
+ ForeignEventProc fep ); // defined in qnpsupport.cpp
+void qt_np_remove_event_proc(
+ ForeignEventProc fep ); // defined in qnpsupport.cpp
+
+
+typedef struct {
+ int empty;
+} QWidgetClassPart;
+
+typedef struct _QWidgetClassRec {
+ CoreClassPart core_class;
+ QWidgetClassPart qwidget_class;
+} QWidgetClassRec;
+
+//static QWidgetClassRec qwidgetClassRec;
+
+typedef struct {
+ /* resources */
+ /* (none) */
+ /* private state */
+ KXtWidget* qxtwidget;
+} QWidgetPart;
+
+typedef struct _QWidgetRec {
+ CorePart core;
+ QWidgetPart qwidget;
+} QWidgetRec;
+
+
+static
+void reparentChildrenOf(QWidget* parent)
+{
+
+ if ( !parent->children() )
+ return; // nothing to do
+
+ for ( QObjectListIt it( *parent->children() ); it.current(); ++it ) {
+ if ( it.current()->isWidgetType() ) {
+ QWidget* widget = (QWidget*)it.current();
+ XReparentWindow( qt_xdisplay(),
+ widget->winId(),
+ parent->winId(),
+ widget->x(),
+ widget->y() );
+ if ( widget->isVisible() )
+ XMapWindow( qt_xdisplay(), widget->winId() );
+ }
+ }
+
+}
+
+void qwidget_realize(
+ Widget widget,
+ XtValueMask* mask,
+ XSetWindowAttributes* attributes
+ )
+{
+ widgetClassRec.core_class.realize(widget, mask, attributes);
+ KXtWidget* qxtw = ((QWidgetRec*)widget)->qwidget.qxtwidget;
+ if (XtWindow(widget) != qxtw->winId()) {
+ qxtw->create(XtWindow(widget), FALSE, FALSE);
+ reparentChildrenOf(qxtw);
+ }
+ qxtw->show();
+ XMapWindow( qt_xdisplay(), qxtw->winId() );
+}
+
+static
+QWidgetClassRec qwidgetClassRec = {
+ { /* core fields */
+ /* superclass */ (WidgetClass) &widgetClassRec,
+ /* class_name */ (char*)"QWidget",
+ /* widget_size */ sizeof(QWidgetRec),
+ /* class_initialize */ 0,
+ /* class_part_initialize */ 0,
+ /* class_inited */ FALSE,
+ /* initialize */ 0,
+ /* initialize_hook */ 0,
+ /* realize */ qwidget_realize,
+ /* actions */ 0,
+ /* num_actions */ 0,
+ /* resources */ 0,
+ /* num_resources */ 0,
+ /* xrm_class */ NULLQUARK,
+ /* compress_motion */ TRUE,
+ /* compress_exposure */ TRUE,
+ /* compress_enterleave */ TRUE,
+ /* visible_interest */ FALSE,
+ /* destroy */ 0,
+ /* resize */ XtInheritResize,
+ /* expose */ XtInheritExpose,
+ /* set_values */ 0,
+ /* set_values_hook */ 0,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ 0,
+ /* accept_focus */ XtInheritAcceptFocus,
+ /* version */ XtVersion,
+ /* callback_private */ 0,
+ /* tm_table */ XtInheritTranslations,
+ /* query_geometry */ XtInheritQueryGeometry,
+ /* display_accelerator */ XtInheritDisplayAccelerator,
+ /* extension */ 0
+ },
+ { /* qwidget fields */
+ /* empty */ 0
+ }
+};
+static WidgetClass qWidgetClass = (WidgetClass)&qwidgetClassRec;
+
+static bool filters_installed = FALSE;
+static KXtApplication* qxtapp = 0;
+static XtAppContext appcon;
+
+static
+Boolean qt_event_handler_wrapper( XEvent* event )
+{
+ return (Boolean)qt_event_handler( event );
+}
+
+static
+void installXtEventFilters()
+{
+ if (filters_installed) return;
+ // Get Xt out of our face - install filter on every event type
+ for (int et=2; et < LASTEvent; et++) {
+ qt_np_cascade_event_handler[et] = XtSetEventDispatcher(
+ qt_xdisplay(), et, qt_event_handler_wrapper );
+ }
+ filters_installed = TRUE;
+}
+
+static
+void removeXtEventFilters()
+{
+ if (!filters_installed) return;
+ // We aren't needed any more... slink back into the shadows.
+ for (int et=2; et < LASTEvent; et++) {
+ XtSetEventDispatcher(
+ qt_xdisplay(), et, qt_np_cascade_event_handler[et] );
+ }
+ filters_installed = FALSE;
+}
+
+// When we are in an event loop of QApplication rather than the browser's
+// event loop (eg. for a modal dialog), we still send events to Xt.
+static
+void np_event_proc( XEvent* e )
+{
+ Widget xtw = XtWindowToWidget( e->xany.display, e->xany.window );
+ if ( xtw && qApp->loopLevel() > 0 ) {
+ // Allow Xt to process the event
+ qt_np_cascade_event_handler[e->type]( e );
+ }
+}
+
+static void np_set_timer( int interval )
+{
+ // Ensure we only have one timeout in progress - QApplication is
+ // computing the one amount of time we need to wait.
+ if ( qt_np_timerid ) {
+ XtRemoveTimeOut( qt_np_timerid );
+ }
+ qt_np_timerid = XtAppAddTimeOut(appcon, interval,
+ (XtTimerCallbackProc)qt_np_timeout, 0);
+}
+
+static void np_do_timers( void*, void* )
+{
+ qt_np_timerid = 0; // It's us, and we just expired, that's why we are here.
+
+ qt_activate_timers();
+
+ timeval *tm = qt_wait_timer();
+
+ if (tm) {
+ int interval = QMIN(tm->tv_sec,INT_MAX/1000)*1000 + tm->tv_usec/1000;
+ np_set_timer( interval );
+ }
+ qxtapp->sendPostedEvents();
+}
+
+/*!
+ \class KXtApplication qxt.h
+ \brief Allows mixing of Xt/Motif and Qt widgets.
+
+ \extension Xt/Motif
+
+ The KXtApplication and KXtWidget classes allow old Xt or Motif widgets
+ to be used in new Qt applications. They also allow Qt widgets to
+ be used in primarily Xt/Motif applications. The facility is intended
+ to aid migration from Xt/Motif to the more comfortable Qt system.
+*/
+
+static bool my_xt;
+
+/*!
+ Constructs a QApplication and initializes the Xt toolkit.
+ The \a appclass, \a options, \a num_options, and \a resources
+ arguments are passed on to XtAppSetFallbackResources and
+ XtDisplayInitialize.
+
+ Use this constructor when writing a new Qt application which
+ needs to use some existing Xt/Motif widgets.
+*/
+KXtApplication::KXtApplication(int& argc, char** argv,
+ const QCString& rAppName, bool allowStyles, bool GUIenabled,
+ XrmOptionDescRec *options, int num_options,
+ char** resources)
+ : KApplication(argc, argv, rAppName, allowStyles, GUIenabled)
+{
+ my_xt = TRUE;
+
+ XtToolkitInitialize();
+ appcon = XtCreateApplicationContext();
+ if (resources) XtAppSetFallbackResources(appcon, (char**)resources);
+ XtDisplayInitialize(appcon, qt_xdisplay(), name(), rAppName, options,
+ num_options, &argc, argv);
+ init();
+}
+
+/*!
+ Constructs a QApplication from the \a display of an already-initialized
+ Xt application.
+
+ Use this constructor when introducing Qt widgets into an existing
+ Xt/Motif application.
+*/
+KXtApplication::KXtApplication(Display* dpy, int& argc, char** argv,
+ const QCString& rAppName, bool allowStyles, bool GUIenabled)
+ : KApplication(dpy, argc, argv, rAppName, allowStyles, GUIenabled)
+{
+ my_xt = FALSE;
+ init();
+ appcon = XtDisplayToApplicationContext(dpy);
+}
+
+/*!
+ Destructs the application. Does not close the Xt toolkit.
+*/
+KXtApplication::~KXtApplication()
+{
+ Q_ASSERT(qxtapp==this);
+ removeXtEventFilters();
+ qxtapp = 0;
+
+ // the manpage says: "or just exit", that's what we do to avoid
+ // double closing of the display
+// if (my_xt) {
+// XtDestroyApplicationContext(appcon);
+// }
+}
+
+void KXtApplication::init()
+{
+ Q_ASSERT(qxtapp==0);
+ qxtapp = this;
+ installXtEventFilters();
+ qt_np_add_timeoutcb(np_do_timers);
+ qt_np_add_timer_setter(np_set_timer);
+ qt_np_add_event_proc(np_event_proc);
+ qt_np_count++;
+/* QTimer *timer = new QTimer( this );
+ timer->start(500);*/
+}
+
+/*!
+ \class KXtWidget qxt.h
+ \brief Allows mixing of Xt/Motif and Qt widgets.
+
+ \extension Xt/Motif
+
+ KXtWidget acts as a bridge between Xt and Qt. For utilizing old
+ Xt widgets, it can be a QWidget
+ based on a Xt widget class. For including Qt widgets in an existing
+ Xt/Motif application, it can be a special Xt widget class that is
+ a QWidget. See the constructors for the different behaviors.
+*/
+
+void KXtWidget::init(const char* name, WidgetClass widget_class,
+ Widget parent, QWidget* qparent,
+ ArgList args, Cardinal num_args,
+ bool managed)
+{
+ need_reroot=FALSE;
+ xtparent = 0;
+ if (parent ) {
+ Q_ASSERT(!qparent);
+ xtw = XtCreateWidget(name, widget_class, parent, args, num_args);
+ if ( widget_class == qWidgetClass )
+ ((QWidgetRec*)xtw)->qwidget.qxtwidget = this;
+ xtparent = parent;
+ if (managed)
+ XtManageChild(xtw);
+ } else {
+ Q_ASSERT(!managed);
+
+ String n, c;
+ XtGetApplicationNameAndClass(qt_xdisplay(), &n, &c);
+ xtw = XtAppCreateShell(n, c, widget_class, qt_xdisplay(),
+ args, num_args);
+ if ( widget_class == qWidgetClass )
+ ((QWidgetRec*)xtw)->qwidget.qxtwidget = this;
+ }
+
+ if ( qparent ) {
+ XtResizeWidget( xtw, 100, 100, 0 );
+ XtSetMappedWhenManaged(xtw, False);
+ XtRealizeWidget(xtw);
+ XSync(qt_xdisplay(), False); // I want all windows to be created now
+ XReparentWindow(qt_xdisplay(), XtWindow(xtw), qparent->winId(), x(), y());
+ XtSetMappedWhenManaged(xtw, True);
+ need_reroot=TRUE;
+ }
+
+ Arg reqargs[20];
+ Cardinal nargs=0;
+ XtSetArg(reqargs[nargs], XtNx, x()); nargs++;
+ XtSetArg(reqargs[nargs], XtNy, y()); nargs++;
+ XtSetArg(reqargs[nargs], XtNwidth, width()); nargs++;
+ XtSetArg(reqargs[nargs], XtNheight, height()); nargs++;
+ //XtSetArg(reqargs[nargs], "mappedWhenManaged", False); nargs++;
+ XtSetValues(xtw, reqargs, nargs);
+
+ //#### destroy(); MLK
+
+ if (!parent || XtIsRealized(parent))
+ XtRealizeWidget(xtw);
+}
+
+
+/*!
+ Constructs a KXtWidget of the special Xt widget class known as
+ "QWidget" to the resource manager.
+
+ Use this constructor to utilize Qt widgets in an Xt/Motif
+ application. The KXtWidget is a QWidget, so you can create
+ subwidgets, layouts, etc. using Qt functionality.
+*/
+KXtWidget::KXtWidget(const char* name, Widget parent, bool managed) :
+ QWidget( 0, name, WResizeNoErase )
+{
+ init(name, qWidgetClass, parent, 0, 0, 0, managed);
+ Arg reqargs[20];
+ Cardinal nargs=0;
+ XtSetArg(reqargs[nargs], XtNborderWidth, 0);
+ nargs++;
+ XtSetValues(xtw, reqargs, nargs);
+}
+
+/*!
+ Constructs a KXtWidget of the given \a widget_class.
+
+ Use this constructor to utilize Xt or Motif widgets in a Qt
+ application. The KXtWidget looks and behaves
+ like the Xt class, but can be used like any QWidget.
+
+ Note that Xt requires that the most toplevel Xt widget is a shell.
+ That means, if \a parent is a KXtWidget, the \a widget_class can be
+ of any kind. If there isn't a parent or the parent is just a normal
+ QWidget, \a widget_class should be something like \c
+ topLevelShellWidgetClass.
+
+ If the \a managed parameter is TRUE and \a parent in not NULL,
+ XtManageChild it used to manage the child.
+*/
+KXtWidget::KXtWidget(const char* name, WidgetClass widget_class,
+ QWidget *parent, ArgList args, Cardinal num_args,
+ bool managed) :
+ QWidget( parent, name, WResizeNoErase )
+{
+ if ( !parent )
+ init(name, widget_class, 0, 0, args, num_args, managed);
+ else if ( parent->inherits("KXtWidget") )
+ init(name, widget_class, ( (KXtWidget*)parent)->xtw , 0, args, num_args, managed);
+ else
+ init(name, widget_class, 0, parent, args, num_args, managed);
+ create(XtWindow(xtw), FALSE, FALSE);
+}
+
+/*!
+ Destructs the KXtWidget.
+*/
+KXtWidget::~KXtWidget()
+{
+ // Delete children first, as Xt will destroy their windows
+ //
+ QObjectList* list = queryList("QWidget", 0, FALSE, FALSE);
+ if ( list ) {
+ QWidget* c;
+ QObjectListIt it( *list );
+ while ( (c = (QWidget*)it.current()) ) {
+ delete c;
+ ++it;
+ }
+ delete list;
+ }
+
+ if ( need_reroot ) {
+ hide();
+ XReparentWindow(qt_xdisplay(), winId(), qApp->desktop()->winId(),
+ x(), y());
+ }
+
+ XtDestroyWidget(xtw);
+ destroy( FALSE, FALSE );
+}
+
+/*!
+ \fn Widget KXtWidget::xtWidget() const
+ Returns the Xt widget equivalent for the Qt widget.
+*/
+
+
+
+/*!
+ Reimplemented to produce the Xt effect of getting focus when the
+ mouse enters the widget. <em>This may be changed.</em>
+*/
+bool KXtWidget::x11Event( XEvent * e )
+{
+ if ( e->type == EnterNotify ) {
+ if ( xtparent )
+ setActiveWindow();
+ }
+ return QWidget::x11Event( e );
+}
+
+
+/*!
+ Implement a degree of focus handling for Xt widgets.
+*/
+void KXtWidget::setActiveWindow()
+{
+ if ( xtparent ) {
+ if ( !QWidget::isActiveWindow() && isActiveWindow() ) {
+ XFocusChangeEvent e;
+ e.type = FocusIn;
+ e.window = winId();
+ e.mode = NotifyNormal;
+ e.detail = NotifyInferior;
+ XSendEvent( qt_xdisplay(), e.window, TRUE, NoEventMask, (XEvent*)&e );
+ }
+ } else {
+ QWidget::setActiveWindow();
+ }
+}
+
+/*!
+ Different from QWidget::isActiveWindow()
+ */
+bool KXtWidget::isActiveWindow() const
+{
+ Window win;
+ int revert;
+ XGetInputFocus( qt_xdisplay(), &win, &revert );
+
+ if ( win == None) return FALSE;
+
+ QWidget *w = find( (WId)win );
+ if ( w ) {
+ // We know that window
+ return w->topLevelWidget() == topLevelWidget();
+ } else {
+ // Window still may be a parent (if top-level is foreign window)
+ Window root, parent;
+ Window cursor = winId();
+ Window *ch;
+ unsigned int nch;
+ while ( XQueryTree(qt_xdisplay(), cursor, &root, &parent, &ch, &nch) ) {
+ if (ch) XFree( (char*)ch);
+ if ( parent == win ) return TRUE;
+ if ( parent == root ) return FALSE;
+ cursor = parent;
+ }
+ return FALSE;
+ }
+}
+
+/*!\reimp
+ */
+void KXtWidget::moveEvent( QMoveEvent* )
+{
+ if ( xtparent )
+ return;
+ XConfigureEvent c;
+ c.type = ConfigureNotify;
+ c.event = winId();
+ c.window = winId();
+ c.x = x();
+ c.y = y();
+ c.width = width();
+ c.height = height();
+ c.border_width = 0;
+ XSendEvent( qt_xdisplay(), c.event, TRUE, NoEventMask, (XEvent*)&c );
+ XtMoveWidget( xtw, x(), y() );
+}
+
+/*!\reimp
+ */
+void KXtWidget::resizeEvent( QResizeEvent* )
+{
+ if ( xtparent )
+ return;
+ XtWidgetGeometry preferred;
+ (void ) XtQueryGeometry( xtw, 0, &preferred );
+ XConfigureEvent c;
+ c.type = ConfigureNotify;
+ c.event = winId();
+ c.window = winId();
+ c.x = x();
+ c.y = y();
+ c.width = width();
+ c.height = height();
+ c.border_width = 0;
+ XSendEvent( qt_xdisplay(), c.event, TRUE, NoEventMask, (XEvent*)&c );
+ XtResizeWidget( xtw, width(), height(), preferred.border_width );
+}
+
+#include "kxt.moc"
+
+#endif
diff --git a/nsplugins/viewer/kxt.h b/nsplugins/viewer/kxt.h
new file mode 100644
index 000000000..1d594b328
--- /dev/null
+++ b/nsplugins/viewer/kxt.h
@@ -0,0 +1,99 @@
+/*
+
+ kxt.h - Xt enabled Qt classed (derived from Qt Extension QXt)
+
+ Copyright (c) 2000 Stefan Schimanski <[email protected]>
+
+ 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.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+*/
+
+/****************************************************************************
+**
+** Definition of Qt extension classes for Xt/Motif support.
+**
+** Created : 980107
+**
+** Copyright (C) 1992-2000 Troll Tech AS. All rights reserved.
+**
+** This file is part of the Qt GUI Toolkit.
+**
+** This file may be distributed under the terms of the Q Public License
+** as defined by Troll Tech AS of Norway and appearing in the file
+** LICENSE.QPL included in the packaging of this file.
+**
+** Licensees holding valid Qt Professional Edition licenses may use this
+** file in accordance with the Qt Professional Edition License Agreement
+** provided with the Qt Professional Edition.
+**
+** See http://www.trolltech.com/pricing.html or email [email protected] for
+** information about the Professional Edition licensing, or see
+** http://www.trolltech.com/qpl/ for QPL licensing information.
+**
+*****************************************************************************/
+#ifndef KXT_H
+#define KXT_H
+
+#include <qglobal.h>
+#if QT_VERSION < 0x030100
+
+#include <kapplication.h>
+#include <qwidget.h>
+#include <X11/Intrinsic.h>
+
+class KXtApplication : public KApplication {
+ Q_OBJECT
+ void init();
+
+public:
+ KXtApplication(int& argc, char** argv,
+ const QCString& rAppName, bool allowStyles=true, bool GUIenabled=true,
+ XrmOptionDescRec *options=0, int num_options=0, char** resources=0);
+ KXtApplication(Display*, int& argc, char** argv, const QCString& rAppName,
+ bool allowStyles=true, bool GUIenabled=true);
+ ~KXtApplication();
+};
+
+class KXtWidget : public QWidget {
+ Q_OBJECT
+ Widget xtw;
+ Widget xtparent;
+ bool need_reroot;
+ void init(const char* name, WidgetClass widget_class,
+ Widget parent, QWidget* qparent,
+ ArgList args, Cardinal num_args,
+ bool managed);
+ friend void qwidget_realize( Widget widget, XtValueMask* mask,
+ XSetWindowAttributes* attributes );
+
+public:
+ KXtWidget(const char* name, Widget parent, bool managed=FALSE);
+ KXtWidget(const char* name, WidgetClass widget_class,
+ QWidget *parent=0, ArgList args=0, Cardinal num_args=0,
+ bool managed=FALSE);
+ ~KXtWidget();
+
+ Widget xtWidget() const { return xtw; }
+ bool isActiveWindow() const;
+ void setActiveWindow();
+
+protected:
+ void moveEvent( QMoveEvent* );
+ void resizeEvent( QResizeEvent* );
+ bool x11Event( XEvent * );
+};
+
+#endif
+#endif
diff --git a/nsplugins/viewer/nsplugin.cpp b/nsplugins/viewer/nsplugin.cpp
new file mode 100644
index 000000000..cb39aa107
--- /dev/null
+++ b/nsplugins/viewer/nsplugin.cpp
@@ -0,0 +1,1980 @@
+/*
+
+ This is an encapsulation of the Netscape plugin API.
+
+
+ Copyright (c) 2000 Matthias Hoelzer-Kluepfel <[email protected]>
+ Stefan Schimanski <[email protected]>
+ 2003-2005 George Staikos <[email protected]>
+
+ 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.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+*/
+
+
+#include "NSPluginCallbackIface_stub.h"
+
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <qdict.h>
+#include <qdir.h>
+#include <qfile.h>
+#include <qtimer.h>
+
+#include "kxt.h"
+#include "nsplugin.h"
+#include "resolve.h"
+
+#ifdef Bool
+#undef Bool
+#endif
+
+#include <dcopclient.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kio/netaccess.h>
+#include <klibloader.h>
+#include <klocale.h>
+#include <kprocess.h>
+#include <kprotocolmanager.h>
+#include <kstandarddirs.h>
+#include <ktempfile.h>
+#include <kurl.h>
+
+#include <X11/Intrinsic.h>
+#include <X11/Composite.h>
+#include <X11/Constraint.h>
+#include <X11/Shell.h>
+#include <X11/StringDefs.h>
+
+// provide these symbols when compiling with gcc 3.x
+
+#if defined __GNUC__ && defined __GNUC_MINOR__
+# define KDE_GNUC_PREREQ(maj, min) \
+ ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
+#else
+# define KDE_GNUC_PREREQ(maj, min) 0
+#endif
+
+
+#if defined(__GNUC__) && KDE_GNUC_PREREQ(3,0)
+extern "C" void* __builtin_new(size_t s)
+{
+ return operator new(s);
+}
+
+extern "C" void __builtin_delete(void* p)
+{
+ operator delete(p);
+}
+
+extern "C" void* __builtin_vec_new(size_t s)
+{
+ return operator new[](s);
+}
+
+extern "C" void __builtin_vec_delete(void* p)
+{
+ operator delete[](p);
+}
+
+extern "C" void __pure_virtual()
+{
+ abort();
+}
+#endif
+
+// server side functions -----------------------------------------------------
+
+// allocate memory
+void *g_NPN_MemAlloc(uint32 size)
+{
+ void *mem = ::malloc(size);
+
+ //kdDebug(1431) << "g_NPN_MemAlloc(), size=" << size << " allocated at " << mem << endl;
+
+ return mem;
+}
+
+
+// free memory
+void g_NPN_MemFree(void *ptr)
+{
+ //kdDebug(1431) << "g_NPN_MemFree() at " << ptr << endl;
+ if (ptr)
+ ::free(ptr);
+}
+
+uint32 g_NPN_MemFlush(uint32 size)
+{
+ Q_UNUSED(size);
+ //kdDebug(1431) << "g_NPN_MemFlush()" << endl;
+ // MAC OS only.. we don't use this
+ return 0;
+}
+
+
+// redraw
+void g_NPN_ForceRedraw(NPP /*instance*/)
+{
+ // http://devedge.netscape.com/library/manuals/2002/plugin/1.0/npn_api3.html#999401
+ // FIXME
+ kdDebug(1431) << "g_NPN_ForceRedraw() [unimplemented]" << endl;
+}
+
+
+// invalidate rect
+void g_NPN_InvalidateRect(NPP /*instance*/, NPRect* /*invalidRect*/)
+{
+ // http://devedge.netscape.com/library/manuals/2002/plugin/1.0/npn_api7.html#999503
+ // FIXME
+ kdDebug(1431) << "g_NPN_InvalidateRect() [unimplemented]" << endl;
+}
+
+
+// invalidate region
+void g_NPN_InvalidateRegion(NPP /*instance*/, NPRegion /*invalidRegion*/)
+{
+ // http://devedge.netscape.com/library/manuals/2002/plugin/1.0/npn_api8.html#999528
+ // FIXME
+ kdDebug(1431) << "g_NPN_InvalidateRegion() [unimplemented]" << endl;
+}
+
+
+// get value
+NPError g_NPN_GetValue(NPP /*instance*/, NPNVariable variable, void *value)
+{
+ kdDebug(1431) << "g_NPN_GetValue(), variable=" << static_cast<int>(variable) << endl;
+
+ switch (variable)
+ {
+ case NPNVxDisplay:
+ *(void**)value = qt_xdisplay();
+ return NPERR_NO_ERROR;
+ case NPNVxtAppContext:
+ *(void**)value = XtDisplayToApplicationContext(qt_xdisplay());
+ return NPERR_NO_ERROR;
+ case NPNVjavascriptEnabledBool:
+ *(bool*)value = true;
+ return NPERR_NO_ERROR;
+ case NPNVasdEnabledBool:
+ // SmartUpdate - we don't do this
+ *(bool*)value = false;
+ return NPERR_NO_ERROR;
+ case NPNVisOfflineBool:
+ // Offline browsing - no thanks
+ *(bool*)value = false;
+ return NPERR_NO_ERROR;
+ case NPNVToolkit:
+ *(NPNToolkitType*)value = NPNVGtk2;
+ return NPERR_NO_ERROR;
+ case NPNVSupportsXEmbedBool:
+ *(bool*)value = true;
+ return NPERR_NO_ERROR;
+ default:
+ return NPERR_INVALID_PARAM;
+ }
+}
+
+
+NPError g_NPN_DestroyStream(NPP instance, NPStream* stream,
+ NPReason reason)
+{
+ // FIXME: is this correct? I imagine it is not. (GS)
+ kdDebug(1431) << "g_NPN_DestroyStream()" << endl;
+
+ NSPluginInstance *inst = (NSPluginInstance*) instance->ndata;
+ inst->streamFinished( (NSPluginStream *)stream->ndata );
+
+ switch (reason) {
+ case NPRES_DONE:
+ return NPERR_NO_ERROR;
+ case NPRES_USER_BREAK:
+ // FIXME: notify the user
+ case NPRES_NETWORK_ERR:
+ // FIXME: notify the user
+ default:
+ return NPERR_GENERIC_ERROR;
+ }
+}
+
+
+NPError g_NPN_RequestRead(NPStream* /*stream*/, NPByteRange* /*rangeList*/)
+{
+ // http://devedge.netscape.com/library/manuals/2002/plugin/1.0/npn_api16.html#999734
+ kdDebug(1431) << "g_NPN_RequestRead() [unimplemented]" << endl;
+
+ // FIXME
+ return NPERR_GENERIC_ERROR;
+}
+
+NPError g_NPN_NewStream(NPP /*instance*/, NPMIMEType /*type*/,
+ const char* /*target*/, NPStream** /*stream*/)
+{
+ // http://devedge.netscape.com/library/manuals/2002/plugin/1.0/npn_api12.html#999628
+ kdDebug(1431) << "g_NPN_NewStream() [unimplemented]" << endl;
+
+ // FIXME
+ // This creates a stream from the plugin to the browser of type "type" to
+ // display in "target"
+ return NPERR_GENERIC_ERROR;
+}
+
+int32 g_NPN_Write(NPP /*instance*/, NPStream* /*stream*/, int32 /*len*/, void* /*buf*/)
+{
+ // http://devedge.netscape.com/library/manuals/2002/plugin/1.0/npn_api21.html#999859
+ kdDebug(1431) << "g_NPN_Write() [unimplemented]" << endl;
+
+ // FIXME
+ return 0;
+}
+
+
+// URL functions
+NPError g_NPN_GetURL(NPP instance, const char *url, const char *target)
+{
+ kdDebug(1431) << "g_NPN_GetURL: url=" << url << " target=" << target << endl;
+
+ NSPluginInstance *inst = static_cast<NSPluginInstance*>(instance->ndata);
+ if (inst) {
+ inst->requestURL( QString::fromLatin1(url), QString::null,
+ QString::fromLatin1(target), 0 );
+ }
+
+ return NPERR_NO_ERROR;
+}
+
+
+NPError g_NPN_GetURLNotify(NPP instance, const char *url, const char *target,
+ void* notifyData)
+{
+ kdDebug(1431) << "g_NPN_GetURLNotify: url=" << url << " target=" << target << " inst=" << (void*)instance << endl;
+ NSPluginInstance *inst = static_cast<NSPluginInstance*>(instance->ndata);
+ if (inst) {
+ kdDebug(1431) << "g_NPN_GetURLNotify: ndata=" << (void*)inst << endl;
+ inst->requestURL( QString::fromLatin1(url), QString::null,
+ QString::fromLatin1(target), notifyData, true );
+ }
+
+ return NPERR_NO_ERROR;
+}
+
+
+NPError g_NPN_PostURLNotify(NPP instance, const char* url, const char* target,
+ uint32 len, const char* buf, NPBool file, void* notifyData)
+{
+// http://devedge.netscape.com/library/manuals/2002/plugin/1.0/npn_api14.html
+ kdDebug(1431) << "g_NPN_PostURLNotify() [incomplete]" << endl;
+ kdDebug(1431) << "url=[" << url << "] target=[" << target << "]" << endl;
+ QByteArray postdata;
+ KParts::URLArgs args;
+
+ if (len == 0) {
+ return NPERR_NO_DATA;
+ }
+
+ if (file) { // buf is a filename
+ QFile f(buf);
+ if (!f.open(IO_ReadOnly)) {
+ return NPERR_FILE_NOT_FOUND;
+ }
+
+ // FIXME: this will not work because we need to strip the header out!
+ postdata = f.readAll();
+ f.close();
+ } else { // buf is raw data
+ // First strip out the header
+ const char *previousStart = buf;
+ uint32 l;
+ bool previousCR = true;
+
+ for (l = 1;; l++) {
+ if (l == len) {
+ break;
+ }
+
+ if (buf[l-1] == '\n' || (previousCR && buf[l-1] == '\r')) {
+ if (previousCR) { // header is done!
+ if ((buf[l-1] == '\r' && buf[l] == '\n') ||
+ (buf[l-1] == '\n' && buf[l] == '\r'))
+ l++;
+ l++;
+ previousStart = &buf[l-1];
+ break;
+ }
+
+ QString thisLine = QString::fromLatin1(previousStart, &buf[l-1] - previousStart).stripWhiteSpace();
+
+ previousStart = &buf[l];
+ previousCR = true;
+
+ kdDebug(1431) << "Found header line: [" << thisLine << "]" << endl;
+ if (thisLine.startsWith("Content-Type: ")) {
+ args.setContentType(thisLine);
+ }
+ } else {
+ previousCR = false;
+ }
+ }
+
+ postdata.duplicate(previousStart, len - l + 1);
+ }
+
+ kdDebug(1431) << "Post data: " << postdata.size() << " bytes" << endl;
+#if 0
+ QFile f("/tmp/nspostdata");
+ f.open(IO_WriteOnly);
+ f.writeBlock(postdata);
+ f.close();
+#endif
+
+ if (!target || !*target) {
+ // Send the results of the post to the plugin
+ // (works by default)
+ } else if (!strcmp(target, "_current") || !strcmp(target, "_self") ||
+ !strcmp(target, "_top")) {
+ // Unload the plugin, put the results in the frame/window that the
+ // plugin was loaded in
+ // FIXME
+ } else if (!strcmp(target, "_new") || !strcmp(target, "_blank")){
+ // Open a new browser window and write the results there
+ // FIXME
+ } else {
+ // Write the results to the specified frame
+ // FIXME
+ }
+
+ NSPluginInstance *inst = static_cast<NSPluginInstance*>(instance->ndata);
+ if (inst && !inst->normalizedURL(QString::fromLatin1(url)).isNull()) {
+ inst->postURL( QString::fromLatin1(url), postdata, args.contentType(),
+ QString::fromLatin1(target), notifyData, args, true );
+ } else {
+ // Unsupported / insecure
+ return NPERR_INVALID_URL;
+ }
+
+ return NPERR_NO_ERROR;
+}
+
+
+NPError g_NPN_PostURL(NPP instance, const char* url, const char* target,
+ uint32 len, const char* buf, NPBool file)
+{
+// http://devedge.netscape.com/library/manuals/2002/plugin/1.0/npn_api13.html
+ kdDebug(1431) << "g_NPN_PostURL()" << endl;
+ kdDebug(1431) << "url=[" << url << "] target=[" << target << "]" << endl;
+ QByteArray postdata;
+ KParts::URLArgs args;
+
+ if (len == 0) {
+ return NPERR_NO_DATA;
+ }
+
+ if (file) { // buf is a filename
+ QFile f(buf);
+ if (!f.open(IO_ReadOnly)) {
+ return NPERR_FILE_NOT_FOUND;
+ }
+
+ // FIXME: this will not work because we need to strip the header out!
+ postdata = f.readAll();
+ f.close();
+ } else { // buf is raw data
+ // First strip out the header
+ const char *previousStart = buf;
+ uint32 l;
+ bool previousCR = true;
+
+ for (l = 1;; l++) {
+ if (l == len) {
+ break;
+ }
+
+ if (buf[l-1] == '\n' || (previousCR && buf[l-1] == '\r')) {
+ if (previousCR) { // header is done!
+ if ((buf[l-1] == '\r' && buf[l] == '\n') ||
+ (buf[l-1] == '\n' && buf[l] == '\r'))
+ l++;
+ l++;
+ previousStart = &buf[l-1];
+ break;
+ }
+
+ QString thisLine = QString::fromLatin1(previousStart, &buf[l-1] - previousStart).stripWhiteSpace();
+
+ previousStart = &buf[l];
+ previousCR = true;
+
+ kdDebug(1431) << "Found header line: [" << thisLine << "]" << endl;
+ if (thisLine.startsWith("Content-Type: ")) {
+ args.setContentType(thisLine);
+ }
+ } else {
+ previousCR = false;
+ }
+ }
+
+ postdata.duplicate(previousStart, len - l + 1);
+ }
+
+ kdDebug(1431) << "Post data: " << postdata.size() << " bytes" << endl;
+#if 0
+ QFile f("/tmp/nspostdata");
+ f.open(IO_WriteOnly);
+ f.writeBlock(postdata);
+ f.close();
+#endif
+
+ if (!target || !*target) {
+ // Send the results of the post to the plugin
+ // (works by default)
+ } else if (!strcmp(target, "_current") || !strcmp(target, "_self") ||
+ !strcmp(target, "_top")) {
+ // Unload the plugin, put the results in the frame/window that the
+ // plugin was loaded in
+ // FIXME
+ } else if (!strcmp(target, "_new") || !strcmp(target, "_blank")){
+ // Open a new browser window and write the results there
+ // FIXME
+ } else {
+ // Write the results to the specified frame
+ // FIXME
+ }
+
+ NSPluginInstance *inst = static_cast<NSPluginInstance*>(instance->ndata);
+ if (inst && !inst->normalizedURL(QString::fromLatin1(url)).isNull()) {
+ inst->postURL( QString::fromLatin1(url), postdata, args.contentType(),
+ QString::fromLatin1(target), 0L, args, false );
+ } else {
+ // Unsupported / insecure
+ return NPERR_INVALID_URL;
+ }
+
+ return NPERR_NO_ERROR;
+}
+
+
+// display status message
+void g_NPN_Status(NPP instance, const char *message)
+{
+ kdDebug(1431) << "g_NPN_Status(): " << message << endl;
+
+ if (!instance)
+ return;
+
+ // turn into an instance signal
+ NSPluginInstance *inst = (NSPluginInstance*) instance->ndata;
+
+ inst->emitStatus(message);
+}
+
+
+// inquire user agent
+const char *g_NPN_UserAgent(NPP /*instance*/)
+{
+ KProtocolManager kpm;
+ QString agent = kpm.userAgentForHost("nspluginviewer");
+ kdDebug(1431) << "g_NPN_UserAgent() = " << agent << endl;
+ // flash crashes without Firefox UA
+ agent = "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.10) Gecko/2007101500 Firefox/2.0.0.10";
+ return agent.latin1();
+}
+
+
+// inquire version information
+void g_NPN_Version(int *plugin_major, int *plugin_minor, int *browser_major, int *browser_minor)
+{
+ kdDebug(1431) << "g_NPN_Version()" << endl;
+
+ // FIXME: Use the sensible values
+ *browser_major = NP_VERSION_MAJOR;
+ *browser_minor = NP_VERSION_MINOR;
+
+ *plugin_major = NP_VERSION_MAJOR;
+ *plugin_minor = NP_VERSION_MINOR;
+}
+
+
+void g_NPN_ReloadPlugins(NPBool reloadPages)
+{
+ // http://devedge.netscape.com/library/manuals/2002/plugin/1.0/npn_api15.html#999713
+ kdDebug(1431) << "g_NPN_ReloadPlugins()" << endl;
+ KProcess p;
+ p << KGlobal::dirs()->findExe("nspluginscan");
+
+ if (reloadPages) {
+ // This is the proper way, but it cannot be done because we have no
+ // handle to the caller! How stupid! We cannot force all konqi windows
+ // to reload - that would be evil.
+ //p.start(KProcess::Block);
+ // Let's only allow the caller to be reloaded, not everything.
+ //if (_callback)
+ // _callback->reloadPage();
+ p.start(KProcess::DontCare);
+ } else {
+ p.start(KProcess::DontCare);
+ }
+}
+
+
+// JAVA functions
+JRIEnv *g_NPN_GetJavaEnv()
+{
+ kdDebug(1431) << "g_NPN_GetJavaEnv() [unimplemented]" << endl;
+ // FIXME - what do these do? I can't find docs, and even Mozilla doesn't
+ // implement them
+ return 0;
+}
+
+
+jref g_NPN_GetJavaPeer(NPP /*instance*/)
+{
+ kdDebug(1431) << "g_NPN_GetJavaPeer() [unimplemented]" << endl;
+ // FIXME - what do these do? I can't find docs, and even Mozilla doesn't
+ // implement them
+ return 0;
+}
+
+
+NPError g_NPN_SetValue(NPP /*instance*/, NPPVariable variable, void* /*value*/)
+{
+ kdDebug(1431) << "g_NPN_SetValue() [unimplemented]" << endl;
+ switch (variable) {
+ case NPPVpluginWindowBool:
+ // FIXME
+ // If true, the plugin is windowless. If false, it is in a window.
+ case NPPVpluginTransparentBool:
+ // FIXME
+ // If true, the plugin is displayed transparent
+ default:
+ return NPERR_GENERIC_ERROR;
+ }
+}
+
+
+
+
+
+/******************************************************************/
+
+void
+NSPluginInstance::forwarder(Widget w, XtPointer cl_data, XEvent * event, Boolean * cont)
+{
+ Q_UNUSED(w);
+ NSPluginInstance *inst = (NSPluginInstance*)cl_data;
+ *cont = True;
+ if (inst->_form == 0 || event->xkey.window == XtWindow(inst->_form))
+ return;
+ *cont = False;
+ event->xkey.window = XtWindow(inst->_form);
+ event->xkey.subwindow = None;
+ XtDispatchEvent(event);
+}
+
+
+NSPluginInstance::NSPluginInstance(NPP privateData, NPPluginFuncs *pluginFuncs,
+ KLibrary *handle, int width, int height,
+ QString src, QString /*mime*/,
+ QString appId, QString callbackId,
+ bool embed, WId xembed,
+ QObject *parent, const char* name )
+ : DCOPObject(), QObject( parent, name )
+{
+ Q_UNUSED(embed);
+ _visible = false;
+ _npp = privateData;
+ _npp->ndata = this;
+ _destroyed = false;
+ _handle = handle;
+ _width = width;
+ _height = height;
+ _tempFiles.setAutoDelete( true );
+ _streams.setAutoDelete( true );
+ _waitingRequests.setAutoDelete( true );
+ _callback = new NSPluginCallbackIface_stub( appId.latin1(), callbackId.latin1() );
+ _xembed_window = xembed;
+ _toplevel = _form = 0;
+
+ KURL base(src);
+ base.setFileName( QString::null );
+ _baseURL = base.url();
+
+ memcpy(&_pluginFuncs, pluginFuncs, sizeof(_pluginFuncs));
+
+ _timer = new QTimer( this );
+ connect( _timer, SIGNAL(timeout()), SLOT(timer()) );
+
+ kdDebug(1431) << "NSPluginInstance::NSPluginInstance" << endl;
+ kdDebug(1431) << "pdata = " << _npp->pdata << endl;
+ kdDebug(1431) << "ndata = " << _npp->ndata << endl;
+
+ if (width == 0)
+ width = 1600;
+
+ if (height == 0)
+ height = 1200;
+
+ if( _xembed_window == 0 ) {
+ // create drawing area
+ Arg args[7];
+ Cardinal nargs = 0;
+ XtSetArg(args[nargs], XtNwidth, width); nargs++;
+ XtSetArg(args[nargs], XtNheight, height); nargs++;
+ XtSetArg(args[nargs], XtNborderWidth, 0); nargs++;
+
+ String n, c;
+ XtGetApplicationNameAndClass(qt_xdisplay(), &n, &c);
+
+ _toplevel = XtAppCreateShell("drawingArea", c, applicationShellWidgetClass,
+ qt_xdisplay(), args, nargs);
+
+ // What exactly does widget mapping mean? Without this call the widget isn't
+ // embedded correctly. With it the viewer doesn't show anything in standalone mode.
+ //if (embed)
+ XtSetMappedWhenManaged(_toplevel, False);
+ XtRealizeWidget(_toplevel);
+
+ // Create form window that is searched for by flash plugin
+ _form = XtVaCreateWidget("form", compositeWidgetClass, _toplevel, NULL);
+ XtSetArg(args[nargs], XtNvisual, QPaintDevice::x11AppVisual()); nargs++;
+ XtSetArg(args[nargs], XtNdepth, QPaintDevice::x11AppDepth()); nargs++;
+ XtSetArg(args[nargs], XtNcolormap, QPaintDevice::x11AppColormap()); nargs++;
+ XtSetValues(_form, args, nargs);
+ XSync(qt_xdisplay(), false);
+
+ // From mozilla - not sure if it's needed yet, nor what to use for embedder
+#if 0
+ /* this little trick seems to finish initializing the widget */
+#if XlibSpecificationRelease >= 6
+ XtRegisterDrawable(qt_xdisplay(), embedderid, _toplevel);
+#else
+ _XtRegisterWindow(embedderid, _toplevel);
+#endif
+#endif
+ XtRealizeWidget(_form);
+ XtManageChild(_form);
+
+ // Register forwarder
+ XtAddEventHandler(_toplevel, (KeyPressMask|KeyReleaseMask),
+ False, forwarder, (XtPointer)this );
+ XtAddEventHandler(_form, (KeyPressMask|KeyReleaseMask),
+ False, forwarder, (XtPointer)this );
+ XSync(qt_xdisplay(), false);
+ }
+}
+
+NSPluginInstance::~NSPluginInstance()
+{
+ kdDebug(1431) << "-> ~NSPluginInstance" << endl;
+ destroy();
+ kdDebug(1431) << "<- ~NSPluginInstance" << endl;
+}
+
+
+void NSPluginInstance::destroy()
+{
+ if ( !_destroyed ) {
+
+ kdDebug(1431) << "delete streams" << endl;
+ _waitingRequests.clear();
+
+ shutdown();
+
+ for( NSPluginStreamBase *s=_streams.first(); s!=0; ) {
+ NSPluginStreamBase *next = _streams.next();
+ s->stop();
+ s = next;
+ }
+
+ _streams.clear();
+
+ kdDebug(1431) << "delete callbacks" << endl;
+ delete _callback;
+ _callback = 0;
+
+ kdDebug(1431) << "destroy plugin" << endl;
+ NPSavedData *saved = 0;
+
+ // As of 7/31/01, nsplugin crashes when used with Qt
+ // linked with libGL if the destroy function is called.
+ // A patch on that date hacked out the following call.
+ // On 11/17/01, Jeremy White has reenabled this destroy
+ // in a an attempt to better understand why this crash
+ // occurs so that the real problem can be found and solved.
+ // It's possible that a flaw in the SetWindow call
+ // caused the crash and it is now fixed.
+ if ( _pluginFuncs.destroy )
+ _pluginFuncs.destroy( _npp, &saved );
+
+ if (saved && saved->len && saved->buf)
+ g_NPN_MemFree(saved->buf);
+ if (saved)
+ g_NPN_MemFree(saved);
+
+ if( _form != 0 ) {
+ XtRemoveEventHandler(_form, (KeyPressMask|KeyReleaseMask),
+ False, forwarder, (XtPointer)this);
+ XtRemoveEventHandler(_toplevel, (KeyPressMask|KeyReleaseMask),
+ False, forwarder, (XtPointer)this);
+ XtDestroyWidget(_form);
+ _form = 0;
+ XtDestroyWidget(_toplevel);
+ _toplevel = 0;
+ }
+
+ if (_npp) {
+ ::free(_npp); // matched with malloc() in newInstance
+ }
+
+ _destroyed = true;
+ }
+}
+
+
+void NSPluginInstance::shutdown()
+{
+ NSPluginClass *cls = dynamic_cast<NSPluginClass*>(parent());
+ //destroy();
+ if (cls) {
+ cls->destroyInstance( this );
+ }
+}
+
+
+void NSPluginInstance::timer()
+{
+ if (!_visible) {
+ _timer->start( 100, true );
+ return;
+ }
+
+ //_streams.clear();
+
+ // start queued requests
+ kdDebug(1431) << "looking for waiting requests" << endl;
+ while ( _waitingRequests.head() ) {
+ kdDebug(1431) << "request found" << endl;
+ Request req( *_waitingRequests.head() );
+ _waitingRequests.remove();
+
+ QString url;
+
+ // make absolute url
+ if ( req.url.left(11).lower()=="javascript:" )
+ url = req.url;
+ else if ( KURL::isRelativeURL(req.url) ) {
+ KURL bu( _baseURL );
+ KURL absUrl( bu, req.url );
+ url = absUrl.url();
+ } else if ( req.url[0]=='/' && KURL(_baseURL).hasHost() ) {
+ KURL absUrl( _baseURL );
+ absUrl.setPath( req.url );
+ url = absUrl.url();
+ } else
+ url = req.url;
+
+ // non empty target = frame target
+ if ( !req.target.isEmpty())
+ {
+ if (_callback)
+ {
+ if ( req.post ) {
+ _callback->postURL( url, req.target, req.data, req.mime );
+ } else {
+ _callback->requestURL( url, req.target );
+ }
+ if ( req.notify ) {
+ NPURLNotify( req.url, NPRES_DONE, req.notify );
+ }
+ }
+ } else {
+ if (!url.isEmpty())
+ {
+ kdDebug(1431) << "Starting new stream " << req.url << endl;
+
+ if (req.post) {
+ // create stream
+ NSPluginStream *s = new NSPluginStream( this );
+ connect( s, SIGNAL(finished(NSPluginStreamBase*)),
+ SLOT(streamFinished(NSPluginStreamBase*)) );
+ _streams.append( s );
+
+ kdDebug() << "posting to " << url << endl;
+
+ emitStatus( i18n("Submitting data to %1").arg(url) );
+ s->post( url, req.data, req.mime, req.notify, req.args );
+ } else if (url.lower().startsWith("javascript:")){
+ if (_callback) {
+ static Q_INT32 _jsrequestid = 0;
+ _jsrequests.insert(_jsrequestid, new Request(req));
+ _callback->evalJavaScript(_jsrequestid++, url.mid(11));
+ } else {
+ kdDebug() << "No callback for javascript: url!" << endl;
+ }
+ } else {
+ // create stream
+ NSPluginStream *s = new NSPluginStream( this );
+ connect( s, SIGNAL(finished(NSPluginStreamBase*)),
+ SLOT(streamFinished(NSPluginStreamBase*)) );
+ _streams.append( s );
+
+ kdDebug() << "getting " << url << endl;
+
+ emitStatus( i18n("Requesting %1").arg(url) );
+ s->get( url, req.mime, req.notify, req.reload );
+ }
+
+ //break;
+ }
+ }
+ }
+}
+
+
+QString NSPluginInstance::normalizedURL(const QString& url) const {
+ KURL bu( _baseURL );
+ KURL inURL(bu, url);
+ KConfig cfg("kcmnspluginrc", true);
+ cfg.setGroup("Misc");
+
+ if (!cfg.readBoolEntry("HTTP URLs Only", false) ||
+ inURL.protocol() == "http" ||
+ inURL.protocol() == "https" ||
+ inURL.protocol() == "javascript") {
+ return inURL.url();
+ }
+
+ // Allow: javascript:, http, https, or no protocol (match loading)
+ kdDebug(1431) << "NSPluginInstance::normalizedURL - I don't think so. http or https only!" << endl;
+ return QString::null;
+}
+
+
+void NSPluginInstance::requestURL( const QString &url, const QString &mime,
+ const QString &target, void *notify, bool forceNotify, bool reload )
+{
+ // Generally this should already be done, but let's be safe for now.
+ QString nurl = normalizedURL(url);
+ if (nurl.isNull()) {
+ return;
+ }
+
+ kdDebug(1431) << "NSPluginInstance::requestURL url=" << nurl << " target=" << target << " notify=" << notify << endl;
+ _waitingRequests.enqueue( new Request( nurl, mime, target, notify, forceNotify, reload ) );
+ _timer->start( 100, true );
+}
+
+
+void NSPluginInstance::postURL( const QString &url, const QByteArray& data,
+ const QString &mime,
+ const QString &target, void *notify,
+ const KParts::URLArgs& args, bool forceNotify )
+{
+ // Generally this should already be done, but let's be safe for now.
+ QString nurl = normalizedURL(url);
+ if (nurl.isNull()) {
+ return;
+ }
+
+ kdDebug(1431) << "NSPluginInstance::postURL url=" << nurl << " target=" << target << " notify=" << notify << endl;
+ _waitingRequests.enqueue( new Request( nurl, data, mime, target, notify, args, forceNotify) );
+ _timer->start( 100, true );
+}
+
+
+void NSPluginInstance::emitStatus(const QString &message)
+{
+ if( _callback )
+ _callback->statusMessage( message );
+}
+
+
+void NSPluginInstance::streamFinished( NSPluginStreamBase* strm )
+{
+ kdDebug(1431) << "-> NSPluginInstance::streamFinished" << endl;
+ emitStatus( QString::null );
+ _streams.setAutoDelete(false); // Don't delete it yet!! we get called from
+ // its slot!
+ _streams.remove(strm);
+ _streams.setAutoDelete(true);
+ strm->deleteLater();
+ _timer->start( 100, true );
+}
+
+int NSPluginInstance::setWindow(Q_INT8 remove)
+{
+ if (remove)
+ {
+ NPSetWindow(0);
+ return NPERR_NO_ERROR;
+ }
+
+ kdDebug(1431) << "-> NSPluginInstance::setWindow" << endl;
+
+ _win.x = 0;
+ _win.y = 0;
+ _win.height = _height;
+ _win.width = _width;
+ _win.type = NPWindowTypeWindow;
+
+ // Well, the docu says sometimes, this is only used on the
+ // MAC, but sometimes it says it's always. Who knows...
+ _win.clipRect.top = 0;
+ _win.clipRect.left = 0;
+ _win.clipRect.bottom = _height;
+ _win.clipRect.right = _width;
+
+ if( _xembed_window ) {
+ _win.window = (void*) _xembed_window;
+ _win_info.type = NP_SETWINDOW;
+ _win_info.display = qt_xdisplay();
+ _win_info.visual = DefaultVisualOfScreen(DefaultScreenOfDisplay(qt_xdisplay()));
+ _win_info.colormap = DefaultColormapOfScreen(DefaultScreenOfDisplay(qt_xdisplay()));
+ _win_info.depth = DefaultDepthOfScreen(DefaultScreenOfDisplay(qt_xdisplay()));
+ } else {
+ _win.window = (void*) XtWindow(_form);
+
+ _win_info.type = NP_SETWINDOW;
+ _win_info.display = XtDisplay(_form);
+ _win_info.visual = DefaultVisualOfScreen(XtScreen(_form));
+ _win_info.colormap = DefaultColormapOfScreen(XtScreen(_form));
+ _win_info.depth = DefaultDepthOfScreen(XtScreen(_form));
+ }
+
+ kdDebug(1431) << "Window ID = " << _win.window << endl;
+
+ _win.ws_info = &_win_info;
+
+ NPError error = NPSetWindow( &_win );
+
+ kdDebug(1431) << "<- NSPluginInstance::setWindow = " << error << endl;
+ return error;
+}
+
+
+static void resizeWidgets(Window w, int width, int height) {
+ Window rroot, parent, *children;
+ unsigned int nchildren = 0;
+
+ if (XQueryTree(qt_xdisplay(), w, &rroot, &parent, &children, &nchildren)) {
+ for (unsigned int i = 0; i < nchildren; i++) {
+ XResizeWindow(qt_xdisplay(), children[i], width, height);
+ }
+ XFree(children);
+ }
+}
+
+
+void NSPluginInstance::resizePlugin(Q_INT32 w, Q_INT32 h)
+{
+ if (w == _width && h == _height)
+ return;
+
+ kdDebug(1431) << "-> NSPluginInstance::resizePlugin( w=" << w << ", h=" << h << " ) " << endl;
+
+ _width = w;
+ _height = h;
+
+ if( _form != 0 ) {
+ XResizeWindow(qt_xdisplay(), XtWindow(_form), w, h);
+ XResizeWindow(qt_xdisplay(), XtWindow(_toplevel), w, h);
+
+ Arg args[7];
+ Cardinal nargs = 0;
+ XtSetArg(args[nargs], XtNwidth, _width); nargs++;
+ XtSetArg(args[nargs], XtNheight, _height); nargs++;
+ XtSetArg(args[nargs], XtNvisual, QPaintDevice::x11AppVisual()); nargs++;
+ XtSetArg(args[nargs], XtNdepth, QPaintDevice::x11AppDepth()); nargs++;
+ XtSetArg(args[nargs], XtNcolormap, QPaintDevice::x11AppColormap()); nargs++;
+ XtSetArg(args[nargs], XtNborderWidth, 0); nargs++;
+
+ XtSetValues(_toplevel, args, nargs);
+ XtSetValues(_form, args, nargs);
+
+ resizeWidgets(XtWindow(_form), _width, _height);
+ }
+
+ // If not visible yet, displayWindow() will call setWindow() again anyway, so avoid this.
+ // This also handled plugins that are broken and cannot handle repeated setWindow() calls
+ // very well.
+ if (!_visible)
+ return;
+
+ setWindow();
+
+ kdDebug(1431) << "<- NSPluginInstance::resizePlugin" << endl;
+}
+
+
+void NSPluginInstance::javascriptResult(Q_INT32 id, QString result) {
+ QMap<int, Request*>::iterator i = _jsrequests.find( id );
+ if (i != _jsrequests.end()) {
+ Request *req = i.data();
+ _jsrequests.remove( i );
+ NSPluginStream *s = new NSPluginStream( this );
+ connect( s, SIGNAL(finished(NSPluginStreamBase*)),
+ SLOT(streamFinished(NSPluginStreamBase*)) );
+ _streams.append( s );
+
+ int len = result.length();
+ s->create( req->url, QString("text/plain"), req->notify, req->forceNotify );
+ kdDebug(1431) << "javascriptResult has been called with: "<<result<<endl;
+ if (len > 0) {
+ QByteArray data(len + 1);
+ memcpy(data.data(), result.latin1(), len);
+ data[len] = 0;
+ s->process(data, 0);
+ } else {
+ len = 7; // "unknown"
+ QByteArray data(len + 1);
+ memcpy(data.data(), "unknown", len);
+ data[len] = 0;
+ s->process(data, 0);
+ }
+ s->finish(false);
+
+ delete req;
+ }
+}
+
+
+NPError NSPluginInstance::NPGetValue(NPPVariable variable, void *value)
+{
+ if( value==0 ) {
+ kdDebug() << "FIXME: value==0 in NSPluginInstance::NPGetValue" << endl;
+ return NPERR_GENERIC_ERROR;
+ }
+
+ if (!_pluginFuncs.getvalue)
+ return NPERR_GENERIC_ERROR;
+
+ NPError error = _pluginFuncs.getvalue(_npp, variable, value);
+
+ CHECK(GetValue,error);
+}
+
+
+NPError NSPluginInstance::NPSetValue(NPNVariable variable, void *value)
+{
+ if( value==0 ) {
+ kdDebug() << "FIXME: value==0 in NSPluginInstance::NPSetValue" << endl;
+ return NPERR_GENERIC_ERROR;
+ }
+
+ if (!_pluginFuncs.setvalue)
+ return NPERR_GENERIC_ERROR;
+
+ NPError error = _pluginFuncs.setvalue(_npp, variable, value);
+
+ CHECK(SetValue,error);
+}
+
+
+NPError NSPluginInstance::NPSetWindow(NPWindow *window)
+{
+ if( window==0 ) {
+ kdDebug() << "FIXME: window==0 in NSPluginInstance::NPSetWindow" << endl;
+ return NPERR_GENERIC_ERROR;
+ }
+
+ if (!_pluginFuncs.setwindow)
+ return NPERR_GENERIC_ERROR;
+
+ NPError error = _pluginFuncs.setwindow(_npp, window);
+
+ CHECK(SetWindow,error);
+}
+
+
+NPError NSPluginInstance::NPDestroyStream(NPStream *stream, NPReason reason)
+{
+ if( stream==0 ) {
+ kdDebug() << "FIXME: stream==0 in NSPluginInstance::NPDestroyStream" << endl;
+ return NPERR_GENERIC_ERROR;
+ }
+
+ if (!_pluginFuncs.destroystream)
+ return NPERR_GENERIC_ERROR;
+
+ NPError error = _pluginFuncs.destroystream(_npp, stream, reason);
+
+ CHECK(DestroyStream,error);
+}
+
+
+NPError NSPluginInstance::NPNewStream(NPMIMEType type, NPStream *stream, NPBool seekable, uint16 *stype)
+{
+ if( stream==0 ) {
+ kdDebug() << "FIXME: stream==0 in NSPluginInstance::NPNewStream" << endl;
+ return NPERR_GENERIC_ERROR;
+ }
+
+ if( stype==0 ) {
+ kdDebug() << "FIXME: stype==0 in NSPluginInstance::NPNewStream" << endl;
+ return NPERR_GENERIC_ERROR;
+ }
+
+ if (!_pluginFuncs.newstream)
+ return NPERR_GENERIC_ERROR;
+
+ NPError error = _pluginFuncs.newstream(_npp, type, stream, seekable, stype);
+
+ CHECK(NewStream,error);
+}
+
+
+void NSPluginInstance::NPStreamAsFile(NPStream *stream, const char *fname)
+{
+ if( stream==0 ) {
+ kdDebug() << "FIXME: stream==0 in NSPluginInstance::NPStreamAsFile" << endl;
+ return;
+ }
+
+ if( fname==0 ) {
+ kdDebug() << "FIXME: fname==0 in NSPluginInstance::NPStreamAsFile" << endl;
+ return;
+ }
+
+ if (!_pluginFuncs.asfile)
+ return;
+
+ _pluginFuncs.asfile(_npp, stream, fname);
+}
+
+
+int32 NSPluginInstance::NPWrite(NPStream *stream, int32 offset, int32 len, void *buf)
+{
+ if( stream==0 ) {
+ kdDebug() << "FIXME: stream==0 in NSPluginInstance::NPWrite" << endl;
+ return 0;
+ }
+
+ if( buf==0 ) {
+ kdDebug() << "FIXME: buf==0 in NSPluginInstance::NPWrite" << endl;
+ return 0;
+ }
+
+ if (!_pluginFuncs.write)
+ return 0;
+
+ return _pluginFuncs.write(_npp, stream, offset, len, buf);
+}
+
+
+int32 NSPluginInstance::NPWriteReady(NPStream *stream)
+{
+ if( stream==0 ) {
+ kdDebug() << "FIXME: stream==0 in NSPluginInstance::NPWriteReady" << endl;
+ return 0;
+ }
+
+ if (!_pluginFuncs.writeready)
+ return 0;
+
+ return _pluginFuncs.writeready(_npp, stream);
+}
+
+
+void NSPluginInstance::NPURLNotify(QString url, NPReason reason, void *notifyData)
+{
+ if (!_pluginFuncs.urlnotify)
+ return;
+
+ _pluginFuncs.urlnotify(_npp, url.ascii(), reason, notifyData);
+}
+
+
+void NSPluginInstance::addTempFile(KTempFile *tmpFile)
+{
+ _tempFiles.append(tmpFile);
+}
+
+/*
+ * We have to call this after we reparent the widget otherwise some plugins
+ * like the ones based on WINE get very confused. (their coordinates are not
+ * adjusted for the mouse at best)
+ */
+void NSPluginInstance::displayPlugin()
+{
+ // display plugin
+ setWindow();
+
+ _visible = true;
+ kdDebug(1431) << "<- NSPluginInstance::displayPlugin = " << (void*)this << endl;
+}
+
+static bool has_focus = false;
+
+void NSPluginInstance::gotFocusIn()
+{
+ has_focus = true;
+}
+
+void NSPluginInstance::gotFocusOut()
+{
+ has_focus = false;
+}
+
+#include <dlfcn.h>
+// Prevent plugins from polling the keyboard regardless of focus.
+static int (*real_xquerykeymap)( Display*, char[32] ) = NULL;
+
+extern "C" KDE_EXPORT
+int XQueryKeymap( Display* dpy, char k[32] )
+{
+ if( real_xquerykeymap == NULL )
+ real_xquerykeymap = (int (*)( Display*, char[32] )) dlsym( RTLD_NEXT, "XQueryKeymap" );
+ if( has_focus )
+ return real_xquerykeymap( dpy, k );
+ memset( k, 0, 32 );
+ return 1;
+}
+
+
+
+/***************************************************************************/
+
+NSPluginViewer::NSPluginViewer( QCString dcopId,
+ QObject *parent, const char *name )
+ : DCOPObject(dcopId), QObject( parent, name )
+{
+ _classes.setAutoDelete( true );
+ connect(KApplication::dcopClient(),
+ SIGNAL(applicationRemoved(const QCString&)),
+ this,
+ SLOT(appUnregistered(const QCString&)));
+}
+
+
+NSPluginViewer::~NSPluginViewer()
+{
+ kdDebug(1431) << "NSPluginViewer::~NSPluginViewer" << endl;
+}
+
+
+void NSPluginViewer::appUnregistered(const QCString& id) {
+ if (id.isEmpty()) {
+ return;
+ }
+
+ QDictIterator<NSPluginClass> it(_classes);
+ NSPluginClass *c;
+ while ( (c = it.current()) ) {
+ QString key = it.currentKey();
+ ++it;
+ if (c->app() == id) {
+ _classes.remove(key);
+ }
+ }
+
+ if (_classes.isEmpty()) {
+ shutdown();
+ }
+}
+
+
+void NSPluginViewer::shutdown()
+{
+ kdDebug(1431) << "NSPluginViewer::shutdown" << endl;
+ _classes.clear();
+#if QT_VERSION < 0x030100
+ quitXt();
+#else
+ qApp->quit();
+#endif
+}
+
+
+DCOPRef NSPluginViewer::newClass( QString plugin )
+{
+ kdDebug(1431) << "NSPluginViewer::NewClass( " << plugin << ")" << endl;
+
+ // search existing class
+ NSPluginClass *cls = _classes[ plugin ];
+ if ( !cls ) {
+ // create new class
+ cls = new NSPluginClass( plugin, this );
+ QCString id = "";
+ DCOPClient *dc = callingDcopClient();
+ if (dc) {
+ id = dc->senderId();
+ }
+ cls->setApp(id);
+ if ( cls->error() ) {
+ kdError(1431) << "Can't create plugin class" << endl;
+ delete cls;
+ return DCOPRef();
+ }
+
+ _classes.insert( plugin, cls );
+ }
+
+ return DCOPRef( kapp->dcopClient()->appId(), cls->objId() );
+}
+
+
+/****************************************************************************/
+
+
+NSPluginClass::NSPluginClass( const QString &library,
+ QObject *parent, const char *name )
+ : DCOPObject(), QObject( parent, name )
+{
+ // initialize members
+ _handle = KLibLoader::self()->library(QFile::encodeName(library));
+ _libname = library;
+ _constructed = false;
+ _error = true;
+ _instances.setAutoDelete( true );
+ _NP_GetMIMEDescription = 0;
+ _NP_Initialize = 0;
+ _NP_Shutdown = 0;
+
+ _timer = new QTimer( this );
+ connect( _timer, SIGNAL(timeout()), SLOT(timer()) );
+
+ // check lib handle
+ if (!_handle) {
+ kdDebug(1431) << "Could not dlopen " << library << endl;
+ return;
+ }
+
+ // get exported lib functions
+ _NP_GetMIMEDescription = (NP_GetMIMEDescriptionUPP *)_handle->symbol("NP_GetMIMEDescription");
+ _NP_Initialize = (NP_InitializeUPP *)_handle->symbol("NP_Initialize");
+ _NP_Shutdown = (NP_ShutdownUPP *)_handle->symbol("NP_Shutdown");
+
+ // check for valid returned ptrs
+ if (!_NP_GetMIMEDescription) {
+ kdDebug(1431) << "Could not get symbol NP_GetMIMEDescription" << endl;
+ return;
+ }
+
+ if (!_NP_Initialize) {
+ kdDebug(1431) << "Could not get symbol NP_Initialize" << endl;
+ return;
+ }
+
+ if (!_NP_Shutdown) {
+ kdDebug(1431) << "Could not get symbol NP_Shutdown" << endl;
+ return;
+ }
+
+ // initialize plugin
+ kdDebug(1431) << "Plugin library " << library << " loaded!" << endl;
+ _constructed = true;
+ _error = initialize()!=NPERR_NO_ERROR;
+}
+
+
+NSPluginClass::~NSPluginClass()
+{
+ _instances.clear();
+ _trash.clear();
+ shutdown();
+ if (_handle)
+ _handle->unload();
+}
+
+
+void NSPluginClass::timer()
+{
+ // delete instances
+ for ( NSPluginInstance *it=_trash.first(); it!=0; it=_trash.next() )
+ _instances.remove(it);
+
+ _trash.clear();
+}
+
+
+int NSPluginClass::initialize()
+{
+ kdDebug(1431) << "NSPluginClass::Initialize()" << endl;
+
+ if ( !_constructed )
+ return NPERR_GENERIC_ERROR;
+
+ // initialize nescape exported functions
+ memset(&_pluginFuncs, 0, sizeof(_pluginFuncs));
+ memset(&_nsFuncs, 0, sizeof(_nsFuncs));
+
+ _pluginFuncs.size = sizeof(_pluginFuncs);
+ _nsFuncs.size = sizeof(_nsFuncs);
+ _nsFuncs.version = (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR;
+ _nsFuncs.geturl = g_NPN_GetURL;
+ _nsFuncs.posturl = g_NPN_PostURL;
+ _nsFuncs.requestread = g_NPN_RequestRead;
+ _nsFuncs.newstream = g_NPN_NewStream;
+ _nsFuncs.write = g_NPN_Write;
+ _nsFuncs.destroystream = g_NPN_DestroyStream;
+ _nsFuncs.status = g_NPN_Status;
+ _nsFuncs.uagent = g_NPN_UserAgent;
+ _nsFuncs.memalloc = g_NPN_MemAlloc;
+ _nsFuncs.memfree = g_NPN_MemFree;
+ _nsFuncs.memflush = g_NPN_MemFlush;
+ _nsFuncs.reloadplugins = g_NPN_ReloadPlugins;
+ _nsFuncs.getJavaEnv = g_NPN_GetJavaEnv;
+ _nsFuncs.getJavaPeer = g_NPN_GetJavaPeer;
+ _nsFuncs.geturlnotify = g_NPN_GetURLNotify;
+ _nsFuncs.posturlnotify = g_NPN_PostURLNotify;
+ _nsFuncs.getvalue = g_NPN_GetValue;
+ _nsFuncs.setvalue = g_NPN_SetValue;
+ _nsFuncs.invalidaterect = g_NPN_InvalidateRect;
+ _nsFuncs.invalidateregion = g_NPN_InvalidateRegion;
+ _nsFuncs.forceredraw = g_NPN_ForceRedraw;
+
+ // initialize plugin
+ NPError error = _NP_Initialize(&_nsFuncs, &_pluginFuncs);
+ CHECK(Initialize,error);
+}
+
+
+QString NSPluginClass::getMIMEDescription()
+{
+ return _NP_GetMIMEDescription();
+}
+
+
+void NSPluginClass::shutdown()
+{
+ kdDebug(1431) << "NSPluginClass::shutdown error=" << _error << endl;
+ if( _NP_Shutdown && !_error )
+ _NP_Shutdown();
+}
+
+
+DCOPRef NSPluginClass::newInstance( QString url, QString mimeType, Q_INT8 embed,
+ QStringList argn, QStringList argv,
+ QString appId, QString callbackId,
+ Q_INT8 reload, Q_INT8 doPost, QByteArray postData, Q_UINT32 xembed )
+{
+ kdDebug(1431) << "-> NSPluginClass::NewInstance" << endl;
+
+ if ( !_constructed )
+ return DCOPRef();
+
+ // copy parameters over
+ unsigned int argc = argn.count();
+ char **_argn = new char*[argc];
+ char **_argv = new char*[argc];
+ QString src = url;
+ int width = 0;
+ int height = 0;
+ QString baseURL = url;
+
+ for (unsigned int i=0; i<argc; i++)
+ {
+ QCString encN = argn[i].utf8();
+ QCString encV = argv[i].utf8();
+
+ const char *n = encN;
+ const char *v = encV;
+
+ _argn[i] = strdup(n);
+ _argv[i] = strdup(v);
+
+ if (!strcasecmp(_argn[i], "WIDTH")) width = argv[i].toInt();
+ if (!strcasecmp(_argn[i], "HEIGHT")) height = argv[i].toInt();
+ if (!strcasecmp(_argn[i], "__KHTML__PLUGINBASEURL")) baseURL = _argv[i];
+ kdDebug(1431) << "argn=" << _argn[i] << " argv=" << _argv[i] << endl;
+ }
+
+ // create plugin instance
+ char mime[256];
+ strncpy(mime, mimeType.ascii(), 255);
+ mime[255] = 0;
+ NPP npp = (NPP)malloc(sizeof(NPP_t)); // I think we should be using
+ // malloc here, just to be safe,
+ // since the nsplugin plays with
+ // this thing
+ memset(npp, 0, sizeof(NPP_t));
+ npp->ndata = NULL;
+
+ // create plugin instance
+ NPError error = _pluginFuncs.newp(mime, npp, embed ? NP_EMBED : NP_FULL,
+ argc, _argn, _argv, 0);
+ kdDebug(1431) << "NPP_New = " << (int)error << endl;
+
+ // don't use bool here, it can be 1 byte, but some plugins write it as int, and I can't find what the spec says
+ int wants_xembed = false;
+ if (_pluginFuncs.getvalue) {
+ NPError error = _pluginFuncs.getvalue(npp, (NPPVariable)14/*NPPVpluginNeedsXEmbed*/, &wants_xembed );
+ if( error != NPERR_NO_ERROR )
+ wants_xembed = false;
+ }
+ kdDebug(1431) << "Plugin requires XEmbed:" << (bool)wants_xembed << endl;
+
+ // Create plugin instance object
+ NSPluginInstance *inst = new NSPluginInstance( npp, &_pluginFuncs, _handle,
+ width, height, baseURL, mimeType,
+ appId, callbackId, embed, wants_xembed ? xembed : 0, this );
+
+ // free arrays with arguments
+ delete [] _argn;
+ delete [] _argv;
+
+ // check for error
+ if ( error!=NPERR_NO_ERROR)
+ {
+ delete inst;
+ //delete npp; double delete!
+ kdDebug(1431) << "<- PluginClass::NewInstance = 0" << endl;
+ return DCOPRef();
+ }
+
+ // create source stream
+ if ( !src.isEmpty() ) {
+ if (doPost) {
+ inst->postURL(src, postData, mimeType, QString::null, 0, KParts::URLArgs(), false);
+ } else {
+ inst->requestURL( src, mimeType, QString::null, 0, false, reload );
+ }
+ }
+
+ _instances.append( inst );
+ return DCOPRef(kapp->dcopClient()->appId(), inst->objId());
+}
+
+
+void NSPluginClass::destroyInstance( NSPluginInstance* inst )
+{
+ // mark for destruction
+ _trash.append( inst );
+ timer(); //_timer->start( 0, TRUE );
+}
+
+/****************************************************************************/
+
+NSPluginStreamBase::NSPluginStreamBase( NSPluginInstance *instance )
+ : QObject( instance ), _instance(instance), _stream(0), _tempFile(0L),
+ _pos(0), _queue(0), _queuePos(0), _error(false)
+{
+ _informed = false;
+}
+
+
+NSPluginStreamBase::~NSPluginStreamBase()
+{
+ if (_stream) {
+ _instance->NPDestroyStream( _stream, NPRES_USER_BREAK );
+ if (_stream && _stream->url)
+ free(const_cast<char*>(_stream->url));
+ delete _stream;
+ _stream = 0;
+ }
+
+ delete _tempFile;
+ _tempFile = 0;
+}
+
+
+void NSPluginStreamBase::stop()
+{
+ finish( true );
+}
+
+void NSPluginStreamBase::inform()
+{
+
+ if (! _informed)
+ {
+ KURL src(_url);
+
+ _informed = true;
+
+ // inform the plugin
+ _instance->NPNewStream( _mimeType.isEmpty() ? (char *) "text/plain" : (char*)_mimeType.ascii(),
+ _stream, false, &_streamType );
+ kdDebug(1431) << "NewStream stype=" << _streamType << " url=" << _url << " mime=" << _mimeType << endl;
+
+ // prepare data transfer
+ _tempFile = 0L;
+
+ if ( _streamType==NP_ASFILE || _streamType==NP_ASFILEONLY ) {
+ _onlyAsFile = _streamType==NP_ASFILEONLY;
+ if ( KURL(_url).isLocalFile() ) {
+ kdDebug(1431) << "local file" << endl;
+ // local file can be passed directly
+ _fileURL = KURL(_url).path();
+
+ // without streaming stream is finished already
+ if ( _onlyAsFile ) {
+ kdDebug() << "local file AS_FILE_ONLY" << endl;
+ finish( false );
+ }
+ } else {
+ kdDebug() << "remote file" << endl;
+
+ // stream into temporary file (use lower() in case the
+ // filename as an upper case X in it)
+ _tempFile = new KTempFile;
+ _tempFile->setAutoDelete( TRUE );
+ _fileURL = _tempFile->name();
+ kdDebug() << "saving into " << _fileURL << endl;
+ }
+ }
+ }
+
+}
+
+bool NSPluginStreamBase::create( const QString& url, const QString& mimeType, void *notify, bool forceNotify)
+{
+ if ( _stream )
+ return false;
+
+ _url = url;
+ _notifyData = notify;
+ _pos = 0;
+ _tries = 0;
+ _onlyAsFile = false;
+ _streamType = NP_NORMAL;
+ _informed = false;
+ _forceNotify = forceNotify;
+
+ // create new stream
+ _stream = new NPStream;
+ _stream->ndata = this;
+ _stream->url = strdup(url.ascii());
+ _stream->end = 0;
+ _stream->pdata = 0;
+ _stream->lastmodified = 0;
+ _stream->notifyData = _notifyData;
+
+ _mimeType = mimeType;
+
+ return true;
+}
+
+void NSPluginStreamBase::updateURL( const KURL& newURL )
+{
+ _url = newURL;
+ free(const_cast<char*>(_stream->url));
+ _stream->url = strdup(_url.url().ascii());
+}
+
+int NSPluginStreamBase::process( const QByteArray &data, int start )
+{
+ int32 max, sent, to_sent, len;
+ char *d = data.data() + start;
+
+ to_sent = data.size() - start;
+ while (to_sent > 0)
+ {
+ inform();
+
+ max = _instance->NPWriteReady(_stream);
+ //kdDebug(1431) << "to_sent == " << to_sent << " and max = " << max << endl;
+ len = QMIN(max, to_sent);
+
+ //kdDebug(1431) << "-> Feeding stream to plugin: offset=" << _pos << ", len=" << len << endl;
+ sent = _instance->NPWrite( _stream, _pos, len, d );
+ //kdDebug(1431) << "<- Feeding stream: sent = " << sent << endl;
+
+ if (sent == 0) // interrupt the stream for a few ms
+ break;
+
+ if (sent < 0) {
+ // stream data rejected/error
+ kdDebug(1431) << "stream data rejected/error" << endl;
+ _error = true;
+ break;
+ }
+
+ if (_tempFile) {
+ _tempFile->dataStream()->writeRawBytes(d, sent);
+ }
+
+ to_sent -= sent;
+ _pos += sent;
+ d += sent;
+ }
+
+ return data.size() - to_sent;
+}
+
+
+bool NSPluginStreamBase::pump()
+{
+ //kdDebug(1431) << "queue pos " << _queuePos << ", size " << _queue.size() << endl;
+
+ inform();
+
+ if ( _queuePos<_queue.size() ) {
+ unsigned newPos;
+
+ // handle AS_FILE_ONLY streams
+ if ( _onlyAsFile ) {
+ if (_tempFile) {
+ _tempFile->dataStream()->writeRawBytes( _queue, _queue.size() );
+ }
+ newPos = _queuePos+_queue.size();
+ } else {
+ // normal streams
+ newPos = process( _queue, _queuePos );
+ }
+
+ // count tries
+ if ( newPos==_queuePos )
+ _tries++;
+ else
+ _tries = 0;
+
+ _queuePos = newPos;
+ }
+
+ // return true if queue finished
+ return _queuePos>=_queue.size();
+}
+
+
+void NSPluginStreamBase::queue( const QByteArray &data )
+{
+ _queue = data;
+ _queue.detach();
+ _queuePos = 0;
+ _tries = 0;
+
+/*
+ kdDebug(1431) << "new queue size=" << data.size()
+ << " data=" << (void*)data.data()
+ << " queue=" << (void*)_queue.data() << " qsize="
+ << _queue.size() << endl;
+*/
+}
+
+
+void NSPluginStreamBase::finish( bool err )
+{
+ kdDebug(1431) << "finish error=" << err << endl;
+
+ _queue.resize( 0 );
+ _pos = 0;
+ _queuePos = 0;
+
+ inform();
+
+ if ( !err ) {
+ if ( _tempFile ) {
+ _tempFile->close();
+ _instance->addTempFile( _tempFile );
+ _tempFile = 0;
+ }
+
+ if ( !_fileURL.isEmpty() ) {
+ kdDebug() << "stream as file " << _fileURL << endl;
+ _instance->NPStreamAsFile( _stream, _fileURL.ascii() );
+ }
+
+ _instance->NPDestroyStream( _stream, NPRES_DONE );
+ if (_notifyData || _forceNotify)
+ _instance->NPURLNotify( _url.url(), NPRES_DONE, _notifyData );
+ } else {
+ // close temp file
+ if ( _tempFile ) {
+ _tempFile->close();
+ }
+
+ // destroy stream
+ _instance->NPDestroyStream( _stream, NPRES_NETWORK_ERR );
+ if (_notifyData || _forceNotify)
+ _instance->NPURLNotify( _url.url(), NPRES_NETWORK_ERR, _notifyData );
+ }
+
+ // delete stream
+ if (_stream && _stream->url)
+ free(const_cast<char *>(_stream->url));
+ delete _stream;
+ _stream = 0;
+
+ // destroy NSPluginStream object
+ emit finished( this );
+}
+
+
+/****************************************************************************/
+
+NSPluginBufStream::NSPluginBufStream( class NSPluginInstance *instance )
+ : NSPluginStreamBase( instance )
+{
+ _timer = new QTimer( this );
+ connect( _timer, SIGNAL(timeout()), this, SLOT(timer()) );
+}
+
+
+NSPluginBufStream::~NSPluginBufStream()
+{
+
+}
+
+
+bool NSPluginBufStream::get( const QString& url, const QString& mimeType,
+ const QByteArray &buf, void *notifyData,
+ bool singleShot )
+{
+ _singleShot = singleShot;
+ if ( create( url, mimeType, notifyData ) ) {
+ queue( buf );
+ _timer->start( 100, true );
+ }
+
+ return false;
+}
+
+
+void NSPluginBufStream::timer()
+{
+ bool finished = pump();
+ if ( _singleShot )
+ finish( false );
+ else {
+
+ if ( !finished && tries()<=8 )
+ _timer->start( 100, true );
+ else
+ finish( error() || tries()>8 );
+ }
+}
+
+
+
+/****************************************************************************/
+
+NSPluginStream::NSPluginStream( NSPluginInstance *instance )
+ : NSPluginStreamBase( instance ), _job(0)
+{
+ _resumeTimer = new QTimer( this );
+ connect(_resumeTimer, SIGNAL(timeout()), this, SLOT(resume()));
+}
+
+
+NSPluginStream::~NSPluginStream()
+{
+ if ( _job )
+ _job->kill( true );
+}
+
+
+bool NSPluginStream::get( const QString& url, const QString& mimeType,
+ void *notify, bool reload )
+{
+ // create new stream
+ if ( create( url, mimeType, notify ) ) {
+ // start the kio job
+ _job = KIO::get(KURL( url ), false, false);
+ _job->addMetaData("errorPage", "false");
+ _job->addMetaData("AllowCompressedPage", "false");
+ if (reload) {
+ _job->addMetaData("cache", "reload");
+ }
+ connect(_job, SIGNAL(data(KIO::Job *, const QByteArray &)),
+ SLOT(data(KIO::Job *, const QByteArray &)));
+ connect(_job, SIGNAL(result(KIO::Job *)), SLOT(result(KIO::Job *)));
+ connect(_job, SIGNAL(totalSize(KIO::Job *, KIO::filesize_t )),
+ SLOT(totalSize(KIO::Job *, KIO::filesize_t)));
+ connect(_job, SIGNAL(mimetype(KIO::Job *, const QString &)),
+ SLOT(mimetype(KIO::Job *, const QString &)));
+ connect(_job, SIGNAL(redirection(KIO::Job *, const KURL&)),
+ SLOT(redirection(KIO::Job *, const KURL&)));
+ }
+
+ return false;
+}
+
+
+bool NSPluginStream::post( const QString& url, const QByteArray& data,
+ const QString& mimeType, void *notify, const KParts::URLArgs& args )
+{
+ // create new stream
+ if ( create( url, mimeType, notify ) ) {
+ // start the kio job
+ _job = KIO::http_post(KURL( url ), data, false);
+ _job->addMetaData("content-type", args.contentType());
+ _job->addMetaData("errorPage", "false");
+ _job->addMetaData("AllowCompressedPage", "false");
+ connect(_job, SIGNAL(data(KIO::Job *, const QByteArray &)),
+ SLOT(data(KIO::Job *, const QByteArray &)));
+ connect(_job, SIGNAL(result(KIO::Job *)), SLOT(result(KIO::Job *)));
+ connect(_job, SIGNAL(totalSize(KIO::Job *, KIO::filesize_t )),
+ SLOT(totalSize(KIO::Job *, KIO::filesize_t)));
+ connect(_job, SIGNAL(mimetype(KIO::Job *, const QString &)),
+ SLOT(mimetype(KIO::Job *, const QString &)));
+ connect(_job, SIGNAL(redirection(KIO::Job *, const KURL&)),
+ SLOT(redirection(KIO::Job *, const KURL&)));
+ }
+
+ return false;
+}
+
+
+void NSPluginStream::data(KIO::Job * job, const QByteArray &data)
+{
+ //kdDebug(1431) << "NSPluginStream::data - job=" << (void*)job << " data size=" << data.size() << endl;
+ queue( data );
+ if ( !pump() ) {
+ _job->suspend();
+ _resumeTimer->start( 100, TRUE );
+ }
+}
+
+void NSPluginStream::redirection(KIO::Job * /*job*/, const KURL& url)
+{
+ updateURL( url );
+}
+
+void NSPluginStream::totalSize(KIO::Job * job, KIO::filesize_t size)
+{
+ kdDebug(1431) << "NSPluginStream::totalSize - job=" << (void*)job << " size=" << KIO::number(size) << endl;
+ _stream->end = size;
+}
+
+void NSPluginStream::mimetype(KIO::Job * job, const QString &mimeType)
+{
+ kdDebug(1431) << "NSPluginStream::QByteArray - job=" << (void*)job << " mimeType=" << mimeType << endl;
+ _mimeType = mimeType;
+}
+
+
+
+
+void NSPluginStream::resume()
+{
+ if ( error() || tries()>8 ) {
+ _job->kill( true );
+ finish( true );
+ return;
+ }
+
+ if ( pump() ) {
+ kdDebug(1431) << "resume job" << endl;
+ _job->resume();
+ } else {
+ kdDebug(1431) << "restart timer" << endl;
+ _resumeTimer->start( 100, TRUE );
+ }
+}
+
+
+void NSPluginStream::result(KIO::Job *job)
+{
+ int err = job->error();
+ _job = 0;
+ finish( err!=0 || error() );
+}
+
+#include "nsplugin.moc"
+// vim: ts=4 sw=4 et
diff --git a/nsplugins/viewer/nsplugin.h b/nsplugins/viewer/nsplugin.h
new file mode 100644
index 000000000..76d2e659b
--- /dev/null
+++ b/nsplugins/viewer/nsplugin.h
@@ -0,0 +1,339 @@
+/*
+
+ This is an encapsulation of the Netscape plugin API.
+
+ Copyright (c) 2000 Matthias Hoelzer-Kluepfel <[email protected]>
+ Stefan Schimanski <[email protected]>
+ Copyright (c) 2003-2005 George Staikos <[email protected]>
+
+ 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.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+*/
+
+
+#ifndef __NS_PLUGIN_H__
+#define __NS_PLUGIN_H__
+
+
+#include <dcopobject.h>
+#include "NSPluginClassIface.h"
+#include "NSPluginCallbackIface_stub.h"
+
+
+#include <qobject.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qptrqueue.h>
+#include <qdict.h>
+#include <qmap.h>
+#include <qintdict.h>
+#include <qguardedptr.h>
+
+#include <kparts/browserextension.h> // for URLArgs
+#include <kio/job.h>
+
+
+#define XP_UNIX
+#define MOZ_X11
+#include "sdk/npupp.h"
+
+typedef char* NP_GetMIMEDescriptionUPP(void);
+typedef NPError NP_InitializeUPP(NPNetscapeFuncs*, NPPluginFuncs*);
+typedef NPError NP_ShutdownUPP(void);
+
+
+#include <X11/Intrinsic.h>
+
+
+void quitXt();
+
+class KLibrary;
+class QTimer;
+
+
+class NSPluginStreamBase : public QObject
+{
+Q_OBJECT
+friend class NSPluginInstance;
+public:
+ NSPluginStreamBase( class NSPluginInstance *instance );
+ ~NSPluginStreamBase();
+
+ KURL url() { return _url; }
+ int pos() { return _pos; }
+ void stop();
+
+signals:
+ void finished( NSPluginStreamBase *strm );
+
+protected:
+ void finish( bool err );
+ bool pump();
+ bool error() { return _error; }
+ void queue( const QByteArray &data );
+ bool create( const QString& url, const QString& mimeType, void *notify, bool forceNotify = false );
+ int tries() { return _tries; }
+ void inform( );
+ void updateURL( const KURL& newURL );
+
+ class NSPluginInstance *_instance;
+ uint16 _streamType;
+ NPStream *_stream;
+ void *_notifyData;
+ KURL _url;
+ QString _fileURL;
+ QString _mimeType;
+ QByteArray _data;
+ class KTempFile *_tempFile;
+
+private:
+ int process( const QByteArray &data, int start );
+
+ unsigned int _pos;
+ QByteArray _queue;
+ unsigned int _queuePos;
+ int _tries;
+ bool _onlyAsFile;
+ bool _error;
+ bool _informed;
+ bool _forceNotify;
+};
+
+
+class NSPluginStream : public NSPluginStreamBase
+{
+ Q_OBJECT
+
+public:
+ NSPluginStream( class NSPluginInstance *instance );
+ ~NSPluginStream();
+
+ bool get(const QString& url, const QString& mimeType, void *notifyData, bool reload = false);
+ bool post(const QString& url, const QByteArray& data, const QString& mimeType, void *notifyData, const KParts::URLArgs& args);
+
+protected slots:
+ void data(KIO::Job *job, const QByteArray &data);
+ void totalSize(KIO::Job *job, KIO::filesize_t size);
+ void mimetype(KIO::Job * job, const QString &mimeType);
+ void result(KIO::Job *job);
+ void redirection(KIO::Job *job, const KURL& url);
+ void resume();
+
+protected:
+ QGuardedPtr<KIO::TransferJob> _job;
+ QTimer *_resumeTimer;
+};
+
+
+class NSPluginBufStream : public NSPluginStreamBase
+{
+ Q_OBJECT
+
+public:
+ NSPluginBufStream( class NSPluginInstance *instance );
+ ~NSPluginBufStream();
+
+ bool get( const QString& url, const QString& mimeType, const QByteArray &buf, void *notifyData, bool singleShot=false );
+
+protected slots:
+ void timer();
+
+protected:
+ QTimer *_timer;
+ bool _singleShot;
+};
+
+
+class NSPluginInstance : public QObject, public virtual NSPluginInstanceIface
+{
+ Q_OBJECT
+
+public:
+
+ // constructor, destructor
+ NSPluginInstance( NPP privateData, NPPluginFuncs *pluginFuncs, KLibrary *handle,
+ int width, int height, QString src, QString mime,
+ QString appId, QString callbackId, bool embed, WId xembed,
+ QObject *parent, const char* name=0 );
+ ~NSPluginInstance();
+
+ // DCOP functions
+ void shutdown();
+ int winId() { return _form != 0 ? XtWindow(_form) : 0; }
+ int setWindow(Q_INT8 remove=0);
+ void resizePlugin(Q_INT32 w, Q_INT32 h);
+ void javascriptResult(Q_INT32 id, QString result);
+ void displayPlugin();
+ void gotFocusIn();
+ void gotFocusOut();
+
+ // value handling
+ NPError NPGetValue(NPPVariable variable, void *value);
+ NPError NPSetValue(NPNVariable variable, void *value);
+
+ // window handling
+ NPError NPSetWindow(NPWindow *window);
+
+ // stream functions
+ NPError NPDestroyStream(NPStream *stream, NPReason reason);
+ NPError NPNewStream(NPMIMEType type, NPStream *stream, NPBool seekable, uint16 *stype);
+ void NPStreamAsFile(NPStream *stream, const char *fname);
+ int32 NPWrite(NPStream *stream, int32 offset, int32 len, void *buf);
+ int32 NPWriteReady(NPStream *stream);
+
+ // URL functions
+ void NPURLNotify(QString url, NPReason reason, void *notifyData);
+
+ // Event handling
+ uint16 HandleEvent(void *event);
+
+ // signal emitters
+ void emitStatus( const QString &message);
+ void requestURL( const QString &url, const QString &mime,
+ const QString &target, void *notify, bool forceNotify = false, bool reload = false );
+ void postURL( const QString &url, const QByteArray& data, const QString &mime,
+ const QString &target, void *notify, const KParts::URLArgs& args, bool forceNotify = false );
+
+ QString normalizedURL(const QString& url) const;
+
+public slots:
+ void streamFinished( NSPluginStreamBase *strm );
+
+private slots:
+ void timer();
+
+private:
+ friend class NSPluginStreamBase;
+
+ static void forwarder(Widget, XtPointer, XEvent *, Boolean*);
+
+ void destroy();
+
+ bool _destroyed;
+ bool _visible;
+ void addTempFile(KTempFile *tmpFile);
+ QPtrList<KTempFile> _tempFiles;
+ NSPluginCallbackIface_stub *_callback;
+ QPtrList<NSPluginStreamBase> _streams;
+ KLibrary *_handle;
+ QTimer *_timer;
+
+ NPP _npp;
+ NPPluginFuncs _pluginFuncs;
+
+ Widget _area, _form, _toplevel;
+ WId _xembed_window;
+ QString _baseURL;
+ int _width, _height;
+
+ struct Request
+ {
+ // A GET request
+ Request( const QString &_url, const QString &_mime,
+ const QString &_target, void *_notify, bool _forceNotify = false,
+ bool _reload = false)
+ { url=_url; mime=_mime; target=_target; notify=_notify; post=false; forceNotify = _forceNotify; reload = _reload; }
+
+ // A POST request
+ Request( const QString &_url, const QByteArray& _data,
+ const QString &_mime, const QString &_target, void *_notify,
+ const KParts::URLArgs& _args, bool _forceNotify = false)
+ { url=_url; mime=_mime; target=_target;
+ notify=_notify; post=true; data=_data; args=_args;
+ forceNotify = _forceNotify; }
+
+ QString url;
+ QString mime;
+ QString target;
+ QByteArray data;
+ bool post;
+ bool forceNotify;
+ bool reload;
+ void *notify;
+ KParts::URLArgs args;
+ };
+
+ NPWindow _win;
+ NPSetWindowCallbackStruct _win_info;
+ QPtrQueue<Request> _waitingRequests;
+ QMap<int, Request*> _jsrequests;
+};
+
+
+class NSPluginClass : public QObject, virtual public NSPluginClassIface
+{
+ Q_OBJECT
+public:
+
+ NSPluginClass( const QString &library, QObject *parent, const char *name=0 );
+ ~NSPluginClass();
+
+ QString getMIMEDescription();
+ DCOPRef newInstance(QString url, QString mimeType, Q_INT8 embed,
+ QStringList argn, QStringList argv,
+ QString appId, QString callbackId, Q_INT8 reload, Q_INT8 post,
+ QByteArray postData, Q_UINT32 xembed );
+ void destroyInstance( NSPluginInstance* inst );
+ bool error() { return _error; }
+
+ void setApp(const QCString& app) { _app = app; }
+ const QCString& app() const { return _app; }
+
+protected slots:
+ void timer();
+
+private:
+ int initialize();
+ void shutdown();
+
+ KLibrary *_handle;
+ QString _libname;
+ bool _constructed;
+ bool _error;
+ QTimer *_timer;
+
+ NP_GetMIMEDescriptionUPP *_NP_GetMIMEDescription;
+ NP_InitializeUPP *_NP_Initialize;
+ NP_ShutdownUPP *_NP_Shutdown;
+
+ NPPluginFuncs _pluginFuncs;
+ NPNetscapeFuncs _nsFuncs;
+
+ QPtrList<NSPluginInstance> _instances;
+ QPtrList<NSPluginInstance> _trash;
+
+ QCString _app;
+};
+
+
+class NSPluginViewer : public QObject, virtual public NSPluginViewerIface
+{
+ Q_OBJECT
+public:
+ NSPluginViewer( QCString dcopId, QObject *parent, const char *name=0 );
+ virtual ~NSPluginViewer();
+
+ void shutdown();
+ DCOPRef newClass( QString plugin );
+
+private slots:
+ void appUnregistered(const QCString& id);
+
+private:
+ QDict<NSPluginClass> _classes;
+};
+
+
+#endif
diff --git a/nsplugins/viewer/qxteventloop.cpp b/nsplugins/viewer/qxteventloop.cpp
new file mode 100644
index 000000000..856cfe67c
--- /dev/null
+++ b/nsplugins/viewer/qxteventloop.cpp
@@ -0,0 +1,472 @@
+/****************************************************************************
+** Implementation of QWidget class
+**
+** Created : 931031
+**
+** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
+**
+** This file is part of the Xt extension of the Qt GUI Toolkit.
+**
+** This file may be distributed under the terms of the Q Public License
+** as defined by Trolltech AS of Norway and appearing in the file
+** LICENSE.QPL included in the packaging of this file.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
+** licenses may use this file in accordance with the Qt Commercial License
+** Agreement provided with the Software.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/pricing.html or email [email protected] for
+** information about Qt Commercial License Agreements.
+** See http://www.trolltech.com/qpl/ for QPL licensing information.
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact [email protected] if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#include <config.h>
+
+#include "qxteventloop.h"
+
+#if QT_VERSION >= 0x030100
+
+#include <qapplication.h>
+#include <qwidgetintdict.h>
+#include <kglobal.h>
+
+// resolve the conflict between X11's FocusIn and QEvent::FocusIn
+const int XFocusOut = FocusOut;
+const int XFocusIn = FocusIn;
+#undef FocusOut
+#undef FocusIn
+
+const int XKeyPress = KeyPress;
+const int XKeyRelease = KeyRelease;
+#undef KeyPress
+#undef KeyRelease
+
+Boolean qmotif_event_dispatcher( XEvent *event );
+
+class QXtEventLoopPrivate
+{
+public:
+ QXtEventLoopPrivate();
+
+ void hookMeUp();
+ void unhook();
+
+ XtAppContext appContext, ownContext;
+ QMemArray<XtEventDispatchProc> dispatchers;
+ QWidgetIntDict mapper;
+
+ QIntDict<QSocketNotifier> socknotDict;
+ bool activate_timers;
+ XtIntervalId timerid;
+
+ // arguments for Xt display initialization
+ const char* applicationClass;
+ XrmOptionDescRec* options;
+ int numOptions;
+};
+static QXtEventLoopPrivate *static_d = 0;
+static XEvent* last_xevent = 0;
+
+
+/*! \internal
+ Redeliver the given XEvent to Xt.
+
+ Rationale: An XEvent handled by Qt does not go through the Xt event
+ handlers, and the internal state of Xt/Motif widgets will not be
+ updated. This function should only be used if an event delivered by
+ Qt to a QWidget needs to be sent to an Xt/Motif widget.
+*/
+bool QXtEventLoop::redeliverEvent( XEvent *event )
+{
+ // redeliver the event to Xt, NOT through Qt
+ if ( static_d->dispatchers[ event->type ]( event ) )
+ return TRUE;
+ return FALSE;
+}
+
+
+/*!\internal
+ */
+XEvent* QXtEventLoop::lastEvent()
+{
+ return last_xevent;
+}
+
+
+QXtEventLoopPrivate::QXtEventLoopPrivate()
+ : appContext(NULL), ownContext(NULL),
+ activate_timers(FALSE), timerid(0)
+{
+}
+
+void QXtEventLoopPrivate::hookMeUp()
+{
+ // worker to plug Qt into Xt (event dispatchers)
+ // and Xt into Qt (QXtEventLoopEventLoop)
+
+ // ### TODO extensions?
+ dispatchers.resize( LASTEvent );
+ dispatchers.fill( 0 );
+ int et;
+ for ( et = 2; et < LASTEvent; et++ )
+ dispatchers[ et ] =
+ XtSetEventDispatcher( QPaintDevice::x11AppDisplay(),
+ et, ::qmotif_event_dispatcher );
+}
+
+void QXtEventLoopPrivate::unhook()
+{
+ // unhook Qt from Xt (event dispatchers)
+ // unhook Xt from Qt? (QXtEventLoopEventLoop)
+
+ // ### TODO extensions?
+ int et;
+ for ( et = 2; et < LASTEvent; et++ )
+ (void) XtSetEventDispatcher( QPaintDevice::x11AppDisplay(),
+ et, dispatchers[ et ] );
+ dispatchers.resize( 0 );
+
+ /*
+ We cannot destroy the app context here because it closes the X
+ display, something QApplication does as well a bit later.
+ if ( ownContext )
+ XtDestroyApplicationContext( ownContext );
+ */
+ appContext = ownContext = 0;
+}
+
+extern bool qt_try_modal( QWidget *, XEvent * ); // defined in qapplication_x11.cpp
+Boolean qmotif_event_dispatcher( XEvent *event )
+{
+ QApplication::sendPostedEvents();
+
+ QWidgetIntDict *mapper = &static_d->mapper;
+ QWidget* qMotif = mapper->find( event->xany.window );
+ if ( !qMotif && QWidget::find( event->xany.window) == 0 ) {
+ // event is not for Qt, try Xt
+ Display* dpy = QPaintDevice::x11AppDisplay();
+ Widget w = XtWindowToWidget( dpy, event->xany.window );
+ while ( w && ! ( qMotif = mapper->find( XtWindow( w ) ) ) ) {
+ if ( XtIsShell( w ) ) {
+ break;
+ }
+ w = XtParent( w );
+ }
+
+ if ( qMotif &&
+ ( event->type == XKeyPress || event->type == XKeyRelease ) ) {
+ // remap key events
+ event->xany.window = qMotif->winId();
+ }
+ }
+
+ last_xevent = event;
+ bool delivered = ( qApp->x11ProcessEvent( event ) != -1 );
+ last_xevent = 0;
+ if ( qMotif ) {
+ switch ( event->type ) {
+ case EnterNotify:
+ case LeaveNotify:
+ event->xcrossing.focus = False;
+ delivered = FALSE;
+ break;
+ case XKeyPress:
+ case XKeyRelease:
+ delivered = TRUE;
+ break;
+ case XFocusIn:
+ case XFocusOut:
+ delivered = FALSE;
+ break;
+ default:
+ delivered = FALSE;
+ break;
+ }
+ }
+
+ if ( delivered )
+ return True;
+
+
+ if ( QApplication::activePopupWidget() )
+ // we get all events through the popup grabs. discard the event
+ return True;
+
+ if ( qMotif && QApplication::activeModalWidget() ) {
+ if ( !qt_try_modal(qMotif, event) )
+ return True;
+
+ }
+
+ if ( static_d->dispatchers[ event->type ]( event ) )
+ // Xt handled the event.
+ return True;
+
+ return False;
+}
+
+
+
+/*!
+ \class QXtEventLoop
+ \brief The QXtEventLoop class is the core behind the Motif Extension.
+
+ \extension Motif
+
+ QXtEventLoop only provides a few public functions, but is the brains
+ behind the integration. QXtEventLoop is responsible for initializing
+ the Xt toolkit and the Xt application context. It does not open a
+ connection to the X server, this is done by using QApplication.
+
+ The only member function in QXtEventLoop that depends on an X server
+ connection is QXtEventLoop::initialize(). QXtEventLoop must be created before
+ QApplication.
+
+ Example usage of QXtEventLoop and QApplication:
+
+ \code
+ static char *resources[] = {
+ ...
+ };
+
+ int main(int argc, char **argv)
+ {
+ QXtEventLoop integrator( "AppClass" );
+ XtAppSetFallbackResources( integrator.applicationContext(),
+ resources );
+ QApplication app( argc, argv );
+
+ ...
+
+ return app.exec();
+ }
+ \endcode
+*/
+
+/*!
+ Creates QXtEventLoop, which allows Qt and Xt/Motif integration.
+
+ If \a context is NULL, QXtEventLoop creates a default application context
+ itself. The context is accessible through applicationContext().
+
+ All arguments passed to this function (\a applicationClass, \a
+ options and \a numOptions) are used to call XtDisplayInitialize()
+ after QApplication has been constructed.
+*/
+
+
+
+QXtEventLoop::QXtEventLoop( const char *applicationClass, XtAppContext context, XrmOptionDescRec *options , int numOptions)
+{
+#if defined(QT_CHECK_STATE)
+ if ( static_d )
+ qWarning( "QXtEventLoop: should only have one QXtEventLoop instance!" );
+#endif
+
+ d = static_d = new QXtEventLoopPrivate;
+ XtToolkitInitialize();
+ if ( context )
+ d->appContext = context;
+ else
+ d->ownContext = d->appContext = XtCreateApplicationContext();
+
+ d->applicationClass = applicationClass;
+ d->options = options;
+ d->numOptions = numOptions;
+}
+
+
+/*!
+ Destroys QXtEventLoop.
+*/
+QXtEventLoop::~QXtEventLoop()
+{
+ // d->unhook();
+ delete d;
+}
+
+/*!
+ Returns the application context.
+*/
+XtAppContext QXtEventLoop::applicationContext() const
+{
+ return d->appContext;
+}
+
+
+void QXtEventLoop::appStartingUp()
+{
+ int argc = qApp->argc();
+ XtDisplayInitialize( d->appContext,
+ QPaintDevice::x11AppDisplay(),
+ qApp->name(),
+ d->applicationClass,
+ d->options,
+ d->numOptions,
+ &argc,
+ qApp->argv() );
+ d->hookMeUp();
+}
+
+void QXtEventLoop::appClosingDown()
+{
+ d->unhook();
+}
+
+
+/*!\internal
+ */
+void QXtEventLoop::registerWidget( QWidget* w )
+{
+ if ( !static_d )
+ return;
+ static_d->mapper.insert( w->winId(), w );
+}
+
+
+/*!\internal
+ */
+void QXtEventLoop::unregisterWidget( QWidget* w )
+{
+ if ( !static_d )
+ return;
+ static_d->mapper.remove( w->winId() );
+}
+
+
+/*! \internal
+ */
+void qmotif_socknot_handler( XtPointer pointer, int *, XtInputId *id )
+{
+ QXtEventLoop *eventloop = (QXtEventLoop *) pointer;
+ QSocketNotifier *socknot = static_d->socknotDict.find( *id );
+ if ( ! socknot ) // this shouldn't happen
+ return;
+ eventloop->setSocketNotifierPending( socknot );
+}
+
+/*! \reimp
+ */
+void QXtEventLoop::registerSocketNotifier( QSocketNotifier *notifier )
+{
+ XtInputMask mask;
+ switch ( notifier->type() ) {
+ case QSocketNotifier::Read:
+ mask = XtInputReadMask;
+ break;
+
+ case QSocketNotifier::Write:
+ mask = XtInputWriteMask;
+ break;
+
+ case QSocketNotifier::Exception:
+ mask = XtInputExceptMask;
+ break;
+
+ default:
+ qWarning( "QXtEventLoopEventLoop: socket notifier has invalid type" );
+ return;
+ }
+
+ XtInputId id = XtAppAddInput( d->appContext,
+ notifier->socket(), (XtPointer) mask,
+ qmotif_socknot_handler, this );
+ d->socknotDict.insert( id, notifier );
+
+ QEventLoop::registerSocketNotifier( notifier );
+}
+
+/*! \reimp
+ */
+void QXtEventLoop::unregisterSocketNotifier( QSocketNotifier *notifier )
+{
+ QIntDictIterator<QSocketNotifier> it( d->socknotDict );
+ while ( it.current() && notifier != it.current() )
+ ++it;
+ if ( ! it.current() ) {
+ // this shouldn't happen
+ qWarning( "QXtEventLoopEventLoop: failed to unregister socket notifier" );
+ return;
+ }
+
+ XtRemoveInput( it.currentKey() );
+ d->socknotDict.remove( it.currentKey() );
+
+ QEventLoop::unregisterSocketNotifier( notifier );
+}
+
+/*! \internal
+ */
+void qmotif_timeout_handler( XtPointer, XtIntervalId * )
+{
+ static_d->activate_timers = TRUE;
+ static_d->timerid = 0;
+}
+
+/*! \reimp
+ */
+bool QXtEventLoop::processEvents( ProcessEventsFlags flags )
+{
+ // Qt uses posted events to do lots of delayed operations, like repaints... these
+ // need to be delivered before we go to sleep
+ QApplication::sendPostedEvents();
+
+ // make sure we fire off Qt's timers
+ int ttw = timeToWait();
+ if ( d->timerid != 0 ) {
+ XtRemoveTimeOut( d->timerid );
+ }
+ d->timerid = 0;
+ if ( ttw != -1 ) {
+ d->timerid =
+ XtAppAddTimeOut( d->appContext, ttw,
+ qmotif_timeout_handler, 0 );
+ }
+
+ // get the pending event mask from Xt and process the next event
+ XtInputMask pendingmask = XtAppPending( d->appContext );
+ XtInputMask mask = pendingmask;
+ if ( pendingmask & XtIMTimer ) {
+ mask &= ~XtIMTimer;
+ // zero timers will starve the Xt X event dispatcher... so process
+ // something *instead* of a timer first...
+ if ( mask != 0 )
+ XtAppProcessEvent( d->appContext, mask );
+ // and process a timer afterwards
+ mask = pendingmask & XtIMTimer;
+ }
+
+ if ( ( flags & WaitForMore ) )
+ XtAppProcessEvent( d->appContext, XtIMAll );
+ else
+ XtAppProcessEvent( d->appContext, mask );
+
+ int nevents = 0;
+ if ( ! ( flags & ExcludeSocketNotifiers ) )
+ nevents += activateSocketNotifiers();
+
+ if ( d->activate_timers ) {
+ nevents += activateTimers();
+ }
+ d->activate_timers = FALSE;
+
+ return ( (flags & WaitForMore) || ( pendingmask != 0 ) || nevents > 0 );
+}
+
+#include "qxteventloop.moc"
+
+#endif
+
diff --git a/nsplugins/viewer/qxteventloop.h b/nsplugins/viewer/qxteventloop.h
new file mode 100644
index 000000000..0bed590b2
--- /dev/null
+++ b/nsplugins/viewer/qxteventloop.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Implementation of QWidget class
+**
+** Created : 931031
+**
+** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
+**
+** This file is part of the xt extension of the Qt GUI Toolkit.
+**
+** This file may be distributed under the terms of the Q Public License
+** as defined by Trolltech AS of Norway and appearing in the file
+** LICENSE.QPL included in the packaging of this file.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
+** licenses may use this file in accordance with the Qt Commercial License
+** Agreement provided with the Software.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/pricing.html or email [email protected] for
+** information about Qt Commercial License Agreements.
+** See http://www.trolltech.com/qpl/ for QPL licensing information.
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact [email protected] if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+#ifndef QXTEVENTLOOP_H
+#define QXTEVENTLOOP_H
+
+#include <qglobal.h>
+
+#if QT_VERSION >= 0x030100
+#include <qeventloop.h>
+
+
+
+#include <X11/Intrinsic.h>
+
+class QXtEventLoopPrivate;
+
+class QXtEventLoop : public QEventLoop
+{
+ Q_OBJECT
+
+public:
+ QXtEventLoop( const char *applicationClass, XtAppContext context = NULL, XrmOptionDescRec *options = 0, int numOptions = 0);
+ ~QXtEventLoop();
+
+ XtAppContext applicationContext() const;
+
+ void registerSocketNotifier( QSocketNotifier * );
+ void unregisterSocketNotifier( QSocketNotifier * );
+
+ static void registerWidget( QWidget* );
+ static void unregisterWidget( QWidget* );
+ static bool redeliverEvent( XEvent *event );
+ static XEvent* lastEvent();
+
+protected:
+ bool processEvents( ProcessEventsFlags flags );
+
+private:
+ void appStartingUp();
+ void appClosingDown();
+ QXtEventLoopPrivate *d;
+
+};
+
+#endif
+
+#endif // QMOTIF_H
diff --git a/nsplugins/viewer/resolve.h b/nsplugins/viewer/resolve.h
new file mode 100644
index 000000000..d3c747ed2
--- /dev/null
+++ b/nsplugins/viewer/resolve.h
@@ -0,0 +1,46 @@
+/*
+ Copyright (c) 2000 Matthias Hoelzer-Kluepfel <[email protected]>
+
+ 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.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+*/
+
+
+#define RESOLVE_RETVAL(fname,error) \
+ kdDebug() << "NSPluginInstance::" << endl; \
+ \
+ if (!_handle) \
+ return error; \
+ \
+ if (!func_ ## fname) \
+ func_ ## fname = _handle->symbol("NPP_"#fname); \
+ \
+ if (!func_ ## fname) \
+ { \
+ kdDebug() << "Failed: NPP_" << endl; \
+ return error; \
+ } \
+ kdDebug() << "Resolved NPP_" << endl;
+
+
+#define RESOLVE(fname) RESOLVE_RETVAL(fname, NPERR_GENERIC_ERROR)
+#define RESOLVE_VOID(fname) RESOLVE_RETVAL(fname, ;)
+
+
+#define CHECK(fname,error) \
+ kdDebug() << "Result of " << #fname << ":" << error << endl; \
+ return error;
+
+
diff --git a/nsplugins/viewer/viewer.cpp b/nsplugins/viewer/viewer.cpp
new file mode 100644
index 000000000..3e23a944a
--- /dev/null
+++ b/nsplugins/viewer/viewer.cpp
@@ -0,0 +1,312 @@
+/*
+
+ This is a standalone application that executes Netscape plugins.
+
+
+ Copyright (c) 2000 Matthias Hoelzer-Kluepfel <[email protected]>
+ Stefan Schimanski <[email protected]>
+
+ 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.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+*/
+
+
+#include <config.h>
+
+#include "nsplugin.h"
+
+#include <dcopclient.h>
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <qptrlist.h>
+#include <qsocketnotifier.h>
+#include <stdlib.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#ifdef Bool
+#undef Bool
+#endif
+#include <kconfig.h>
+
+#if QT_VERSION < 0x030100
+#include "kxt.h"
+#include <X11/Intrinsic.h>
+#include <X11/Shell.h>
+#else
+#include "qxteventloop.h"
+#include "glibevents.h"
+#endif
+
+/**
+ * Use RLIMIT_DATA on systems that don't define RLIMIT_AS,
+ * such as FreeBSD 4.
+ */
+
+#ifndef RLIMIT_AS
+#define RLIMIT_AS RLIMIT_DATA
+#endif
+
+/**
+ * The error handler catches all X errors, writes the error
+ * message to the debug log and continues.
+ *
+ * This is done to prevent abortion of the plugin viewer
+ * in case the plugin does some invalid X operation.
+ *
+ */
+static int x_errhandler(Display *dpy, XErrorEvent *error)
+{
+ char errstr[256];
+ XGetErrorText(dpy, error->error_code, errstr, 256);
+ kdDebug(1430) << "Detected X Error: " << errstr << endl;
+ return 1;
+}
+
+/*
+ * As the plugin viewer needs to be a motif application, I give in to
+ * the "old style" and keep lot's of global vars. :-)
+ */
+
+static QCString g_dcopId;
+
+/**
+ * parseCommandLine - get command line parameters
+ *
+ */
+void parseCommandLine(int argc, char *argv[])
+{
+ for (int i=0; i<argc; i++)
+ {
+ if (!strcmp(argv[i], "-dcopid") && (i+1 < argc))
+ {
+ g_dcopId = argv[i+1];
+ i++;
+ }
+ }
+}
+
+#if QT_VERSION < 0x030100
+
+static XtAppContext g_appcon;
+static bool g_quit = false;
+
+void quitXt()
+{
+ g_quit = true;
+}
+
+
+/**
+ * socket notifier handling
+ *
+ */
+
+struct SocketNot
+{
+ int fd;
+ QObject *obj;
+ XtInputId id;
+};
+
+QPtrList<SocketNot> _notifiers[3];
+
+/**
+ * socketCallback - send event to the socket notifier
+ *
+ */
+void socketCallback(void *client_data, int* /*source*/, XtInputId* /*id*/)
+{
+ kdDebug(1430) << "-> socketCallback( client_data=" << client_data << " )" << endl;
+
+ QEvent event( QEvent::SockAct );
+ SocketNot *socknot = (SocketNot *)client_data;
+ kdDebug(1430) << "obj=" << (void*)socknot->obj << endl;
+ QApplication::sendEvent( socknot->obj, &event );
+
+ kdDebug(1430) << "<- socketCallback" << endl;
+}
+
+
+/**
+ * qt_set_socket_handler - redefined internal qt function to register sockets
+ * The linker looks in the main binary first and finds this implementation before
+ * the original one in Qt. I hope this works with every dynamic library loader on any OS.
+ *
+ */
+extern bool qt_set_socket_handler( int, int, QObject *, bool );
+bool qt_set_socket_handler( int sockfd, int type, QObject *obj, bool enable )
+{
+ if ( sockfd < 0 || type < 0 || type > 2 || obj == 0 ) {
+#if defined(CHECK_RANGE)
+ qWarning( "QSocketNotifier: Internal error" );
+#endif
+ return FALSE;
+ }
+
+ XtPointer inpMask = 0;
+
+ switch (type) {
+ case QSocketNotifier::Read: inpMask = (XtPointer)XtInputReadMask; break;
+ case QSocketNotifier::Write: inpMask = (XtPointer)XtInputWriteMask; break;
+ case QSocketNotifier::Exception: inpMask = (XtPointer)XtInputExceptMask; break;
+ default: return FALSE;
+ }
+
+ if (enable) {
+ SocketNot *sn = new SocketNot;
+ sn->obj = obj;
+ sn->fd = sockfd;
+
+ if( _notifiers[type].isEmpty() ) {
+ _notifiers[type].insert( 0, sn );
+ } else {
+ SocketNot *p = _notifiers[type].first();
+ while ( p && p->fd > sockfd )
+ p = _notifiers[type].next();
+
+#if defined(CHECK_STATE)
+ if ( p && p->fd==sockfd ) {
+ static const char *t[] = { "read", "write", "exception" };
+ qWarning( "QSocketNotifier: Multiple socket notifiers for "
+ "same socket %d and type %s", sockfd, t[type] );
+ }
+#endif
+ if ( p )
+ _notifiers[type].insert( _notifiers[type].at(), sn );
+ else
+ _notifiers[type].append( sn );
+ }
+
+ sn->id = XtAppAddInput( g_appcon, sockfd, inpMask, socketCallback, sn );
+
+ } else {
+
+ SocketNot *sn = _notifiers[type].first();
+ while ( sn && !(sn->obj == obj && sn->fd == sockfd) )
+ sn = _notifiers[type].next();
+ if ( !sn ) // not found
+ return FALSE;
+
+ XtRemoveInput( sn->id );
+ _notifiers[type].remove();
+ }
+
+ return TRUE;
+}
+#endif
+
+
+int main(int argc, char** argv)
+{
+ // nspluginviewer is a helper app, it shouldn't do session management at all
+ setenv( "SESSION_MANAGER", "", 1 );
+
+ // trap X errors
+ kdDebug(1430) << "1 - XSetErrorHandler" << endl;
+ XSetErrorHandler(x_errhandler);
+ setvbuf( stderr, NULL, _IONBF, 0 );
+
+ kdDebug(1430) << "2 - parseCommandLine" << endl;
+ parseCommandLine(argc, argv);
+
+#if QT_VERSION < 0x030100
+ // Create application
+ kdDebug(1430) << "3 - XtToolkitInitialize" << endl;
+ XtToolkitInitialize();
+ g_appcon = XtCreateApplicationContext();
+ Display *dpy = XtOpenDisplay(g_appcon, NULL, "nspluginviewer", "nspluginviewer",
+ 0, 0, &argc, argv);
+
+ _notifiers[0].setAutoDelete( TRUE );
+ _notifiers[1].setAutoDelete( TRUE );
+ _notifiers[2].setAutoDelete( TRUE );
+
+ kdDebug(1430) << "4 - KXtApplication app" << endl;
+ KLocale::setMainCatalogue("nsplugin");
+ KXtApplication app(dpy, argc, argv, "nspluginviewer");
+#else
+ kdDebug(1430) << "3 - create QXtEventLoop" << endl;
+ QXtEventLoop integrator( "nspluginviewer" );
+ parseCommandLine(argc, argv);
+ KLocale::setMainCatalogue("nsplugin");
+
+ kdDebug(1430) << "4 - create KApplication" << endl;
+ KApplication app( argc, argv, "nspluginviewer" );
+ GlibEvents glibevents;
+#endif
+
+ {
+ KConfig cfg("kcmnspluginrc", true);
+ cfg.setGroup("Misc");
+ int v = KCLAMP(cfg.readNumEntry("Nice Level", 0), 0, 19);
+ if (v > 0) {
+ nice(v);
+ }
+ v = cfg.readNumEntry("Max Memory", 0);
+ if (v > 0) {
+ rlimit rl;
+ memset(&rl, 0, sizeof(rl));
+ if (0 == getrlimit(RLIMIT_AS, &rl)) {
+ rl.rlim_cur = kMin(v, int(rl.rlim_max));
+ setrlimit(RLIMIT_AS, &rl);
+ }
+ }
+ }
+
+ // initialize the dcop client
+ kdDebug(1430) << "5 - app.dcopClient" << endl;
+ DCOPClient *dcop = app.dcopClient();
+ if (!dcop->attach())
+ {
+ KMessageBox::error(NULL,
+ i18n("There was an error connecting to the Desktop "
+ "communications server. Please make sure that "
+ "the 'dcopserver' process has been started, and "
+ "then try again."),
+ i18n("Error Connecting to DCOP Server"));
+ exit(1);
+ }
+
+ kdDebug(1430) << "6 - dcop->registerAs" << endl;
+ if (g_dcopId)
+ g_dcopId = dcop->registerAs( g_dcopId, false );
+ else
+ g_dcopId = dcop->registerAs("nspluginviewer");
+
+ dcop->setNotifications(true);
+
+ // create dcop interface
+ kdDebug(1430) << "7 - new NSPluginViewer" << endl;
+ NSPluginViewer *viewer = new NSPluginViewer( "viewer", 0 );
+
+ // start main loop
+#if QT_VERSION < 0x030100
+ kdDebug(1430) << "8 - XtAppProcessEvent" << endl;
+ while (!g_quit)
+ XtAppProcessEvent( g_appcon, XtIMAll);
+#else
+ kdDebug(1430) << "8 - app.exec()" << endl;
+ app.exec();
+#endif
+
+ // delete viewer
+ delete viewer;
+}