diff options
| author | Michele Calgaro <michele.calgaro@yahoo.it> | 2024-09-04 11:53:23 +0900 | 
|---|---|---|
| committer | Michele Calgaro <michele.calgaro@yahoo.it> | 2024-09-04 13:56:43 +0900 | 
| commit | 0582c90a9ed4b965629267713f51c0da7c38b39d (patch) | |
| tree | cae95e850081d0a7f2be6cef5837f43a28d53d2c /extensions/nsplugin/src/tqnp.cpp | |
| parent | 39f8a475b4ec5c87a11a7e9300a30ef1c5b4a7e1 (diff) | |
| download | tqt-0582c90a.tar.gz tqt-0582c90a.zip | |
Rename remaining ntq[m-r]* related files to equivalent tq* (except ntqmodules.h)
Signed-off-by: Michele Calgaro <michele.calgaro@yahoo.it>
Diffstat (limited to 'extensions/nsplugin/src/tqnp.cpp')
| -rw-r--r-- | extensions/nsplugin/src/tqnp.cpp | 2071 | 
1 files changed, 2071 insertions, 0 deletions
| diff --git a/extensions/nsplugin/src/tqnp.cpp b/extensions/nsplugin/src/tqnp.cpp new file mode 100644 index 000000000..cd373ad45 --- /dev/null +++ b/extensions/nsplugin/src/tqnp.cpp @@ -0,0 +1,2071 @@ +/**************************************************************************** +** +** Implementation of TQt extension classes for Netscape Plugin support. +** +** Created : 970601 +** +** Copyright (C) 1992-2008 Trolltech ASA.  All rights reserved. +** +** This file is part of the TQt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.TQPL +** included in the packaging of this file.  Licensees holding valid TQt +** Commercial licenses may use this file in accordance with the TQt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + + +// Remaining TQ_WS_X11 considerations: +//   - What if !piApp upon NPP_NewStream?  Are we safe? +//      - Yes, but users need to know of this:  that no GUI can be +//         done until after setWindow is called. +//   - Use NPN_GetValue in Communicator4.0 to get the display earlier! +//   - For ClientMessage events, trap them, and if they are not for us, +//	untrap them and retransmit them and set a timer to retrap them +//	after N seconds. + +// Remaining TQ_WS_WIN considerations: +//   - we need to activateZeroTimers() at some time. +//   - we need to call winEventFilter on events +//   - timers: +//    if ( msg.message == WM_TIMER ) {            // timer message received +//        activateTimer( msg.wParam ); +//        return TRUE; +//    } +//    if ( msg.message == WM_KEYDOWN || msg.message == WM_KEYUP ) { +//        if ( translateKeyCode(msg.wParam) == 0 ) { +//            TranslateMessage( &msg );           // translate to WM_CHAR +//            return TRUE; +//        } +//    } +//   - qWinProcessConfigRequests? + +// Remaining general stuff: +//   - Provide the "reason" parameter to streamDestroyed + +// TQt stuff +#include <ntqapplication.h> +#include <tqeventloop.h> +#include <tqwidget.h> +#include <tqobjectlist.h> +#include <tqcursor.h> +#include <tqprinter.h> +#include <tqfile.h> +#include <tqpainter.h> + +#include "tqnp.h" + +#include <stdlib.h>		// Must be here for Borland C++ +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <limits.h> + +#ifdef TQ_WS_X11 +#include <X11/Intrinsic.h> + +class TQNPXtPrivate; + +class TQNPXt : public TQEventLoop +{ +public: +    TQNPXt( const char *applicationClass, XtAppContext context = NULL, XrmOptionDescRec *options = 0, int numOptions = 0); +    ~TQNPXt(); + +    XtAppContext applicationContext() const; + +    void registerSocketNotifier( TQSocketNotifier * ); +    void unregisterSocketNotifier( TQSocketNotifier * ); + +    static void registerWidget( TQWidget* ); +    static void unregisterWidget( TQWidget* ); +    static bool redeliverEvent( XEvent *event ); +    static XEvent* lastEvent(); + +protected: +    bool processEvents( ProcessEventsFlags flags ); + +private: +    void appStartingUp(); +    void appClosingDown(); +    TQNPXtPrivate *d; + +}; + +#define	 GC GC_QQQ +#endif + +extern "C" { +// +// Netscape plugin API +// +#ifdef TQ_WS_WIN +#ifndef _WINDOWS +#define _WINDOWS +#endif +#endif +#ifdef TQ_WS_X11 +#define XP_UNIX +#endif + + +// This is to allow mingw support on windows without altering the sun header files +#if defined(Q_CC_GNU) && defined(TQ_WS_WIN) && !defined(_MSC_VER) +#define _MSC_VER 1 +#include "npapi.h" +#undef _MSC_VER +#else +#include "npapi.h" +#endif + +#ifdef TQ_WS_X11 +#undef XP_UNIX +#include "npunix.c" +#endif + +// +// Stuff for the NPP_SetWindow function: +// +#ifdef TQ_WS_X11 +#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> +//#include <dlfcn.h> +#endif +#ifdef TQ_WS_WIN +#include <windows.h> +#endif +} + +#ifdef TQ_WS_WIN +#include "npwin.cpp" +#endif + +static TQEventLoop* event_loop = 0; +static TQApplication* application = 0; + +struct _NPInstance +{ +    uint16            fMode; + +#ifdef TQ_WS_WIN +    HWND            window; +#endif + +    NPP npp; + +#ifdef TQ_WS_X11 +    Window window; +    Display *display; +#endif + +    uint32 x, y; +    uint32 width, height; + +    TQNPWidget* widget; +    TQNPInstance* instance; + +    int16 argc; +    TQString *argn; +    TQString *argv; +}; + + + +// The single global plugin +static TQNPlugin *qNP=0; +static int instance_count=0; + +// Temporary parameter passed `around the side' of calls to user functions +static _NPInstance* next_pi=0; + +// To avoid looping when browser OR plugin can delete streams +static int qnps_no_call_back = 0; + +#ifdef TQ_WS_WIN +// defined in qapplication_win.cpp +TQ_EXPORT extern bool qt_win_use_simple_timers; +TQ_EXPORT void qWinProcessConfigRequests(); +static HHOOK hhook = 0; + +LRESULT CALLBACK FilterProc( int nCode, WPARAM wParam, LPARAM lParam ) +{ +    if ( tqApp ) { +	tqApp->sendPostedEvents(); +	tqApp->eventLoop()->activateSocketNotifiers(); +	qWinProcessConfigRequests(); +    } + +    return CallNextHookEx( hhook, nCode, wParam, lParam ); +} + +#endif + +#ifdef TQ_WS_X11 +static int (*original_x_errhandler)( Display *dpy, XErrorEvent * ) = 0; +static int dummy_x_errhandler( Display *, XErrorEvent * ) +{ +    return 0; +} +#endif + +/****************************************************************************** + * Plug-in Calls - these are called by Netscape + *****************************************************************************/ + + +// Instance state information about the plugin. + +#ifdef TQ_WS_X11 + +extern "C" char* +NPP_GetMIMEDescription(void) +{ +    if (!qNP) qNP = TQNPlugin::create(); +    return (char*)qNP->getMIMEDescription(); +} + + + +extern "C" NPError +NPP_GetValue(void * /*future*/, NPPVariable variable, void *value) +{ +    if (!qNP) qNP = TQNPlugin::create(); +    NPError err = NPERR_NO_ERROR; +    if (variable == NPPVpluginNameString) +	*((const char **)value) = qNP->getPluginNameString(); +    else if (variable == NPPVpluginDescriptionString) +	*((const char **)value) = qNP->getPluginDescriptionString(); +    else +	err = NPERR_GENERIC_ERROR; + +    return err; +} + +#endif + +/* +** NPP_Initialize is called when your DLL is being loaded to do any +** DLL-specific initialization. +*/ +extern "C" NPError +NPP_Initialize(void) +{ +#ifdef TQ_WS_WIN +    qt_win_use_simple_timers = TRUE; +    // Nothing more - we do it in DLLMain +#endif + +    if (!qNP) qNP = TQNPlugin::create(); +    return NPERR_NO_ERROR; +} + +static jref plugin_java_class = 0; + +/* +** NPP_GetJavaClass is called during initialization to ask your plugin +** what its associated Java class is. If you don't have one, just return +** NULL. Otherwise, use the javah-generated "use_" function to both +** initialize your class and return it. If you can't find your class, an +** error will be signalled by "use_" and will cause the Navigator to +** complain to the user. +*/ +extern "C" jref +NPP_GetJavaClass(void) +{ +    if (!qNP) qNP = TQNPlugin::create(); +    plugin_java_class = (jref)qNP->getJavaClass(); +    return plugin_java_class; +} + +/* +** NPP_Shutdown is called when your DLL is being unloaded to do any +** DLL-specific shut-down. You should be a good citizen and declare that +** you're not using your java class any more. This allows java to unload +** it, freeing up memory. +*/ +extern "C" void +NPP_Shutdown(void) +{ +    if (qNP) { +	if (plugin_java_class) +	    qNP->unuseJavaClass(); +	delete qNP; +	qNP = 0; +    } + +#ifdef TQ_WS_X11 +    if ( original_x_errhandler ) +    	XSetErrorHandler( original_x_errhandler ); +#endif +    if ( tqApp) { +#ifdef TQ_WS_WIN32 +	if ( hhook ) +	    UnhookWindowsHookEx( hhook ); +	hhook = 0; +#endif +	delete application; +	delete event_loop; +    } + +} + + +struct NS_Private { +    uchar* a; +    uchar* b; +}; + +/* +** NPP_New is called when your plugin is instantiated (i.e. when an EMBED +** tag appears on a page). +*/ +extern "C" NPError +NPP_New(NPMIMEType /*pluginType*/, +    NPP instance, +    uint16 mode, +    int16 argc, +    char* argn[], +    char* argv[], +    NPSavedData* /*saved*/) +{ +    NPError result = NPERR_NO_ERROR; +    _NPInstance* This; + +    if (instance == NULL) +	return NPERR_INVALID_INSTANCE_ERROR; + +    instance->pdata = new _NPInstance; + +    This = (_NPInstance*) instance->pdata; + +    if (This == NULL) +	return NPERR_OUT_OF_MEMORY_ERROR; + +    This->npp = instance; + +    /* mode is NP_EMBED, NP_FULL, or NP_BACKGROUND (see npapi.h) */ +    This->fMode = mode; + +    This->window = 0; +    This->widget = 0; + +    This->argc = argc; +    This->argn = new TQString[argc+1]; +    This->argv = new TQString[argc+1]; +    for (int i=0; i<This->argc; i++) { +	This->argn[i] = argn[i]; +	This->argv[i] = argv[i]; +    } + +    // Everything is set up - we can let TQNPInstance be created now. +    next_pi = This; +    qNP->newInstance(); +    instance_count++; + +    return result; +} + +extern "C" NPError +NPP_Destroy(NPP instance, NPSavedData** /*save*/) +{ +    _NPInstance* This; + +    if (instance == NULL) +	return NPERR_INVALID_INSTANCE_ERROR; + +    This = (_NPInstance*) instance->pdata; + +    if (This != NULL) { +	delete This->widget; +	delete This->instance; +	delete [] This->argn; +	delete [] This->argv; + +	delete This; +	instance->pdata = NULL; + +	instance_count--; +    } + +    return NPERR_NO_ERROR; +} + +extern "C" NPError +NPP_SetWindow(NPP instance, NPWindow* window) +{ +    if (!qNP) qNP = TQNPlugin::create(); +    NPError result = NPERR_NO_ERROR; +    _NPInstance* This; + +    if (instance == NULL) +	return NPERR_INVALID_INSTANCE_ERROR; + +    This = (_NPInstance*) instance->pdata; + + +    // take a shortcut if all that was changed is the geometry +    if ( This->widget && window +#ifdef TQ_WS_X11 +	 && This->window == (Window) window->window +#endif +#ifdef TQ_WS_WIN +	 && This->window == (HWND) window->window +#endif +	) { +	This->x = window->x; +	This->y = window->y; +	This->width = window->width; +	This->height = window->height; +	This->widget->resize( This->width, This->height ); +	return result; +    } + +    delete This->widget; + +    if ( !window ) +	return result; + +#ifdef TQ_WS_X11 +    This->window = (Window) window->window; +    This->display = +	((NPSetWindowCallbackStruct *)window->ws_info)->display; +#endif +#ifdef TQ_WS_WIN +    This->window = (HWND) window->window; +#endif + +    This->x = window->x; +    This->y = window->y; +    This->width = window->width; +    This->height = window->height; + + +    if (!tqApp) { +#ifdef TQ_WS_X11 +	// We are the first TQt-based plugin to arrive +	event_loop = new TQNPXt( "qnp", XtDisplayToApplicationContext(This->display) ); +	application = new TQApplication(This->display); +#endif +#ifdef TQ_WS_WIN +	static int argc=0; +	static char **argv={ 0 }; +	application = new TQApplication( argc, argv ); +#ifdef UNICODE +	if ( qWinVersion() & TQt::WV_NT_based ) +	    hhook = SetWindowsHookExW( WH_GETMESSAGE, FilterProc, 0, GetCurrentThreadId() ); +	else +#endif +	    hhook = SetWindowsHookExA( WH_GETMESSAGE, FilterProc, 0, GetCurrentThreadId() ); +#endif +    } + +#ifdef TQ_WS_X11 +    if ( !original_x_errhandler ) +    	original_x_errhandler = XSetErrorHandler( dummy_x_errhandler ); +#endif + +    // New widget on this new window. +    next_pi = This; +    /* This->widget = */ // (happens sooner - in TQNPWidget constructor) +    This->instance->newWindow(); + +    if ( !This->widget ) +	return result; + +#ifdef TQ_WS_X11 +    This->widget->resize( This->width, This->height ); +    XReparentWindow( This->widget->x11Display(), This->widget->winId(), This->window, 0, 0 ); +    XSync( This->widget->x11Display(), False ); +#endif +#ifdef TQ_WS_WIN +    LONG oldLong = GetWindowLong(This->window, GWL_STYLE); +    ::SetWindowLong(This->window, GWL_STYLE, oldLong | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); +    ::SetWindowLong( This->widget->winId(), GWL_STYLE, WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS ); +    ::SetParent( This->widget->winId(), This->window ); +    This->widget->raise(); +    This->widget->setGeometry( 0, 0, This->width, This->height ); +#endif +    This->widget->show(); +    return result; +} + + +extern "C" NPError +NPP_NewStream(NPP instance, +	  NPMIMEType type, +	  NPStream *stream, +	  NPBool seekable, +	  uint16 *stype) +{ +    _NPInstance* This; + +    if (instance == NULL) +	return NPERR_INVALID_INSTANCE_ERROR; + +    This = (_NPInstance*) instance->pdata; + +    if ( This ) { +	TQNPStream* qnps = new TQNPStream(This->instance,type,stream,seekable); +	stream->pdata = qnps; +	TQNPInstance::StreamMode sm = (TQNPInstance::StreamMode)*stype; +	if (!This->instance->newStreamCreated(qnps, sm)) { +	    return NPERR_GENERIC_ERROR; +	} +	*stype = sm; +    } + +    return NPERR_NO_ERROR; +} + + +int32 STREAMBUFSIZE = 0X0FFFFFFF; /* If we are reading from a file in NPAsFile +				   * mode so we can take any size stream in our +				   * write call (since we ignore it) */ + +extern "C" int32 +NPP_WriteReady(NPP instance, NPStream *stream) +{ +    _NPInstance* This; +    if (instance != NULL) { +	This = (_NPInstance*) instance->pdata; +    } else { +	// Yikes, that's unusual! +	return 0; +    } + +    if (This) { +	return This->instance->writeReady((TQNPStream*)stream->pdata); +    } + +    /* Number of bytes ready to accept in NPP_Write() */ +    return STREAMBUFSIZE; +} + + +extern "C" int32 +NPP_Write(NPP instance, NPStream *stream, int32 offset, int32 len, void *buffer) +{ +    if (instance != NULL) +    { +	_NPInstance* This = (_NPInstance*) instance->pdata; + +	if (This) { +	    return This->instance->write((TQNPStream*)stream->pdata, +		offset, len, buffer); +	} +    } + +    return len;        /* The number of bytes accepted */ +} + + +extern "C" NPError +NPP_DestroyStream(NPP instance, NPStream *stream, NPError reason) +{ +    _NPInstance* This; + +    if (instance == NULL) +	return NPERR_INVALID_INSTANCE_ERROR; + +    if (!qnps_no_call_back) { +	This = (_NPInstance*) instance->pdata; + +	TQNPStream* qnps = (TQNPStream*)stream->pdata; +	if ( qnps ) +	    switch (reason) { +		case NPRES_DONE: +		    qnps->setComplete(TRUE); +		    break; +		case NPRES_USER_BREAK: +		    break; +		case NPRES_NETWORK_ERR: +		    qnps->setOkay(FALSE); +		    break; +	    } + +	if (This) { +	    // Give the instance a chance to do something +	    This->instance->streamDestroyed(qnps); +	} + +	qnps_no_call_back++; +	delete qnps; +	qnps_no_call_back--; +    } + +    return NPERR_NO_ERROR; +} + + +extern "C" void +NPP_StreamAsFile(NPP instance, NPStream *stream, const char* fname) +{ +    _NPInstance* This; + +    if (instance == NULL) return; + +    This = (_NPInstance*) instance->pdata; + +    if ( This ) { +	TQNPStream* qnps = (TQNPStream*)stream->pdata; +	This->instance->streamAsFile(qnps, fname); +    } +} + +typedef struct +{ +    int32    type; +    FILE*    fp; +} NPPrintCallbackStruct; + +#ifdef TQ_WS_X11 + +class TQNPPrinter : public TQPrinter { +    TQFile file; +public: +    TQNPPrinter(FILE* fp) +    { +	file.open(IO_WriteOnly, fp); +	TQPDevCmdParam param; +	param.device = &file; +	cmd(PdcSetdev, 0, ¶m); +    } +    void end() +    { +	TQPDevCmdParam param; +	param.device = 0; +	cmd(PdcSetdev, 0, ¶m); +    } +}; +#endif + +extern "C" void +NPP_Print(NPP instance, NPPrint* printInfo) +{ +    if(printInfo == NULL) +	return; + +    if (instance != NULL) { +	_NPInstance* This = (_NPInstance*) instance->pdata; + +	if (printInfo->mode == NP_FULL) { +	    printInfo->print.fullPrint.pluginPrinted = +		This->instance->printFullPage(); +	} else if (printInfo->mode == NP_EMBED) { +#ifdef TQ_WS_X11 +	    void* platformPrint = +		printInfo->print.embedPrint.platformPrint; +	    FILE* outfile = ((NPPrintCallbackStruct*)platformPrint)->fp; +	    if (ftell(outfile)) { +// 		NPWindow* w = +// 		    &(printInfo->print.embedPrint.window); +		TQNPPrinter prn(outfile); +		TQPainter painter(&prn); +		// #### config viewport with w->{x,y,width,height} +		This->instance->print(&painter); +		prn.end(); +	    } else { +		// Why does the browser make spurious NPP_Print calls? +	    } +#endif +#ifdef TQ_WS_WIN +	    NPWindow* printWindow = +		&(printInfo->print.embedPrint.window); +	    void* platformPrint = +		printInfo->print.embedPrint.platformPrint; +	    // #### Nothing yet. +#endif +	} +    } +} + +extern "C" void +NPP_URLNotify(NPP instance, +	      const char* url, +	      NPReason reason, +	      void* notifyData) +{ +    if (instance != NULL) { +	TQNPInstance::Reason r; +	switch (reason) { +	case NPRES_DONE: +	    r = TQNPInstance::ReasonDone; +	    break; +	case NPRES_USER_BREAK: +	    r = TQNPInstance::ReasonBreak; +	    break; +	case NPRES_NETWORK_ERR: +	    r = TQNPInstance::ReasonError; +	    break; +	default: +	    r = TQNPInstance::ReasonUnknown; +	    break; +	} +	_NPInstance* This = (_NPInstance*) instance->pdata; +	This->instance->notifyURL(url, r, notifyData); +    } +} + + + +#ifdef TQ_WS_WIN + +BOOL   WINAPI   DllMain (HANDLE hInst, +			ULONG ul_reason_for_call, +			LPVOID lpReserved) +{ +    return TRUE; +} + +#endif + + + +/*! +    \class TQNPWidget tqnp.h +    \brief The TQNPWidget class provides a TQWidget that is a web browser plugin window. + +    \extension Netscape Plugin + +    Derive from TQNPWidget to create a widget that can be used as a +    web browser plugin window, or create one and add child widgets. +    Instances of TQNPWidget may only be created when +    TQNPInstance::newWindow() is called by the browser. + +    A common way to develop a plugin widget is to develop it as a +    stand-alone application window, then make it a \e child of a +    plugin widget to use it as a browser plugin. The technique is: + +\code +class MyPluginWindow : public TQNPWidget +{ +    TQWidget* child; +public: +    MyPluginWindow() +    { +	// Some widget that is normally used as a top-level widget +	child = new MyIndependentlyDevelopedWidget(); + +	// Use the background color of the web page +	child->setBackgroundColor( backgroundColor() ); + +	// Fill the plugin widget +	child->setGeometry( 0, 0, width(), height() ); +    } + +    void resizeEvent(TQResizeEvent*) +    { +	// Fill the plugin widget +	child->resize(size()); +    } +}; +\endcode + +    The default implementation is an empty window. +*/ + +/*! +    Creates a TQNPWidget. +*/ +TQNPWidget::TQNPWidget() : +     pi(next_pi) +{ +    if (!next_pi) { +	tqFatal("TQNPWidget must only be created within call to newWindow"); +    } +    next_pi->widget = this; +    next_pi = 0; + +#ifdef TQ_WS_WIN +    clearWFlags( WStyle_NormalBorder | WStyle_Title | WStyle_MinMax | WStyle_SysMenu ); +    topData()->ftop = 0; +    topData()->fright = 0; +    topData()->fleft = 0; +    topData()->fbottom = 0; +#endif +} + +/*! +    Destroys the window. This will be called by the plugin binding +    code when the window is no longer required. The web browser will +    delete windows when they leave the page. The bindings will change +    the TQWidget::winId() of the window when the window is resized, but +    this should not affect normal widget behavior. +*/ +TQNPWidget::~TQNPWidget() +{ +#ifdef TQ_WS_X11 +    destroy( FALSE, FALSE ); // X has destroyed all windows +#endif +} + + +/*!\internal */ +void TQNPWidget::enterEvent(TQEvent*) +{ +    enterInstance(); +} + +/*!\internal */ +void TQNPWidget:: leaveEvent(TQEvent*) +{ +    if ( !TQApplication::activePopupWidget() ) +	leaveInstance(); +} + +/*! +    Called when the mouse enters the plugin window. Does nothing by +    default. +*/ +void TQNPWidget::enterInstance() +{ +} + +/*! +    Called when the mouse leaves the plugin window. Does nothing by +    default. +*/ +void TQNPWidget::leaveInstance() +{ +} + +/*! +    Returns the instance for which this widget is the plugin window. +*/ +TQNPInstance* TQNPWidget::instance() +{ +    return pi->instance; +} + + + + + +/*! +    \class TQNPInstance tqnp.h +    \brief The TQNPInstance class provides a TQObject that is a web browser plugin. + +    \extension Netscape Plugin + +    Deriving from TQNPInstance creates an object that represents a +    single \c{<EMBED>} tag in an HTML document. + +    The TQNPInstance is responsible for creating an appropriate +    TQNPWidget window if required (not all plugins have windows), and +    for interacting with the input/output facilities intrinsic to +    plugins. + +    Note that there is \e{absolutely no guarantee} regarding the order +    in which functions are called. Sometimes the browser will call +    newWindow() first, at other times, newStreamCreated() will be +    called first (assuming the \c{<EMBED>} tag has a SRC parameter). + +    \e{None of TQt's GUI functionality} may be used until after the +    first call to newWindow(). This includes any use of TQPaintDevice +    (i.e. TQPixmap, TQWidget, and all subclasses), TQApplication, anything +    related to TQPainter (TQBrush, etc.), fonts, TQMovie, TQToolTip, etc. +    Useful classes which specifically \e can be used are TQImage, +    TQFile, and TQBuffer. + +    This restriction can easily be accommodated by structuring your +    plugin so that the task of the TQNPInstance is to gather data, +    while the task of the TQNPWidget is to provide a graphical +    interface to that data. +*/ + +/*! +    \enum TQNPInstance::InstanceMode + +    This enum type provides TQt-style names for three #defines in +    \c npapi.h: + +    \value Embed - corresponds to NP_EMBED +    \value Full - corresponds to NP_FULL +    \value Background - corresponds to NP_BACKGROUND + +*/ + +/*! +    \enum TQNPInstance::Reason + +    \value ReasonDone +    \value ReasonBreak +    \value ReasonError +    \value ReasonUnknown +*/ + +/*! +    \enum TQNPInstance::StreamMode + +    \value Normal +    \value Seek +    \value AsFile +    \value AsFileOnly +*/ + +/*! +    Creates a TQNPInstance. + +    Can only be called from within a derived class created within +    TQNPlugin::newInstance(). +*/ +TQNPInstance::TQNPInstance() : +    pi(next_pi) +{ +    if (!next_pi) { +	tqFatal("TQNPInstance must only be created within call to newInstance"); +    } +    next_pi->instance = this; +    next_pi = 0; +} + +/*! +    Called when the plugin instance is about to be deleted. +*/ +TQNPInstance::~TQNPInstance() +{ +} + +/*! +    Called at most once, at some time after the TQNPInstance is +    created. If the plugin requires a window, this function should +    return a derived class of TQNPWidget that provides the required +    interface. +*/ +TQNPWidget* TQNPInstance::newWindow() +{ +    // No window by default +    next_pi = 0; +    return 0; +} + +/*! +    Returns the plugin window created by newWindow(), if any. +*/ +TQNPWidget* TQNPInstance::widget() +{ +    return pi->widget; +} + +/*! +    \fn bool TQNPInstance::newStreamCreated(TQNPStream*, StreamMode& smode) + +    This function is called when a new stream has been created. The +    instance should return TRUE if it accepts the processing of the +    stream. If the instance requires the stream as a file, it should +    set \a smode to \c AsFileOnly, in which case the data will be +    delivered some time later to the streamAsFile() function. +    Otherwise, the data will be delivered in chunks to the write() +    function, which must consume at least as much data as returned +    by the most recent call to writeReady(). + +    Note that the \c AsFileOnly method is not supported by Netscape +    2.0 and MSIE 3.0. + +    The default implementation accepts any stream. +*/ +bool TQNPInstance::newStreamCreated(TQNPStream*, StreamMode&) +{ +    return TRUE; +} + +/*! +    Called when a stream is delivered as a single file called \a fname +    rather than as chunks. This may be simpler for a plugin to deal +    with, but precludes any incremental behavior. + +    Note that the \c AsFileOnly method is not supported by Netscape +    2.0 and MSIE 3.0. + +    \sa newStreamCreated(), newStream() +*/ +void TQNPInstance::streamAsFile(TQNPStream*, const char* fname) +{ +} + +/*! +    Called when a stream is destroyed. At this point, the stream may +    be complete() and okay(). If it is not okay(), then an error has +    occurred. If it is okay(), but not complete(), then the user has +    cancelled the transmission; do not give an error message in this +    case. +*/ +void TQNPInstance::streamDestroyed(TQNPStream*) +{ +} + +/*! +    Returns the minimum amount of data the instance is willing to +    receive from the given stream. + +    The default returns a very large value. +*/ +int TQNPInstance::writeReady(TQNPStream*) +{ +    // Yes, we can handle any amount of data at once. +    return 0X0FFFFFFF; +} + +/*! +    \fn int TQNPInstance::write(TQNPStream*, int offset, int len, void* buffer) + +    Called when incoming data is available for processing by the +    instance. The instance \e must consume at least the amount that it +    returned in the most recent call to writeReady(), but it may +    consume up to the amount given by \a len. \a buffer is the data +    available for consumption. The \a offset argument is merely an +    informational value indicating the total amount of data that has +    been consumed in prior calls. + +    This function should return the amount of data actually consumed. +*/ +int TQNPInstance::write(TQNPStream*, int, int len, void*) +{ +    // Yes, we processed it all... into the bit bucket. +    return len; +} + +/*! +    Requests that the \a url be retrieved and sent to the named \a +    window. See Netscape's JavaScript documentation for an explanation +    of window names. +*/ +void TQNPInstance::getURL(const char* url, const char* window) +{ +    NPN_GetURL( pi->npp, url, window ); +} + +/*! +    \preliminary + +    This function is \e{not tested}. + +    It is an interface to the NPN_PostURL function of the Netscape +    Plugin API. + +    Passes \a url, \a window, \a buf, \a len, and \a file to +    NPN_PostURL. +*/ +void TQNPInstance::postURL(const char* url, const char* window, +	     uint len, const char* buf, bool file) +{ +    NPN_PostURL( pi->npp, url, window, len, buf, file ); +} + +/*! +    Requests that the given \a url be retrieved and sent to +    the named \a window. See Netscape's JavaScript documentation for +    an explanation of window names. Passes the arguments including \a +    data to NPN_GetURLNotify. + +    \sa +    \link http://developer.netscape.com/docs/manuals/communicator/plugin/refpgur.htm#npngeturlnotify +    Netscape: NPN_GetURLNotify method\endlink +*/ +void TQNPInstance::getURLNotify(const char* url, const char* window, void*data) +{ +#ifdef TQ_WS_WIN // Only on Windows? +    NPN_GetURLNotify( pi->npp, url, window, data ); +#else +    Q_UNUSED( url ); +    Q_UNUSED( window ); +    Q_UNUSED( data ); +#endif +} + +/*! +    \preliminary + +    This function is \e{not tested}. + +    It is an encapsulation of the NPP_Print function of the Netscape +    Plugin API. +*/ +bool TQNPInstance::printFullPage() +{ +    return FALSE; +} + +/*! +    \preliminary + +    This function is \e{not tested}. + +    Print the instance embedded in a page. + +    It is an encapsulation of the NPP_Print function of the Netscape +    Plugin API. +*/ +void TQNPInstance::print(TQPainter*) +{ +    // ### default could redirected-print the window. +} + +/*! +    Returns the number of arguments to the instance. Note that you +    should not normally rely on the ordering of arguments, and +    note that the SGML specification does not permit multiple +    arguments with the same name. + +    \sa arg(), argn() +*/ +int TQNPInstance::argc() const +{ +    return pi->argc; +} + +/*! +    Returns the name of the \a{i}-th argument. + +    \sa argc(), argv() +*/ +const char* TQNPInstance::argn(int i) const +{ +    return pi->argn[i]; +} + +/*! +    \preliminary + +    This function is \e{not tested}. + +    Called whenever a \a url is notified after a call to +    NPN_GetURLNotify with \a notifyData. The reason is given in \a r. + +    It is an encapsulation of the NPP_URLNotify function of the +    Netscape Plugin API. + +    See also: +    \link http://developer.netscape.com/docs/manuals/communicator/plugin/refpgur.htm#nppurlnotify +    Netscape: NPP_URLNotify method\endlink +*/ +void TQNPInstance::notifyURL(const char*, Reason, void*) +{ +} + +/*! +    Returns the value of the \a{i}-th argument. + +    \as argc(), arg() +*/ +const char* TQNPInstance::argv(int i) const +{ +    return pi->argv[i]; +} + +/*! +    Returns the mode of the plugin. +*/ +TQNPInstance::InstanceMode TQNPInstance::mode() const +{ +    return (TQNPInstance::InstanceMode)pi->fMode; +} + +/*! +    Returns the value of the named arguments, or 0 if no argument +    called \a name appears in the \c{<EMBED>} tag of this instance. +    If the argument appears, but has no value assigned, the empty +    string is returned. In summary: + +    \table +    \header \i Tag \i Result +    \row \i \c{<EMBED ...>} \i arg("FOO") == 0 +    \row \i \c{<EMBED FOO ...>} \i arg("FOO") == "" +    \row \i \c{<EMBED FOO=BAR ...>} \i arg("FOO") == "BAR" +    \endtable +*/ +const char* TQNPInstance::arg(const char* name) const +{ +    for (int i=0; i<pi->argc; i++) { +	// SGML: names are case insensitive +	if ( tqstricmp( name, pi->argn[i] ) == 0 ) { +	    if (pi->argv[i].isEmpty()) +		return ""; +	    else +		return pi->argv[i]; +	} +    } +    return 0; +} + +/*! +    Returns the user agent (browser name) containing this instance. +*/ +const char* TQNPInstance::userAgent() const +{ +    return NPN_UserAgent(pi->npp); +} + +/*! +    \preliminary + +    This function is \e{not tested}. + +    Requests the creation of a new data stream \e from the plugin. +    The MIME type and window are passed in \a mimetype and \a window. +    \a as_file holds the \c AsFileOnly flag. It is an interface to the +    NPN_NewStream function of the Netscape Plugin API. +*/ +TQNPStream* TQNPInstance::newStream(const char* mimetype, const char* window, +    bool as_file) +{ +    NPStream* s=0; +    NPError err = NPN_NewStream(pi->npp, (char*)mimetype, window, &s); +    if (err != NPERR_NO_ERROR) return 0; +    return s ? new TQNPStream(this, mimetype, s, as_file) : 0; +} + +/*! +    Sets the status message in the browser containing this instance to +    \a msg. +*/ +void TQNPInstance::status(const char* msg) +{ +    NPN_Status(pi->npp, msg); +} + + +/*! +    Returns the Java object associated with the plugin instance, an +    object of the \link TQNPlugin::getJavaClass() plugin's Java +    class\endlink, or 0 if the plug-in does not have a Java class, +    Java is disabled, or an error occurred. + +    The return value is actually a \c{jref} we use \c{void*} so as to +    avoid burdening plugins which do not require Java. + +    \sa TQNPlugin::getJavaClass(), TQNPlugin::getJavaEnv(), getJavaPeer() +*/ +void* TQNPInstance::getJavaPeer() const +{ +    return NPN_GetJavaPeer(pi->npp); +} + + +/*! +    \class TQNPStream tqnp.h +    \brief The TQNPStream class provides a stream of data provided to a TQNPInstance by the browser. + +    \extension Netscape Plugin + +    Note that this is neither a TQTextStream nor a TQDataStream. + +    \sa TQNPInstance::write(), TQNPInstance::newStreamCreated() +*/ + +/*! +    Creates a stream. Plugins should not call this; they should call +    TQNPInstance::newStream() if they need a stream. + +    Takes a TQNPInstance \a in, MIME type \a mt, a pointer to an +    _NPStream \a st and a seekable flag \a se. +*/ +TQNPStream::TQNPStream(TQNPInstance* in,const char* mt, _NPStream* st, bool se) : +    inst(in), +    stream(st), +    mtype(mt), +    seek(se) +{ +    isokay = TRUE; +    iscomplete = FALSE; +} + +/*! +    Destroys the stream. +*/ +TQNPStream::~TQNPStream() +{ +    if (!qnps_no_call_back) { +	qnps_no_call_back++; +	NPN_DestroyStream(inst->pi->npp, stream, NPRES_USER_BREAK); +	qnps_no_call_back--; +    } +} + +/*! +    \fn TQNPInstance* TQNPStream::instance() + +    Returns the TQNPInstance for which this stream was created. +*/ + +/*! +    Returns the URL from which the stream was created. +*/ +const char* TQNPStream::url() const +{ +    return stream->url; +} + +/*! +    Returns the length of the stream in bytes. The function might +    return 0 for streams of unknown length. +*/ +uint TQNPStream::end() const +{ +    return stream->end; +} + +/*! +    Returns the time when the source of the stream was last modified. +*/ +uint TQNPStream::lastModified() const +{ +    return stream->lastmodified; +} + +/*! +    Returns the MIME type of the stream. +*/ +const char* TQNPStream::type() const +{ +    return mtype; +} + +/*! +    Returns TRUE if the stream is seekable; otherwise returns FALSE. +*/ +bool TQNPStream::seekable() const +{ +    return seek; +} + +/*! +  \internal +*/ +void TQNPStream::setOkay(bool y) +{ +    isokay = y; +} + +/*! +  \internal +*/ +void TQNPStream::setComplete(bool y) +{ +    iscomplete = y; +} + +/*! +    Returns TRUE if no errors have occurred on the stream; otherwise +    returns FALSE. +*/ +bool TQNPStream::okay() const +{ +    return isokay; +} + +/*! +    Returns TRUE if the stream has received all the data from the +    source; otherwise returns FALSE. +*/ +bool TQNPStream::complete() const +{ +    return iscomplete; +} + +/*! +    Requests the section of the stream, of \a length bytes from \a +    offset, be sent to the TQNPInstance::write() function of the +    instance() of this stream. +*/ +void TQNPStream::requestRead(int offset, uint length) +{ +    NPByteRange range; +    range.offset = offset; +    range.length = length; +    range.next = 0; // ### Only one supported at this time +    NPN_RequestRead(stream, &range); +} + +/*! +    Writes \a len bytes from \a buffer \e to the stream. +*/ +int TQNPStream::write( int len, void* buffer ) +{ +    return NPN_Write(inst->pi->npp, stream, len, buffer); +} + + + +/****************************************************************************** + * The plugin itself - only one ever exists, created by TQNPlugin::create() + *****************************************************************************/ + + +/*! +    \class TQNPlugin tqnp.h +    \brief The TQNPlugin class provides the main factory for plugin objects. + +    \extension Netscape Plugin + +    This class is the heart of the plugin. One instance of this object +    is created when the plugin is \e first needed, by calling +    TQNPlugin::create(), which must be implemented in your plugin code +    to return some derived class of TQNPlugin. The one TQNPlugin object +    creates all TQNPInstance instances for a web browser running in a +    single process. + +    Additionally, if TQt is linked to the plugin as a dynamic library, +    only one instance of TQApplication will exist \e{across all plugins +    that have been made with TQt}. So, your plugin should tread lightly +    on global settings. Do not, for example, use +    TQApplication::setFont() - that will change the font in every +    widget of every TQt-based plugin currently loaded! +*/ + +/*! +    \fn TQNPlugin* TQNPlugin::create() + +    This function must be implemented by your plugin code. It should return a +    derived class of TQNPlugin. +*/ + +/*! +    Returns the plugin most recently returned by TQNPlugin::create(). +*/ +TQNPlugin* TQNPlugin::actual() +{ +    return qNP; +} + +/*! +    Creates a TQNPlugin. This may only be used by the constructor +    of the class, derived from TQNPlugin, that is returned by your +    plugin's implementation of the TQNPlugin::create() function. +*/ +TQNPlugin::TQNPlugin() +{ +    // Encourage linker to include stuff. +    static void* a; +    a = (void*)NP_Initialize; +    a = (void*)NP_Shutdown; +} + +/*! +    Destroys the TQNPlugin. This is called by the plugin binding code +    just before the plugin is about to be unloaded from memory. If +    newWindow() has been called, a TQApplication will still exist at +    this time, but will be deleted shortly after, just before the plugin +    is deleted. +*/ +TQNPlugin::~TQNPlugin() +{ +} + +/*! +    Populates \e *\a plugin_major and \e *\a plugin_minor with the +    version of the plugin API and populates \e *\a browser_major and +    \e *\a browser_minor with the version of the web browser. +*/ +void TQNPlugin::getVersionInfo(int& plugin_major, int& plugin_minor, +	     int& browser_major, int& browser_minor) +{ +    NPN_Version(&plugin_major, &plugin_minor, &browser_major, &browser_minor); +} + +/*! +    \fn TQNPInstance* TQNPlugin::newInstance() + +    Override this function to return an appropriate derived class of +    TQNPInstance. +*/ + +/*! +    \fn const char* TQNPlugin::getMIMEDescription() const + +    Override this function to return the MIME description of the data formats +    supported by your plugin. The format of this string is shown by +    the following example: + +\code +    const char* getMIMEDescription() const +    { +	return "image/x-png:png:PNG Image;" +	       "image/png:png:PNG Image;" +	       "image/x-portable-bitmap:pbm:PBM Image;" +	       "image/x-portable-graymap:pgm:PGM Image;" +	       "image/x-portable-pixmap:ppm:PPM Image;" +	       "image/bmp:bmp:BMP Image;" +	       "image/x-ms-bmp:bmp:BMP Image;" +	       "image/x-xpixmap:xpm:XPM Image;" +	       "image/xpm:xpm:XPM Image"; +    } +\endcode +*/ + +/*! +    \fn const char* TQNPlugin::getPluginNameString() const + +    Returns a pointer to the plain-text name of the plugin. +*/ + +/*! +    \fn const char* TQNPlugin::getPluginDescriptionString() const + +    Returns a pointer to the plain-text description of the plugin. +*/ + +/*! +    Override this function to return a reference to the Java class that represents +    the plugin. The default returns 0, indicating no class. + +    If you override this class, you must also override +    TQNPlugin::unuseJavaClass(). + +    The return value is actually a \c{jref}; we use \c{void*} so as to +    avoid burdening plugins which do not require Java. + +    \sa getJavaEnv(), TQNPInstance::getJavaPeer() +*/ +void* TQNPlugin::getJavaClass() +{ +    return NULL; +} + +/*! +    This function is called when the plugin is shutting down. The +    function should \e unuse the Java class returned earlier by +    getJavaClass(). +*/ +void TQNPlugin::unuseJavaClass() +{ +    tqFatal("TQNPlugin::unuseJavaClass() must be overridden along with getJavaClass()"); +} + +/*! +    Returns a pointer to the Java execution environment, or 0 if +    either Java is disabled or an error occurred. + +    The return value is actually a \c{JRIEnv*}; we use \c{void*} so as +    to avoid burdening plugins which do not require Java. + +    \sa getJavaClass(), TQNPInstance::getJavaPeer() +*/ +void* TQNPlugin::getJavaEnv() const +{ +    return NPN_GetJavaEnv(); +} + +#ifdef TQ_WS_X11 + +#include <ntqapplication.h> +#include <tqwidgetintdict.h> + +// resolve the conflict between X11's FocusIn and TQEvent::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 qnpxt_event_dispatcher( XEvent *event ); +static void qnpxt_keep_alive(); +void qnpxt_timeout_handler( XtPointer, XtIntervalId * ); + +class TQNPXtPrivate +{ +public: +    TQNPXtPrivate(); + +    void hookMeUp(); +    void unhook(); + +    XtAppContext appContext, ownContext; +    TQMemArray<XtEventDispatchProc> dispatchers; +    TQWidgetIntDict mapper; + +    TQIntDict<TQSocketNotifier> socknotDict; +    uint pending_socknots; +    bool activate_timers; +    int timerid; + +    // arguments for Xt display initialization +    const char* applicationClass; +    XrmOptionDescRec* options; +    int numOptions; +}; +static TQNPXtPrivate *static_d = 0; +static XEvent* last_xevent = 0; + + +bool TQNPXt::redeliverEvent( XEvent *event ) +{ +    // redeliver the event to Xt, NOT through TQt +    if ( static_d->dispatchers[ event->type ]( event ) ) { +	// tqDebug( "Xt: redelivered event" ); +	return TRUE; +    } +    return FALSE; +}; + + +XEvent* TQNPXt::lastEvent() +{ +    return last_xevent; +} + + +TQNPXtPrivate::TQNPXtPrivate() +    : appContext(NULL), ownContext(NULL), +      pending_socknots(0), activate_timers(FALSE), timerid(-1) +{ +} + +void TQNPXtPrivate::hookMeUp() +{ +    // worker to plug TQt into Xt (event dispatchers) +    // and Xt into TQt (TQNPXtEventLoop) + +    // ### TODO extensions? +    dispatchers.resize( LASTEvent ); +    dispatchers.fill( 0 ); +    int et; +    for ( et = 2; et < LASTEvent; et++ ) +	dispatchers[ et ] = +	    XtSetEventDispatcher( TQPaintDevice::x11AppDisplay(), +				  et, ::qnpxt_event_dispatcher ); +} + +void TQNPXtPrivate::unhook() +{ +    // unhook TQt from Xt (event dispatchers) +    // unhook Xt from TQt? (TQNPXtEventLoop) + +    // ### TODO extensions? +    int et; +    for ( et = 2; et < LASTEvent; et++ ) +	(void) XtSetEventDispatcher( TQPaintDevice::x11AppDisplay(), +				     et, dispatchers[ et ] ); +    dispatchers.resize( 0 ); + +    /* +      We cannot destroy the app context here because it closes the X +      display, something TQApplication does as well a bit later. +      if ( ownContext ) +          XtDestroyApplicationContext( ownContext ); +     */ +    appContext = ownContext = 0; +} + +extern bool tqt_try_modal( TQWidget *, XEvent * ); // defined in qapplication_x11.cpp +Boolean qnpxt_event_dispatcher( XEvent *event ) +{ +    static bool grabbed = FALSE; + +    TQApplication::sendPostedEvents(); + +    TQWidgetIntDict *mapper = &static_d->mapper; +    TQWidget* qnpxt = mapper->find( event->xany.window ); +    if ( !qnpxt && TQWidget::find( event->xany.window) == 0 ) { +	// event is not for TQt, try Xt +	Widget w = XtWindowToWidget( TQPaintDevice::x11AppDisplay(), +				     event->xany.window ); +	while ( w && ! ( qnpxt = mapper->find( XtWindow( w ) ) ) ) { +	    if ( XtIsShell( w ) ) { +		break; +	    } +	    w = XtParent( w ); +	} + + 	if ( qnpxt && ( event->type == XKeyPress || +			 event->type == XKeyRelease ) )  { +	    // remap key events to keep accelerators working + 	    event->xany.window = qnpxt->winId(); + 	} + +	if ( w ) { +	    if ( !grabbed && ( event->type        == XFocusIn && +			       event->xfocus.mode == NotifyGrab ) ) { +		// tqDebug( "Xt: grab started" ); +		grabbed = TRUE; +	    } else if ( grabbed && ( event->type        == XFocusOut && +				     event->xfocus.mode == NotifyUngrab ) ) { +		// tqDebug( "Xt: grab ended" ); +		grabbed = FALSE; +	    } +	} +    } + +    /* +      If the mouse has been grabbed for a window that we don't know +      about, we shouldn't deliver any pointer events, since this will +      intercept the event that ends the mouse grab that Xt/Motif +      started. +    */ +    bool do_deliver = TRUE; +    if ( grabbed && ( event->type == ButtonPress   || +		      event->type == ButtonRelease || +		      event->type == MotionNotify  || +		      event->type == EnterNotify   || +		      event->type == LeaveNotify ) ) +	do_deliver = FALSE; + +    last_xevent = event; +    bool delivered = do_deliver && ( tqApp->x11ProcessEvent( event ) != -1 ); +    last_xevent = 0; +    if ( qnpxt ) { +	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; +	} +    } + +    qnpxt_keep_alive(); + +    if ( delivered ) { +	// tqDebug( "TQt: delivered event" ); +	return True; +    } + +    // discard user input events when we have an active popup widget +    if ( TQApplication::activePopupWidget() ) { +	switch ( event->type ) { +	case ButtonPress:			// disallow mouse/key events +	case ButtonRelease: +	case MotionNotify: +	case XKeyPress: +	case XKeyRelease: +	case EnterNotify: +	case LeaveNotify: +	case ClientMessage: +	    // tqDebug( "TQt: active popup - discarding event" ); +	    return True; + +	default: +	    break; +	} +    } + +    if ( TQApplication::activeModalWidget() ) { +	if ( qnpxt ) { +	    // send event through TQt modality handling... +	    if ( !tqt_try_modal( qnpxt, event ) ) { +		// tqDebug( "TQt: active modal widget discarded event" ); +		return True; +	    } +	} else if ( !grabbed ) { +	    // we could have a pure Xt shell as a child of the active +	    // modal widget +	    TQWidget *qw = 0; +	    Widget xw = XtWindowToWidget( TQPaintDevice::x11AppDisplay(), +					  event->xany.window ); +	    while ( xw && !( qw = mapper->find( XtWindow( xw ) ) ) ) +		xw = XtParent( xw ); + +	    while ( qw && qw != TQApplication::activeModalWidget() ) +		qw = qw->parentWidget(); + +	    if ( !qw ) { +		// event is destined for an Xt widget, but since TQt has an +		// active modal widget, we stop here... +		switch ( event->type ) { +		case ButtonPress:			// disallow mouse/key events +		case ButtonRelease: +		case MotionNotify: +		case XKeyPress: +		case XKeyRelease: +		case EnterNotify: +		case LeaveNotify: +		case ClientMessage: +		    // tqDebug( "TQt: active modal widget discarded unknown event" ); +		    return True; +		default: +		    break; +		} +	    } +	} +    } + +    if ( static_d->dispatchers[ event->type ]( event ) ) { +	// tqDebug( "Xt: delivered event" ); +	// Xt handled the event. +	return True; +    } + +    return False; +} + + + +TQNPXt::TQNPXt( const char *applicationClass, XtAppContext context, +		XrmOptionDescRec *options , int numOptions) +{ +#if defined(QT_CHECK_STATE) +    if ( static_d ) +	tqWarning( "TQNPXt: should only have one TQNPXt instance!" ); +#endif + +    d = static_d = new TQNPXtPrivate; +    XtToolkitInitialize(); +    if ( context ) +	d->appContext = context; +    else +	d->ownContext = d->appContext = XtCreateApplicationContext(); + +    d->applicationClass = applicationClass; +    d->options = options; +    d->numOptions = numOptions; +} + + +TQNPXt::~TQNPXt() +{ +    delete d; +    static_d = 0; +} + +XtAppContext TQNPXt::applicationContext() const +{ +    return d->appContext; +} + + +void TQNPXt::appStartingUp() +{ +    /* +      TQApplication could be using a Display from an outside source, so +      we should only initialize the display if the current application +      context does not contain the TQApplication display +    */ + +    bool display_found = FALSE; +    Display **displays; +    Cardinal x, count; +    XtGetDisplays( d->appContext, &displays, &count ); +    for ( x = 0; x < count && ! display_found; ++x ) { +	if ( displays[x] == TQPaintDevice::x11AppDisplay() ) +	    display_found = TRUE; +    } +    if ( displays ) +	XtFree( (char *) displays ); + +    if ( ! display_found ) { +	int argc = tqApp->argc(); +	XtDisplayInitialize( d->appContext, +			     TQPaintDevice::x11AppDisplay(), +			     tqApp->name(), +			     d->applicationClass, +			     d->options, +			     d->numOptions, +			     &argc, +			     tqApp->argv() ); +    } + +    d->hookMeUp(); + +    // start a zero-timer to get the timer keep-alive working +    d->timerid = XtAppAddTimeOut( d->appContext, 0, qnpxt_timeout_handler, 0 ); +} + +void TQNPXt::appClosingDown() +{ +    if ( d->timerid != -1 ) +	XtRemoveTimeOut( d->timerid ); +    d->timerid = -1; + +    d->unhook(); +} + + +void TQNPXt::registerWidget( TQWidget* w ) +{ +    if ( !static_d ) +	return; +    static_d->mapper.insert( w->winId(), w ); +} + + +void TQNPXt::unregisterWidget( TQWidget* w ) +{ +    if ( !static_d ) +	return; +    static_d->mapper.remove( w->winId() ); +} + + +void qnpxt_socknot_handler( XtPointer pointer, int *, XtInputId *id ) +{ +    TQNPXt *eventloop = (TQNPXt *) pointer; +    TQSocketNotifier *socknot = static_d->socknotDict.find( *id ); +    if ( ! socknot ) // this shouldn't happen +	return; +    eventloop->setSocketNotifierPending( socknot ); +    if ( ++static_d->pending_socknots > static_d->socknotDict.count() ) { +	/* +	  We have too many pending socket notifiers.  Since Xt prefers +	  socket notifiers over X events, we should go ahead and +	  activate all our pending socket notifiers so that the event +	  loop doesn't freeze up because of this. +	*/ +	eventloop->activateSocketNotifiers(); +	static_d->pending_socknots = 0; +    } +} + +void TQNPXt::registerSocketNotifier( TQSocketNotifier *notifier ) +{ +    XtInputMask mask; +    switch ( notifier->type() ) { +    case TQSocketNotifier::Read: +	mask = XtInputReadMask; +	break; + +    case TQSocketNotifier::Write: +	mask = XtInputWriteMask; +	break; + +    case TQSocketNotifier::Exception: +	mask = XtInputExceptMask; +	break; + +    default: +	tqWarning( "TQNPXtEventLoop: socket notifier has invalid type" ); +	return; +    } + +    XtInputId id = XtAppAddInput( d->appContext, +				  notifier->socket(), (XtPointer) mask, +				  qnpxt_socknot_handler, this ); +    d->socknotDict.insert( id, notifier ); + +    TQEventLoop::registerSocketNotifier( notifier ); +} + +void TQNPXt::unregisterSocketNotifier( TQSocketNotifier *notifier ) +{ +    TQIntDictIterator<TQSocketNotifier> it( d->socknotDict ); +    while ( it.current() && notifier != it.current() ) +	++it; +    if ( ! it.current() ) { +	// this shouldn't happen +	tqWarning( "TQNPXtEventLoop: failed to unregister socket notifier" ); +	return; +    } + +    XtRemoveInput( it.currentKey() ); +    d->socknotDict.remove( it.currentKey() ); + +    TQEventLoop::unregisterSocketNotifier( notifier ); +} + +static void qnpxt_keep_alive() { +    // make sure we fire off TQt's timers +    int ttw = TQApplication::eventLoop()->timeToWait(); +    if ( static_d->timerid != -1 ) +	XtRemoveTimeOut( static_d->timerid ); +    static_d->timerid = -1; +    if ( ttw != -1 ) { +	static_d->timerid = +	    XtAppAddTimeOut( static_d->appContext, ttw, qnpxt_timeout_handler, 0 ); +    } +} + +void qnpxt_timeout_handler( XtPointer, XtIntervalId * ) +{ +    static_d->timerid = -1; + +    if ( ! TQApplication::eventLoop()->loopLevel() ) { +	/* +	  when the TQt eventloop is not running, make sure that TQt +	  timers still work with an Xt keep-alive timer +	*/ +	TQApplication::eventLoop()->activateTimers(); +	static_d->activate_timers = FALSE; + +	qnpxt_keep_alive(); +    } else { +	static_d->activate_timers = TRUE; +    } +} + +bool TQNPXt::processEvents( ProcessEventsFlags flags ) +{ +    // TQt uses posted events to do lots of delayed operations, like +    // repaints... these need to be delivered before we go to sleep +    TQApplication::sendPostedEvents(); + +    bool canWait = ( flags & WaitForMore ); + +    qnpxt_keep_alive(); + +    // 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 ( canWait ) +	XtAppProcessEvent( d->appContext, XtIMAll ); +    else +	XtAppProcessEvent( d->appContext, mask ); + +    int nevents = 0; +    if ( ! ( flags & ExcludeSocketNotifiers ) ) { +	nevents += activateSocketNotifiers(); +	d->pending_socknots = 0; +    } + +    if ( d->activate_timers ) { +	nevents += activateTimers(); +    } +    d->activate_timers = FALSE; + +    return ( canWait || ( pendingmask != 0 ) || nevents > 0 ); +} + + +#endif // TQ_WS_X11 | 
