nspluginwrapper-1.1.0
Taken from Ubuntu orig.tar.gz file.
This commit is contained in:
parent
e9ae927da7
commit
10bbf2f098
515
ChangeLog
515
ChangeLog
|
@ -1,264 +1,376 @@
|
|||
2008-06-29 20:19 Gwenole Beauchesne <gb.public@free.fr>
|
||||
2008-07-06 20:55 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* README: Fix documentation.
|
||||
* nspluginwrapper.spec: Add libnoxshm.so to filelist.
|
||||
|
||||
2008-06-29 20:18 Gwenole Beauchesne <gb.public@free.fr>
|
||||
2008-07-06 20:53 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* NEWS, README, TODO, nspluginwrapper.spec: Updates for 1.1.0
|
||||
release.
|
||||
|
||||
2008-07-06 20:38 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-viewer.c: Add ALLOW_WINDOWLESS_PLUGINS compile-time
|
||||
macro to allow/forbid windowless plugins.
|
||||
|
||||
2008-07-06 20:14 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* Makefile: Add LN_S definition for ln -sf command.
|
||||
|
||||
2008-07-06 20:09 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-viewer.c, src/npw-wrapper.c: Implement
|
||||
NPN_InvalidateRect() for Flash Player 10 beta 2.
|
||||
|
||||
2008-07-06 19:52 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-wrapper.c: Flush the X output buffer so that the call to
|
||||
gdk_pixmap_foreign_new() (and thus XGetGeometry()) can work in
|
||||
the viewer. Otherwise, we sometimes get a BadDrawable.
|
||||
|
||||
2008-07-06 19:47 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-viewer.c: Fix NPNVnetscapeWindow wrapper to create a
|
||||
GdkWindow from it as windowless plugins expect to find a
|
||||
toplevel gdk window (and gtk window TBD).
|
||||
|
||||
2008-07-06 19:16 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-viewer.c: Synchronize more NPWindow items in successive
|
||||
NPP_SetWindow() calls, i.e. updates case.
|
||||
create_window_attributes() and destroy_window_attributes() now
|
||||
operate on an NPSetWindowCallbackStruct directly.
|
||||
|
||||
2008-07-06 17:05 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-viewer.c: Make sure to commit the pixmap in
|
||||
NPN_HandleEvent() for GraphicsExpose events.
|
||||
|
||||
2008-07-06 17:02 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-viewer.c: Add support for windowless plugins.
|
||||
|
||||
2008-07-06 14:55 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-rpc.c, src/npw-viewer.c, src/npw-wrapper.c: Implement
|
||||
NPP_HandleEvent().
|
||||
|
||||
2008-07-06 14:28 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-rpc.h: Add missing method and type ids for windowless
|
||||
plugins.
|
||||
|
||||
2008-07-06 14:23 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-rpc.c, src/npw-viewer.c: Marshal
|
||||
NPSetWindowCallbackStruct: only reconstruct XVisual based on the
|
||||
visualID we pass-through RPC. This will be useful for windowless
|
||||
plugins support.
|
||||
|
||||
2008-07-06 13:14 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-rpc.c, src/npw-viewer.c, src/npw-wrapper.c: Propagate
|
||||
NPNVnetscapeWindow.
|
||||
|
||||
2008-07-04 20:57 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-rpc.c, src/npw-viewer.c: Propagate
|
||||
NPNVSupportsWindowless.
|
||||
|
||||
2008-07-04 20:52 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-rpc.c, src/npw-viewer.c, src/npw-wrapper.c: Implement
|
||||
NPN_SetValue() for boolean variables only.
|
||||
|
||||
2008-07-04 20:31 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-rpc.c: Add fix for Mozilla bug #406251:
|
||||
NPVariant.intValue is now a signed int.
|
||||
|
||||
2008-07-04 20:26 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-rpc.h: Add missing methods for NPN_SetValue(),
|
||||
NPN_Enumerate() and NPN_Construct().
|
||||
|
||||
2008-07-04 20:20 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* npapi/npapi.h, npapi/npruntime.h, npapi/npupp.h: Update NPAPI
|
||||
headers to 0.19.
|
||||
|
||||
2008-07-01 20:38 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* Makefile: Fix build on platforms that are not biarch devel
|
||||
capable.
|
||||
|
||||
2008-06-29 21:17 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* configure: Document --enable-strip.
|
||||
|
||||
2008-06-29 14:54 Gwenole Beauchesne <gb.public@free.fr>
|
||||
2008-06-26 20:45 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* ChangeLog: Generated by svn2cl.
|
||||
* src/npw-config.c: Don't install wrapped root plugins system-wide
|
||||
but stick them to private mozilla plugins dir (typically
|
||||
~root/.mozilla/plugins/).
|
||||
|
||||
2008-06-29 14:47 Gwenole Beauchesne <gb.public@free.fr>
|
||||
2008-06-23 22:08 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* NEWS, README, nspluginwrapper.spec: Prepare for 1.0.0 release.
|
||||
* src/npw-player.c: Use the underlying g_quark_from_string() to
|
||||
get a unique id from a string. This function is available on
|
||||
older glib version 2.8 (FreeBSD 6.1). Quarks increase from zero.
|
||||
|
||||
2008-06-26 20:50 Gwenole Beauchesne <gb.public@free.fr>
|
||||
2008-06-23 21:58 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-config.c: Backport from trunk.
|
||||
|
||||
Don't install wrapped root plugins system-wide but stick them to
|
||||
private mozilla plugins dir (typically ~root/.mozilla/plugins/).
|
||||
* Makefile: Fix install.npplayer dependency. Explicitly link
|
||||
against the pthread library since we are using gthread-2.0
|
||||
(though this one should be linked against pthread by itself on
|
||||
freebsd).
|
||||
|
||||
2008-06-29 14:47 Gwenole Beauchesne <gb.public@free.fr>
|
||||
2008-06-23 21:56 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* NEWS, README, nspluginwrapper.spec: Prepare for 1.0.0 release.
|
||||
* configure: Check for GTK+ for standalone player build too.
|
||||
|
||||
2008-06-26 20:50 Gwenole Beauchesne <gb.public@free.fr>
|
||||
2008-06-23 21:55 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-config.c: Backport from trunk.
|
||||
|
||||
Don't install wrapped root plugins system-wide but stick them to
|
||||
private mozilla plugins dir (typically ~root/.mozilla/plugins/).
|
||||
* src/glibcurl.h: Fix missing include for older (and broken) curl
|
||||
headers.
|
||||
|
||||
2008-06-29 14:47 Gwenole Beauchesne <gb.public@free.fr>
|
||||
2008-06-23 21:17 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* NEWS, README, nspluginwrapper.spec: Prepare for 1.0.0 release.
|
||||
* Makefile: Always link against libgthread-2.0 (Ruediger Oertel),
|
||||
including for non biarch build case.
|
||||
|
||||
2008-06-26 20:50 Gwenole Beauchesne <gb.public@free.fr>
|
||||
2008-06-23 21:11 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-config.c: Backport from trunk.
|
||||
|
||||
Don't install wrapped root plugins system-wide but stick them to
|
||||
private mozilla plugins dir (typically ~root/.mozilla/plugins/).
|
||||
* src/libnoxshm.c: Fix aliasing problems (Stanislav Brabec).
|
||||
|
||||
2008-06-23 22:16 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* ChangeLog: Generated by svn2cl.
|
||||
|
||||
2008-06-23 22:11 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* Makefile: Backport from trunk.
|
||||
|
||||
Always link against libgthread-2.0 (Ruediger Oertel), including
|
||||
for non biarch build case.
|
||||
|
||||
2008-06-23 22:11 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* Makefile: Backport from trunk.
|
||||
|
||||
Always link against libgthread-2.0 (Ruediger Oertel), including
|
||||
for non biarch build case.
|
||||
|
||||
2008-06-23 21:06 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* NEWS, nspluginwrapper.spec: Update changes.
|
||||
|
||||
2008-06-23 21:05 Gwenole Beauchesne <gb.public@free.fr>
|
||||
2008-06-23 21:04 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* Makefile: Don't bother with language and/or timezone during
|
||||
automatic changelog generation.
|
||||
|
||||
2008-06-23 21:02 Gwenole Beauchesne <gb.public@free.fr>
|
||||
2008-06-23 21:00 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* Makefile, README, configure, utils/getdeps.sh,
|
||||
utils/mkruntime.sh, utils/repackage.sh: Update copyright dates.
|
||||
|
||||
2008-06-23 20:54 Gwenole Beauchesne <gb.public@free.fr>
|
||||
2008-06-22 08:26 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-viewer.c: Backport from trunk.
|
||||
|
||||
Don't pretend to support XEMBED if the plugin does not.
|
||||
* Makefile, src/libnoxshm.c, src/npw-viewer.sh: Don't allow
|
||||
MIT-SHM (XShm, XVideo) when using QEMU as it causes some
|
||||
endianness issues. Initial patch by Alexander Graf. Note that
|
||||
you may also disable MIT-SHM for other platforms through
|
||||
NPW_USE_XSHM set to no.
|
||||
|
||||
2008-06-21 20:54 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* ChangeLog: Generated by svn2cl.
|
||||
|
||||
2008-06-21 20:52 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* ChangeLog: Generated by svn2cl.
|
||||
|
||||
2008-06-21 20:36 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* ChangeLog: Generated by svn2cl.
|
||||
|
||||
2008-06-21 20:52 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* ChangeLog: Generated by svn2cl.
|
||||
|
||||
2008-06-21 20:36 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* ChangeLog: Generated by svn2cl.
|
||||
|
||||
2008-06-21 20:35 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* ChangeLog: Try to fix (generated) changelog.
|
||||
|
||||
2008-06-21 20:24 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* ChangeLog: Generated by svn2cl.
|
||||
|
||||
2008-06-21 20:22 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* ChangeLog: Generated by svn2cl.
|
||||
|
||||
2008-06-21 20:18 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* NEWS, nspluginwrapper.spec: Prepare for "1.0" release candidate.
|
||||
|
||||
2008-06-21 20:15 Gwenole Beauchesne <gb.public@free.fr>
|
||||
2008-06-21 20:14 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/cxxabi-compat.cpp, src/debug.c, src/debug.h, src/libxpcom.c,
|
||||
src/npruntime-impl.h, src/npruntime.c,
|
||||
src/npw-config-template.h, src/npw-config.c, src/npw-rpc.c,
|
||||
src/npw-rpc.h, src/npw-viewer.c, src/npw-wrapper.c, src/rpc.c,
|
||||
src/rpc.h, src/sysdeps.h, src/utils.c, src/utils.h,
|
||||
src/xembed.h: Update copyright info.
|
||||
src/npw-config-template.h, src/npw-config.c, src/npw-player.c,
|
||||
src/npw-rpc.c, src/npw-rpc.h, src/npw-viewer.c,
|
||||
src/npw-wrapper.c, src/rpc.c, src/rpc.h, src/sysdeps.h,
|
||||
src/utils.c, src/utils.h, src/xembed.h: Update copyright info.
|
||||
|
||||
2008-06-21 19:57 Gwenole Beauchesne <gb.public@free.fr>
|
||||
2008-06-21 16:15 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* ChangeLog: Updates.
|
||||
* src/npw-viewer.c: Don't pretend to support XEMBED if the plugin
|
||||
does not.
|
||||
|
||||
2008-06-21 19:46 Gwenole Beauchesne <gb.public@free.fr>
|
||||
2008-06-21 16:14 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-wrapper.c: Backport from trunk.
|
||||
* src/npw-viewer.c: Zero-initialize XtData on allocation.
|
||||
|
||||
2008-06-21 16:12 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-player.c: Fix support for non XEMBED plugins wrt. to
|
||||
input focus (e.g. Acrobat7).
|
||||
|
||||
2008-06-04 20:49 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/rpc.c: In rpc_method_wait_for_reply(), move down arg type
|
||||
extraction from varargs where it starts to be actually useful.
|
||||
|
||||
2008-06-04 20:44 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-wrapper.c: Properly fix parsing for npviewer.bin --info
|
||||
with lengthy stdout.
|
||||
|
||||
2008-06-04 20:11 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-wrapper.c: Fix for npviewer.bin --info returning lines
|
||||
larger than 255 chars (poor fix).
|
||||
|
||||
2008-05-25 15:22 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-player.c: Handle seekable streams (NP_SEEK) later,
|
||||
currently consider they are not.
|
||||
|
||||
2008-05-25 15:10 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-player.c: Fix handling of NP_ASFILE and NP_ASFILEONLY
|
||||
streams.
|
||||
|
||||
2008-05-25 10:03 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-player.c: Fix NPP_Write() emulation to actually emit the
|
||||
current offset in the stream, not in the buffer being sent.
|
||||
|
||||
2008-05-25 10:00 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-player.c: Improve initialization of streams, i.e. try to
|
||||
retrieve some information about the remote file (size, last
|
||||
modification time).
|
||||
|
||||
2008-05-23 22:34 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-player.c: Fix check for size change.
|
||||
|
||||
2008-05-23 21:59 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-player.c: Propagate window resize requests.
|
||||
|
||||
2008-05-23 20:50 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-player.c: Fix propagation of a stream when it was fully
|
||||
read prior to starting the emission to the other side. e.g. fix
|
||||
advertising in Magic Pen or make Youtube playlists actually work.
|
||||
|
||||
2008-05-23 20:46 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-player.c: Allow arbitrary title to be set with the
|
||||
--title option.
|
||||
|
||||
2008-05-23 20:44 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-player.c: Use <ctrl>-Q or <ctrl>-Escape to quit the
|
||||
application.
|
||||
|
||||
2008-05-22 22:56 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* Makefile, configure, nspluginwrapper.spec, src/glibcurl.c,
|
||||
src/glibcurl.h, src/gtk2xtbin.c, src/gtk2xtbin.h,
|
||||
src/npw-player.c, src/sysdeps.h: Add standalone NPAPI plugins
|
||||
player (Gtk backend only).
|
||||
|
||||
2008-05-22 21:24 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-viewer.c: Improve debugging messages for npruntime
|
||||
functions (NPVariant related) and NPP_NewStream().
|
||||
|
||||
2008-05-22 20:45 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-viewer.c: Fix NPP_SetWindow() when the platform-specific
|
||||
NPWindow::window member value is NULL. This means the plug-in
|
||||
should not longer use the specified window and must free any
|
||||
resources associated with it. Firefox doesn't do that but WebKit
|
||||
does.
|
||||
|
||||
2008-05-22 16:49 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-rpc.c, src/npw-rpc.h, src/npw-viewer.c,
|
||||
src/npw-wrapper.c, src/rpc.c, src/rpc.h: Drop last global
|
||||
variable in RPC code (g_message_descriptors).
|
||||
|
||||
Fix for npviewer.bin --info returning lines larger than 255
|
||||
chars (extraneous lines from the plugin for example).
|
||||
As a consequence, message descriptors MUST be added to any
|
||||
connection prior to using it. Actually, this now operates like
|
||||
method descriptors. This is an API change that also drops
|
||||
functions to remove methods or message types from a connection.
|
||||
i.e. no need to expose an API that can still change in the
|
||||
future (nspluginwrapper2).
|
||||
|
||||
2008-06-21 19:42 Gwenole Beauchesne <gb.public@free.fr>
|
||||
2008-05-22 14:56 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-viewer.c: Backport from trunk.
|
||||
|
||||
Fix NPP_SetWindow() when the platform-specific NPWindow::window
|
||||
member value is NULL. This means the plug-in should not longer
|
||||
use the specified window and must free any resources associated
|
||||
with it. Firefox doesn't do that but WebKit does.
|
||||
* src/rpc.c: Fix propagation of the error code to the other side
|
||||
when a message handler was not found.
|
||||
|
||||
2008-06-21 19:36 Gwenole Beauchesne <gb.public@free.fr>
|
||||
2008-05-22 14:29 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/rpc.c: Backport from trunk.
|
||||
|
||||
Robustify error cases during creation of a connection.
|
||||
* TODO, src/rpc.c: Fix passing of array elements to match exactly
|
||||
what is defined in the message descriptor (.size field). i.e.
|
||||
dynamic allocation of the element is delegated to the handler.
|
||||
So, the array can be of static values or pointers to values, it
|
||||
just depends on what the handler does.
|
||||
|
||||
2008-05-22 12:10 Gwenole Beauchesne <gb.public@free.fr>
|
||||
2008-05-22 13:53 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/rpc.c: Robusty error cases during creation of a connection.
|
||||
|
||||
2008-05-22 13:04 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-rpc.h, src/rpc.c, src/rpc.h: Fix rpc_connection_ref() to
|
||||
return self.
|
||||
|
||||
2008-05-22 12:55 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-rpc.h: Add RPC method and datatype IDs for debugging.
|
||||
|
||||
2008-05-22 12:34 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/debug.h, src/npw-rpc.h, src/rpc.c, src/rpc.h, src/sysdeps.h,
|
||||
src/utils.h: Add guards for inclusion into C++ code.
|
||||
|
||||
2008-05-22 09:09 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* nspluginwrapper.spec: Trunk heads to 1.2.0.
|
||||
|
||||
2008-05-22 08:03 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* Makefile, configure: Rename a few options to --enable-style.
|
||||
Allow stripping of binaries only through --enable-strip.
|
||||
|
||||
2007-12-25 11:04 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* ChangeLog: Generated by svn2cl.
|
||||
|
||||
2008-05-22 11:58 Gwenole Beauchesne <gb.public@free.fr>
|
||||
2007-12-23 20:01 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* gwenole/projects/nspluginwrapper/branches/1.0-branch, .: Rename
|
||||
to nspluginwrapper-1.0-branch (as upstream name). Other namings
|
||||
are possible, e.g. fedora-1.0-branch, redirect-branch.
|
||||
* Makefile, src/npw-viewer.c: Initialize glib for multithreading,
|
||||
aka fix crashes with newer Flash Player plugin (9.0.115).
|
||||
|
||||
2008-05-22 09:03 Gwenole Beauchesne <gb.public@free.fr>
|
||||
2007-09-20 21:47 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* gwenole/projects/nspluginwrapper/branches/1.0-branch/Makefile,
|
||||
gwenole/projects/nspluginwrapper/branches/1.0-branch/configure,
|
||||
gwenole/projects/nspluginwrapper/branches/1.0-branch/nspluginwrapper.spec:
|
||||
Backport from trunk.
|
||||
|
||||
Rename a few options to --enable-* style. Allow stripping of
|
||||
binaries only through --enable-strip. Bump version for new beta
|
||||
towards 1.0.
|
||||
* configure: Fix C99 support flag for Intel compiler.
|
||||
|
||||
2008-05-22 08:43 Gwenole Beauchesne <gb.public@free.fr>
|
||||
2007-09-20 21:41 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* gwenole/projects/nspluginwrapper/branches/0.9.91-branch,
|
||||
gwenole/projects/nspluginwrapper/branches/1.0-branch: Rename to
|
||||
1.0-branch.
|
||||
* Makefile, configure: Allow build with XLC.
|
||||
|
||||
2008-05-22 09:03 Gwenole Beauchesne <gb.public@free.fr>
|
||||
2007-09-02 06:35 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* Makefile, configure, nspluginwrapper.spec: Backport from trunk.
|
||||
|
||||
Rename a few options to --enable-* style. Allow stripping of
|
||||
binaries only through --enable-strip. Bump version for new beta
|
||||
towards 1.0.
|
||||
* ChangeLog: Generated by svn2cl.
|
||||
|
||||
2007-12-23 20:06 Gwenole Beauchesne <gb.public@free.fr>
|
||||
2007-09-02 06:34 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* NEWS, nspluginwrapper.spec: Prepare for 0.9.91.6.
|
||||
* src/npw-wrapper.c: Use per-plugin connection references. This
|
||||
will prevent the use of the new (restarted) RPC connection with
|
||||
old NPP instances.
|
||||
|
||||
2007-12-25 11:16 Gwenole Beauchesne <gb.public@free.fr>
|
||||
2007-09-02 05:35 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* Makefile: Fix generation of (accumulated) ChangeLog.
|
||||
* src/npw-viewer.c, src/npw-wrapper.c, src/rpc.c, src/rpc.h:
|
||||
Implement and use rpc_connection_{ref,unref}().
|
||||
|
||||
2007-12-23 20:06 Gwenole Beauchesne <gb.public@free.fr>
|
||||
2007-09-01 23:05 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* NEWS, nspluginwrapper.spec: Prepare for 0.9.91.6.
|
||||
* src/npw-viewer.c, src/npw-wrapper.c: Improve NPP_WriteReady()
|
||||
and NPP_Write() error handling, aka consume as many bytes as
|
||||
possible when we have an RPC error (for rpc_method_invoke() and
|
||||
rpc_method_wait_for_reply'()).
|
||||
|
||||
2007-12-25 11:16 Gwenole Beauchesne <gb.public@free.fr>
|
||||
2007-09-01 22:15 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* Makefile: Fix generation of (accumulated) ChangeLog.
|
||||
* NEWS, nspluginwrapper.spec, src/npw-wrapper.c: Restart plugins
|
||||
viewer when it crashed (initial patch by Martin Stransky).
|
||||
|
||||
2007-12-23 20:06 Gwenole Beauchesne <gb.public@free.fr>
|
||||
2007-09-01 17:58 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* NEWS, nspluginwrapper.spec: Prepare for 0.9.91.6.
|
||||
* src/rpc.c: Fix rpc_dispatch() to set error status accordingly,
|
||||
not for simple method IDs. Check connection state prior to
|
||||
marshaling data in rpc_method_*().
|
||||
|
||||
2007-12-25 11:16 Gwenole Beauchesne <gb.public@free.fr>
|
||||
2007-09-01 16:04 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* Makefile: Fix generation of (accumulated) ChangeLog.
|
||||
|
||||
2007-12-23 20:06 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* NEWS, nspluginwrapper.spec: Prepare for 0.9.91.6.
|
||||
|
||||
2007-12-25 11:16 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* Makefile: Fix generation of (accumulated) ChangeLog.
|
||||
|
||||
2007-12-23 20:06 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* NEWS, nspluginwrapper.spec: Prepare for 0.9.91.6.
|
||||
|
||||
2007-12-23 20:03 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* Makefile, src/npw-viewer.c: Merge from trunk: Initialize glib
|
||||
for multithreading, aka fix crashes with newer Flash Player
|
||||
plugin (9.0.115).
|
||||
|
||||
2007-12-23 15:33 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* Makefile, configure: Merge from trunk: Fix C99 support flag for
|
||||
Intel compiler. Allow build with XLC.
|
||||
|
||||
2007-12-23 20:06 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* NEWS, nspluginwrapper.spec: Prepare for 0.9.91.6.
|
||||
|
||||
2007-12-23 20:03 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* Makefile, src/npw-viewer.c: Merge from trunk: Initialize glib
|
||||
for multithreading, aka fix crashes with newer Flash Player
|
||||
plugin (9.0.115).
|
||||
|
||||
2007-12-23 15:33 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* Makefile, configure: Merge from trunk: Fix C99 support flag for
|
||||
Intel compiler. Allow build with XLC.
|
||||
|
||||
2007-12-23 15:31 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-viewer.c, src/npw-wrapper.c: Merge from trunk:
|
||||
Improve NPP_WriteReady() and NPP_Write() error handling, aka
|
||||
consume as many bytes as possible when we have an RPC error (for
|
||||
rpc_method_invoke() and rpc_method_wait_for_reply()).
|
||||
|
||||
2007-12-23 15:20 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* Created 0.9.91-branch from 0.9.91.5.
|
||||
* src/rpc.c, src/rpc.h: Maintain an RPC status (initial patch by
|
||||
Martin Stransky for error handling). Fix rpc_method_send_reply()
|
||||
to return RPC_ERROR_CONNECTION_NULL with NULL connections.
|
||||
|
||||
2007-08-26 09:53 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
|
@ -273,15 +385,6 @@
|
|||
|
||||
* ChangeLog: Generated by svn2cl.
|
||||
|
||||
2007-08-26 06:31 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* src/npw-viewer.c: Nuke the window border, it's quite disturbing
|
||||
to see it during resizing.
|
||||
|
||||
2007-08-25 23:03 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* ChangeLog: Generated by svn2cl.
|
||||
|
||||
2007-08-25 22:48 Gwenole Beauchesne <gb.public@free.fr>
|
||||
|
||||
* NEWS, nspluginwrapper.spec: 0.9.91.5
|
||||
|
|
63
Makefile
63
Makefile
|
@ -35,6 +35,8 @@ ifeq ($(ALLOW_STRIP), yes)
|
|||
STRIP_OPT = -s
|
||||
endif
|
||||
|
||||
LN_S = ln -sf
|
||||
|
||||
ifneq (,$(findstring $(OS),linux))
|
||||
libdl_LDFLAGS = -ldl
|
||||
endif
|
||||
|
@ -121,6 +123,13 @@ npviewer_OBJECTS += npviewer-cxxabi-compat.o
|
|||
npviewer_LDFLAGS += -lsupc++
|
||||
endif
|
||||
|
||||
npplayer_PROGRAM = npplayer
|
||||
npplayer_SOURCES = npw-player.c debug.c rpc.c utils.c glibcurl.c gtk2xtbin.c $(tidy_SOURCES)
|
||||
npplayer_OBJECTS = $(npplayer_SOURCES:%.c=npplayer-%.o)
|
||||
npplayer_CFLAGS = $(GTK_CFLAGS) $(MOZILLA_CFLAGS) $(CURL_CFLAGS) $(X_CFLAGS)
|
||||
npplayer_LDFLAGS = $(GTK_LDFLAGS) $(CURL_LDFLAGS) $(X_LDFLAGS)
|
||||
npplayer_LDFLAGS += -lgthread-2.0 $(libpthread_LDFLAGS)
|
||||
|
||||
libxpcom_LIBRARY = libxpcom.so
|
||||
libxpcom_RAWSRCS = libxpcom.c debug.c
|
||||
libxpcom_SOURCES = $(libxpcom_RAWSRCS:%.c=$(SRC_PATH)/src/%.c)
|
||||
|
@ -131,6 +140,16 @@ libxpcom_CFLAGS += -I$(LSB_INC_DIR)
|
|||
libxpcom_LDFLAGS = $(LDFLAGS_32) -L$(LSB_OBJ_DIR)
|
||||
endif
|
||||
|
||||
libnoxshm_LIBRARY = libnoxshm.so
|
||||
libnoxshm_RAWSRCS = libnoxshm.c
|
||||
libnoxshm_SOURCES = $(libnoxshm_RAWSRCS:%.c=$(SRC_PATH)/src/%.c)
|
||||
libnoxshm_OBJECTS = $(libnoxshm_RAWSRCS:%.c=libnoxshm-%.o)
|
||||
libnoxshm_CFLAGS = $(PIC_CFLAGS)
|
||||
ifeq ($(biarch),yes)
|
||||
libnoxshm_CFLAGS += -I$(LSB_INC_DIR)
|
||||
libnoxshm_LDFLAGS = $(LDFLAGS_32) -L$(LSB_OBJ_DIR)
|
||||
endif
|
||||
|
||||
npconfig_PROGRAM = npconfig
|
||||
npconfig_RAWSRCS = npw-config.c
|
||||
npconfig_SOURCES = $(npconfig_RAWSRCS:%.c=$(SRC_PATH)/src/%.c)
|
||||
|
@ -154,6 +173,10 @@ TARGETS += $(npwrapper_LIBRARY)
|
|||
ifeq ($(build_viewer),yes)
|
||||
TARGETS += $(npviewer_PROGRAM)
|
||||
TARGETS += $(libxpcom_LIBRARY)
|
||||
TARGETS += $(libnoxshm_LIBRARY)
|
||||
endif
|
||||
ifeq ($(build_player),yes)
|
||||
TARGETS += $(npplayer_PROGRAM)
|
||||
endif
|
||||
|
||||
archivedir = files/
|
||||
|
@ -192,7 +215,7 @@ clean:
|
|||
distclean: clean
|
||||
rm -f config-host.* config.*
|
||||
|
||||
uninstall: uninstall.wrapper uninstall.viewer uninstall.libxpcom uninstall.loader uninstall.config uninstall.mkruntime uninstall.dirs
|
||||
uninstall: uninstall.player uninstall.wrapper uninstall.viewer uninstall.libxpcom uninstall.libnoxshm uninstall.loader uninstall.config uninstall.mkruntime uninstall.dirs
|
||||
uninstall.dirs:
|
||||
rmdir $(DESTDIR)$(pkglibdir)/noarch
|
||||
rmdir $(DESTDIR)$(pkglibdir)/$(ARCH)/$(OS)
|
||||
|
@ -201,6 +224,8 @@ ifneq ($(ARCH),$(ARCH_32))
|
|||
rmdir $(DESTDIR)$(pkglibdir)/$(ARCH_32)/$(TARGET_OS)
|
||||
rmdir $(DESTDIR)$(pkglibdir)/$(ARCH_32)
|
||||
endif
|
||||
uninstall.player:
|
||||
rm -f $(DESTDIR)$(pkglibdir)/$(ARCH)/$(OS)/$(npplayer_PROGRAM)
|
||||
uninstall.wrapper:
|
||||
rm -f $(DESTDIR)$(pkglibdir)/$(ARCH)/$(OS)/$(npwrapper_LIBRARY)
|
||||
uninstall.viewer:
|
||||
|
@ -208,6 +233,8 @@ uninstall.viewer:
|
|||
rm -f $(DESTDIR)$(pkglibdir)/$(ARCH_32)/$(TARGET_OS)/$(npviewer_PROGRAM:%.bin=%)
|
||||
uninstall.libxpcom:
|
||||
rm -f $(DESTDIR)$(pkglibdir)/$(ARCH_32)/$(TARGET_OS)/$(libxpcom_LIBRARY)
|
||||
uninstall.libnoxshm:
|
||||
rm -f $(DESTDIR)$(pkglibdir)/$(ARCH_32)/$(TARGET_OS)/$(libnoxshm_LIBRARY)
|
||||
uninstall.loader:
|
||||
rm -f $(DESTDIR)$(pkglibdir)/noarch/$(nploader_PROGRAM)
|
||||
uninstall.config:
|
||||
|
@ -216,7 +243,7 @@ uninstall.config:
|
|||
uninstall.mkruntime:
|
||||
rm -f $(DESTDIR)$(pkglibdir)/noarch/mkruntime
|
||||
|
||||
install: install.dirs install.wrapper install.viewer install.libxpcom install.loader install.config install.mkruntime
|
||||
install: install.dirs install.player install.wrapper install.viewer install.libxpcom install.libnoxshm install.loader install.config install.mkruntime
|
||||
install.dirs:
|
||||
mkdir -p $(DESTDIR)$(pkglibdir)/noarch
|
||||
mkdir -p $(DESTDIR)$(pkglibdir)/$(ARCH)
|
||||
|
@ -225,14 +252,24 @@ ifneq ($(ARCH),$(ARCH_32))
|
|||
mkdir -p $(DESTDIR)$(pkglibdir)/$(ARCH_32)
|
||||
mkdir -p $(DESTDIR)$(pkglibdir)/$(ARCH_32)/$(TARGET_OS)
|
||||
endif
|
||||
ifeq ($(build_player),yes)
|
||||
install.player: $(npplayer_PROGRAM)
|
||||
install -m 755 $(STRIP_OPT) $(npplayer_PROGRAM) $(DESTDIR)$(pkglibdir)/$(ARCH)/$(OS)/$(npplayer_PROGRAM)
|
||||
mkdir -p $(DESTDIR)$(bindir)
|
||||
$(LN_S) $(pkglibdir)/$(ARCH)/$(OS)/$(npplayer_PROGRAM) $(DESTDIR)$(bindir)/nspluginplayer
|
||||
else
|
||||
install.player:
|
||||
endif
|
||||
install.wrapper: $(npwrapper_LIBRARY)
|
||||
install -m 755 $(STRIP_OPT) $(npwrapper_LIBRARY) $(DESTDIR)$(pkglibdir)/$(ARCH)/$(OS)/$(npwrapper_LIBRARY)
|
||||
ifeq ($(build_viewer),yes)
|
||||
install.viewer: install.viewer.bin install.viewer.glue
|
||||
install.libxpcom: do.install.libxpcom
|
||||
install.libnoxshm: do.install.libnoxshm
|
||||
else
|
||||
install.viewer:
|
||||
install.libxpcom:
|
||||
install.libnoxshm:
|
||||
endif
|
||||
install.viewer.bin: $(npviewer_PROGRAM)
|
||||
install -m 755 $(STRIP_OPT) $(npviewer_PROGRAM) $(DESTDIR)$(pkglibdir)/$(ARCH_32)/$(TARGET_OS)/$(npviewer_PROGRAM)
|
||||
|
@ -245,10 +282,12 @@ install.viewer.glue::
|
|||
chmod 755 $$p
|
||||
do.install.libxpcom: $(libxpcom_LIBRARY)
|
||||
install -m 755 $(STRIP_OPT) $(libxpcom_LIBRARY) $(DESTDIR)$(pkglibdir)/$(ARCH_32)/$(TARGET_OS)/$(libxpcom_LIBRARY)
|
||||
do.install.libnoxshm: $(libnoxshm_LIBRARY)
|
||||
install -m 755 $(STRIP_OPT) $(libnoxshm_LIBRARY) $(DESTDIR)$(pkglibdir)/$(ARCH_32)/$(TARGET_OS)/$(libnoxshm_LIBRARY)
|
||||
install.config: $(npconfig_PROGRAM)
|
||||
install -m 755 $(STRIP_OPT) $(npconfig_PROGRAM) $(DESTDIR)$(pkglibdir)/$(ARCH)/$(OS)/$(npconfig_PROGRAM)
|
||||
mkdir -p $(DESTDIR)$(bindir)
|
||||
ln -sf $(pkglibdir)/$(ARCH)/$(OS)/$(npconfig_PROGRAM) $(DESTDIR)$(bindir)/nspluginwrapper
|
||||
$(LN_S) $(pkglibdir)/$(ARCH)/$(OS)/$(npconfig_PROGRAM) $(DESTDIR)$(bindir)/nspluginwrapper
|
||||
install.loader: $(nploader_PROGRAM)
|
||||
install -m 755 $(nploader_PROGRAM) $(DESTDIR)$(pkglibdir)/noarch/$(nploader_PROGRAM)
|
||||
install.mkruntime: $(SRC_PATH)/utils/mkruntime.sh
|
||||
|
@ -290,7 +329,7 @@ localrpm: $(archivedir)$(SRCARCHIVE).bz2
|
|||
|
||||
changelog: ../common/authors.xml
|
||||
svn_prefix=`svn info .|sed -n '/^URL *: .*\/svn\/\(.*\)$$/s//\1\//p'`; \
|
||||
LC_ALL=C TZ=GMT svn2cl --strip-prefix=$$svn_prefix --authors=../common/authors.xml --accum || :
|
||||
LC_ALL=C TZ=GMT svn2cl --strip-prefix=$$svn_prefix --authors=../common/authors.xml || :
|
||||
changelog.commit: changelog
|
||||
svn commit -m "Generated by svn2cl." ChangeLog
|
||||
|
||||
|
@ -309,12 +348,26 @@ npviewer-%.o: $(SRC_PATH)/src/%.c
|
|||
npviewer-%.o: $(SRC_PATH)/src/%.cpp
|
||||
$(CXX) $(CFLAGS_32) -o $@ -c $< $(CPPFLAGS) $(npviewer_CFLAGS) -DBUILD_VIEWER
|
||||
|
||||
$(npplayer_PROGRAM): $(npplayer_OBJECTS) $(npplayer_MAPFILE) $(LSB_OBJ_DIR) $(LSB_LIBS)
|
||||
$(CC) $(LDFLAGS) -o $@ $(npplayer_OBJECTS) $(npplayer_LDFLAGS)
|
||||
|
||||
npplayer-%.o: $(SRC_PATH)/src/%.c
|
||||
$(CC) $(CFLAGS) -o $@ -c $< $(CPPFLAGS) $(npplayer_CFLAGS) -DBUILD_PLAYER
|
||||
npplayer-%.o: $(SRC_PATH)/src/tidy/%.c
|
||||
$(CC) $(CFLAGS) -o $@ -c $< $(CPPFLAGS) $(npplayer_CFLAGS) -DBUILD_PLAYER
|
||||
|
||||
$(libxpcom_LIBRARY): $(libxpcom_OBJECTS) $(LSB_OBJ_DIR) $(LSB_LIBS)
|
||||
$(CC) $(LDFLAGS_32) $(DSO_LDFLAGS) -o $@ $(libxpcom_OBJECTS) $(libxpcom_LDFLAGS) -Wl,--soname,libxpcom.so
|
||||
|
||||
libxpcom-%.o: $(SRC_PATH)/src/%.c
|
||||
$(CC) $(CFLAGS_32) -o $@ -c $< $(CPPFLAGS) $(libxpcom_CFLAGS) -DBUILD_XPCOM
|
||||
|
||||
$(libnoxshm_LIBRARY): $(libnoxshm_OBJECTS) $(LSB_OBJ_DIR) $(LSB_LIBS)
|
||||
$(CC) $(LDFLAGS_32) $(DSO_LDFLAGS) -o $@ $(libnoxshm_OBJECTS) $(libnoxshm_LDFLAGS) -Wl,--soname,libnoxshm.so
|
||||
|
||||
libnoxshm-%.o: $(SRC_PATH)/src/%.c
|
||||
$(CC) $(CFLAGS_32) -o $@ -c $< $(CPPFLAGS) $(libnoxshm_CFLAGS)
|
||||
|
||||
$(npconfig_PROGRAM): $(npconfig_OBJECTS)
|
||||
$(CC) -o $@ $(npconfig_OBJECTS) $(npconfig_LDFLAGS)
|
||||
|
||||
|
@ -339,7 +392,7 @@ $(LSB_OBJ_DIR)/libc.so: $(LSB_OBJ_DIR)/libc_main.so $(LSB_OBJ_DIR)/libc_nonshare
|
|||
@echo "GROUP ( $(LSB_OBJ_DIR)/libc_main.so $(LSB_OBJ_DIR)/libc_nonshared.a )" >> $@
|
||||
|
||||
$(LSB_OBJ_DIR)/libgcc_s_32.so: $(LSB_OBJ_DIR)/libgcc_s.so
|
||||
ln -sf libgcc_s.so $@
|
||||
$(LN_S) libgcc_s.so $@
|
||||
|
||||
$(LSB_OBJ_DIR)/%.so: $(LSB_OBJ_DIR)/%.o
|
||||
$(CC) $(LDFLAGS_32) -nostdlib $(DSO_LDFLAGS) $< -o $@ \
|
||||
|
|
7
NEWS
7
NEWS
|
@ -1,6 +1,11 @@
|
|||
nspluginwrapper NEWS -- history of user-visible changes. 2008-06-29
|
||||
nspluginwrapper NEWS -- history of user-visible changes. 2008-07-06
|
||||
Copyright (C) 2005-2008 Gwenole Beauchesne
|
||||
|
||||
Version 1.1.0 (BETA) - 06.Jul.2008
|
||||
* Add support for windowless plugins (Flash Player 10 beta 2)
|
||||
* Add standalone plugins player (nspluginplayer)
|
||||
* Restart plugins viewer on error (Martin Stransky)
|
||||
|
||||
Version 1.0.0 - 29.Jun.2008
|
||||
* Don't wrap root plugins to system locations, keep them private
|
||||
* Fix support for Acrobat Reader 8 (focus problems)
|
||||
|
|
6
README
6
README
|
@ -75,10 +75,10 @@ The following plugins work reasonnably well:
|
|||
- Acrobat Reader 5.0.9
|
||||
- Acrobat Reader 7.0.1
|
||||
- Acrobat Reader 8.1.2
|
||||
- DejaVu Libre 3.5.14
|
||||
- Flash Player 7.0
|
||||
- DejaVu Libre 3.5.14
|
||||
- Flash Player 7.0
|
||||
- Flash Player 9.0.124
|
||||
- Flash Player 10.0.1.218 (beta)
|
||||
- Flash Player 10.0 (beta 2)
|
||||
- Linux J2K 0.0.2
|
||||
- Mplayerplug-in 2.80
|
||||
- Mplayerplug-in 3.25
|
||||
|
|
8
TODO
8
TODO
|
@ -18,3 +18,11 @@
|
|||
* Import minimal GLib functions (hashes, etc.)
|
||||
* Split toolkit specific code (npviewer-{x11,gtk,win}.c)
|
||||
* Use winelib + override win32 socket to support AF_UNIX (Linux "native")
|
||||
- RPC
|
||||
* Need a way to differenciate array of pointers or array of values
|
||||
=> RPC_TYPE_DYNAMIC (allocate space), RPC_TYPE_STATIC (assumes data alloc'ed?)
|
||||
=> Rearrange RPC message type descriptors
|
||||
- Viewer:
|
||||
* Allow run-time (de)activation of windowless plugins
|
||||
* Allow run-time (de)activation of XEMBED
|
||||
* 0.19 API for Java Plugin2 (NPAPI based)
|
||||
|
|
|
@ -26,6 +26,7 @@ lib64=""
|
|||
x_base_dirs=""
|
||||
biarch="guess"
|
||||
build_viewer="guess"
|
||||
build_player="yes"
|
||||
linux_only="guess"
|
||||
strip="no"
|
||||
cc="gcc"
|
||||
|
@ -108,6 +109,12 @@ case "$opt" in
|
|||
--disable-viewer)
|
||||
build_viewer="no"
|
||||
;;
|
||||
--enable-player)
|
||||
build_player="yes"
|
||||
;;
|
||||
--disable-player)
|
||||
build_player="no"
|
||||
;;
|
||||
--with-lib32=*)
|
||||
lib32=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
|
@ -147,7 +154,7 @@ if test "$biarch" = "guess"; then
|
|||
esac
|
||||
fi
|
||||
|
||||
# check for viewer builds
|
||||
# check for viewer build
|
||||
if test "$build_viewer" = "guess"; then
|
||||
build_viewer="no"
|
||||
case $host_os in
|
||||
|
@ -355,7 +362,7 @@ fi
|
|||
rm -f $TMPC $TMPE
|
||||
|
||||
# check for GTK+ 2.0 compile CFLAGS
|
||||
if test "$build_viewer" = "yes"; then
|
||||
if test "$build_viewer" = "yes" -o "$build_player" = "yes"; then
|
||||
if $pkgconfig --exists gtk+-2.0; then
|
||||
GTK_CFLAGS=`$pkgconfig --cflags gtk+-2.0`
|
||||
GTK_LDFLAGS=`$pkgconfig --libs gtk+-2.0`
|
||||
|
@ -378,6 +385,36 @@ EOF
|
|||
rm -f $TMPC $TMPE
|
||||
fi
|
||||
|
||||
# check for cURL compile CFLAGS
|
||||
if test "$build_player" = "yes"; then
|
||||
if $pkgconfig --exists libcurl; then
|
||||
CURL_CFLAGS=`$pkgconfig --cflags libcurl`
|
||||
CURL_LDFLAGS=`$pkgconfig --libs libcurl`
|
||||
else
|
||||
curlconfig=`which curl-config`
|
||||
if test -n "$curlconfig"; then
|
||||
CURL_CFLAGS=`$curlconfig --cflags`
|
||||
CURL_LDFLAGS=`$curlconfig --libs`
|
||||
else
|
||||
echo "cURL environment not found"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
cat > $TMPC << EOF
|
||||
#include <curl/curl.h>
|
||||
int main(void) {
|
||||
curl_global_init(CURL_GLOBAL_NOTHING);
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if ! $cc $CFLAGS $CURL_CFLAGS $CURL_LDFLAGS $TMPC -o $TMPE > /dev/null 2>&1; then
|
||||
echo "cURL environment not usable"
|
||||
rm -f $TMPC
|
||||
exit 1
|
||||
fi
|
||||
rm -f $TMPC $TMPE
|
||||
fi
|
||||
|
||||
# check for X11 base dir
|
||||
if test -z "$x_base_dirs"; then
|
||||
x_base_dirs="
|
||||
|
@ -511,6 +548,7 @@ echo " --pkglibdir=ROOT install private files in ROOT [$pkglibdir]"
|
|||
echo " --target-os=OS build plugin support for target OS [$target_os]"
|
||||
echo " --target-cpu=CPU build plugin support for target CPU [$target_cpu]"
|
||||
echo " --enable-viewer build viewer [$build_viewer]"
|
||||
echo " --enable-player build player [$build_player]"
|
||||
echo ""
|
||||
echo "Advanced options (experts only):"
|
||||
echo " --source-path=PATH path of source code [$source_path]"
|
||||
|
@ -533,6 +571,7 @@ echo "Strip binaries $strip"
|
|||
echo "Bi-arch build $biarch"
|
||||
echo "Build viewer $build_viewer"
|
||||
echo "Build for Linux only $linux_only"
|
||||
echo "Build standalone player $build_player"
|
||||
echo "32-bit library dir name $lib32"
|
||||
echo "64-bit library dir name $lib64"
|
||||
echo "Source path $source_path"
|
||||
|
@ -558,6 +597,8 @@ echo "GLIB_CFLAGS=$GLIB_CFLAGS" >> $config_mak
|
|||
echo "GLIB_LDFLAGS=$GLIB_LDFLAGS" >> $config_mak
|
||||
echo "GTK_CFLAGS=$GTK_CFLAGS" >> $config_mak
|
||||
echo "GTK_LDFLAGS=$GTK_LDFLAGS" >> $config_mak
|
||||
echo "CURL_CFLAGS=$CURL_CFLAGS" >> $config_mak
|
||||
echo "CURL_LDFLAGS=$CURL_LDFLAGS" >> $config_mak
|
||||
if test "$biarch" = "yes"; then
|
||||
echo "LDFLAGS_32=-m32" >> $config_mak
|
||||
echo "CFLAGS_32=$CFLAGS_32" >> $config_mak
|
||||
|
@ -626,6 +667,7 @@ fi
|
|||
|
||||
echo "SRC_PATH=$source_path" >> $config_mak
|
||||
echo "build_viewer=$build_viewer" >> $config_mak
|
||||
echo "build_player=$build_player" >> $config_mak
|
||||
echo "biarch=$biarch" >> $config_mak
|
||||
echo "lib32=$lib32" >> $config_mak
|
||||
echo "lib64=$lib64" >> $config_mak
|
||||
|
|
|
@ -126,7 +126,7 @@
|
|||
/*----------------------------------------------------------------------*/
|
||||
|
||||
#define NP_VERSION_MAJOR 0
|
||||
#define NP_VERSION_MINOR 17
|
||||
#define NP_VERSION_MINOR 19
|
||||
|
||||
|
||||
/* The OS/2 version of Netscape uses RC_DATA to define the
|
||||
|
@ -437,7 +437,10 @@ typedef enum {
|
|||
NPNVWindowNPObject = 15,
|
||||
|
||||
/* Get the NPObject wrapper for the plugins DOM element. */
|
||||
NPNVPluginElementNPObject = 16
|
||||
NPNVPluginElementNPObject = 16,
|
||||
|
||||
NPNVSupportsWindowless = 17
|
||||
|
||||
} NPNVariable;
|
||||
|
||||
/*
|
||||
|
@ -636,6 +639,8 @@ enum NPEventType {
|
|||
#define NPVERS_HAS_FORM_VALUES 15
|
||||
#define NPVERS_HAS_POPUPS_ENABLED_STATE 16
|
||||
#define NPVERS_HAS_RESPONSE_HEADERS 17
|
||||
#define NPVERS_HAS_NPOBJECT_ENUM 18
|
||||
#define NPVERS_HAS_PLUGIN_THREAD_ASYNC_CALL 19
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Function Prototypes */
|
||||
|
@ -728,6 +733,9 @@ void NP_LOADDS NPN_InvalidateRegion(NPP instance, NPRegion invalidRegion);
|
|||
void NP_LOADDS NPN_ForceRedraw(NPP instance);
|
||||
void NP_LOADDS NPN_PushPopupsEnabledState(NPP instance, NPBool enabled);
|
||||
void NP_LOADDS NPN_PopPopupsEnabledState(NPP instance);
|
||||
void NP_LOADDS NPN_PluginThreadAsyncCall(NPP instance,
|
||||
void (*func) (void *),
|
||||
void *userData);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end extern "C" */
|
||||
|
|
|
@ -133,7 +133,7 @@ typedef struct _NPVariant {
|
|||
NPVariantType type;
|
||||
union {
|
||||
bool boolValue;
|
||||
uint32_t intValue;
|
||||
int32_t intValue;
|
||||
double doubleValue;
|
||||
NPString stringValue;
|
||||
NPObject *objectValue;
|
||||
|
@ -292,6 +292,12 @@ typedef bool (*NPSetPropertyFunctionPtr)(NPObject *npobj, NPIdentifier name,
|
|||
const NPVariant *value);
|
||||
typedef bool (*NPRemovePropertyFunctionPtr)(NPObject *npobj,
|
||||
NPIdentifier name);
|
||||
typedef bool (*NPEnumerationFunctionPtr)(NPObject *npobj, NPIdentifier **value,
|
||||
uint32_t *count);
|
||||
typedef bool (*NPConstructFunctionPtr)(NPObject *npobj,
|
||||
const NPVariant *args,
|
||||
uint32_t argCount,
|
||||
NPVariant *result);
|
||||
|
||||
/*
|
||||
NPObjects returned by create, retain, invoke, and getProperty pass
|
||||
|
@ -310,6 +316,11 @@ typedef bool (*NPRemovePropertyFunctionPtr)(NPObject *npobj,
|
|||
will typically return immediately, with 0 or NULL, from an attempt
|
||||
to dispatch to a NPObject, but this behavior should not be
|
||||
depended upon.)
|
||||
|
||||
The NPEnumerationFunctionPtr function may pass an array of
|
||||
NPIdentifiers back to the caller. The callee allocs the memory of
|
||||
the array using NPN_MemAlloc(), and it's the caller's responsibility
|
||||
to release it using NPN_MemFree().
|
||||
*/
|
||||
struct NPClass
|
||||
{
|
||||
|
@ -324,9 +335,20 @@ struct NPClass
|
|||
NPGetPropertyFunctionPtr getProperty;
|
||||
NPSetPropertyFunctionPtr setProperty;
|
||||
NPRemovePropertyFunctionPtr removeProperty;
|
||||
NPEnumerationFunctionPtr enumerate;
|
||||
NPConstructFunctionPtr construct;
|
||||
};
|
||||
|
||||
#define NP_CLASS_STRUCT_VERSION 1
|
||||
#define NP_CLASS_STRUCT_VERSION 3
|
||||
|
||||
#define NP_CLASS_STRUCT_VERSION_ENUM 2
|
||||
#define NP_CLASS_STRUCT_VERSION_CTOR 3
|
||||
|
||||
#define NP_CLASS_STRUCT_VERSION_HAS_ENUM(npclass) \
|
||||
((npclass)->structVersion >= NP_CLASS_STRUCT_VERSION_ENUM)
|
||||
|
||||
#define NP_CLASS_STRUCT_VERSION_HAS_CTOR(npclass) \
|
||||
((npclass)->structVersion >= NP_CLASS_STRUCT_VERSION_CTOR)
|
||||
|
||||
struct NPObject {
|
||||
NPClass *_class;
|
||||
|
@ -381,6 +403,10 @@ bool NPN_SetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName,
|
|||
bool NPN_RemoveProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName);
|
||||
bool NPN_HasProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName);
|
||||
bool NPN_HasMethod(NPP npp, NPObject *npobj, NPIdentifier methodName);
|
||||
bool NPN_Enumerate(NPP npp, NPObject *npobj, NPIdentifier **identifier,
|
||||
uint32_t *count);
|
||||
bool NPN_Construct(NPP npp, NPObject *npobj, const NPVariant *args,
|
||||
uint32_t argCount, NPVariant *result);
|
||||
|
||||
/*
|
||||
NPN_SetException may be called to trigger a script exception upon
|
||||
|
|
|
@ -1639,6 +1639,27 @@ typedef bool (* NP_LOADDS NPN_PopPopupsEnabledStateUPP)(NPP npp);
|
|||
|
||||
#endif
|
||||
|
||||
/* NPN_Enumerate */
|
||||
typedef bool (* NP_LOADDS NPN_EnumerateUPP)(NPP npp, NPObject *obj, NPIdentifier **identifier, uint32_t *count);
|
||||
#define NewNPN_EnumerateProc(FUNC) \
|
||||
((NPN_EnumerateUPP) (FUNC))
|
||||
#define CallNPN_EnumerateProc(FUNC, ARG1, ARG2, ARG3, ARG4) \
|
||||
(*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4))
|
||||
|
||||
/* NPN_PluginThreadAsyncCall */
|
||||
typedef void (* NP_LOADDS NPN_PluginThreadAsyncCallUPP)(NPP instance, void (*func)(void *), void *userData);
|
||||
#define NewNPN_PluginThreadAsyncCallProc(FUNC) \
|
||||
((NPN_PluginThreadAsyncCallUPP) (FUNC))
|
||||
#define CallNPN_PluginThreadAsyncCallProc(FUNC, ARG1, ARG2, ARG3) \
|
||||
(*(FUNC))((ARG1), (ARG2), (ARG3))
|
||||
|
||||
/* NPN_Construct */
|
||||
typedef bool (* NP_LOADDS NPN_ConstructUPP)(NPP npp, NPObject* obj, const NPVariant *args, uint32_t argCount, NPVariant *result);
|
||||
#define NewNPN_ConstructProc(FUNC) \
|
||||
((NPN_ConstructUPP) (FUNC))
|
||||
#define CallNPN_ConstructProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5) \
|
||||
(*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4), (ARG5))
|
||||
|
||||
|
||||
|
||||
/******************************************************************************************
|
||||
|
@ -1715,6 +1736,9 @@ typedef struct _NPNetscapeFuncs {
|
|||
NPN_SetExceptionUPP setexception;
|
||||
NPN_PushPopupsEnabledStateUPP pushpopupsenabledstate;
|
||||
NPN_PopPopupsEnabledStateUPP poppopupsenabledstate;
|
||||
NPN_EnumerateUPP enumerate;
|
||||
NPN_PluginThreadAsyncCallUPP pluginthreadasynccall;
|
||||
NPN_ConstructUPP construct;
|
||||
} NPNetscapeFuncs;
|
||||
|
||||
#ifdef XP_MAC
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
%define name nspluginwrapper
|
||||
%define version 1.0.0
|
||||
%define version 1.1.0
|
||||
%define release 1
|
||||
#define svndate 20080629
|
||||
#define svndate 20080706
|
||||
|
||||
# define 32-bit arch of multiarch platforms
|
||||
%define arch_32 %{nil}
|
||||
|
@ -45,6 +45,11 @@
|
|||
%{expand: %{?_with_generic: %%global build_generic 1}}
|
||||
%{expand: %{?_without_generic: %%global build_generic 0}}
|
||||
|
||||
# define to build the standalone NPAPI plugins player
|
||||
%define build_player 1
|
||||
%{expand: %{?_with_player: %%global build_player 1}}
|
||||
%{expand: %{?_without_player: %%global build_player 0}}
|
||||
|
||||
Summary: A compatibility layer for Netscape 4 plugins
|
||||
Name: %{name}
|
||||
Version: %{version}
|
||||
|
@ -87,6 +92,18 @@ This package consists in:
|
|||
This package provides the npviewer program for %{target_arch}.
|
||||
%endif
|
||||
|
||||
%if %{build_player}
|
||||
%package -n nspluginplayer
|
||||
Summary: A viewer for %{target_arch} compiled Netscape 4 plugins
|
||||
Group: Networking/WWW
|
||||
BuildRequires: curl-devel
|
||||
# XXX: the Gtk version can work with non-wrapped plugins so this ought to be a Suggests: tag
|
||||
#Requires: %{name} = %{version}-%{release}
|
||||
|
||||
%description -n nspluginplayer
|
||||
nspluginplayer is a standalone player for NPAPI plugins.
|
||||
%endif
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
|
||||
|
@ -98,10 +115,17 @@ enable_biarch="--disable-biarch"
|
|||
%endif
|
||||
%if %{build_generic}
|
||||
enable_generic="--enable-generic"
|
||||
%else
|
||||
enable_generic="--disable-generic"
|
||||
%endif
|
||||
%if %{build_player}
|
||||
enable_player="--enable-player"
|
||||
%else
|
||||
enable_player="--disable-player"
|
||||
%endif
|
||||
mkdir objs
|
||||
pushd objs
|
||||
../configure --prefix=%{_prefix} $enable_biarch $enable_generic
|
||||
../configure --prefix=%{_prefix} $enable_biarch $enable_generic $enable_player
|
||||
make
|
||||
popd
|
||||
|
||||
|
@ -144,6 +168,7 @@ fi
|
|||
%{pkglibdir}/%{_arch}/%{_os}/npviewer
|
||||
%{pkglibdir}/%{_arch}/%{_os}/npviewer.bin
|
||||
%{pkglibdir}/%{_arch}/%{_os}/libxpcom.so
|
||||
%{pkglibdir}/%{_arch}/%{_os}/libnoxshm.so
|
||||
%endif
|
||||
%{pkglibdir}/%{_arch}/%{_os}/npwrapper.so
|
||||
|
||||
|
@ -155,9 +180,23 @@ fi
|
|||
%{pkglibdir}/%{target_arch}/%{target_os}/npviewer
|
||||
%{pkglibdir}/%{target_arch}/%{target_os}/npviewer.bin
|
||||
%{pkglibdir}/%{target_arch}/%{target_os}/libxpcom.so
|
||||
%{pkglibdir}/%{target_arch}/%{target_os}/libnoxshm.so
|
||||
%endif
|
||||
|
||||
%if %{build_player}
|
||||
%files -n nspluginplayer
|
||||
%defattr(-,root,root)
|
||||
%doc README COPYING NEWS
|
||||
%{_bindir}/nspluginplayer
|
||||
%{pkglibdir}/%{_arch}/%{_os}/npplayer
|
||||
%endif
|
||||
|
||||
%changelog
|
||||
* Sun Jul 6 2008 Gwenole Beauchesne <gb.public@free.fr> 1.1.0-1
|
||||
- add support for windowless plugins (Flash Player 10 beta 2)
|
||||
- add standalone plugins player (nspluginplayer)
|
||||
- restart plugins viewer on error (Martin Stransky)
|
||||
|
||||
* Sun Jun 29 2008 Gwenole Beauchesne <gb.public@free.fr> 1.0.0-1
|
||||
- don't wrap root plugins to system locations, keep them private
|
||||
- fix support for Acrobat Reader 8 (focus problems)
|
||||
|
|
|
@ -23,6 +23,10 @@
|
|||
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern void npw_dprintf(const char *format, ...) attribute_hidden;
|
||||
|
||||
extern void npw_printf(const char *format, ...) attribute_hidden;
|
||||
|
@ -35,4 +39,8 @@ extern void npw_vprintf(const char *format, va_list args) attribute_hidden;
|
|||
#define D(x) ;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* DEBUG_H */
|
||||
|
|
|
@ -0,0 +1,546 @@
|
|||
/* $Id: glibcurl.c,v 1.14 2004/12/05 16:15:12 atterer Exp $ -*- C -*-
|
||||
__ _
|
||||
|_) /| Copyright (C) 2004 | richard@
|
||||
| \/¯| Richard Atterer | atterer.net
|
||||
¯ '` ¯
|
||||
All rights reserved.
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of a copyright holder shall
|
||||
not be used in advertising or otherwise to promote the sale, use or other
|
||||
dealings in this Software without prior written authorization of the
|
||||
copyright holder.
|
||||
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
#include "glibcurl.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* #define D(_args) fprintf _args; */
|
||||
#define D(_args)
|
||||
|
||||
/* #if 1 */
|
||||
#ifdef G_OS_WIN32
|
||||
/*______________________________________________________________________*/
|
||||
|
||||
/* Timeout for the fds passed to glib's poll() call, in millisecs.
|
||||
curl_multi_fdset(3) says we should call curl_multi_perform() at regular
|
||||
intervals. */
|
||||
#define GLIBCURL_TIMEOUT 500
|
||||
|
||||
/* A structure which "derives" (in glib speak) from GSource */
|
||||
typedef struct CurlGSource_ {
|
||||
GSource source; /* First: The type we're deriving from */
|
||||
|
||||
CURLM* multiHandle;
|
||||
GThread* selectThread;
|
||||
GCond* cond; /* To signal selectThread => main thread: call perform() */
|
||||
GMutex* mutex; /* Not held by selectThread whenever it is waiting */
|
||||
|
||||
gboolean callPerform; /* TRUE => Call curl_multi_perform() Real Soon */
|
||||
gint gtkBlockAndWait;
|
||||
gboolean selectRunning; /* FALSE => selectThread terminates */
|
||||
|
||||
/* For data returned by curl_multi_fdset */
|
||||
fd_set fdRead;
|
||||
fd_set fdWrite;
|
||||
fd_set fdExc;
|
||||
int fdMax;
|
||||
|
||||
} CurlGSource;
|
||||
|
||||
/* Global state: Our CurlGSource object */
|
||||
static CurlGSource* curlSrc = 0;
|
||||
|
||||
/* The "methods" of CurlGSource */
|
||||
static gboolean prepare(GSource* source, gint* timeout);
|
||||
static gboolean check(GSource* source);
|
||||
static gboolean dispatch(GSource* source, GSourceFunc callback,
|
||||
gpointer user_data);
|
||||
static void finalize(GSource* source);
|
||||
|
||||
static GSourceFuncs curlFuncs = {
|
||||
&prepare, &check, &dispatch, &finalize, 0, 0
|
||||
};
|
||||
/*______________________________________________________________________*/
|
||||
|
||||
void glibcurl_init() {
|
||||
/* Create source object for curl file descriptors, and hook it into the
|
||||
default main context. */
|
||||
GSource* src = g_source_new(&curlFuncs, sizeof(CurlGSource));
|
||||
curlSrc = (CurlGSource*)src;
|
||||
g_source_attach(&curlSrc->source, NULL);
|
||||
|
||||
if (!g_thread_supported()) g_thread_init(NULL);
|
||||
|
||||
/* Init rest of our data */
|
||||
curlSrc->callPerform = 0;
|
||||
curlSrc->selectThread = 0;
|
||||
curlSrc->cond = g_cond_new();
|
||||
curlSrc->mutex = g_mutex_new();
|
||||
curlSrc->gtkBlockAndWait = 0;
|
||||
|
||||
/* Init libcurl */
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
curlSrc->multiHandle = curl_multi_init();
|
||||
}
|
||||
/*______________________________________________________________________*/
|
||||
|
||||
void glibcurl_cleanup() {
|
||||
D((stderr, "glibcurl_cleanup\n"));
|
||||
/* You must call curl_multi_remove_handle() and curl_easy_cleanup() for all
|
||||
requests before calling this. */
|
||||
/* assert(curlSrc->callPerform == 0); */
|
||||
|
||||
/* All easy handles must be finished */
|
||||
|
||||
/* Lock before accessing selectRunning/selectThread */
|
||||
g_mutex_lock(curlSrc->mutex);
|
||||
curlSrc->selectRunning = FALSE;
|
||||
while (curlSrc->selectThread != NULL) {
|
||||
g_mutex_unlock(curlSrc->mutex);
|
||||
g_thread_yield();
|
||||
g_cond_signal(curlSrc->cond); /* Make the select thread shut down */
|
||||
g_thread_yield();
|
||||
g_mutex_lock(curlSrc->mutex); /* Wait until it has shut down */
|
||||
}
|
||||
g_mutex_unlock(curlSrc->mutex);
|
||||
|
||||
assert(curlSrc->selectThread == NULL);
|
||||
|
||||
g_cond_free(curlSrc->cond);
|
||||
g_mutex_free(curlSrc->mutex);
|
||||
|
||||
curl_multi_cleanup(curlSrc->multiHandle);
|
||||
curlSrc->multiHandle = 0;
|
||||
curl_global_cleanup();
|
||||
|
||||
g_source_unref(&curlSrc->source);
|
||||
curlSrc = 0;
|
||||
}
|
||||
/*______________________________________________________________________*/
|
||||
|
||||
CURLM* glibcurl_handle() {
|
||||
return curlSrc->multiHandle;
|
||||
}
|
||||
/*______________________________________________________________________*/
|
||||
|
||||
CURLMcode glibcurl_add(CURL *easy_handle) {
|
||||
assert(curlSrc != 0);
|
||||
assert(curlSrc->multiHandle != 0);
|
||||
glibcurl_start();
|
||||
return curl_multi_add_handle(curlSrc->multiHandle, easy_handle);
|
||||
}
|
||||
/*______________________________________________________________________*/
|
||||
|
||||
CURLMcode glibcurl_remove(CURL *easy_handle) {
|
||||
D((stderr, "glibcurl_remove %p\n", easy_handle));
|
||||
assert(curlSrc != 0);
|
||||
assert(curlSrc->multiHandle != 0);
|
||||
return curl_multi_remove_handle(curlSrc->multiHandle, easy_handle);
|
||||
}
|
||||
/*______________________________________________________________________*/
|
||||
|
||||
/* Call this whenever you have added a request using
|
||||
curl_multi_add_handle(). */
|
||||
void glibcurl_start() {
|
||||
D((stderr, "glibcurl_start\n"));
|
||||
curlSrc->callPerform = TRUE;
|
||||
}
|
||||
/*______________________________________________________________________*/
|
||||
|
||||
void glibcurl_set_callback(GlibcurlCallback function, void* data) {
|
||||
g_source_set_callback(&curlSrc->source, (GSourceFunc)function, data,
|
||||
NULL);
|
||||
}
|
||||
/*______________________________________________________________________*/
|
||||
|
||||
static gpointer selectThread(gpointer data) {
|
||||
int fdCount;
|
||||
struct timeval timeout;
|
||||
assert(data == 0); /* Just to get rid of unused param warning */
|
||||
|
||||
D((stderr, "selectThread\n"));
|
||||
g_mutex_lock(curlSrc->mutex);
|
||||
D((stderr, "selectThread: got lock\n"));
|
||||
|
||||
curlSrc->selectRunning = TRUE;
|
||||
while (curlSrc->selectRunning) {
|
||||
|
||||
FD_ZERO(&curlSrc->fdRead);
|
||||
FD_ZERO(&curlSrc->fdWrite);
|
||||
FD_ZERO(&curlSrc->fdExc);
|
||||
curlSrc->fdMax = -1;
|
||||
/* What fds does libcurl want us to poll? */
|
||||
curl_multi_fdset(curlSrc->multiHandle, &curlSrc->fdRead,
|
||||
&curlSrc->fdWrite, &curlSrc->fdExc, &curlSrc->fdMax);
|
||||
timeout.tv_sec = GLIBCURL_TIMEOUT / 1000;
|
||||
timeout.tv_usec = (GLIBCURL_TIMEOUT % 1000) * 1000;
|
||||
fdCount = select(curlSrc->fdMax + 1, &curlSrc->fdRead, &curlSrc->fdWrite,
|
||||
&curlSrc->fdExc, &timeout);
|
||||
D((stderr, "selectThread: select() fdCount=%d\n", fdCount));
|
||||
|
||||
g_atomic_int_inc(&curlSrc->gtkBlockAndWait); /* "GTK thread, block!" */
|
||||
D((stderr, "selectThread: waking up GTK thread %d\n",
|
||||
curlSrc->gtkBlockAndWait));
|
||||
/* GTK thread will almost immediately block in prepare() */
|
||||
g_main_context_wakeup(NULL);
|
||||
|
||||
/* Now unblock GTK thread, continue after it signals us */
|
||||
D((stderr, "selectThread: pre-wait\n"));
|
||||
g_cond_wait(curlSrc->cond, curlSrc->mutex);
|
||||
D((stderr, "selectThread: post-wait\n"));
|
||||
|
||||
}
|
||||
|
||||
curlSrc->selectThread = NULL;
|
||||
D((stderr, "selectThread: exit\n"));
|
||||
g_mutex_unlock(curlSrc->mutex);
|
||||
return NULL;
|
||||
}
|
||||
/*______________________________________________________________________*/
|
||||
|
||||
/* Returning FALSE may cause the main loop to block indefinitely, but that is
|
||||
not a problem, we use g_main_context_wakeup to wake it up */
|
||||
/* Returns TRUE iff it holds the mutex lock */
|
||||
gboolean prepare(GSource* source, gint* timeout) {
|
||||
assert(source == &curlSrc->source);
|
||||
D((stderr, "prepare: callPerform=%d, thread=%p\n",
|
||||
curlSrc->callPerform, curlSrc->selectThread));
|
||||
|
||||
*timeout = -1;
|
||||
|
||||
if (g_atomic_int_dec_and_test(&curlSrc->gtkBlockAndWait)) {
|
||||
/* The select thread wants us to block */
|
||||
D((stderr, "prepare: trying lock\n"));
|
||||
g_mutex_lock(curlSrc->mutex);
|
||||
D((stderr, "prepare: got lock\n"));
|
||||
return TRUE;
|
||||
} else {
|
||||
g_atomic_int_inc(&curlSrc->gtkBlockAndWait);
|
||||
}
|
||||
|
||||
/* Usual behaviour: Nothing happened, so don't dispatch. */
|
||||
if (!curlSrc->callPerform) return FALSE;
|
||||
|
||||
/* Always dispatch if callPerform, i.e. 1st download just starting. */
|
||||
D((stderr, "prepare: trying lock 2\n"));
|
||||
/* Problem: We can block up to GLIBCURL_TIMEOUT msecs here, until the
|
||||
select() call returns. However, under Win32 this does not appear to be a
|
||||
problem (don't know why) - it _does_ tend to block the GTK thread under
|
||||
Linux. */
|
||||
g_mutex_lock(curlSrc->mutex);
|
||||
D((stderr, "prepare: got lock 2\n"));
|
||||
curlSrc->callPerform = FALSE;
|
||||
if (curlSrc->selectThread == NULL) {
|
||||
D((stderr, "prepare: starting select thread\n"));
|
||||
/* Note that the thread will stop soon because we hold mutex */
|
||||
curlSrc->selectThread = g_thread_create(&selectThread, 0, FALSE, NULL);
|
||||
assert(curlSrc->selectThread != NULL);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
/*______________________________________________________________________*/
|
||||
|
||||
/* Called after all the file descriptors are polled by glib. */
|
||||
gboolean check(GSource* source) {
|
||||
assert(source == &curlSrc->source);
|
||||
return FALSE;
|
||||
}
|
||||
/*______________________________________________________________________*/
|
||||
|
||||
gboolean dispatch(GSource* source, GSourceFunc callback,
|
||||
gpointer user_data) {
|
||||
CURLMcode x;
|
||||
int multiCount;
|
||||
|
||||
assert(source == &curlSrc->source);
|
||||
do {
|
||||
x = curl_multi_perform(curlSrc->multiHandle, &multiCount);
|
||||
D((stderr, "dispatched: code=%d, reqs=%d\n", x, multiCount));
|
||||
} while (x == CURLM_CALL_MULTI_PERFORM);
|
||||
|
||||
if (multiCount == 0)
|
||||
curlSrc->selectRunning = FALSE;
|
||||
|
||||
if (callback != 0) (*callback)(user_data);
|
||||
|
||||
/* Let selectThread call select() again */
|
||||
g_cond_signal(curlSrc->cond);
|
||||
g_mutex_unlock(curlSrc->mutex);
|
||||
|
||||
return TRUE; /* "Do not destroy me" */
|
||||
}
|
||||
/*______________________________________________________________________*/
|
||||
|
||||
void finalize(GSource* source) {
|
||||
assert(source == &curlSrc->source);
|
||||
}
|
||||
/*======================================================================*/
|
||||
|
||||
#else /* !G_OS_WIN32 */
|
||||
|
||||
/* Number of highest allowed fd */
|
||||
#define GLIBCURL_FDMAX 127
|
||||
|
||||
/* Timeout for the fds passed to glib's poll() call, in millisecs.
|
||||
curl_multi_fdset(3) says we should call curl_multi_perform() at regular
|
||||
intervals. */
|
||||
#define GLIBCURL_TIMEOUT 1000
|
||||
|
||||
/* GIOCondition event masks */
|
||||
#define GLIBCURL_READ (G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP)
|
||||
#define GLIBCURL_WRITE (G_IO_OUT | G_IO_ERR | G_IO_HUP)
|
||||
#define GLIBCURL_EXC (G_IO_ERR | G_IO_HUP)
|
||||
|
||||
/** A structure which "derives" (in glib speak) from GSource */
|
||||
typedef struct CurlGSource_ {
|
||||
GSource source; /* First: The type we're deriving from */
|
||||
|
||||
CURLM* multiHandle;
|
||||
|
||||
/* Previously seen FDs, for comparing with libcurl's current fd_sets */
|
||||
GPollFD lastPollFd[GLIBCURL_FDMAX + 1];
|
||||
int lastPollFdMax; /* Index of highest non-empty entry in lastPollFd */
|
||||
|
||||
int callPerform; /* Non-zero => curl_multi_perform() gets called */
|
||||
|
||||
/* For data returned by curl_multi_fdset */
|
||||
fd_set fdRead;
|
||||
fd_set fdWrite;
|
||||
fd_set fdExc;
|
||||
int fdMax;
|
||||
|
||||
} CurlGSource;
|
||||
|
||||
/* Global state: Our CurlGSource object */
|
||||
static CurlGSource* curlSrc = 0;
|
||||
|
||||
/* The "methods" of CurlGSource */
|
||||
static gboolean prepare(GSource* source, gint* timeout);
|
||||
static gboolean check(GSource* source);
|
||||
static gboolean dispatch(GSource* source, GSourceFunc callback,
|
||||
gpointer user_data);
|
||||
static void finalize(GSource* source);
|
||||
|
||||
static GSourceFuncs curlFuncs = {
|
||||
&prepare, &check, &dispatch, &finalize, 0, 0
|
||||
};
|
||||
/*______________________________________________________________________*/
|
||||
|
||||
void glibcurl_init() {
|
||||
int fd;
|
||||
/* Create source object for curl file descriptors, and hook it into the
|
||||
default main context. */
|
||||
curlSrc = (CurlGSource*)g_source_new(&curlFuncs, sizeof(CurlGSource));
|
||||
g_source_attach(&curlSrc->source, NULL);
|
||||
|
||||
/* Init rest of our data */
|
||||
memset(&curlSrc->lastPollFd, 0, sizeof(curlSrc->lastPollFd));
|
||||
for (fd = 1; fd <= GLIBCURL_FDMAX; ++fd)
|
||||
curlSrc->lastPollFd[fd].fd = fd;
|
||||
curlSrc->lastPollFdMax = 0;
|
||||
curlSrc->callPerform = 0;
|
||||
|
||||
/* Init libcurl */
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
curlSrc->multiHandle = curl_multi_init();
|
||||
|
||||
D((stderr, "events: R=%x W=%x X=%x\n", GLIBCURL_READ, GLIBCURL_WRITE,
|
||||
GLIBCURL_EXC));
|
||||
}
|
||||
/*______________________________________________________________________*/
|
||||
|
||||
CURLM* glibcurl_handle() {
|
||||
return curlSrc->multiHandle;
|
||||
}
|
||||
/*______________________________________________________________________*/
|
||||
|
||||
CURLMcode glibcurl_add(CURL *easy_handle) {
|
||||
assert(curlSrc->multiHandle != 0);
|
||||
curlSrc->callPerform = -1;
|
||||
return curl_multi_add_handle(curlSrc->multiHandle, easy_handle);
|
||||
}
|
||||
/*______________________________________________________________________*/
|
||||
|
||||
CURLMcode glibcurl_remove(CURL *easy_handle) {
|
||||
assert(curlSrc != 0);
|
||||
assert(curlSrc->multiHandle != 0);
|
||||
return curl_multi_remove_handle(curlSrc->multiHandle, easy_handle);
|
||||
}
|
||||
/*______________________________________________________________________*/
|
||||
|
||||
/* Call this whenever you have added a request using curl_multi_add_handle().
|
||||
This is necessary to start new requests. It does so by triggering a call
|
||||
to curl_multi_perform() even in the case where no open fds cause that
|
||||
function to be called anyway. */
|
||||
void glibcurl_start() {
|
||||
curlSrc->callPerform = -1;
|
||||
}
|
||||
/*______________________________________________________________________*/
|
||||
|
||||
void glibcurl_set_callback(GlibcurlCallback function, void* data) {
|
||||
g_source_set_callback(&curlSrc->source, (GSourceFunc)function, data,
|
||||
NULL);
|
||||
}
|
||||
/*______________________________________________________________________*/
|
||||
|
||||
void glibcurl_cleanup() {
|
||||
/* You must call curl_multi_remove_handle() and curl_easy_cleanup() for all
|
||||
requests before calling this. */
|
||||
/* assert(curlSrc->callPerform == 0); */
|
||||
|
||||
curl_multi_cleanup(curlSrc->multiHandle);
|
||||
curlSrc->multiHandle = 0;
|
||||
curl_global_cleanup();
|
||||
|
||||
/* g_source_destroy(&curlSrc->source); */
|
||||
g_source_unref(&curlSrc->source);
|
||||
curlSrc = 0;
|
||||
}
|
||||
/*______________________________________________________________________*/
|
||||
|
||||
static void registerUnregisterFds() {
|
||||
int fd, fdMax;
|
||||
|
||||
FD_ZERO(&curlSrc->fdRead);
|
||||
FD_ZERO(&curlSrc->fdWrite);
|
||||
FD_ZERO(&curlSrc->fdExc);
|
||||
curlSrc->fdMax = -1;
|
||||
/* What fds does libcurl want us to poll? */
|
||||
curl_multi_fdset(curlSrc->multiHandle, &curlSrc->fdRead,
|
||||
&curlSrc->fdWrite, &curlSrc->fdExc, &curlSrc->fdMax);
|
||||
/*fprintf(stderr, "registerUnregisterFds: fdMax=%d\n", curlSrc->fdMax);*/
|
||||
assert(curlSrc->fdMax >= -1 && curlSrc->fdMax <= GLIBCURL_FDMAX);
|
||||
|
||||
fdMax = curlSrc->fdMax;
|
||||
if (fdMax < curlSrc->lastPollFdMax) fdMax = curlSrc->lastPollFdMax;
|
||||
|
||||
/* Has the list of required events for any of the fds changed? */
|
||||
for (fd = 0; fd <= fdMax; ++fd) {
|
||||
gushort events = 0;
|
||||
if (FD_ISSET(fd, &curlSrc->fdRead)) events |= GLIBCURL_READ;
|
||||
if (FD_ISSET(fd, &curlSrc->fdWrite)) events |= GLIBCURL_WRITE;
|
||||
if (FD_ISSET(fd, &curlSrc->fdExc)) events |= GLIBCURL_EXC;
|
||||
|
||||
/* List of events unchanged => no (de)registering */
|
||||
if (events == curlSrc->lastPollFd[fd].events) continue;
|
||||
|
||||
D((stderr, "registerUnregisterFds: fd %d: old events %x, "
|
||||
"new events %x\n", fd, curlSrc->lastPollFd[fd].events, events));
|
||||
|
||||
/* fd is already a lastPollFd, but event type has changed => do nothing.
|
||||
Due to the implementation of g_main_context_query(), the new event
|
||||
flags will be picked up automatically. */
|
||||
if (events != 0 && curlSrc->lastPollFd[fd].events != 0) {
|
||||
curlSrc->lastPollFd[fd].events = events;
|
||||
continue;
|
||||
}
|
||||
curlSrc->lastPollFd[fd].events = events;
|
||||
|
||||
/* Otherwise, (de)register as appropriate */
|
||||
if (events == 0) {
|
||||
g_source_remove_poll(&curlSrc->source, &curlSrc->lastPollFd[fd]);
|
||||
curlSrc->lastPollFd[fd].revents = 0;
|
||||
D((stderr, "unregister fd %d\n", fd));
|
||||
} else {
|
||||
g_source_add_poll(&curlSrc->source, &curlSrc->lastPollFd[fd]);
|
||||
D((stderr, "register fd %d\n", fd));
|
||||
}
|
||||
}
|
||||
|
||||
curlSrc->lastPollFdMax = curlSrc->fdMax;
|
||||
}
|
||||
|
||||
/* Called before all the file descriptors are polled by the glib main loop.
|
||||
We must have a look at all fds that libcurl wants polled. If any of them
|
||||
are new/no longer needed, we have to (de)register them with glib. */
|
||||
gboolean prepare(GSource* source, gint* timeout) {
|
||||
D((stderr, "prepare\n"));
|
||||
assert(source == &curlSrc->source);
|
||||
|
||||
if (curlSrc->multiHandle == 0) return FALSE;
|
||||
|
||||
registerUnregisterFds();
|
||||
|
||||
*timeout = GLIBCURL_TIMEOUT;
|
||||
/* return FALSE; */
|
||||
return curlSrc->callPerform == -1 ? TRUE : FALSE;
|
||||
}
|
||||
/*______________________________________________________________________*/
|
||||
|
||||
/* Called after all the file descriptors are polled by glib.
|
||||
g_main_context_check() has copied back the revents fields (set by glib's
|
||||
poll() call) to our GPollFD objects. How inefficient all that copying
|
||||
is... let's add some more and copy the results of these revents into
|
||||
libcurl's fd_sets! */
|
||||
gboolean check(GSource* source) {
|
||||
int fd, somethingHappened = 0;
|
||||
|
||||
if (curlSrc->multiHandle == 0) return FALSE;
|
||||
|
||||
assert(source == &curlSrc->source);
|
||||
FD_ZERO(&curlSrc->fdRead);
|
||||
FD_ZERO(&curlSrc->fdWrite);
|
||||
FD_ZERO(&curlSrc->fdExc);
|
||||
for (fd = 0; fd <= curlSrc->fdMax; ++fd) {
|
||||
gushort revents = curlSrc->lastPollFd[fd].revents;
|
||||
if (revents == 0) continue;
|
||||
somethingHappened = 1;
|
||||
/* D((stderr, "[fd%d] ", fd)); */
|
||||
if (revents & (G_IO_IN | G_IO_PRI))
|
||||
FD_SET((unsigned)fd, &curlSrc->fdRead);
|
||||
if (revents & G_IO_OUT)
|
||||
FD_SET((unsigned)fd, &curlSrc->fdWrite);
|
||||
if (revents & (G_IO_ERR | G_IO_HUP))
|
||||
FD_SET((unsigned)fd, &curlSrc->fdExc);
|
||||
}
|
||||
/* D((stderr, "check: fdMax %d\n", curlSrc->fdMax)); */
|
||||
|
||||
/* return TRUE; */
|
||||
/* return FALSE; */
|
||||
return curlSrc->callPerform == -1 || somethingHappened != 0 ? TRUE : FALSE;
|
||||
}
|
||||
/*______________________________________________________________________*/
|
||||
|
||||
gboolean dispatch(GSource* source, GSourceFunc callback,
|
||||
gpointer user_data) {
|
||||
CURLMcode x;
|
||||
|
||||
assert(source == &curlSrc->source);
|
||||
assert(curlSrc->multiHandle != 0);
|
||||
do {
|
||||
x = curl_multi_perform(curlSrc->multiHandle, &curlSrc->callPerform);
|
||||
/* D((stderr, "dispatched %d\n", x)); */
|
||||
} while (x == CURLM_CALL_MULTI_PERFORM);
|
||||
|
||||
/* If no more calls to curl_multi_perform(), unregister left-over fds */
|
||||
if (curlSrc->callPerform == 0) registerUnregisterFds();
|
||||
|
||||
if (callback != 0) (*callback)(user_data);
|
||||
|
||||
return TRUE; /* "Do not destroy me" */
|
||||
}
|
||||
/*______________________________________________________________________*/
|
||||
|
||||
void finalize(GSource* source) {
|
||||
assert(source == &curlSrc->source);
|
||||
registerUnregisterFds();
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,82 @@
|
|||
/* $Id: glibcurl.h,v 1.7 2004/12/04 13:58:29 atterer Exp $ -*- C -*-
|
||||
__ _
|
||||
|_) /| Copyright (C) 2004 | richard@
|
||||
| \/¯| Richard Atterer | atterer.net
|
||||
¯ '` ¯
|
||||
All rights reserved.
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of a copyright holder shall
|
||||
not be used in advertising or otherwise to promote the sale, use or other
|
||||
dealings in this Software without prior written authorization of the
|
||||
copyright holder.
|
||||
|
||||
*/
|
||||
|
||||
/** @file
|
||||
Use the libcurl multi interface from GTK+/glib programs without having to
|
||||
resort to multithreading */
|
||||
|
||||
#ifndef GLIBCURL_H
|
||||
#define GLIBCURL_H
|
||||
|
||||
/* XXX: older curl (7.18.0) needs fd_set defined for <curl/multi.h> */
|
||||
#include <sys/select.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Initialize libcurl. Call this once at the beginning of your program. This
|
||||
function makes calls to curl_global_init() and curl_multi_init() */
|
||||
void glibcurl_init();
|
||||
|
||||
/** Return global multi handle */
|
||||
CURLM* glibcurl_handle();
|
||||
|
||||
/** Convenience function, just executes
|
||||
curl_multi_add_handle(glibcurl_handle(), easy_handle); glibcurl_start()*/
|
||||
CURLMcode glibcurl_add(CURL* easy_handle);
|
||||
|
||||
/** Convenience function, just executes
|
||||
curl_multi_remove_handle(glibcurl_handle(), easy_handle) */
|
||||
CURLMcode glibcurl_remove(CURL* easy_handle);
|
||||
|
||||
/** Call this whenever you have added a request using
|
||||
curl_multi_add_handle(). This is necessary to start new requests. It does
|
||||
so by triggering a call to curl_multi_perform() even in the case where no
|
||||
open fds cause that function to be called anyway. The call happens
|
||||
"later", i.e. during the next iteration of the glib main loop.
|
||||
glibcurl_start() only sets a flag to make it happen. */
|
||||
void glibcurl_start();
|
||||
|
||||
/** Callback function for glibcurl_set_callback */
|
||||
typedef void (*GlibcurlCallback)(void*);
|
||||
/** Set function to call after each invocation of curl_multi_perform(). Pass
|
||||
function==0 to unregister a previously set callback. The callback
|
||||
function will be called with the supplied data pointer as its first
|
||||
argument. */
|
||||
void glibcurl_set_callback(GlibcurlCallback function, void* data);
|
||||
|
||||
/** You must call glibcurl_remove() and curl_easy_cleanup() for all requests
|
||||
before calling this. This function makes calls to curl_multi_cleanup()
|
||||
and curl_global_cleanup(). */
|
||||
void glibcurl_cleanup();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
251
src/gtk2xtbin.c
251
src/gtk2xtbin.c
|
@ -42,17 +42,23 @@
|
|||
* inside a GTK application.
|
||||
*/
|
||||
|
||||
#include "sysdeps.h"
|
||||
|
||||
#include "xembed.h"
|
||||
#include "gtk2xtbin.h"
|
||||
#ifdef BUILD_VIEWER
|
||||
#include <gtk/gtk.h>
|
||||
#else
|
||||
#include <gtk/gtkmain.h>
|
||||
#include <gtk/gtkprivate.h>
|
||||
#endif
|
||||
#include <gdk/gdkx.h>
|
||||
#include <glib.h>
|
||||
#include <assert.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <gdk/gdkx.h>
|
||||
#include "xembed.h"
|
||||
#include "gtk2xtbin.h"
|
||||
|
||||
/* Xlib/Xt stuff */
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
|
@ -62,7 +68,9 @@
|
|||
|
||||
/* uncomment this if you want debugging information about widget
|
||||
creation and destruction */
|
||||
#define DEBUG_XTBIN 1
|
||||
#undef DEBUG_XTBIN
|
||||
|
||||
#define XTBIN_MAX_EVENTS 30
|
||||
|
||||
static void gtk_xtbin_class_init (GtkXtBinClass *klass);
|
||||
static void gtk_xtbin_init (GtkXtBin *xtbin);
|
||||
|
@ -73,7 +81,6 @@ static void gtk_xtbin_shutdown (GtkObject *object);
|
|||
|
||||
/* Xt aware XEmbed */
|
||||
static void xt_client_init (XtClient * xtclient,
|
||||
Display *xtdisplay,
|
||||
Visual *xtvisual,
|
||||
Colormap xtcolormap,
|
||||
int xtdepth);
|
||||
|
@ -107,12 +114,107 @@ static int error_handler (Display *display,
|
|||
XErrorEvent *error);
|
||||
/* For error trap of XEmbed */
|
||||
static void trap_errors(void);
|
||||
static int untrap_errors(void);
|
||||
static int untrap_error(void);
|
||||
static int (*old_error_handler) (Display *, XErrorEvent *);
|
||||
static int trapped_error_code = 0;
|
||||
|
||||
static GtkWidgetClass *parent_class = NULL;
|
||||
|
||||
static Display *xtdisplay = NULL;
|
||||
static String *fallback = NULL;
|
||||
static gboolean xt_is_initialized = FALSE;
|
||||
static gint num_widgets = 0;
|
||||
|
||||
static GPollFD xt_event_poll_fd;
|
||||
static gint xt_polling_timer_id = 0;
|
||||
static guint tag = 0;
|
||||
|
||||
static gboolean
|
||||
xt_event_prepare (GSource* source_data,
|
||||
gint *timeout)
|
||||
{
|
||||
int mask;
|
||||
|
||||
GDK_THREADS_ENTER();
|
||||
mask = XPending(xtdisplay);
|
||||
GDK_THREADS_LEAVE();
|
||||
|
||||
return (gboolean)mask;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
xt_event_check (GSource* source_data)
|
||||
{
|
||||
GDK_THREADS_ENTER ();
|
||||
|
||||
if (xt_event_poll_fd.revents & G_IO_IN) {
|
||||
int mask;
|
||||
mask = XPending(xtdisplay);
|
||||
GDK_THREADS_LEAVE ();
|
||||
return (gboolean)mask;
|
||||
}
|
||||
|
||||
GDK_THREADS_LEAVE ();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
xt_event_dispatch (GSource* source_data,
|
||||
GSourceFunc call_back,
|
||||
gpointer user_data)
|
||||
{
|
||||
XEvent event;
|
||||
XtAppContext ac;
|
||||
int i = 0;
|
||||
|
||||
ac = XtDisplayToApplicationContext(xtdisplay);
|
||||
|
||||
GDK_THREADS_ENTER ();
|
||||
|
||||
/* Process only real X traffic here. We only look for data on the
|
||||
* pipe, limit it to XTBIN_MAX_EVENTS and only call
|
||||
* XtAppProcessEvent so that it will look for X events. There's no
|
||||
* timer processing here since we already have a timer callback that
|
||||
* does it. */
|
||||
for (i=0; i < XTBIN_MAX_EVENTS && XPending(xtdisplay); i++) {
|
||||
XtAppProcessEvent(ac, XtIMXEvent);
|
||||
}
|
||||
|
||||
GDK_THREADS_LEAVE ();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GSourceFuncs xt_event_funcs = {
|
||||
xt_event_prepare,
|
||||
xt_event_check,
|
||||
xt_event_dispatch,
|
||||
g_free,
|
||||
(GSourceFunc)NULL,
|
||||
(GSourceDummyMarshal)NULL
|
||||
};
|
||||
|
||||
static gboolean
|
||||
xt_event_polling_timer_callback(gpointer user_data)
|
||||
{
|
||||
Display * display;
|
||||
XtAppContext ac;
|
||||
int eventsToProcess = 20;
|
||||
|
||||
display = (Display *)user_data;
|
||||
ac = XtDisplayToApplicationContext(display);
|
||||
|
||||
/* We need to process many Xt events here. If we just process
|
||||
one event we might starve one or more Xt consumers. On the other hand
|
||||
this could hang the whole app if Xt events come pouring in. So process
|
||||
up to 20 Xt events right now and save the rest for later. This is a hack,
|
||||
but it oughta work. We *really* should have out of process plugins.
|
||||
*/
|
||||
while (eventsToProcess-- && XtAppPending(ac))
|
||||
XtAppProcessEvent(ac, XtIMAll);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GtkType
|
||||
gtk_xtbin_get_type (void)
|
||||
{
|
||||
|
@ -208,11 +310,7 @@ gtk_xtbin_realize (GtkWidget *widget)
|
|||
|
||||
|
||||
GtkWidget*
|
||||
gtk_xtbin_new (GdkWindow *parent_window,
|
||||
Display *xtdisplay,
|
||||
Visual *xtvisual,
|
||||
Colormap xtcolormap,
|
||||
int xtdepth)
|
||||
gtk_xtbin_new (GdkWindow *parent_window, String * f)
|
||||
{
|
||||
GtkXtBin *xtbin;
|
||||
gpointer user_data;
|
||||
|
@ -223,13 +321,68 @@ gtk_xtbin_new (GdkWindow *parent_window,
|
|||
if (!xtbin)
|
||||
return (GtkWidget*)NULL;
|
||||
|
||||
if (f)
|
||||
fallback = f;
|
||||
|
||||
/* Initialize the Xt toolkit */
|
||||
xtbin->parent_window = parent_window;
|
||||
|
||||
xt_client_init(&(xtbin->xtclient), xtdisplay, xtvisual, xtcolormap, xtdepth);
|
||||
xt_client_init(&(xtbin->xtclient),
|
||||
GDK_VISUAL_XVISUAL(gdk_window_get_visual(parent_window )),
|
||||
GDK_COLORMAP_XCOLORMAP(gdk_window_get_colormap(parent_window)),
|
||||
gdk_window_get_visual(parent_window )->depth);
|
||||
|
||||
if (!xtbin->xtclient.xtdisplay) {
|
||||
/* If XtOpenDisplay failed, we can't go any further.
|
||||
* Bail out.
|
||||
*/
|
||||
#ifdef DEBUG_XTBIN
|
||||
printf("gtk_xtbin_init: XtOpenDisplay() returned NULL.\n");
|
||||
#endif
|
||||
g_free (xtbin);
|
||||
return (GtkWidget *)NULL;
|
||||
}
|
||||
|
||||
/* If this is the first running widget, hook this display into the
|
||||
mainloop */
|
||||
if (0 == num_widgets) {
|
||||
int cnumber;
|
||||
/*
|
||||
* hook Xt event loop into the glib event loop.
|
||||
*/
|
||||
|
||||
/* the assumption is that gtk_init has already been called */
|
||||
GSource* gs = g_source_new(&xt_event_funcs, sizeof(GSource));
|
||||
if (!gs) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_source_set_priority(gs, GDK_PRIORITY_EVENTS);
|
||||
g_source_set_can_recurse(gs, TRUE);
|
||||
tag = g_source_attach(gs, (GMainContext*)NULL);
|
||||
#ifdef VMS
|
||||
cnumber = XConnectionNumber(xtdisplay);
|
||||
#else
|
||||
cnumber = ConnectionNumber(xtdisplay);
|
||||
#endif
|
||||
xt_event_poll_fd.fd = cnumber;
|
||||
xt_event_poll_fd.events = G_IO_IN;
|
||||
xt_event_poll_fd.revents = 0; /* hmm... is this correct? */
|
||||
|
||||
g_main_context_add_poll ((GMainContext*)NULL,
|
||||
&xt_event_poll_fd,
|
||||
G_PRIORITY_LOW);
|
||||
/* add a timer so that we can poll and process Xt timers */
|
||||
xt_polling_timer_id =
|
||||
gtk_timeout_add(25,
|
||||
(GtkFunction)xt_event_polling_timer_callback,
|
||||
xtdisplay);
|
||||
}
|
||||
|
||||
/* Bump up our usage count */
|
||||
num_widgets++;
|
||||
|
||||
/* Build the hierachy */
|
||||
assert(xtbin->xtclient.xtdisplay != NULL);
|
||||
xtbin->xtdisplay = xtbin->xtclient.xtdisplay;
|
||||
gtk_widget_set_parent_window(GTK_WIDGET(xtbin), parent_window);
|
||||
gdk_window_get_user_data(xtbin->parent_window, &user_data);
|
||||
|
@ -321,6 +474,21 @@ gtk_xtbin_destroy (GtkObject *object)
|
|||
/* remove the event handler */
|
||||
xt_client_destroy(&(xtbin->xtclient));
|
||||
xtbin->xtwindow = 0;
|
||||
|
||||
num_widgets--; /* reduce our usage count */
|
||||
|
||||
/* If this is the last running widget, remove the Xt display
|
||||
connection from the mainloop */
|
||||
if (0 == num_widgets) {
|
||||
#ifdef DEBUG_XTBIN
|
||||
printf("removing the Xt connection from the main loop\n");
|
||||
#endif
|
||||
g_main_context_remove_poll((GMainContext*)NULL, &xt_event_poll_fd);
|
||||
g_source_remove(tag);
|
||||
|
||||
gtk_timeout_remove(xt_polling_timer_id);
|
||||
xt_polling_timer_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
GTK_OBJECT_CLASS(parent_class)->destroy(object);
|
||||
|
@ -333,13 +501,38 @@ gtk_xtbin_destroy (GtkObject *object)
|
|||
/* Initial Xt plugin */
|
||||
static void
|
||||
xt_client_init( XtClient * xtclient,
|
||||
Display *xtdisplay,
|
||||
Visual *xtvisual,
|
||||
Colormap xtcolormap,
|
||||
int xtdepth)
|
||||
{
|
||||
XtAppContext app_context;
|
||||
char *mArgv[1];
|
||||
int mArgc = 0;
|
||||
|
||||
/*
|
||||
* Initialize Xt stuff
|
||||
*/
|
||||
xtclient->top_widget = NULL;
|
||||
xtclient->child_widget = NULL;
|
||||
xtclient->xtdisplay = NULL;
|
||||
xtclient->xtvisual = NULL;
|
||||
xtclient->xtcolormap = 0;
|
||||
xtclient->xtdepth = 0;
|
||||
|
||||
if (!xt_is_initialized) {
|
||||
#ifdef DEBUG_XTBIN
|
||||
printf("starting up Xt stuff\n");
|
||||
#endif
|
||||
XtToolkitInitialize();
|
||||
app_context = XtCreateApplicationContext();
|
||||
if (fallback)
|
||||
XtAppSetFallbackResources(app_context, fallback);
|
||||
|
||||
xtdisplay = XtOpenDisplay(app_context, gdk_get_display(), NULL,
|
||||
"Wrapper", NULL, 0, &mArgc, mArgv);
|
||||
if (xtdisplay)
|
||||
xt_is_initialized = TRUE;
|
||||
}
|
||||
xtclient->xtdisplay = xtdisplay;
|
||||
xtclient->xtvisual = xtvisual;
|
||||
xtclient->xtcolormap = xtcolormap;
|
||||
|
@ -362,9 +555,7 @@ xt_client_create ( XtClient* xtclient ,
|
|||
#ifdef DEBUG_XTBIN
|
||||
printf("xt_client_create() \n");
|
||||
#endif
|
||||
String app_name, app_class;
|
||||
XtGetApplicationNameAndClass(xtclient->xtdisplay, &app_name, &app_class);
|
||||
top_widget = XtAppCreateShell("drawingArea", app_class,
|
||||
top_widget = XtAppCreateShell("drawingArea", "Wrapper",
|
||||
applicationShellWidgetClass,
|
||||
xtclient->xtdisplay,
|
||||
NULL, 0);
|
||||
|
@ -414,7 +605,6 @@ xt_client_create ( XtClient* xtclient ,
|
|||
xtclient->child_widget = child_widget;
|
||||
|
||||
/* set the event handler */
|
||||
#if 0
|
||||
XtAddEventHandler(child_widget,
|
||||
0x0FFFFF & ~ResizeRedirectMask,
|
||||
TRUE,
|
||||
|
@ -424,12 +614,6 @@ xt_client_create ( XtClient* xtclient ,
|
|||
TRUE,
|
||||
(XtEventHandler)xt_client_focus_listener,
|
||||
xtclient);
|
||||
#else
|
||||
XtAddEventHandler(child_widget,
|
||||
(SubstructureNotifyMask | ButtonReleaseMask),
|
||||
TRUE,
|
||||
(XtEventHandler)xt_client_event_handler, xtclient);
|
||||
#endif
|
||||
XSync(xtclient->xtdisplay, FALSE);
|
||||
}
|
||||
|
||||
|
@ -607,7 +791,7 @@ send_xembed_message (XtClient *xtclient,
|
|||
XSendEvent (dpy, w, False, NoEventMask, &xevent);
|
||||
XSync (dpy,False);
|
||||
|
||||
if((errorcode = untrap_errors())) {
|
||||
if((errorcode = untrap_error())) {
|
||||
#ifdef DEBUG_XTBIN
|
||||
printf("send_xembed_message error(%d)!!!\n",errorcode);
|
||||
#endif
|
||||
|
@ -629,7 +813,7 @@ trap_errors(void)
|
|||
}
|
||||
|
||||
static int
|
||||
untrap_errors(void)
|
||||
untrap_error(void)
|
||||
{
|
||||
XSetErrorHandler(old_error_handler);
|
||||
if(trapped_error_code) {
|
||||
|
@ -705,7 +889,7 @@ xt_add_focus_listener( Widget w, XtPointer user_data)
|
|||
TRUE,
|
||||
(XtEventHandler)xt_client_focus_listener,
|
||||
xtclient);
|
||||
untrap_errors();
|
||||
untrap_error();
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -717,7 +901,7 @@ xt_remove_focus_listener(Widget w, XtPointer user_data)
|
|||
XtRemoveEventHandler(w, SubstructureNotifyMask | ButtonReleaseMask, TRUE,
|
||||
(XtEventHandler)xt_client_focus_listener, user_data);
|
||||
|
||||
untrap_errors();
|
||||
untrap_error();
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -734,11 +918,11 @@ xt_add_focus_listener_tree ( Widget treeroot, XtPointer user_data)
|
|||
xt_add_focus_listener( treeroot, user_data);
|
||||
trap_errors();
|
||||
if(!XQueryTree(dpy, win, &root, &parent, &children, &nchildren)) {
|
||||
untrap_errors();
|
||||
untrap_error();
|
||||
return;
|
||||
}
|
||||
|
||||
if(untrap_errors())
|
||||
if(untrap_error())
|
||||
return;
|
||||
|
||||
for(i=0; i<nchildren; ++i) {
|
||||
|
@ -750,4 +934,3 @@ xt_add_focus_listener_tree ( Widget treeroot, XtPointer user_data)
|
|||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
163
src/gtk2xtbin.h
163
src/gtk2xtbin.h
|
@ -40,6 +40,169 @@
|
|||
#ifndef __GTK_XTBIN_H__
|
||||
#define __GTK_XTBIN_H__
|
||||
|
||||
#ifdef BUILD_VIEWER
|
||||
#include <gtk/gtk.h>
|
||||
#else
|
||||
#include <gtk/gtksocket.h>
|
||||
#endif
|
||||
#include <X11/Intrinsic.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Xlib.h>
|
||||
#ifdef MOZILLA_CLIENT
|
||||
#include "nscore.h"
|
||||
#ifdef _IMPL_GTKXTBIN_API
|
||||
#define GTKXTBIN_API(type) NS_EXPORT_(type)
|
||||
#else
|
||||
#define GTKXTBIN_API(type) NS_IMPORT_(type)
|
||||
#endif
|
||||
#else
|
||||
#define GTKXTBIN_API(type) type
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct _GtkXtBin GtkXtBin;
|
||||
typedef struct _GtkXtBinClass GtkXtBinClass;
|
||||
|
||||
#define GTK_TYPE_XTBIN (gtk_xtbin_get_type ())
|
||||
#define GTK_XTBIN(obj) (GTK_CHECK_CAST ((obj), \
|
||||
GTK_TYPE_XTBIN, GtkXtBin))
|
||||
#define GTK_XTBIN_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), \
|
||||
GTK_TYPE_XTBIN, GtkXtBinClass))
|
||||
#define GTK_IS_XTBIN(obj) (GTK_CHECK_TYPE ((obj), \
|
||||
GTK_TYPE_XTBIN))
|
||||
#define GTK_IS_XTBIN_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), \
|
||||
GTK_TYPE_XTBIN))
|
||||
typedef struct _XtClient XtClient;
|
||||
|
||||
struct _XtClient {
|
||||
Display *xtdisplay;
|
||||
Widget top_widget; /* The toplevel widget */
|
||||
Widget child_widget; /* The embedded widget */
|
||||
Visual *xtvisual;
|
||||
int xtdepth;
|
||||
Colormap xtcolormap;
|
||||
Window oldwindow;
|
||||
};
|
||||
|
||||
struct _GtkXtBin
|
||||
{
|
||||
GtkSocket gsocket;
|
||||
GdkWindow *parent_window;
|
||||
Display *xtdisplay; /* Xt Toolkit Display */
|
||||
|
||||
Window xtwindow; /* Xt Toolkit XWindow */
|
||||
gint x, y;
|
||||
gint width, height;
|
||||
XtClient xtclient; /* Xt Client for XEmbed */
|
||||
};
|
||||
|
||||
struct _GtkXtBinClass
|
||||
{
|
||||
GtkSocketClass widget_class;
|
||||
};
|
||||
|
||||
GTKXTBIN_API(GtkType) gtk_xtbin_get_type (void);
|
||||
GTKXTBIN_API(GtkWidget *) gtk_xtbin_new (GdkWindow *parent_window, String *f);
|
||||
GTKXTBIN_API(void) gtk_xtbin_set_position (GtkXtBin *xtbin,
|
||||
gint x,
|
||||
gint y);
|
||||
GTKXTBIN_API(void) gtk_xtbin_resize (GtkWidget *widget,
|
||||
gint width,
|
||||
gint height);
|
||||
|
||||
typedef struct _XtTMRec {
|
||||
XtTranslations translations; /* private to Translation Manager */
|
||||
XtBoundActions proc_table; /* procedure bindings for actions */
|
||||
struct _XtStateRec *current_state; /* Translation Manager state ptr */
|
||||
unsigned long lastEventTime;
|
||||
} XtTMRec, *XtTM;
|
||||
|
||||
typedef struct _CorePart {
|
||||
Widget self; /* pointer to widget itself */
|
||||
WidgetClass widget_class; /* pointer to Widget's ClassRec */
|
||||
Widget parent; /* parent widget */
|
||||
XrmName xrm_name; /* widget resource name quarkified */
|
||||
Boolean being_destroyed; /* marked for destroy */
|
||||
XtCallbackList destroy_callbacks; /* who to call when widget destroyed */
|
||||
XtPointer constraints; /* constraint record */
|
||||
Position x, y; /* window position */
|
||||
Dimension width, height; /* window dimensions */
|
||||
Dimension border_width; /* window border width */
|
||||
Boolean managed; /* is widget geometry managed? */
|
||||
Boolean sensitive; /* is widget sensitive to user events*/
|
||||
Boolean ancestor_sensitive; /* are all ancestors sensitive? */
|
||||
XtEventTable event_table; /* private to event dispatcher */
|
||||
XtTMRec tm; /* translation management */
|
||||
XtTranslations accelerators; /* accelerator translations */
|
||||
Pixel border_pixel; /* window border pixel */
|
||||
Pixmap border_pixmap; /* window border pixmap or NULL */
|
||||
WidgetList popup_list; /* list of popups */
|
||||
Cardinal num_popups; /* how many popups */
|
||||
String name; /* widget resource name */
|
||||
Screen *screen; /* window's screen */
|
||||
Colormap colormap; /* colormap */
|
||||
Window window; /* window ID */
|
||||
Cardinal depth; /* number of planes in window */
|
||||
Pixel background_pixel; /* window background pixel */
|
||||
Pixmap background_pixmap; /* window background pixmap or NULL */
|
||||
Boolean visible; /* is window mapped and not occluded?*/
|
||||
Boolean mapped_when_managed;/* map window if it's managed? */
|
||||
} CorePart;
|
||||
|
||||
typedef struct _WidgetRec {
|
||||
CorePart core;
|
||||
} WidgetRec, CoreRec;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __GTK_XTBIN_H__ */
|
||||
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim:expandtab:shiftwidth=2:tabstop=2: */
|
||||
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is the Gtk2XtBin Widget Implementation.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Sun Microsystems, Inc.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef __GTK_XTBIN_H__
|
||||
#define __GTK_XTBIN_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <X11/Intrinsic.h>
|
||||
#include <X11/Xutil.h>
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* This is a simple hacky library that disables the SHM-MIT and XVideo extenstions on any X application requesting
|
||||
* it. To compile this run
|
||||
*
|
||||
* gcc -shared -ldl -o noshm.so noshm.c
|
||||
*
|
||||
* Author: Alexander Graf
|
||||
* SuSE Linux Products GmbH
|
||||
*
|
||||
* License: Public Domain
|
||||
*
|
||||
*/
|
||||
|
||||
int (*real_XQueryExtension)(register void *dpy,const char *name,int *major_opcode,int *first_event,int *first_error) = NULL;
|
||||
void *RTLD_NEXT = (void*)-1l;
|
||||
void *dlsym(void *handle, const char *symbol);
|
||||
|
||||
int
|
||||
XQueryExtension(
|
||||
register void *dpy,
|
||||
const char *name,
|
||||
int *major_opcode,
|
||||
int *first_event,
|
||||
int *first_error)
|
||||
{
|
||||
if(!strcmp(name, "MIT-SHM")) return 0;
|
||||
if(!strcmp(name, "XVideo")) return 0;
|
||||
if(!real_XQueryExtension) {
|
||||
real_XQueryExtension = dlsym(RTLD_NEXT, "XQueryExtension");
|
||||
}
|
||||
return real_XQueryExtension(dpy, name, major_opcode, first_event, first_error);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
577
src/npw-rpc.c
577
src/npw-rpc.c
|
@ -47,8 +47,12 @@ int rpc_type_of_NPNVariable(int variable)
|
|||
case NPNVasdEnabledBool:
|
||||
case NPNVisOfflineBool:
|
||||
case NPNVSupportsXEmbedBool:
|
||||
case NPNVSupportsWindowless:
|
||||
type = RPC_TYPE_BOOLEAN;
|
||||
break;
|
||||
case NPNVnetscapeWindow:
|
||||
type = RPC_TYPE_UINT32;
|
||||
break;
|
||||
case NPNVWindowNPObject:
|
||||
case NPNVPluginElementNPObject:
|
||||
type = RPC_TYPE_NP_OBJECT;
|
||||
|
@ -69,13 +73,15 @@ int rpc_type_of_NPPVariable(int variable)
|
|||
case NPPVformValue: // byte values of 0 does not appear in the UTF-8 encoding but for U+0000
|
||||
type = RPC_TYPE_STRING;
|
||||
break;
|
||||
case NPPVpluginWindowBool:
|
||||
case NPPVpluginTransparentBool:
|
||||
case NPPVpluginWindowSize:
|
||||
case NPPVpluginTimerInterval:
|
||||
type = RPC_TYPE_INT32;
|
||||
break;
|
||||
case NPPVpluginNeedsXEmbed:
|
||||
case NPPVpluginWindowBool:
|
||||
case NPPVpluginTransparentBool:
|
||||
case NPPVjavascriptPushCallerBool:
|
||||
case NPPVpluginKeepLibraryInMemory:
|
||||
type = RPC_TYPE_BOOLEAN;
|
||||
break;
|
||||
case NPPVpluginScriptableNPObject:
|
||||
|
@ -365,6 +371,71 @@ static int do_recv_NPRect(rpc_message_t *message, void *p_value)
|
|||
* Process NPWindow objects
|
||||
*/
|
||||
|
||||
static int do_send_NPSetWindowCallbackStruct(rpc_message_t *message, void *p_value)
|
||||
{
|
||||
NPSetWindowCallbackStruct *ws_info = (NPSetWindowCallbackStruct *)p_value;
|
||||
int error;
|
||||
|
||||
if (ws_info) {
|
||||
if ((error = rpc_message_send_uint32(message, 1)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_int32(message, ws_info->type)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_uint32(message, XVisualIDFromVisual(ws_info->visual))) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_uint32(message, ws_info->colormap)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_uint32(message, ws_info->depth)) < 0)
|
||||
return error;
|
||||
}
|
||||
else {
|
||||
if ((error = rpc_message_send_uint32(message, 0)) < 0)
|
||||
return error;
|
||||
}
|
||||
|
||||
return RPC_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
static int do_recv_NPSetWindowCallbackStruct(rpc_message_t *message, void *p_value)
|
||||
{
|
||||
NPSetWindowCallbackStruct **ws_info_p = (NPSetWindowCallbackStruct **)p_value;
|
||||
NPSetWindowCallbackStruct *ws_info;
|
||||
int32_t type;
|
||||
uint32_t has_ws_info, visual_id, colormap, depth;
|
||||
int error;
|
||||
|
||||
if (ws_info_p)
|
||||
*ws_info_p = NULL;
|
||||
|
||||
if ((error = rpc_message_recv_uint32(message, &has_ws_info)) < 0)
|
||||
return error;
|
||||
|
||||
if (has_ws_info) {
|
||||
if ((error = rpc_message_recv_int32(message, &type)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_uint32(message, &visual_id)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_uint32(message, &colormap)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_uint32(message, &depth)) < 0)
|
||||
return error;
|
||||
|
||||
if (ws_info_p) {
|
||||
if ((ws_info = calloc(1, sizeof(*ws_info))) == NULL)
|
||||
return RPC_ERROR_NO_MEMORY;
|
||||
ws_info->type = type;
|
||||
// display shall be filled in by the plugin
|
||||
// visual shall be reconstructed by the plugin based on the visualID
|
||||
ws_info->visual = (void *)(uintptr_t)visual_id;
|
||||
ws_info->colormap = colormap;
|
||||
ws_info->depth = depth;
|
||||
*ws_info_p = ws_info;
|
||||
}
|
||||
}
|
||||
|
||||
return RPC_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
static int do_send_NPWindowData(rpc_message_t *message, void *p_value)
|
||||
{
|
||||
NPWindow *window = (NPWindow *)p_value;
|
||||
|
@ -387,6 +458,8 @@ static int do_send_NPWindowData(rpc_message_t *message, void *p_value)
|
|||
return error;
|
||||
if ((error = rpc_message_send_int32(message, window->type)) < 0)
|
||||
return error;
|
||||
if ((error = do_send_NPSetWindowCallbackStruct(message, window->ws_info)) < 0)
|
||||
return 0;
|
||||
|
||||
return RPC_ERROR_NO_ERROR;
|
||||
}
|
||||
|
@ -394,6 +467,7 @@ static int do_send_NPWindowData(rpc_message_t *message, void *p_value)
|
|||
static int do_recv_NPWindowData(rpc_message_t *message, void *p_value)
|
||||
{
|
||||
NPWindow *window = (NPWindow *)p_value;
|
||||
NPSetWindowCallbackStruct *ws_info;
|
||||
uint32_t window_id;
|
||||
int32_t window_type;
|
||||
int error;
|
||||
|
@ -415,9 +489,11 @@ static int do_recv_NPWindowData(rpc_message_t *message, void *p_value)
|
|||
return error;
|
||||
if ((error = rpc_message_recv_int32(message, &window_type)) < 0)
|
||||
return error;
|
||||
if ((error = do_recv_NPSetWindowCallbackStruct(message, &ws_info)) < 0)
|
||||
return error;
|
||||
window->type = window_type;
|
||||
window->ws_info = NULL; // to be filled in by the plugin
|
||||
window->window = (void *)(Window)window_id;
|
||||
window->ws_info = ws_info;
|
||||
|
||||
return RPC_ERROR_NO_ERROR;
|
||||
}
|
||||
|
@ -467,6 +543,487 @@ static int do_recv_NPWindow(rpc_message_t *message, void *p_value)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* Process NPEvent objects
|
||||
*/
|
||||
|
||||
// XXX: those are not real XEvent generated by the X server, i.e. some
|
||||
// fields can be optimized out, which is what Firefox does
|
||||
static bool is_valid_NPEvent_type(NPEvent *event)
|
||||
{
|
||||
switch (event->type) {
|
||||
case GraphicsExpose:
|
||||
case FocusIn:
|
||||
case FocusOut:
|
||||
case EnterNotify:
|
||||
case LeaveNotify:
|
||||
case MotionNotify:
|
||||
case ButtonPress:
|
||||
case ButtonRelease:
|
||||
case KeyPress:
|
||||
case KeyRelease:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int do_send_XAnyEvent(rpc_message_t *message, XEvent *xevent)
|
||||
{
|
||||
int error;
|
||||
if ((error = rpc_message_send_uint32(message, xevent->xany.serial)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_uint32(message, xevent->xany.send_event)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_uint32(message, xevent->xany.window)) < 0)
|
||||
return error;
|
||||
return RPC_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
static int do_send_XGraphicsExposeEvent(rpc_message_t *message, XEvent *xevent)
|
||||
{
|
||||
int error;
|
||||
if ((error = do_send_XAnyEvent(message, xevent)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_int32(message, xevent->xgraphicsexpose.x)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_int32(message, xevent->xgraphicsexpose.y)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_uint32(message, xevent->xgraphicsexpose.width)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_uint32(message, xevent->xgraphicsexpose.height)) < 0)
|
||||
return error;
|
||||
return RPC_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
static int do_send_XFocusChangeEvent(rpc_message_t *message, XEvent *xevent)
|
||||
{
|
||||
return RPC_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
static int do_send_XCrossingEvent(rpc_message_t *message, XEvent *xevent)
|
||||
{
|
||||
int error;
|
||||
if ((error = do_send_XAnyEvent(message, xevent)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_uint32(message, xevent->xcrossing.root)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_uint32(message, xevent->xcrossing.subwindow)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_uint32(message, xevent->xcrossing.time)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_int32(message, xevent->xcrossing.x)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_int32(message, xevent->xcrossing.y)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_int32(message, xevent->xcrossing.x_root)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_int32(message, xevent->xcrossing.y_root)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_int32(message, xevent->xcrossing.mode)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_int32(message, xevent->xcrossing.detail)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_int32(message, xevent->xcrossing.same_screen)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_int32(message, xevent->xcrossing.focus)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_uint32(message, xevent->xcrossing.state)) < 0)
|
||||
return error;
|
||||
return RPC_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
static int do_send_XMotionEvent(rpc_message_t *message, XEvent *xevent)
|
||||
{
|
||||
int error;
|
||||
if ((error = do_send_XAnyEvent(message, xevent)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_uint32(message, xevent->xmotion.root)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_uint32(message, xevent->xmotion.subwindow)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_uint32(message, xevent->xmotion.time)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_int32(message, xevent->xmotion.x)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_int32(message, xevent->xmotion.y)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_int32(message, xevent->xmotion.x_root)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_int32(message, xevent->xmotion.y_root)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_uint32(message, xevent->xmotion.state)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_char(message, xevent->xmotion.is_hint)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_int32(message, xevent->xmotion.same_screen)) < 0)
|
||||
return error;
|
||||
return RPC_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
static int do_send_XButtonEvent(rpc_message_t *message, XEvent *xevent)
|
||||
{
|
||||
int error;
|
||||
if ((error = do_send_XAnyEvent(message, xevent)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_uint32(message, xevent->xbutton.root)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_uint32(message, xevent->xbutton.subwindow)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_uint32(message, xevent->xbutton.time)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_int32(message, xevent->xbutton.x)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_int32(message, xevent->xbutton.y)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_int32(message, xevent->xbutton.x_root)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_int32(message, xevent->xbutton.y_root)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_uint32(message, xevent->xbutton.state)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_uint32(message, xevent->xbutton.button)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_int32(message, xevent->xbutton.same_screen)) < 0)
|
||||
return error;
|
||||
return RPC_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
static int do_send_XKeyEvent(rpc_message_t *message, XEvent *xevent)
|
||||
{
|
||||
int error;
|
||||
if ((error = do_send_XAnyEvent(message, xevent)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_uint32(message, xevent->xkey.root)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_uint32(message, xevent->xkey.subwindow)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_uint32(message, xevent->xkey.time)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_int32(message, xevent->xkey.x)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_int32(message, xevent->xkey.y)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_int32(message, xevent->xkey.x_root)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_int32(message, xevent->xkey.y_root)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_uint32(message, xevent->xkey.state)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_uint32(message, xevent->xkey.keycode)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_send_int32(message, xevent->xkey.same_screen)) < 0)
|
||||
return error;
|
||||
return RPC_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
static int do_send_NPEvent(rpc_message_t *message, void *p_value)
|
||||
{
|
||||
NPEvent *event = (NPEvent *)p_value;
|
||||
int error;
|
||||
|
||||
if (event == NULL || !is_valid_NPEvent_type(event))
|
||||
return RPC_ERROR_MESSAGE_ARGUMENT_INVALID;
|
||||
|
||||
if ((error = rpc_message_send_int32(message, event->type)) < 0)
|
||||
return error;
|
||||
|
||||
switch (event->type) {
|
||||
case GraphicsExpose:
|
||||
if ((error = do_send_XGraphicsExposeEvent(message, event)) < 0)
|
||||
return error;
|
||||
break;
|
||||
case FocusIn:
|
||||
case FocusOut:
|
||||
if ((error = do_send_XFocusChangeEvent(message, event)) < 0)
|
||||
return error;
|
||||
break;
|
||||
case EnterNotify:
|
||||
case LeaveNotify:
|
||||
if ((error = do_send_XCrossingEvent(message, event)) < 0)
|
||||
return error;
|
||||
break;
|
||||
case MotionNotify:
|
||||
if ((error = do_send_XMotionEvent(message, event)) < 0)
|
||||
return error;
|
||||
break;
|
||||
case ButtonPress:
|
||||
case ButtonRelease:
|
||||
if ((error = do_send_XButtonEvent(message, event)) < 0)
|
||||
return error;
|
||||
break;
|
||||
case KeyPress:
|
||||
case KeyRelease:
|
||||
if ((error = do_send_XKeyEvent(message, event)) < 0)
|
||||
return error;
|
||||
break;
|
||||
default:
|
||||
return RPC_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
return RPC_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
static int do_recv_XAnyEvent(rpc_message_t *message, XEvent *xevent)
|
||||
{
|
||||
uint32_t serial, send_event, window;
|
||||
int error;
|
||||
if ((error = rpc_message_recv_uint32(message, &serial)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_uint32(message, &send_event)) < 0)
|
||||
return error;
|
||||
// display shall be filled in by the plugin
|
||||
if ((error = rpc_message_recv_uint32(message, &window)) < 0)
|
||||
return error;
|
||||
xevent->xany.serial = serial;
|
||||
xevent->xany.send_event = send_event;
|
||||
xevent->xany.window = window;
|
||||
return RPC_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
static int do_recv_XGraphicsExposeEvent(rpc_message_t *message, XEvent *xevent)
|
||||
{
|
||||
int32_t x, y;
|
||||
uint32_t width, height;
|
||||
int error;
|
||||
if ((error = do_recv_XAnyEvent(message, xevent)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_int32(message, &x)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_int32(message, &y)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_uint32(message, &width)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_uint32(message, &height)) < 0)
|
||||
return error;
|
||||
xevent->xgraphicsexpose.x = x;
|
||||
xevent->xgraphicsexpose.y = y;
|
||||
xevent->xgraphicsexpose.width = width;
|
||||
xevent->xgraphicsexpose.height = height;
|
||||
return RPC_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
static int do_recv_XFocusChangeEvent(rpc_message_t *message, XEvent *xevent)
|
||||
{
|
||||
return RPC_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
static int do_recv_XCrossingEvent(rpc_message_t *message, XEvent *xevent)
|
||||
{
|
||||
int32_t x, y, x_root, y_root, mode, detail, same_screen, focus;
|
||||
uint32_t root, subwindow, time, state;
|
||||
int error;
|
||||
if ((error = do_recv_XAnyEvent(message, xevent)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_uint32(message, &root)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_uint32(message, &subwindow)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_uint32(message, &time)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_int32(message, &x)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_int32(message, &y)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_int32(message, &x_root)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_int32(message, &y_root)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_int32(message, &mode)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_int32(message, &detail)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_int32(message, &same_screen)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_int32(message, &focus)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_uint32(message, &state)) < 0)
|
||||
return error;
|
||||
xevent->xcrossing.root = root;
|
||||
xevent->xcrossing.subwindow = subwindow;
|
||||
xevent->xcrossing.time = time;
|
||||
xevent->xcrossing.x = x;
|
||||
xevent->xcrossing.y = y;
|
||||
xevent->xcrossing.x_root = x_root;
|
||||
xevent->xcrossing.y_root = y_root;
|
||||
xevent->xcrossing.mode = mode;
|
||||
xevent->xcrossing.detail = detail;
|
||||
xevent->xcrossing.same_screen = same_screen;
|
||||
xevent->xcrossing.focus = focus;
|
||||
xevent->xcrossing.state = state;
|
||||
return RPC_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
static int do_recv_XMotionEvent(rpc_message_t *message, XEvent *xevent)
|
||||
{
|
||||
char is_hint;
|
||||
int32_t x, y, x_root, y_root, same_screen;
|
||||
uint32_t root, subwindow, time, state;
|
||||
int error;
|
||||
if ((error = do_recv_XAnyEvent(message, xevent)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_uint32(message, &root)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_uint32(message, &subwindow)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_uint32(message, &time)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_int32(message, &x)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_int32(message, &y)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_int32(message, &x_root)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_int32(message, &y_root)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_uint32(message, &state)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_char(message, &is_hint)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_int32(message, &same_screen)) < 0)
|
||||
return error;
|
||||
xevent->xmotion.root = root;
|
||||
xevent->xmotion.subwindow = subwindow;
|
||||
xevent->xmotion.time = time;
|
||||
xevent->xmotion.x = x;
|
||||
xevent->xmotion.y = y;
|
||||
xevent->xmotion.x_root = x_root;
|
||||
xevent->xmotion.y_root = y_root;
|
||||
xevent->xmotion.state = state;
|
||||
xevent->xmotion.is_hint = is_hint;
|
||||
xevent->xmotion.same_screen = same_screen;
|
||||
return RPC_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
static int do_recv_XButtonEvent(rpc_message_t *message, XEvent *xevent)
|
||||
{
|
||||
int32_t x, y, x_root, y_root, same_screen;
|
||||
uint32_t root, subwindow, time, state, button;
|
||||
int error;
|
||||
if ((error = do_recv_XAnyEvent(message, xevent)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_uint32(message, &root)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_uint32(message, &subwindow)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_uint32(message, &time)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_int32(message, &x)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_int32(message, &y)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_int32(message, &x_root)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_int32(message, &y_root)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_uint32(message, &state)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_uint32(message, &button)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_int32(message, &same_screen)) < 0)
|
||||
return error;
|
||||
xevent->xbutton.root = root;
|
||||
xevent->xbutton.subwindow = subwindow;
|
||||
xevent->xbutton.time = time;
|
||||
xevent->xbutton.x = x;
|
||||
xevent->xbutton.y = y;
|
||||
xevent->xbutton.x_root = x_root;
|
||||
xevent->xbutton.y_root = y_root;
|
||||
xevent->xbutton.state = state;
|
||||
xevent->xbutton.button = button;
|
||||
xevent->xbutton.same_screen = same_screen;
|
||||
return RPC_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
static int do_recv_XKeyEvent(rpc_message_t *message, XEvent *xevent)
|
||||
{
|
||||
int32_t x, y, x_root, y_root, same_screen;
|
||||
uint32_t root, subwindow, time, state, keycode;
|
||||
int error;
|
||||
if ((error = do_recv_XAnyEvent(message, xevent)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_uint32(message, &root)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_uint32(message, &subwindow)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_uint32(message, &time)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_int32(message, &x)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_int32(message, &y)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_int32(message, &x_root)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_int32(message, &y_root)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_uint32(message, &state)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_uint32(message, &keycode)) < 0)
|
||||
return error;
|
||||
if ((error = rpc_message_recv_int32(message, &same_screen)) < 0)
|
||||
return error;
|
||||
xevent->xkey.root = root;
|
||||
xevent->xkey.subwindow = subwindow;
|
||||
xevent->xkey.time = time;
|
||||
xevent->xkey.x = x;
|
||||
xevent->xkey.y = y;
|
||||
xevent->xkey.x_root = x_root;
|
||||
xevent->xkey.y_root = y_root;
|
||||
xevent->xkey.state = state;
|
||||
xevent->xkey.keycode = keycode;
|
||||
xevent->xkey.same_screen = same_screen;
|
||||
return RPC_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
static int do_recv_NPEvent(rpc_message_t *message, void *p_value)
|
||||
{
|
||||
NPEvent *event = (NPEvent *)p_value;
|
||||
int32_t event_type;
|
||||
int error;
|
||||
|
||||
if ((error = rpc_message_recv_int32(message, &event_type)) < 0)
|
||||
return error;
|
||||
memset(event, 0, sizeof(*event));
|
||||
event->type = event_type;
|
||||
|
||||
switch (event->type) {
|
||||
case GraphicsExpose:
|
||||
if ((error = do_recv_XGraphicsExposeEvent(message, event)) < 0)
|
||||
return error;
|
||||
break;
|
||||
case FocusIn:
|
||||
case FocusOut:
|
||||
if ((error = do_recv_XFocusChangeEvent(message, event)) < 0)
|
||||
return error;
|
||||
break;
|
||||
case EnterNotify:
|
||||
case LeaveNotify:
|
||||
if ((error = do_recv_XCrossingEvent(message, event)) < 0)
|
||||
return error;
|
||||
break;
|
||||
case MotionNotify:
|
||||
if ((error = do_recv_XMotionEvent(message, event)) < 0)
|
||||
return error;
|
||||
break;
|
||||
case ButtonPress:
|
||||
case ButtonRelease:
|
||||
if ((error = do_recv_XButtonEvent(message, event)) < 0)
|
||||
return error;
|
||||
break;
|
||||
case KeyPress:
|
||||
case KeyRelease:
|
||||
if ((error = do_recv_XKeyEvent(message, event)) < 0)
|
||||
return error;
|
||||
break;
|
||||
default:
|
||||
return RPC_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
return RPC_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Process NPFullPrint objects
|
||||
*/
|
||||
|
@ -781,7 +1338,7 @@ static int do_send_NPVariant(rpc_message_t *message, void *p_value)
|
|||
return error;
|
||||
break;
|
||||
case NPVariantType_Int32:
|
||||
if ((error = rpc_message_send_uint32(message, variant->value.intValue)) < 0)
|
||||
if ((error = rpc_message_send_int32(message, variant->value.intValue)) < 0)
|
||||
return error;
|
||||
break;
|
||||
case NPVariantType_Double:
|
||||
|
@ -829,7 +1386,7 @@ static int do_recv_NPVariant(rpc_message_t *message, void *p_value)
|
|||
break;
|
||||
}
|
||||
case NPVariantType_Int32:
|
||||
if ((error = rpc_message_recv_uint32(message, &result.value.intValue)) < 0)
|
||||
if ((error = rpc_message_recv_int32(message, &result.value.intValue)) < 0)
|
||||
return error;
|
||||
break;
|
||||
case NPVariantType_Double:
|
||||
|
@ -902,6 +1459,12 @@ static const rpc_message_descriptor_t message_descs[] = {
|
|||
do_send_NPWindow,
|
||||
do_recv_NPWindow
|
||||
},
|
||||
{
|
||||
RPC_TYPE_NP_EVENT,
|
||||
sizeof(NPEvent),
|
||||
do_send_NPEvent,
|
||||
do_recv_NPEvent
|
||||
},
|
||||
{
|
||||
RPC_TYPE_NP_PRINT,
|
||||
sizeof(NPPrint),
|
||||
|
@ -952,7 +1515,7 @@ static const rpc_message_descriptor_t message_descs[] = {
|
|||
}
|
||||
};
|
||||
|
||||
int rpc_add_np_marshalers(void)
|
||||
int rpc_add_np_marshalers(rpc_connection_t *connection)
|
||||
{
|
||||
return rpc_message_add_callbacks(message_descs, sizeof(message_descs) / sizeof(message_descs[0]));
|
||||
return rpc_connection_add_message_descriptors(connection, message_descs, sizeof(message_descs) / sizeof(message_descs[0]));
|
||||
}
|
||||
|
|
|
@ -21,65 +21,77 @@
|
|||
#ifndef NPW_RPC_H
|
||||
#define NPW_RPC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// NPAPI methods
|
||||
enum {
|
||||
RPC_METHOD_NP_GET_VALUE = 1,
|
||||
RPC_METHOD_NP_GET_VALUE = 1, /* 1 */
|
||||
RPC_METHOD_NP_GET_MIME_DESCRIPTION,
|
||||
RPC_METHOD_NP_INITIALIZE,
|
||||
RPC_METHOD_NP_SHUTDOWN,
|
||||
|
||||
RPC_METHOD_NPN_USER_AGENT,
|
||||
RPC_METHOD_NPN_USER_AGENT, /* 5 */
|
||||
RPC_METHOD_NPN_GET_VALUE,
|
||||
RPC_METHOD_NPN_SET_VALUE,
|
||||
RPC_METHOD_NPN_GET_URL,
|
||||
RPC_METHOD_NPN_GET_URL_NOTIFY,
|
||||
RPC_METHOD_NPN_POST_URL,
|
||||
RPC_METHOD_NPN_POST_URL, /* 10 */
|
||||
RPC_METHOD_NPN_POST_URL_NOTIFY,
|
||||
RPC_METHOD_NPN_STATUS,
|
||||
RPC_METHOD_NPN_PRINT_DATA,
|
||||
RPC_METHOD_NPN_REQUEST_READ,
|
||||
RPC_METHOD_NPN_NEW_STREAM,
|
||||
RPC_METHOD_NPN_NEW_STREAM, /* 15 */
|
||||
RPC_METHOD_NPN_DESTROY_STREAM,
|
||||
RPC_METHOD_NPN_WRITE,
|
||||
RPC_METHOD_NPN_PUSH_POPUPS_ENABLED_STATE,
|
||||
RPC_METHOD_NPN_POP_POPUPS_ENABLED_STATE,
|
||||
RPC_METHOD_NPN_FORCE_REDRAW, /* 20 */
|
||||
RPC_METHOD_NPN_INVALIDATE_RECT,
|
||||
RPC_METHOD_NPN_INVALIDATE_REGION,
|
||||
|
||||
RPC_METHOD_NPP_NEW,
|
||||
RPC_METHOD_NPP_DESTROY,
|
||||
RPC_METHOD_NPP_SET_WINDOW,
|
||||
RPC_METHOD_NPP_SET_WINDOW, /* 25 */
|
||||
RPC_METHOD_NPP_HANDLE_EVENT,
|
||||
RPC_METHOD_NPP_GET_VALUE,
|
||||
RPC_METHOD_NPP_SET_VALUE,
|
||||
RPC_METHOD_NPP_URL_NOTIFY,
|
||||
RPC_METHOD_NPP_NEW_STREAM,
|
||||
RPC_METHOD_NPP_NEW_STREAM, /* 30 */
|
||||
RPC_METHOD_NPP_DESTROY_STREAM,
|
||||
RPC_METHOD_NPP_WRITE_READY,
|
||||
RPC_METHOD_NPP_WRITE,
|
||||
RPC_METHOD_NPP_STREAM_AS_FILE,
|
||||
RPC_METHOD_NPP_PRINT,
|
||||
RPC_METHOD_NPP_PRINT, /* 35 */
|
||||
|
||||
RPC_METHOD_NPN_CREATE_OBJECT,
|
||||
RPC_METHOD_NPN_RETAIN_OBJECT,
|
||||
RPC_METHOD_NPN_RELEASE_OBJECT,
|
||||
RPC_METHOD_NPN_INVOKE,
|
||||
RPC_METHOD_NPN_INVOKE_DEFAULT,
|
||||
RPC_METHOD_NPN_INVOKE_DEFAULT, /* 40 */
|
||||
RPC_METHOD_NPN_EVALUATE,
|
||||
RPC_METHOD_NPN_GET_PROPERTY,
|
||||
RPC_METHOD_NPN_SET_PROPERTY,
|
||||
RPC_METHOD_NPN_REMOVE_PROPERTY,
|
||||
RPC_METHOD_NPN_HAS_PROPERTY,
|
||||
RPC_METHOD_NPN_HAS_PROPERTY, /* 45 */
|
||||
RPC_METHOD_NPN_HAS_METHOD,
|
||||
RPC_METHOD_NPN_SET_EXCEPTION,
|
||||
RPC_METHOD_NPN_ENUMERATE,
|
||||
RPC_METHOD_NPN_CONSTRUCT,
|
||||
|
||||
RPC_METHOD_NPN_GET_STRING_IDENTIFIER,
|
||||
RPC_METHOD_NPN_GET_STRING_IDENTIFIER, /* 50 */
|
||||
RPC_METHOD_NPN_GET_STRING_IDENTIFIERS,
|
||||
RPC_METHOD_NPN_GET_INT_IDENTIFIER,
|
||||
RPC_METHOD_NPN_IDENTIFIER_IS_STRING,
|
||||
RPC_METHOD_NPN_UTF8_FROM_IDENTIFIER,
|
||||
RPC_METHOD_NPN_INT_FROM_IDENTIFIER,
|
||||
RPC_METHOD_NPN_INT_FROM_IDENTIFIER, /* 55 */
|
||||
|
||||
RPC_METHOD_NPCLASS_INVALIDATE,
|
||||
RPC_METHOD_NPCLASS_HAS_METHOD,
|
||||
RPC_METHOD_NPCLASS_INVOKE,
|
||||
RPC_METHOD_NPCLASS_INVOKE_DEFAULT,
|
||||
RPC_METHOD_NPCLASS_HAS_PROPERTY,
|
||||
RPC_METHOD_NPCLASS_HAS_PROPERTY, /* 60 */
|
||||
RPC_METHOD_NPCLASS_GET_PROPERTY,
|
||||
RPC_METHOD_NPCLASS_SET_PROPERTY,
|
||||
RPC_METHOD_NPCLASS_REMOVE_PROPERTY,
|
||||
|
@ -87,20 +99,21 @@ enum {
|
|||
|
||||
// NPAPI data types
|
||||
enum {
|
||||
RPC_TYPE_NPP = 1,
|
||||
RPC_TYPE_NPP = 1, /* 1 */
|
||||
RPC_TYPE_NP_STREAM,
|
||||
RPC_TYPE_NP_BYTE_RANGE,
|
||||
RPC_TYPE_NP_SAVED_DATA,
|
||||
RPC_TYPE_NP_NOTIFY_DATA,
|
||||
RPC_TYPE_NP_NOTIFY_DATA, /* 5 */
|
||||
RPC_TYPE_NP_RECT,
|
||||
RPC_TYPE_NP_WINDOW,
|
||||
RPC_TYPE_NP_EVENT,
|
||||
RPC_TYPE_NP_PRINT,
|
||||
RPC_TYPE_NP_FULL_PRINT,
|
||||
RPC_TYPE_NP_FULL_PRINT, /* 10 */
|
||||
RPC_TYPE_NP_EMBED_PRINT,
|
||||
RPC_TYPE_NP_PRINT_DATA,
|
||||
RPC_TYPE_NP_OBJECT,
|
||||
RPC_TYPE_NP_IDENTIFIER,
|
||||
RPC_TYPE_NP_STRING,
|
||||
RPC_TYPE_NP_STRING, /* 15 */
|
||||
RPC_TYPE_NP_VARIANT,
|
||||
};
|
||||
|
||||
|
@ -111,10 +124,14 @@ typedef struct _NPPrintData {
|
|||
} NPPrintData;
|
||||
|
||||
// Initialize marshalers for NS4 plugin types
|
||||
extern int rpc_add_np_marshalers(void) attribute_hidden;
|
||||
extern int rpc_add_np_marshalers(rpc_connection_t *connection) attribute_hidden;
|
||||
|
||||
// RPC types
|
||||
extern int rpc_type_of_NPNVariable(int variable) attribute_hidden;
|
||||
extern int rpc_type_of_NPPVariable(int variable) attribute_hidden;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NPW_RPC_H */
|
||||
|
|
383
src/npw-viewer.c
383
src/npw-viewer.c
|
@ -61,6 +61,9 @@
|
|||
// Define to use XEMBED
|
||||
#define USE_XEMBED 1
|
||||
|
||||
// Define to allow windowless plugins
|
||||
#define ALLOW_WINDOWLESS_PLUGINS 1
|
||||
|
||||
// XXX unimplemented functions
|
||||
#define UNIMPLEMENTED() npw_printf("WARNING: Unimplemented function %s at line %d\n", __func__, __LINE__)
|
||||
|
||||
|
@ -73,9 +76,11 @@ typedef struct _PluginInstance {
|
|||
NPP instance;
|
||||
uint32_t instance_id;
|
||||
bool use_xembed;
|
||||
bool is_windowless;
|
||||
NPWindow window;
|
||||
uint32_t width, height;
|
||||
void *toolkit_data;
|
||||
GdkWindow *browser_toplevel;
|
||||
} PluginInstance;
|
||||
|
||||
// Browser side data for an NPStream instance
|
||||
|
@ -98,6 +103,15 @@ typedef struct _GtkData {
|
|||
GtkWidget *socket;
|
||||
} GtkData;
|
||||
|
||||
#define PLUGIN_INSTANCE(INSTANCE) plugin_instance(INSTANCE)
|
||||
|
||||
static inline PluginInstance *plugin_instance(NPP instance)
|
||||
{
|
||||
PluginInstance *plugin = (PluginInstance *)instance->ndata;
|
||||
assert(plugin->instance == instance);
|
||||
return plugin;
|
||||
}
|
||||
|
||||
|
||||
/* ====================================================================== */
|
||||
/* === X Toolkit glue === */
|
||||
|
@ -340,39 +354,26 @@ extern nsresult NS_GetServiceManager(nsIServiceManager **result);
|
|||
/* ====================================================================== */
|
||||
|
||||
// Reconstruct window attributes
|
||||
static int create_window_attributes(NPWindow *window)
|
||||
static int create_window_attributes(NPSetWindowCallbackStruct *ws_info)
|
||||
{
|
||||
if (window == NULL || window->window == NULL)
|
||||
if (ws_info == NULL)
|
||||
return -1;
|
||||
if (window->ws_info == NULL) {
|
||||
if ((window->ws_info = malloc(sizeof(NPSetWindowCallbackStruct))) == NULL) {
|
||||
npw_printf("ERROR: could not allocate window attributes for NPWindow %p\n", window->window);
|
||||
return -2;
|
||||
}
|
||||
GdkVisual *gdk_visual = gdkx_visual_get((uintptr_t)ws_info->visual);
|
||||
if (gdk_visual == NULL) {
|
||||
npw_printf("ERROR: could not reconstruct XVisual from visualID\n");
|
||||
return -2;
|
||||
}
|
||||
NPSetWindowCallbackStruct *ws_info = window->ws_info;
|
||||
ws_info->type = 0; // should be NP_SETWINDOW but Mozilla sets it to 0
|
||||
ws_info->display = x_display;
|
||||
XWindowAttributes win_attr;
|
||||
if (!XGetWindowAttributes(ws_info->display, (Window)window->window, &win_attr)) {
|
||||
npw_printf("ERROR: could not reconstruct window attributes from NPWindow\n");
|
||||
return -3;
|
||||
}
|
||||
ws_info->visual = win_attr.visual;
|
||||
ws_info->colormap = win_attr.colormap;
|
||||
ws_info->depth = win_attr.depth;
|
||||
ws_info->visual = gdk_x11_visual_get_xvisual(gdk_visual);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Destroy window attributes struct
|
||||
static void destroy_window_attributes(NPWindow *window)
|
||||
static void destroy_window_attributes(NPSetWindowCallbackStruct *ws_info)
|
||||
{
|
||||
if (window == NULL)
|
||||
if (ws_info == NULL)
|
||||
return;
|
||||
if (window->ws_info) {
|
||||
free(window->ws_info);
|
||||
window->ws_info = NULL;
|
||||
}
|
||||
free(ws_info);
|
||||
}
|
||||
|
||||
// Fix size hints in NPWindow (Flash Player doesn't like null width)
|
||||
|
@ -390,7 +391,7 @@ static void fixup_size_hints(PluginInstance *plugin)
|
|||
}
|
||||
|
||||
// check actual window size and commit back to plugin data
|
||||
if (window->width == 0 || window->height == 0) {
|
||||
if (window->window && (window->width == 0 || window->height == 0)) {
|
||||
XWindowAttributes win_attr;
|
||||
if (XGetWindowAttributes(x_display, (Window)window->window, &win_attr)) {
|
||||
plugin->width = window->width = win_attr.width;
|
||||
|
@ -406,17 +407,26 @@ static void fixup_size_hints(PluginInstance *plugin)
|
|||
// Create a new window from NPWindow
|
||||
static int create_window(PluginInstance *plugin, NPWindow *window)
|
||||
{
|
||||
// cache new window information
|
||||
// XXX destroy previous window here?
|
||||
if (plugin->is_windowless)
|
||||
destroy_window_attributes(plugin->window.ws_info);
|
||||
else
|
||||
assert(plugin->window.ws_info == NULL);
|
||||
|
||||
// cache new window information (and take ownership of window->ws_info)
|
||||
memcpy(&plugin->window, window, sizeof(*window));
|
||||
window = &plugin->window;
|
||||
fixup_size_hints(plugin);
|
||||
|
||||
// reconstruct window attributes
|
||||
if (create_window_attributes(window) < 0)
|
||||
if (create_window_attributes(window->ws_info) < 0)
|
||||
return -1;
|
||||
NPSetWindowCallbackStruct *ws_info = window->ws_info;
|
||||
|
||||
// that's all for windowless plugins
|
||||
if (plugin->is_windowless)
|
||||
return 0;
|
||||
|
||||
// create the new window
|
||||
if (plugin->use_xembed) {
|
||||
// XXX it's my understanding that the following plug-forwarding
|
||||
|
@ -440,7 +450,7 @@ static int create_window(PluginInstance *plugin, NPWindow *window)
|
|||
return 0;
|
||||
}
|
||||
|
||||
XtData *toolkit = malloc(sizeof(*toolkit));
|
||||
XtData *toolkit = calloc(1, sizeof(*toolkit));
|
||||
if (toolkit == NULL)
|
||||
return -1;
|
||||
|
||||
|
@ -484,6 +494,30 @@ static int create_window(PluginInstance *plugin, NPWindow *window)
|
|||
// Update window information from NPWindow
|
||||
static int update_window(PluginInstance *plugin, NPWindow *window)
|
||||
{
|
||||
// always synchronize window attributes (and take ownership of window->ws_info)
|
||||
if (plugin->window.ws_info) {
|
||||
destroy_window_attributes(plugin->window.ws_info);
|
||||
plugin->window.ws_info = NULL;
|
||||
}
|
||||
if (window->ws_info) {
|
||||
create_window_attributes(window->ws_info);
|
||||
plugin->window.ws_info = window->ws_info;
|
||||
}
|
||||
else {
|
||||
npw_printf("ERROR: no window attributes for window %p\n", window->window);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// synchronize cliprect
|
||||
memcpy(&plugin->window.clipRect, &window->clipRect, sizeof(window->clipRect));;
|
||||
|
||||
// synchronize window position, if it changed
|
||||
if (plugin->window.x != window->x || plugin->window.y != window->y) {
|
||||
plugin->window.x = window->x;
|
||||
plugin->window.y = window->y;
|
||||
}
|
||||
|
||||
// synchronize window size, if it changed
|
||||
if (plugin->window.width != window->width || plugin->window.height != window->height) {
|
||||
plugin->window.width = window->width;
|
||||
plugin->window.height = window->height;
|
||||
|
@ -509,8 +543,10 @@ static void destroy_window(PluginInstance *plugin)
|
|||
if (plugin->toolkit_data) {
|
||||
if (plugin->use_xembed) {
|
||||
GtkData *toolkit = (GtkData *)plugin->toolkit_data;
|
||||
if (toolkit->container)
|
||||
if (toolkit->container) {
|
||||
gtk_widget_destroy(toolkit->container);
|
||||
toolkit->container = NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
XtData *toolkit = (XtData *)plugin->toolkit_data;
|
||||
|
@ -525,7 +561,10 @@ static void destroy_window(PluginInstance *plugin)
|
|||
plugin->toolkit_data = NULL;
|
||||
}
|
||||
|
||||
destroy_window_attributes(&plugin->window);
|
||||
if (plugin->window.ws_info) {
|
||||
destroy_window_attributes(plugin->window.ws_info);
|
||||
plugin->window.ws_info = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -646,6 +685,18 @@ invoke_NPN_GetValue(NPP instance, NPNVariable variable, void *value)
|
|||
|
||||
int32_t ret;
|
||||
switch (rpc_type_of_NPNVariable(variable)) {
|
||||
case RPC_TYPE_UINT32:
|
||||
{
|
||||
uint32_t n = 0;
|
||||
error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_INT32, &ret, RPC_TYPE_UINT32, &n, RPC_TYPE_INVALID);
|
||||
if (error != RPC_ERROR_NO_ERROR) {
|
||||
npw_perror("NPN_GetValue() wait for reply", error);
|
||||
ret = NPERR_GENERIC_ERROR;
|
||||
}
|
||||
D(bug(" value: %u\n", n));
|
||||
*((unsigned int *)value) = n;
|
||||
break;
|
||||
}
|
||||
case RPC_TYPE_BOOLEAN:
|
||||
{
|
||||
uint32_t b = 0;
|
||||
|
@ -675,6 +726,16 @@ invoke_NPN_GetValue(NPP instance, NPNVariable variable, void *value)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static Window
|
||||
get_real_netscape_window(NPP instance)
|
||||
{
|
||||
GdkNativeWindow window;
|
||||
int ret = invoke_NPN_GetValue(instance, NPNVnetscapeWindow, &window);
|
||||
if (ret == NPERR_NO_ERROR)
|
||||
return window;
|
||||
return None;
|
||||
}
|
||||
|
||||
static NPError
|
||||
g_NPN_GetValue(NPP instance, NPNVariable variable, void *value)
|
||||
{
|
||||
|
@ -699,6 +760,22 @@ g_NPN_GetValue(NPP instance, NPNVariable variable, void *value)
|
|||
*(nsIServiceManager **)value = sm;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case NPNVnetscapeWindow: {
|
||||
PluginInstance *plugin = PLUGIN_INSTANCE(instance);
|
||||
if (plugin->browser_toplevel == NULL) {
|
||||
GdkNativeWindow netscape_xid = get_real_netscape_window(instance);
|
||||
if (netscape_xid == None)
|
||||
return NPERR_GENERIC_ERROR;
|
||||
plugin->browser_toplevel = gdk_window_foreign_new(netscape_xid);
|
||||
if (plugin->browser_toplevel == NULL)
|
||||
return NPERR_GENERIC_ERROR;
|
||||
}
|
||||
*((GdkNativeWindow *)value) = GDK_WINDOW_XWINDOW(plugin->browser_toplevel);
|
||||
break;
|
||||
}
|
||||
#if ALLOW_WINDOWLESS_PLUGINS
|
||||
case NPNVSupportsWindowless:
|
||||
#endif
|
||||
#if USE_XEMBED
|
||||
case NPNVSupportsXEmbedBool:
|
||||
|
@ -719,12 +796,37 @@ g_NPN_GetValue(NPP instance, NPNVariable variable, void *value)
|
|||
}
|
||||
|
||||
// Invalidates specified drawing area prior to repainting or refreshing a windowless plug-in
|
||||
static void
|
||||
invoke_NPN_InvalidateRect(NPP instance, NPRect *invalidRect)
|
||||
{
|
||||
int error = rpc_method_invoke(g_rpc_connection,
|
||||
RPC_METHOD_NPN_INVALIDATE_RECT,
|
||||
RPC_TYPE_NPP, instance,
|
||||
RPC_TYPE_NP_RECT, invalidRect,
|
||||
RPC_TYPE_INVALID);
|
||||
|
||||
if (error != RPC_ERROR_NO_ERROR) {
|
||||
npw_perror("NPN_InvalidateRect() invoke", error);
|
||||
return;
|
||||
}
|
||||
|
||||
error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_INVALID);
|
||||
|
||||
if (error != RPC_ERROR_NO_ERROR) {
|
||||
npw_perror("NPN_InvalidateRect() wait for reply", error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
g_NPN_InvalidateRect(NPP instance, NPRect *invalidRect)
|
||||
{
|
||||
D(bug("NPN_InvalidateRect instance=%p\n", instance));
|
||||
if (instance == NULL || invalidRect == NULL)
|
||||
return;
|
||||
|
||||
UNIMPLEMENTED();
|
||||
D(bug("NPN_InvalidateRect instance=%p\n", instance));
|
||||
invoke_NPN_InvalidateRect(instance, invalidRect);
|
||||
D(bug(" done\n"));
|
||||
}
|
||||
|
||||
// Invalidates specified region prior to repainting or refreshing a windowless plug-in
|
||||
|
@ -912,14 +1014,52 @@ g_NPN_RequestRead(NPStream *stream, NPByteRange *rangeList)
|
|||
}
|
||||
|
||||
// Sets various modes of plug-in operation
|
||||
static NPError
|
||||
invoke_NPN_SetValue(PluginInstance *plugin, NPPVariable variable, void *value)
|
||||
{
|
||||
switch (rpc_type_of_NPPVariable(variable)) {
|
||||
case RPC_TYPE_BOOLEAN:
|
||||
break;
|
||||
default:
|
||||
npw_printf("WARNING: unhandled variable %d in NPN_SetValue()\n", variable);
|
||||
return NPERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
int error = rpc_method_invoke(g_rpc_connection,
|
||||
RPC_METHOD_NPN_SET_VALUE,
|
||||
RPC_TYPE_NPP, plugin->instance,
|
||||
RPC_TYPE_UINT32, variable,
|
||||
RPC_TYPE_BOOLEAN, (uint32_t)(uintptr_t)value,
|
||||
RPC_TYPE_INVALID);
|
||||
|
||||
if (error != RPC_ERROR_NO_ERROR) {
|
||||
npw_perror("NPN_SetValue() invoke", error);
|
||||
return NPERR_GENERIC_ERROR;
|
||||
}
|
||||
|
||||
int32_t ret;
|
||||
error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_INT32, &ret, RPC_TYPE_INVALID);
|
||||
if (error != RPC_ERROR_NO_ERROR) {
|
||||
npw_perror("NPN_SetValue() wait for reply", error);
|
||||
return NPERR_GENERIC_ERROR;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static NPError
|
||||
g_NPN_SetValue(NPP instance, NPPVariable variable, void *value)
|
||||
{
|
||||
D(bug("NPN_SetValue instance=%p\n", instance));
|
||||
if (instance == NULL)
|
||||
return NPERR_INVALID_INSTANCE_ERROR;
|
||||
|
||||
UNIMPLEMENTED();
|
||||
PluginInstance *plugin = PLUGIN_INSTANCE(instance);
|
||||
if (plugin == NULL)
|
||||
return NPERR_INVALID_INSTANCE_ERROR;
|
||||
|
||||
return NPERR_GENERIC_ERROR;
|
||||
D(bug("NPN_SetValue instance=%p, variable=%d\n", instance, variable));
|
||||
NPError ret = invoke_NPN_SetValue(plugin, variable, value);
|
||||
D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret)));
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Displays a message on the status line of the browser window
|
||||
|
@ -1240,6 +1380,62 @@ g_NPN_PopPopupsEnabledState(NPP instance)
|
|||
/* === NPRuntime glue === */
|
||||
/* ====================================================================== */
|
||||
|
||||
// make sure to deallocate with g_free() since it comes from a GString
|
||||
static gchar *
|
||||
string_of_NPVariant(const NPVariant *arg)
|
||||
{
|
||||
#if DEBUG
|
||||
GString *str = g_string_new(NULL);
|
||||
switch (arg->type)
|
||||
{
|
||||
case NPVariantType_Void:
|
||||
g_string_append_printf(str, "void");
|
||||
break;
|
||||
case NPVariantType_Null:
|
||||
g_string_append_printf(str, "null");
|
||||
break;
|
||||
case NPVariantType_Bool:
|
||||
g_string_append(str, arg->value.boolValue ? "true" : "false");
|
||||
break;
|
||||
case NPVariantType_Int32:
|
||||
g_string_append_printf(str, "%d", arg->value.intValue);
|
||||
break;
|
||||
case NPVariantType_Double:
|
||||
g_string_append_printf(str, "%f", arg->value.doubleValue);
|
||||
break;
|
||||
case NPVariantType_String:
|
||||
g_string_append_printf(str, "'%s'",
|
||||
arg->value.stringValue.utf8characters);
|
||||
break;
|
||||
case NPVariantType_Object:
|
||||
g_string_append_printf(str, "<object %p>", arg->value.objectValue);
|
||||
break;
|
||||
default:
|
||||
g_string_append_printf(str, "<invalid type %d>", arg->type);
|
||||
break;
|
||||
}
|
||||
return g_string_free(str, FALSE);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
print_npvariant_args(const NPVariant *args, uint32_t nargs)
|
||||
{
|
||||
#if DEBUG
|
||||
GString *str = g_string_new(NULL);
|
||||
for (int i = 0; i < nargs; i++) {
|
||||
if (i > 0)
|
||||
g_string_append(str, ", ");
|
||||
gchar *argstr = string_of_NPVariant(&args[i]);
|
||||
g_string_append(str, argstr);
|
||||
g_free(argstr);
|
||||
}
|
||||
D(bug(" %u args (%s)\n", nargs, str->str));
|
||||
g_string_free(str, TRUE);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Allocates a new NPObject
|
||||
static uint32_t
|
||||
invoke_NPN_CreateObject(NPP instance)
|
||||
|
@ -1398,9 +1594,12 @@ g_NPN_Invoke(NPP instance, NPObject *npobj, NPIdentifier methodName,
|
|||
if (!instance || !npobj || !npobj->_class || !npobj->_class->invoke)
|
||||
return false;
|
||||
|
||||
D(bug("NPN_Invoke instance=%p, npobj=%p\n", instance, npobj));
|
||||
D(bug("NPN_Invoke instance=%p, npobj=%p, methodName=%p\n", instance, npobj, methodName));
|
||||
print_npvariant_args(args, argCount);
|
||||
bool ret = invoke_NPN_Invoke(instance, npobj, methodName, args, argCount, result);
|
||||
D(bug(" return: %d\n", ret));
|
||||
gchar *result_str = string_of_NPVariant(result);
|
||||
D(bug(" return: %d (%s)\n", ret, result_str));
|
||||
g_free(result_str);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1443,8 +1642,11 @@ g_NPN_InvokeDefault(NPP instance, NPObject *npobj,
|
|||
return false;
|
||||
|
||||
D(bug("NPN_InvokeDefault instance=%p, npobj=%p\n", instance, npobj));
|
||||
print_npvariant_args(args, argCount);
|
||||
bool ret = invoke_NPN_InvokeDefault(instance, npobj, args, argCount, result);
|
||||
D(bug(" return: %d\n", ret));
|
||||
gchar *result_str = string_of_NPVariant(result);
|
||||
D(bug(" return: %d (%s)\n", ret, result_str));
|
||||
g_free(result_str);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1489,7 +1691,9 @@ g_NPN_Evaluate(NPP instance, NPObject *npobj, NPString *script, NPVariant *resul
|
|||
|
||||
D(bug("NPN_Evaluate instance=%p, npobj=%p\n", instance, npobj));
|
||||
bool ret = invoke_NPN_Evaluate(instance, npobj, script, result);
|
||||
D(bug(" return: %d\n", ret));
|
||||
gchar *result_str = string_of_NPVariant(result);
|
||||
D(bug(" return: %d (%s)\n", ret, result_str));
|
||||
g_free(result_str);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1531,9 +1735,11 @@ g_NPN_GetProperty(NPP instance, NPObject *npobj, NPIdentifier propertyName,
|
|||
if (!instance || !npobj || !npobj->_class || !npobj->_class->getProperty)
|
||||
return false;
|
||||
|
||||
D(bug("NPN_GetProperty instance=%p, npobj=%p\n", instance, npobj));
|
||||
D(bug("NPN_GetProperty instance=%p, npobj=%p, propertyName=%p\n", instance, npobj, propertyName));
|
||||
bool ret = invoke_NPN_GetProperty(instance, npobj, propertyName, result);
|
||||
D(bug(" return: %d\n", ret));
|
||||
gchar *result_str = string_of_NPVariant(result);
|
||||
D(bug(" return: %d (%s)\n", ret, result_str));
|
||||
g_free(result_str);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1575,7 +1781,7 @@ g_NPN_SetProperty(NPP instance, NPObject *npobj, NPIdentifier propertyName,
|
|||
if (!instance || !npobj || !npobj->_class || !npobj->_class->setProperty)
|
||||
return false;
|
||||
|
||||
D(bug("NPN_SetProperty instance=%p, npobj=%p\n", instance, npobj));
|
||||
D(bug("NPN_SetProperty instance=%p, npobj=%p, propertyName=%p\n", instance, npobj, propertyName));
|
||||
bool ret = invoke_NPN_SetProperty(instance, npobj, propertyName, value);
|
||||
D(bug(" return: %d\n", ret));
|
||||
return ret;
|
||||
|
@ -1616,7 +1822,7 @@ g_NPN_RemoveProperty(NPP instance, NPObject *npobj, NPIdentifier propertyName)
|
|||
if (!instance || !npobj || !npobj->_class || !npobj->_class->removeProperty)
|
||||
return false;
|
||||
|
||||
D(bug("NPN_RemoveProperty instance=%p, npobj=%p\n", instance, npobj));
|
||||
D(bug("NPN_RemoveProperty instance=%p, npobj=%p, propertyName=%p\n", instance, npobj, propertyName));
|
||||
bool ret = invoke_NPN_RemoveProperty(instance, npobj, propertyName);
|
||||
D(bug(" return: %d\n", ret));
|
||||
return ret;
|
||||
|
@ -1657,7 +1863,7 @@ g_NPN_HasProperty(NPP instance, NPObject *npobj, NPIdentifier propertyName)
|
|||
if (!instance || !npobj || !npobj->_class || !npobj->_class->hasProperty)
|
||||
return false;
|
||||
|
||||
D(bug("NPN_HasProperty instance=%p, npobj=%p\n", instance, npobj));
|
||||
D(bug("NPN_HasProperty instance=%p, npobj=%p, propertyName=%p\n", instance, npobj, propertyName));
|
||||
bool ret = invoke_NPN_HasProperty(instance, npobj, propertyName);
|
||||
D(bug(" return: %d\n", ret));
|
||||
return ret;
|
||||
|
@ -1698,7 +1904,7 @@ g_NPN_HasMethod(NPP instance, NPObject *npobj, NPIdentifier methodName)
|
|||
if (!instance || !npobj || !npobj->_class || !npobj->_class->hasMethod)
|
||||
return false;
|
||||
|
||||
D(bug("NPN_HasMethod instance=%p, npobj=%p\n", instance, npobj));
|
||||
D(bug("NPN_HasMethod instance=%p, npobj=%p, methodName=%p\n", instance, npobj, methodName));
|
||||
bool ret = invoke_NPN_HasMethod(instance, npobj, methodName);
|
||||
D(bug(" return: %d\n", ret));
|
||||
return ret;
|
||||
|
@ -2268,6 +2474,8 @@ static int handle_NPP_New(rpc_connection_t *connection)
|
|||
{
|
||||
D(bug("handle_NPP_New\n"));
|
||||
|
||||
rpc_connection_ref(connection);
|
||||
|
||||
uint32_t instance_id;
|
||||
NPMIMEType plugin_type;
|
||||
int32_t mode;
|
||||
|
@ -2322,6 +2530,10 @@ static NPError g_NPP_Destroy(NPP instance, NPSavedData **sdata)
|
|||
|
||||
PluginInstance *plugin = instance->ndata;
|
||||
if (plugin) {
|
||||
if (plugin->browser_toplevel) {
|
||||
g_object_unref(plugin->browser_toplevel);
|
||||
plugin->browser_toplevel = NULL;
|
||||
}
|
||||
destroy_window(plugin);
|
||||
id_remove(plugin->instance_id);
|
||||
free(plugin);
|
||||
|
@ -2344,7 +2556,10 @@ static int handle_NPP_Destroy(rpc_connection_t *connection)
|
|||
|
||||
NPSavedData *save_area;
|
||||
NPError ret = g_NPP_Destroy(instance, &save_area);
|
||||
return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_NP_SAVED_DATA, save_area, RPC_TYPE_INVALID);
|
||||
|
||||
error = rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_NP_SAVED_DATA, save_area, RPC_TYPE_INVALID);
|
||||
rpc_connection_unref(connection);
|
||||
return error;
|
||||
}
|
||||
|
||||
// NPP_SetWindow
|
||||
|
@ -2361,8 +2576,10 @@ g_NPP_SetWindow(NPP instance, NPWindow *np_window)
|
|||
if (plugin == NULL)
|
||||
return NPERR_INVALID_INSTANCE_ERROR;
|
||||
|
||||
plugin->is_windowless = np_window && np_window->type == NPWindowTypeDrawable;
|
||||
|
||||
NPWindow *window = np_window;
|
||||
if (window && window->window) {
|
||||
if (window && (window->window || plugin->is_windowless)) {
|
||||
if (plugin->toolkit_data) {
|
||||
if (update_window(plugin, window) < 0)
|
||||
return NPERR_GENERIC_ERROR;
|
||||
|
@ -2378,7 +2595,7 @@ g_NPP_SetWindow(NPP instance, NPWindow *np_window)
|
|||
NPError ret = plugin_funcs.setwindow(instance, window);
|
||||
D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret)));
|
||||
|
||||
if (np_window == NULL || np_window->window == NULL)
|
||||
if (np_window == NULL || (np_window->window == NULL && !plugin->is_windowless))
|
||||
destroy_window(plugin);
|
||||
|
||||
return ret;
|
||||
|
@ -2527,8 +2744,8 @@ g_NPP_NewStream(NPP instance, NPMIMEType type, NPStream *stream, NPBool seekable
|
|||
if (plugin_funcs.newstream == NULL)
|
||||
return NPERR_INVALID_FUNCTABLE_ERROR;
|
||||
|
||||
D(bug("NPP_NewStream instance=%p, stream=%p, type='%s', seekable=%d, stype=%s\n",
|
||||
instance, stream, type, seekable, string_of_NPStreamType(*stype)));
|
||||
D(bug("NPP_NewStream instance=%p, stream=%p, url='%s', type='%s', seekable=%d, stype=%s, notifyData=%p\n",
|
||||
instance, stream, stream->url, type, seekable, string_of_NPStreamType(*stype), stream->notifyData));
|
||||
NPError ret = plugin_funcs.newstream(instance, type, stream, seekable, stype);
|
||||
D(bug(" return: %d [%s], stype=%s\n", ret, string_of_NPError(ret), string_of_NPStreamType(*stype)));
|
||||
return ret;
|
||||
|
@ -2833,7 +3050,7 @@ static int handle_NPP_Print(rpc_connection_t *connection)
|
|||
printInfo.print.embedPrint.platformPrint = &printer;
|
||||
// XXX the window ID is unlikely to work here as is. The NPWindow
|
||||
// is probably only used as a bounding box?
|
||||
create_window_attributes(&printInfo.print.embedPrint.window);
|
||||
create_window_attributes(printInfo.print.embedPrint.window.ws_info);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2864,8 +3081,13 @@ static int handle_NPP_Print(rpc_connection_t *connection)
|
|||
fclose(printer.fp);
|
||||
}
|
||||
|
||||
if (printInfo.mode == NP_EMBED)
|
||||
destroy_window_attributes(&printInfo.print.embedPrint.window);
|
||||
if (printInfo.mode == NP_EMBED) {
|
||||
NPWindow *window = &printInfo.print.embedPrint.window;
|
||||
if (window->ws_info) {
|
||||
destroy_window_attributes(window->ws_info);
|
||||
window->ws_info = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t plugin_printed = FALSE;
|
||||
if (printInfo.mode == NP_FULL)
|
||||
|
@ -2873,6 +3095,50 @@ static int handle_NPP_Print(rpc_connection_t *connection)
|
|||
return rpc_method_send_reply(connection, RPC_TYPE_BOOLEAN, plugin_printed, RPC_TYPE_INVALID);
|
||||
}
|
||||
|
||||
// Delivers a platform-specific window event to the instance
|
||||
static int16
|
||||
g_NPP_HandleEvent(NPP instance, NPEvent *event)
|
||||
{
|
||||
if (instance == NULL)
|
||||
return false;
|
||||
|
||||
if (plugin_funcs.event == NULL)
|
||||
return false;
|
||||
|
||||
if (event == NULL)
|
||||
return false;
|
||||
|
||||
D(bug("NPP_HandleEvent instance=%p, event=%p\n", instance, event));
|
||||
int16 ret = plugin_funcs.event(instance, event);
|
||||
D(bug(" return: %d\n", ret));
|
||||
|
||||
/* XXX: let's have a chance to commit the pixmap before it's gone */
|
||||
if (event->type == GraphicsExpose)
|
||||
gdk_flush();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int handle_NPP_HandleEvent(rpc_connection_t *connection)
|
||||
{
|
||||
NPP instance;
|
||||
NPEvent event;
|
||||
int error = rpc_method_get_args(connection,
|
||||
RPC_TYPE_NPP, &instance,
|
||||
RPC_TYPE_NP_EVENT, &event,
|
||||
RPC_TYPE_INVALID);
|
||||
|
||||
if (error != RPC_ERROR_NO_ERROR) {
|
||||
npw_perror("NPP_HandleEvent() get args", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
event.xany.display = x_display;
|
||||
int16 ret = g_NPP_HandleEvent(instance, &event);
|
||||
|
||||
return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_INVALID);
|
||||
}
|
||||
|
||||
|
||||
/* ====================================================================== */
|
||||
/* === Events processing === */
|
||||
|
@ -2995,14 +3261,14 @@ static int do_main(int argc, char **argv, const char *connection_path)
|
|||
gtk_init(&argc, &argv);
|
||||
|
||||
// Initialize RPC communication channel
|
||||
if (rpc_add_np_marshalers() < 0) {
|
||||
npw_printf("ERROR: failed to initialize plugin-side marshalers\n");
|
||||
return 1;
|
||||
}
|
||||
if ((g_rpc_connection = rpc_init_server(connection_path)) == NULL) {
|
||||
npw_printf("ERROR: failed to initialize plugin-side RPC server connection\n");
|
||||
return 1;
|
||||
}
|
||||
if (rpc_add_np_marshalers(g_rpc_connection) < 0) {
|
||||
npw_printf("ERROR: failed to initialize plugin-side marshalers\n");
|
||||
return 1;
|
||||
}
|
||||
static const rpc_method_descriptor_t vtable[] = {
|
||||
{ RPC_METHOD_NP_GET_MIME_DESCRIPTION, handle_NP_GetMIMEDescription },
|
||||
{ RPC_METHOD_NP_GET_VALUE, handle_NP_GetValue },
|
||||
|
@ -3019,6 +3285,7 @@ static int do_main(int argc, char **argv, const char *connection_path)
|
|||
{ RPC_METHOD_NPP_WRITE, handle_NPP_Write },
|
||||
{ RPC_METHOD_NPP_STREAM_AS_FILE, handle_NPP_StreamAsFile },
|
||||
{ RPC_METHOD_NPP_PRINT, handle_NPP_Print },
|
||||
{ RPC_METHOD_NPP_HANDLE_EVENT, handle_NPP_HandleEvent },
|
||||
{ RPC_METHOD_NPCLASS_INVALIDATE, npclass_handle_Invalidate },
|
||||
{ RPC_METHOD_NPCLASS_HAS_METHOD, npclass_handle_HasMethod },
|
||||
{ RPC_METHOD_NPCLASS_INVOKE, npclass_handle_Invoke },
|
||||
|
@ -3028,7 +3295,7 @@ static int do_main(int argc, char **argv, const char *connection_path)
|
|||
{ RPC_METHOD_NPCLASS_SET_PROPERTY, npclass_handle_SetProperty },
|
||||
{ RPC_METHOD_NPCLASS_REMOVE_PROPERTY, npclass_handle_RemoveProperty },
|
||||
};
|
||||
if (rpc_method_add_callbacks(g_rpc_connection, vtable, sizeof(vtable) / sizeof(vtable[0])) < 0) {
|
||||
if (rpc_connection_add_method_descriptors(g_rpc_connection, vtable, sizeof(vtable) / sizeof(vtable[0])) < 0) {
|
||||
npw_printf("ERROR: failed to setup NPP method callbacks\n");
|
||||
return 1;
|
||||
}
|
||||
|
@ -3077,7 +3344,7 @@ static int do_main(int argc, char **argv, const char *connection_path)
|
|||
if (g_user_agent)
|
||||
free(g_user_agent);
|
||||
if (g_rpc_connection)
|
||||
rpc_exit(g_rpc_connection);
|
||||
rpc_connection_unref(g_rpc_connection);
|
||||
|
||||
id_kill();
|
||||
return 0;
|
||||
|
|
|
@ -21,6 +21,11 @@ NPW_VIEWER_DIR=$NPW_LIBDIR/$TARGET_ARCH/$TARGET_OS
|
|||
# Set a new LD_LIBRARY_PATH that is TARGET specific
|
||||
export LD_LIBRARY_PATH=$NPW_VIEWER_DIR
|
||||
|
||||
# Note that a clever DBT will work at the function level and XShm
|
||||
# should be possible with a proper native replacement to emulated code
|
||||
# XXX: BTW, anything other than "yes" is interpreted as "no"
|
||||
NPW_USE_XSHM=${NPW_USE_XSHM:-yes}
|
||||
|
||||
case $ARCH in
|
||||
i?86)
|
||||
ARCH=i386
|
||||
|
@ -49,6 +54,8 @@ if test "$ARCH" != "$TARGET_ARCH"; then
|
|||
LOADER="none"
|
||||
else
|
||||
LOADER=`which qemu-i386`
|
||||
# Don't allow Xshm with qemu
|
||||
NPW_USE_XSHM=no
|
||||
fi
|
||||
;;
|
||||
ppc)
|
||||
|
@ -60,6 +67,8 @@ if test "$ARCH" != "$TARGET_ARCH"; then
|
|||
esac
|
||||
else
|
||||
LOADER=`which qemu-ppc`
|
||||
# Don't allow Xshm with qemu
|
||||
NPW_USE_XSHM=no
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
@ -71,6 +80,18 @@ if test "$ARCH" != "$TARGET_ARCH"; then
|
|||
fi
|
||||
fi
|
||||
|
||||
# Disallow Xshm (implying XVideo too)
|
||||
if test "$NPW_USE_XSHM" != "yes"; then
|
||||
if test -x "$NPW_VIEWER_DIR/libnoxshm.so"; then
|
||||
if test -n "$LD_PRELOAD"; then
|
||||
LD_PRELOAD="$LD_PRELOAD:$NPW_VIEWER_DIR/libnoxshm.so"
|
||||
else
|
||||
LD_PRELOAD="$NPW_VIEWER_DIR/libnoxshm.so"
|
||||
fi
|
||||
export LD_PRELOAD
|
||||
fi
|
||||
fi
|
||||
|
||||
# Expand PATH for RealPlayer package on NetBSD (realplay)
|
||||
if test "$OS" = "NetBSD"; then
|
||||
REALPLAYER_HOME="/usr/pkg/lib/RealPlayer"
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#define _GNU_SOURCE 1 /* RTLD_DEFAULT */
|
||||
#include "sysdeps.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -73,6 +74,9 @@ static const char *plugin_path = NPW_Plugin.path;
|
|||
// Netscape exported functions
|
||||
static NPNetscapeFuncs mozilla_funcs;
|
||||
|
||||
// NPAPI version nspluginwrapper supports
|
||||
static int npapi_version = 0;
|
||||
|
||||
// Wrapper plugin data
|
||||
typedef struct {
|
||||
int initialized;
|
||||
|
@ -89,6 +93,7 @@ static Plugin g_plugin = { 0, -1, 0, NULL, NULL, NULL };
|
|||
typedef struct _PluginInstance {
|
||||
NPP instance;
|
||||
uint32_t instance_id;
|
||||
rpc_connection_t *connection;
|
||||
} PluginInstance;
|
||||
|
||||
// Plugin side data for an NPStream instance
|
||||
|
@ -101,6 +106,33 @@ typedef struct _StreamInstance {
|
|||
// Prototypes
|
||||
static void plugin_init(int is_NP_Initialize);
|
||||
static void plugin_exit(void);
|
||||
static NPError plugin_restart_if_needed(void);
|
||||
|
||||
/*
|
||||
* Notes concerning NSPluginWrapper recovery model.
|
||||
*
|
||||
* NSPluginWrapper will restart the Viewer if it detected to be
|
||||
* dead. It will not attempt to "replay" the plugin. This means that
|
||||
* if a plugin crashed, its window will remain grayed: only new
|
||||
* instances will start a new viewer.
|
||||
*
|
||||
* Each PlugInstance holds a reference to the RPC connection it was
|
||||
* created with. g_rpc_connection can be seen as the "master"
|
||||
* connection (used to initialize and shutdown things). The RPC
|
||||
* connections are reference counted so that when the master
|
||||
* connection is set to a new one, previous connections are still
|
||||
* live. That way, old NPP instances are not passed down with the new
|
||||
* connection and thus can fail early/gracefully in subsequent calls
|
||||
* to NPP_*() functions.
|
||||
*
|
||||
* TODO: make NPRuntime aware of per-plugin connections? This
|
||||
* shouldn't matter from the Wrapper side because npruntime requests
|
||||
* come from the Viewer side (see NPN_*() handlers). XXX: even with a
|
||||
* running script (NPClass handlers)?
|
||||
*/
|
||||
|
||||
// Minimal time between two plugin restarts in sec
|
||||
#define MIN_RESTART_INTERVAL 1
|
||||
|
||||
// Consume as many bytes as possible when we are not NPP_WriteReady()
|
||||
// XXX: move to a common place to Wrapper and Viewer
|
||||
|
@ -114,6 +146,39 @@ static void plugin_exit(void);
|
|||
#define max(x, y) ((x) > (y) ? (x) : (y))
|
||||
#endif
|
||||
|
||||
#define PLUGIN_INSTANCE(INSTANCE) plugin_instance(INSTANCE)
|
||||
|
||||
static inline PluginInstance *plugin_instance(NPP instance)
|
||||
{
|
||||
PluginInstance *plugin = (PluginInstance *)instance->pdata;
|
||||
assert(plugin->instance == instance);
|
||||
return plugin;
|
||||
}
|
||||
|
||||
// Flush the X output buffer
|
||||
static void toolkit_flush(void)
|
||||
{
|
||||
// Always prefer gdk_flush() if the master binary is linked against Gtk
|
||||
static void (*INVALID)(void) = (void (*)(void))(intptr_t)-1;
|
||||
static void (*lib_gdk_flush)(void) = NULL;
|
||||
if (lib_gdk_flush == NULL) {
|
||||
if ((lib_gdk_flush = dlsym(RTLD_DEFAULT, "gdk_flush")) == NULL)
|
||||
lib_gdk_flush = INVALID;
|
||||
}
|
||||
if (lib_gdk_flush != INVALID) {
|
||||
lib_gdk_flush();
|
||||
return;
|
||||
}
|
||||
|
||||
// Try raw X11
|
||||
Display *x_display = NULL;
|
||||
int error = mozilla_funcs.getvalue(NULL, NPNVxDisplay, (void *)&x_display);
|
||||
if (error == NPERR_NO_ERROR && x_display) {
|
||||
XSync(x_display, False);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ====================================================================== */
|
||||
/* === RPC communication === */
|
||||
|
@ -239,6 +304,12 @@ static int handle_NPN_GetValue(rpc_connection_t *connection)
|
|||
|
||||
NPError ret = NPERR_GENERIC_ERROR;
|
||||
switch (rpc_type_of_NPNVariable(variable)) {
|
||||
case RPC_TYPE_UINT32:
|
||||
{
|
||||
uint32_t n = 0;
|
||||
ret = g_NPN_GetValue(instance, variable, (void *)&n);
|
||||
return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_UINT32, n, RPC_TYPE_INVALID);
|
||||
}
|
||||
case RPC_TYPE_BOOLEAN:
|
||||
{
|
||||
PRBool b = PR_FALSE;
|
||||
|
@ -256,6 +327,72 @@ static int handle_NPN_GetValue(rpc_connection_t *connection)
|
|||
abort();
|
||||
}
|
||||
|
||||
// NPN_SetValue
|
||||
static NPError
|
||||
g_NPN_SetValue(NPP instance, NPNVariable variable, void *value)
|
||||
{
|
||||
if (mozilla_funcs.setvalue == NULL)
|
||||
return NPERR_INVALID_FUNCTABLE_ERROR;
|
||||
|
||||
D(bug("NPN_SetValue instance=%p, variable=%d\n", instance, variable));
|
||||
NPError ret = mozilla_funcs.setvalue(instance, variable, value);
|
||||
D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret)));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int handle_NPN_SetValue(rpc_connection_t *connection)
|
||||
{
|
||||
D(bug("handle_NPN_SetValue\n"));
|
||||
|
||||
NPP instance;
|
||||
uint32_t variable, value;
|
||||
int error = rpc_method_get_args(connection,
|
||||
RPC_TYPE_NPP, &instance,
|
||||
RPC_TYPE_UINT32, &variable,
|
||||
RPC_TYPE_BOOLEAN, &value,
|
||||
RPC_TYPE_INVALID);
|
||||
|
||||
if (error != RPC_ERROR_NO_ERROR) {
|
||||
npw_perror("NPN_SetValue() get args", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
NPError ret = g_NPN_SetValue(instance, variable, (void *)(uintptr_t)value);
|
||||
return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_INVALID);
|
||||
}
|
||||
|
||||
// NPN_InvalidateRect
|
||||
static void g_NPN_InvalidateRect(NPP instance, NPRect *invalidRect)
|
||||
{
|
||||
if (mozilla_funcs.invalidaterect == NULL)
|
||||
return;
|
||||
|
||||
D(bug("NPN_InvalidateRect instance=%p\n", instance));
|
||||
CallNPN_InvalidateRectProc(mozilla_funcs.invalidaterect, instance, invalidRect);
|
||||
D(bug(" done\n"));
|
||||
}
|
||||
|
||||
static int handle_NPN_InvalidateRect(rpc_connection_t *connection)
|
||||
{
|
||||
D(bug("handle_NPN_InvalidateRect\n"));
|
||||
|
||||
NPP instance;
|
||||
NPRect invalidRect;
|
||||
int error = rpc_method_get_args(connection,
|
||||
RPC_TYPE_NPP, &instance,
|
||||
RPC_TYPE_NP_RECT, &invalidRect,
|
||||
RPC_TYPE_INVALID);
|
||||
|
||||
if (error != RPC_ERROR_NO_ERROR) {
|
||||
npw_perror("NPN_InvalidateRect() get args", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
g_NPN_InvalidateRect(instance, &invalidRect);
|
||||
|
||||
return RPC_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
// NPN_GetURL
|
||||
static NPError g_NPN_GetURL(NPP instance, const char *url, const char *target)
|
||||
{
|
||||
|
@ -1181,13 +1318,13 @@ static int handle_NPN_IntFromIdentifier(rpc_connection_t *connection)
|
|||
|
||||
// Creates a new instance of a plug-in
|
||||
static NPError
|
||||
invoke_NPP_New(NPMIMEType mime_type, NPP instance,
|
||||
invoke_NPP_New(PluginInstance *plugin, NPMIMEType mime_type,
|
||||
uint16_t mode, int16_t argc, char *argn[], char *argv[],
|
||||
NPSavedData *saved)
|
||||
{
|
||||
int error = rpc_method_invoke(g_rpc_connection,
|
||||
int error = rpc_method_invoke(plugin->connection,
|
||||
RPC_METHOD_NPP_NEW,
|
||||
RPC_TYPE_UINT32, ((PluginInstance *)instance->pdata)->instance_id,
|
||||
RPC_TYPE_UINT32, plugin->instance_id,
|
||||
RPC_TYPE_STRING, mime_type,
|
||||
RPC_TYPE_INT32, (int32_t)mode,
|
||||
RPC_TYPE_ARRAY, RPC_TYPE_STRING, (uint32_t)argc, argn,
|
||||
|
@ -1201,7 +1338,7 @@ invoke_NPP_New(NPMIMEType mime_type, NPP instance,
|
|||
}
|
||||
|
||||
int32_t ret;
|
||||
error = rpc_method_wait_for_reply(g_rpc_connection,
|
||||
error = rpc_method_wait_for_reply(plugin->connection,
|
||||
RPC_TYPE_INT32, &ret,
|
||||
RPC_TYPE_INVALID);
|
||||
|
||||
|
@ -1220,17 +1357,25 @@ g_NPP_New(NPMIMEType mime_type, NPP instance,
|
|||
{
|
||||
if (instance == NULL)
|
||||
return NPERR_INVALID_INSTANCE_ERROR;
|
||||
|
||||
|
||||
// Check if we need to restart the plug-in
|
||||
NPError ret = plugin_restart_if_needed();
|
||||
if (ret != NPERR_NO_ERROR)
|
||||
return ret;
|
||||
|
||||
PluginInstance *plugin = malloc(sizeof(*plugin));
|
||||
if (plugin == NULL)
|
||||
return NPERR_OUT_OF_MEMORY_ERROR;
|
||||
memset(plugin, 0, sizeof(*plugin));
|
||||
plugin->instance = instance;
|
||||
plugin->instance_id = id_create(plugin);
|
||||
plugin->connection = g_rpc_connection;
|
||||
instance->pdata = plugin;
|
||||
|
||||
rpc_connection_ref(plugin->connection);
|
||||
|
||||
D(bug("NPP_New instance=%p\n", instance));
|
||||
NPError ret = invoke_NPP_New(mime_type, instance, mode, argc, argn, argv, saved);
|
||||
ret = invoke_NPP_New(plugin, mime_type, mode, argc, argn, argv, saved);
|
||||
D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret)));
|
||||
|
||||
if (saved) {
|
||||
|
@ -1244,11 +1389,11 @@ g_NPP_New(NPMIMEType mime_type, NPP instance,
|
|||
|
||||
// Deletes a specific instance of a plug-in
|
||||
static NPError
|
||||
invoke_NPP_Destroy(NPP instance, NPSavedData **save)
|
||||
invoke_NPP_Destroy(PluginInstance *plugin, NPSavedData **save)
|
||||
{
|
||||
int error = rpc_method_invoke(g_rpc_connection,
|
||||
int error = rpc_method_invoke(plugin->connection,
|
||||
RPC_METHOD_NPP_DESTROY,
|
||||
RPC_TYPE_NPP, instance,
|
||||
RPC_TYPE_NPP, plugin->instance,
|
||||
RPC_TYPE_INVALID);
|
||||
|
||||
if (error != RPC_ERROR_NO_ERROR) {
|
||||
|
@ -1258,7 +1403,7 @@ invoke_NPP_Destroy(NPP instance, NPSavedData **save)
|
|||
|
||||
int32_t ret;
|
||||
NPSavedData *save_area = NULL;
|
||||
error = rpc_method_wait_for_reply(g_rpc_connection,
|
||||
error = rpc_method_wait_for_reply(plugin->connection,
|
||||
RPC_TYPE_INT32, &ret,
|
||||
RPC_TYPE_NP_SAVED_DATA, &save_area,
|
||||
RPC_TYPE_INVALID);
|
||||
|
@ -1284,28 +1429,29 @@ g_NPP_Destroy(NPP instance, NPSavedData **save)
|
|||
{
|
||||
if (instance == NULL)
|
||||
return NPERR_INVALID_INSTANCE_ERROR;
|
||||
PluginInstance *plugin = PLUGIN_INSTANCE(instance);
|
||||
if (plugin == NULL)
|
||||
return NPERR_INVALID_INSTANCE_ERROR;
|
||||
|
||||
D(bug("NPP_Destroy instance=%p\n", instance));
|
||||
NPError ret = invoke_NPP_Destroy(instance, save);
|
||||
NPError ret = invoke_NPP_Destroy(plugin, save);
|
||||
D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret)));
|
||||
|
||||
PluginInstance *plugin = instance->pdata;
|
||||
if (plugin) {
|
||||
id_remove(plugin->instance_id);
|
||||
free(plugin);
|
||||
instance->pdata = NULL;
|
||||
}
|
||||
rpc_connection_unref(plugin->connection);
|
||||
|
||||
id_remove(plugin->instance_id);
|
||||
free(plugin);
|
||||
instance->pdata = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Tells the plug-in when a window is created, moved, sized, or destroyed
|
||||
static NPError
|
||||
invoke_NPP_SetWindow(NPP instance, NPWindow *window)
|
||||
invoke_NPP_SetWindow(PluginInstance *plugin, NPWindow *window)
|
||||
{
|
||||
int error = rpc_method_invoke(g_rpc_connection,
|
||||
int error = rpc_method_invoke(plugin->connection,
|
||||
RPC_METHOD_NPP_SET_WINDOW,
|
||||
RPC_TYPE_NPP, instance,
|
||||
RPC_TYPE_NPP, plugin->instance,
|
||||
RPC_TYPE_NP_WINDOW, window,
|
||||
RPC_TYPE_INVALID);
|
||||
|
||||
|
@ -1315,7 +1461,7 @@ invoke_NPP_SetWindow(NPP instance, NPWindow *window)
|
|||
}
|
||||
|
||||
int32_t ret;
|
||||
error = rpc_method_wait_for_reply(g_rpc_connection,
|
||||
error = rpc_method_wait_for_reply(plugin->connection,
|
||||
RPC_TYPE_INT32, &ret,
|
||||
RPC_TYPE_INVALID);
|
||||
|
||||
|
@ -1332,20 +1478,23 @@ g_NPP_SetWindow(NPP instance, NPWindow *window)
|
|||
{
|
||||
if (instance == NULL)
|
||||
return NPERR_INVALID_INSTANCE_ERROR;
|
||||
PluginInstance *plugin = PLUGIN_INSTANCE(instance);
|
||||
if (plugin == NULL)
|
||||
return NPERR_INVALID_INSTANCE_ERROR;
|
||||
|
||||
D(bug("NPP_SetWindow instance=%p\n", instance));
|
||||
NPError ret = invoke_NPP_SetWindow(instance, window);
|
||||
NPError ret = invoke_NPP_SetWindow(plugin, window);
|
||||
D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret)));
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Allows the browser to query the plug-in for information
|
||||
static NPError
|
||||
invoke_NPP_GetValue(NPP instance, NPPVariable variable, void *value)
|
||||
invoke_NPP_GetValue(PluginInstance *plugin, NPPVariable variable, void *value)
|
||||
{
|
||||
int error = rpc_method_invoke(g_rpc_connection,
|
||||
int error = rpc_method_invoke(plugin->connection,
|
||||
RPC_METHOD_NPP_GET_VALUE,
|
||||
RPC_TYPE_NPP, instance,
|
||||
RPC_TYPE_NPP, plugin->instance,
|
||||
RPC_TYPE_INT32, variable,
|
||||
RPC_TYPE_INVALID);
|
||||
|
||||
|
@ -1359,7 +1508,7 @@ invoke_NPP_GetValue(NPP instance, NPPVariable variable, void *value)
|
|||
case RPC_TYPE_STRING:
|
||||
{
|
||||
char *str = NULL;
|
||||
error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_INT32, &ret, RPC_TYPE_STRING, &str, RPC_TYPE_INVALID);
|
||||
error = rpc_method_wait_for_reply(plugin->connection, RPC_TYPE_INT32, &ret, RPC_TYPE_STRING, &str, RPC_TYPE_INVALID);
|
||||
if (error != RPC_ERROR_NO_ERROR) {
|
||||
npw_perror("NPP_GetValue() wait for reply", error);
|
||||
ret = NPERR_GENERIC_ERROR;
|
||||
|
@ -1388,7 +1537,7 @@ invoke_NPP_GetValue(NPP instance, NPPVariable variable, void *value)
|
|||
case RPC_TYPE_INT32:
|
||||
{
|
||||
int32_t n = 0;
|
||||
error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_INT32, &ret, RPC_TYPE_INT32, &n, RPC_TYPE_INVALID);
|
||||
error = rpc_method_wait_for_reply(plugin->connection, RPC_TYPE_INT32, &ret, RPC_TYPE_INT32, &n, RPC_TYPE_INVALID);
|
||||
if (error != RPC_ERROR_NO_ERROR) {
|
||||
npw_perror("NPP_GetValue() wait for reply", error);
|
||||
ret = NPERR_GENERIC_ERROR;
|
||||
|
@ -1400,7 +1549,7 @@ invoke_NPP_GetValue(NPP instance, NPPVariable variable, void *value)
|
|||
case RPC_TYPE_BOOLEAN:
|
||||
{
|
||||
uint32_t b = 0;
|
||||
error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_INT32, &ret, RPC_TYPE_BOOLEAN, &b, RPC_TYPE_INVALID);
|
||||
error = rpc_method_wait_for_reply(plugin->connection, RPC_TYPE_INT32, &ret, RPC_TYPE_BOOLEAN, &b, RPC_TYPE_INVALID);
|
||||
if (error != RPC_ERROR_NO_ERROR) {
|
||||
npw_perror("NPP_GetValue() wait for reply", error);
|
||||
ret = NPERR_GENERIC_ERROR;
|
||||
|
@ -1412,7 +1561,7 @@ invoke_NPP_GetValue(NPP instance, NPPVariable variable, void *value)
|
|||
case RPC_TYPE_NP_OBJECT:
|
||||
{
|
||||
NPObject *npobj = NULL;
|
||||
error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_INT32, &ret, RPC_TYPE_NP_OBJECT, &npobj, RPC_TYPE_INVALID);
|
||||
error = rpc_method_wait_for_reply(plugin->connection, RPC_TYPE_INT32, &ret, RPC_TYPE_NP_OBJECT, &npobj, RPC_TYPE_INVALID);
|
||||
if (error != RPC_ERROR_NO_ERROR) {
|
||||
npw_perror("NPP_GetValue() wait for reply", error);
|
||||
ret = NPERR_GENERIC_ERROR;
|
||||
|
@ -1431,6 +1580,9 @@ g_NPP_GetValue(NPP instance, NPPVariable variable, void *value)
|
|||
{
|
||||
if (instance == NULL)
|
||||
return NPERR_INVALID_INSTANCE_ERROR;
|
||||
PluginInstance *plugin = PLUGIN_INSTANCE(instance);
|
||||
if (plugin == NULL)
|
||||
return NPERR_INVALID_INSTANCE_ERROR;
|
||||
|
||||
switch (rpc_type_of_NPPVariable(variable)) {
|
||||
case RPC_TYPE_STRING:
|
||||
|
@ -1444,14 +1596,14 @@ g_NPP_GetValue(NPP instance, NPPVariable variable, void *value)
|
|||
}
|
||||
|
||||
D(bug("NPP_GetValue instance=%p, variable=%d\n", instance, variable));
|
||||
NPError ret = invoke_NPP_GetValue(instance, variable, value);
|
||||
NPError ret = invoke_NPP_GetValue(plugin, variable, value);
|
||||
D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret)));
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Sets information about the plug-in
|
||||
static NPError
|
||||
invoke_NPP_SetValue(NPP instance, NPPVariable variable, void *value)
|
||||
invoke_NPP_SetValue(PluginInstance *plugin, NPPVariable variable, void *value)
|
||||
{
|
||||
UNIMPLEMENTED();
|
||||
|
||||
|
@ -1463,20 +1615,23 @@ g_NPP_SetValue(NPP instance, NPPVariable variable, void *value)
|
|||
{
|
||||
if (instance == NULL)
|
||||
return NPERR_INVALID_INSTANCE_ERROR;
|
||||
PluginInstance *plugin = PLUGIN_INSTANCE(instance);
|
||||
if (plugin == NULL)
|
||||
return NPERR_INVALID_INSTANCE_ERROR;
|
||||
|
||||
D(bug("NPP_SetValue instance=%p, variable=%d\n", instance, variable));
|
||||
NPError ret = invoke_NPP_SetValue(instance, variable, value);
|
||||
NPError ret = invoke_NPP_SetValue(plugin, variable, value);
|
||||
D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret)));
|
||||
return NPERR_GENERIC_ERROR;
|
||||
}
|
||||
|
||||
// Notifies the instance of the completion of a URL request
|
||||
static void
|
||||
invoke_NPP_URLNotify(NPP instance, const char *url, NPReason reason, void *notifyData)
|
||||
invoke_NPP_URLNotify(PluginInstance *plugin, const char *url, NPReason reason, void *notifyData)
|
||||
{
|
||||
int error = rpc_method_invoke(g_rpc_connection,
|
||||
int error = rpc_method_invoke(plugin->connection,
|
||||
RPC_METHOD_NPP_URL_NOTIFY,
|
||||
RPC_TYPE_NPP, instance,
|
||||
RPC_TYPE_NPP, plugin->instance,
|
||||
RPC_TYPE_STRING, url,
|
||||
RPC_TYPE_INT32, reason,
|
||||
RPC_TYPE_NP_NOTIFY_DATA, notifyData,
|
||||
|
@ -1487,7 +1642,7 @@ invoke_NPP_URLNotify(NPP instance, const char *url, NPReason reason, void *notif
|
|||
return;
|
||||
}
|
||||
|
||||
error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_INVALID);
|
||||
error = rpc_method_wait_for_reply(plugin->connection, RPC_TYPE_INVALID);
|
||||
|
||||
if (error != RPC_ERROR_NO_ERROR)
|
||||
npw_perror("NPP_URLNotify() wait for reply", error);
|
||||
|
@ -1498,19 +1653,22 @@ g_NPP_URLNotify(NPP instance, const char *url, NPReason reason, void *notifyData
|
|||
{
|
||||
if (instance == NULL)
|
||||
return;
|
||||
PluginInstance *plugin = PLUGIN_INSTANCE(instance);
|
||||
if (plugin == NULL)
|
||||
return;
|
||||
|
||||
D(bug("NPP_URLNotify instance=%p, url='%s', reason=%d, notifyData=%p\n", instance, url, reason, notifyData));
|
||||
invoke_NPP_URLNotify(instance, url, reason, notifyData);
|
||||
invoke_NPP_URLNotify(plugin, url, reason, notifyData);
|
||||
D(bug(" done\n"));
|
||||
}
|
||||
|
||||
// Notifies a plug-in instance of a new data stream
|
||||
static NPError
|
||||
invoke_NPP_NewStream(NPP instance, NPMIMEType type, NPStream *stream, NPBool seekable, uint16 *stype)
|
||||
invoke_NPP_NewStream(PluginInstance *plugin, NPMIMEType type, NPStream *stream, NPBool seekable, uint16 *stype)
|
||||
{
|
||||
int error = rpc_method_invoke(g_rpc_connection,
|
||||
int error = rpc_method_invoke(plugin->connection,
|
||||
RPC_METHOD_NPP_NEW_STREAM,
|
||||
RPC_TYPE_NPP, instance,
|
||||
RPC_TYPE_NPP, plugin->instance,
|
||||
RPC_TYPE_STRING, type,
|
||||
RPC_TYPE_UINT32, ((StreamInstance *)stream->pdata)->stream_id,
|
||||
RPC_TYPE_STRING, stream->url,
|
||||
|
@ -1528,7 +1686,7 @@ invoke_NPP_NewStream(NPP instance, NPMIMEType type, NPStream *stream, NPBool see
|
|||
|
||||
int32_t ret;
|
||||
uint32_t r_stype;
|
||||
error = rpc_method_wait_for_reply(g_rpc_connection,
|
||||
error = rpc_method_wait_for_reply(plugin->connection,
|
||||
RPC_TYPE_INT32, &ret,
|
||||
RPC_TYPE_UINT32, &r_stype,
|
||||
RPC_TYPE_NP_NOTIFY_DATA, &stream->notifyData,
|
||||
|
@ -1548,6 +1706,9 @@ g_NPP_NewStream(NPP instance, NPMIMEType type, NPStream *stream, NPBool seekable
|
|||
{
|
||||
if (instance == NULL)
|
||||
return NPERR_INVALID_INSTANCE_ERROR;
|
||||
PluginInstance *plugin = PLUGIN_INSTANCE(instance);
|
||||
if (plugin == NULL)
|
||||
return NPERR_INVALID_INSTANCE_ERROR;
|
||||
|
||||
StreamInstance *stream_pdata = malloc(sizeof(*stream_pdata));
|
||||
if (stream_pdata == NULL)
|
||||
|
@ -1559,18 +1720,18 @@ g_NPP_NewStream(NPP instance, NPMIMEType type, NPStream *stream, NPBool seekable
|
|||
stream->pdata = stream_pdata;
|
||||
|
||||
D(bug("NPP_NewStream instance=%p\n", instance));
|
||||
NPError ret = invoke_NPP_NewStream(instance, type, stream, seekable, stype);
|
||||
NPError ret = invoke_NPP_NewStream(plugin, type, stream, seekable, stype);
|
||||
D(bug(" return: %d [%s], stype=%s\n", ret, string_of_NPError(ret), string_of_NPStreamType(*stype)));
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Tells the plug-in that a stream is about to be closed or destroyed
|
||||
static NPError
|
||||
invoke_NPP_DestroyStream(NPP instance, NPStream *stream, NPReason reason)
|
||||
invoke_NPP_DestroyStream(PluginInstance *plugin, NPStream *stream, NPReason reason)
|
||||
{
|
||||
int error = rpc_method_invoke(g_rpc_connection,
|
||||
int error = rpc_method_invoke(plugin->connection,
|
||||
RPC_METHOD_NPP_DESTROY_STREAM,
|
||||
RPC_TYPE_NPP, instance,
|
||||
RPC_TYPE_NPP, plugin->instance,
|
||||
RPC_TYPE_NP_STREAM, stream,
|
||||
RPC_TYPE_INT32, reason,
|
||||
RPC_TYPE_INVALID);
|
||||
|
@ -1581,7 +1742,7 @@ invoke_NPP_DestroyStream(NPP instance, NPStream *stream, NPReason reason)
|
|||
}
|
||||
|
||||
int32_t ret;
|
||||
error = rpc_method_wait_for_reply(g_rpc_connection,
|
||||
error = rpc_method_wait_for_reply(plugin->connection,
|
||||
RPC_TYPE_INT32, &ret,
|
||||
RPC_TYPE_INVALID);
|
||||
|
||||
|
@ -1598,9 +1759,12 @@ g_NPP_DestroyStream(NPP instance, NPStream *stream, NPReason reason)
|
|||
{
|
||||
if (instance == NULL)
|
||||
return NPERR_INVALID_INSTANCE_ERROR;
|
||||
PluginInstance *plugin = PLUGIN_INSTANCE(instance);
|
||||
if (plugin == NULL)
|
||||
return NPERR_INVALID_INSTANCE_ERROR;
|
||||
|
||||
D(bug("NPP_DestroyStream instance=%p\n", instance));
|
||||
NPError ret = invoke_NPP_DestroyStream(instance, stream, reason);
|
||||
NPError ret = invoke_NPP_DestroyStream(plugin, stream, reason);
|
||||
D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret)));
|
||||
|
||||
StreamInstance *stream_pdata = stream->pdata;
|
||||
|
@ -1615,11 +1779,11 @@ g_NPP_DestroyStream(NPP instance, NPStream *stream, NPReason reason)
|
|||
|
||||
// Provides a local file name for the data from a stream
|
||||
static void
|
||||
invoke_NPP_StreamAsFile(NPP instance, NPStream *stream, const char *fname)
|
||||
invoke_NPP_StreamAsFile(PluginInstance *plugin, NPStream *stream, const char *fname)
|
||||
{
|
||||
int error = rpc_method_invoke(g_rpc_connection,
|
||||
int error = rpc_method_invoke(plugin->connection,
|
||||
RPC_METHOD_NPP_STREAM_AS_FILE,
|
||||
RPC_TYPE_NPP, instance,
|
||||
RPC_TYPE_NPP, plugin->instance,
|
||||
RPC_TYPE_NP_STREAM, stream,
|
||||
RPC_TYPE_STRING, fname,
|
||||
RPC_TYPE_INVALID);
|
||||
|
@ -1629,7 +1793,7 @@ invoke_NPP_StreamAsFile(NPP instance, NPStream *stream, const char *fname)
|
|||
return;
|
||||
}
|
||||
|
||||
error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_INVALID);
|
||||
error = rpc_method_wait_for_reply(plugin->connection, RPC_TYPE_INVALID);
|
||||
|
||||
if (error != RPC_ERROR_NO_ERROR)
|
||||
npw_perror("NPP_StreamAsFile() wait for reply", error);
|
||||
|
@ -1640,19 +1804,22 @@ g_NPP_StreamAsFile(NPP instance, NPStream *stream, const char *fname)
|
|||
{
|
||||
if (instance == NULL)
|
||||
return;
|
||||
PluginInstance *plugin = PLUGIN_INSTANCE(instance);
|
||||
if (plugin == NULL)
|
||||
return;
|
||||
|
||||
D(bug("NPP_StreamAsFile instance=%p\n", instance));
|
||||
invoke_NPP_StreamAsFile(instance, stream, fname);
|
||||
invoke_NPP_StreamAsFile(plugin, stream, fname);
|
||||
D(bug(" done\n"));
|
||||
}
|
||||
|
||||
// Determines maximum number of bytes that the plug-in can consume
|
||||
static int32
|
||||
invoke_NPP_WriteReady(NPP instance, NPStream *stream)
|
||||
invoke_NPP_WriteReady(PluginInstance *plugin, NPStream *stream)
|
||||
{
|
||||
int error = rpc_method_invoke(g_rpc_connection,
|
||||
int error = rpc_method_invoke(plugin->connection,
|
||||
RPC_METHOD_NPP_WRITE_READY,
|
||||
RPC_TYPE_NPP, instance,
|
||||
RPC_TYPE_NPP, plugin->instance,
|
||||
RPC_TYPE_NP_STREAM, stream,
|
||||
RPC_TYPE_INVALID);
|
||||
|
||||
|
@ -1662,7 +1829,7 @@ invoke_NPP_WriteReady(NPP instance, NPStream *stream)
|
|||
}
|
||||
|
||||
int32_t ret;
|
||||
error = rpc_method_wait_for_reply(g_rpc_connection,
|
||||
error = rpc_method_wait_for_reply(plugin->connection,
|
||||
RPC_TYPE_INT32, &ret,
|
||||
RPC_TYPE_INVALID);
|
||||
|
||||
|
@ -1679,9 +1846,12 @@ g_NPP_WriteReady(NPP instance, NPStream *stream)
|
|||
{
|
||||
if (instance == NULL)
|
||||
return 0;
|
||||
PluginInstance *plugin = PLUGIN_INSTANCE(instance);
|
||||
if (plugin == NULL)
|
||||
return 0;
|
||||
|
||||
D(bug("NPP_WriteReady instance=%p\n", instance));
|
||||
int32 ret = invoke_NPP_WriteReady(instance, stream);
|
||||
int32 ret = invoke_NPP_WriteReady(plugin, stream);
|
||||
D(bug(" return: %d\n", ret));
|
||||
return ret;
|
||||
}
|
||||
|
@ -1689,11 +1859,11 @@ g_NPP_WriteReady(NPP instance, NPStream *stream)
|
|||
|
||||
// Delivers data to a plug-in instance
|
||||
static int32
|
||||
invoke_NPP_Write(NPP instance, NPStream *stream, int32 offset, int32 len, void *buf)
|
||||
invoke_NPP_Write(PluginInstance *plugin, NPStream *stream, int32 offset, int32 len, void *buf)
|
||||
{
|
||||
int error = rpc_method_invoke(g_rpc_connection,
|
||||
int error = rpc_method_invoke(plugin->connection,
|
||||
RPC_METHOD_NPP_WRITE,
|
||||
RPC_TYPE_NPP, instance,
|
||||
RPC_TYPE_NPP, plugin->instance,
|
||||
RPC_TYPE_NP_STREAM, stream,
|
||||
RPC_TYPE_INT32, offset,
|
||||
RPC_TYPE_ARRAY, RPC_TYPE_CHAR, len, buf,
|
||||
|
@ -1705,7 +1875,7 @@ invoke_NPP_Write(NPP instance, NPStream *stream, int32 offset, int32 len, void *
|
|||
}
|
||||
|
||||
int32_t ret;
|
||||
error = rpc_method_wait_for_reply(g_rpc_connection,
|
||||
error = rpc_method_wait_for_reply(plugin->connection,
|
||||
RPC_TYPE_INT32, &ret,
|
||||
RPC_TYPE_INVALID);
|
||||
|
||||
|
@ -1722,16 +1892,19 @@ g_NPP_Write(NPP instance, NPStream *stream, int32 offset, int32 len, void *buf)
|
|||
{
|
||||
if (instance == NULL)
|
||||
return -1;
|
||||
PluginInstance *plugin = PLUGIN_INSTANCE(instance);
|
||||
if (plugin == NULL)
|
||||
return -1;
|
||||
|
||||
D(bug("NPP_Write instance=%p\n", instance));
|
||||
int32 ret = invoke_NPP_Write(instance, stream, offset, len, buf);
|
||||
int32 ret = invoke_NPP_Write(plugin, stream, offset, len, buf);
|
||||
D(bug(" return: %d\n", ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
// Requests a platform-specific print operation for an embedded or full-screen plug-in
|
||||
static void invoke_NPP_Print(NPP instance, NPPrint *PrintInfo)
|
||||
static void invoke_NPP_Print(PluginInstance *plugin, NPPrint *PrintInfo)
|
||||
{
|
||||
NPPrintCallbackStruct *platformPrint;
|
||||
switch (PrintInfo->mode) {
|
||||
|
@ -1750,9 +1923,9 @@ static void invoke_NPP_Print(NPP instance, NPPrint *PrintInfo)
|
|||
platform_print_id = id_create(platformPrint);
|
||||
D(bug(" platformPrint=%p\n", platformPrint));
|
||||
|
||||
int error = rpc_method_invoke(g_rpc_connection,
|
||||
int error = rpc_method_invoke(plugin->connection,
|
||||
RPC_METHOD_NPP_PRINT,
|
||||
RPC_TYPE_NPP, instance,
|
||||
RPC_TYPE_NPP, plugin->instance,
|
||||
RPC_TYPE_UINT32, platform_print_id,
|
||||
RPC_TYPE_NP_PRINT, PrintInfo,
|
||||
RPC_TYPE_INVALID);
|
||||
|
@ -1763,7 +1936,7 @@ static void invoke_NPP_Print(NPP instance, NPPrint *PrintInfo)
|
|||
}
|
||||
|
||||
uint32_t pluginPrinted;
|
||||
error = rpc_method_wait_for_reply(g_rpc_connection,
|
||||
error = rpc_method_wait_for_reply(plugin->connection,
|
||||
RPC_TYPE_BOOLEAN, &pluginPrinted,
|
||||
RPC_TYPE_INVALID);
|
||||
|
||||
|
@ -1784,21 +1957,43 @@ static void g_NPP_Print(NPP instance, NPPrint *PrintInfo)
|
|||
{
|
||||
if (instance == NULL)
|
||||
return;
|
||||
PluginInstance *plugin = PLUGIN_INSTANCE(instance);
|
||||
if (plugin == NULL)
|
||||
return;
|
||||
|
||||
if (PrintInfo == NULL)
|
||||
return;
|
||||
|
||||
D(bug("NPP_Print instance=%p\n", instance));
|
||||
invoke_NPP_Print(instance, PrintInfo);
|
||||
invoke_NPP_Print(plugin, PrintInfo);
|
||||
D(bug(" done\n"));
|
||||
}
|
||||
|
||||
// Delivers a platform-specific window event to the instance
|
||||
static int16 invoke_NPP_HandleEvent(NPP instance, void *event)
|
||||
static int16 invoke_NPP_HandleEvent(PluginInstance *plugin, void *event)
|
||||
{
|
||||
UNIMPLEMENTED();
|
||||
int error = rpc_method_invoke(plugin->connection,
|
||||
RPC_METHOD_NPP_HANDLE_EVENT,
|
||||
RPC_TYPE_NPP, plugin->instance,
|
||||
RPC_TYPE_NP_EVENT, event,
|
||||
RPC_TYPE_INVALID);
|
||||
|
||||
return 0;
|
||||
if (error != RPC_ERROR_NO_ERROR) {
|
||||
npw_perror("NPP_HandleEvent() invoke", error);
|
||||
return NPERR_GENERIC_ERROR;
|
||||
}
|
||||
|
||||
int32_t ret;
|
||||
error = rpc_method_wait_for_reply(plugin->connection,
|
||||
RPC_TYPE_INT32, &ret,
|
||||
RPC_TYPE_INVALID);
|
||||
|
||||
if (error != RPC_ERROR_NO_ERROR) {
|
||||
npw_perror("NPP_HandleEvent() wait for reply", error);
|
||||
return NPERR_GENERIC_ERROR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int16 g_NPP_HandleEvent(NPP instance, void *event)
|
||||
|
@ -1806,8 +2001,18 @@ static int16 g_NPP_HandleEvent(NPP instance, void *event)
|
|||
if (instance == NULL)
|
||||
return NPERR_INVALID_INSTANCE_ERROR;
|
||||
|
||||
PluginInstance *plugin = PLUGIN_INSTANCE(instance);
|
||||
if (plugin == NULL)
|
||||
return NPERR_INVALID_INSTANCE_ERROR;
|
||||
|
||||
if (((NPEvent *)event)->type == GraphicsExpose) {
|
||||
/* XXX: flush the X output buffer so that the call to
|
||||
gdk_pixmap_foreign_new() in the viewer can work */
|
||||
toolkit_flush();
|
||||
}
|
||||
|
||||
D(bug("NPP_HandleEvent instance=%p\n", instance));
|
||||
int16 ret = invoke_NPP_HandleEvent(instance, event);
|
||||
int16 ret = invoke_NPP_HandleEvent(plugin, event);
|
||||
D(bug(" return: ret\n", ret));
|
||||
return ret;
|
||||
}
|
||||
|
@ -1816,7 +2021,7 @@ static int16 g_NPP_HandleEvent(NPP instance, void *event)
|
|||
NPError
|
||||
NP_GetValue(void *future, NPPVariable variable, void *value)
|
||||
{
|
||||
D(bug("NP_GetValue\n"));
|
||||
D(bug("NP_GetValue variable=%d\n", variable));
|
||||
|
||||
if (g_plugin.initialized == 0)
|
||||
plugin_init(0);
|
||||
|
@ -1841,7 +2046,7 @@ NP_GetValue(void *future, NPPVariable variable, void *value)
|
|||
str =
|
||||
"<a href=\"http://gwenole.beauchesne.info/projects/nspluginwrapper/\">nspluginwrapper</a> "
|
||||
" is a cross-platform NPAPI plugin viewer, in particular for linux/i386 plugins.<br>"
|
||||
"This software is available under the terms of the GNU General Public License.<br>"
|
||||
"This is <b>beta</b> software available under the terms of the GNU General Public License.<br>"
|
||||
;
|
||||
ret = NPERR_NO_ERROR;
|
||||
}
|
||||
|
@ -2314,6 +2519,30 @@ static bool is_konqueror(void)
|
|||
}
|
||||
|
||||
// Provides global initialization for a plug-in
|
||||
static NPError
|
||||
invoke_NP_Initialize(uint32_t npapi_version)
|
||||
{
|
||||
int error = rpc_method_invoke(g_rpc_connection,
|
||||
RPC_METHOD_NP_INITIALIZE,
|
||||
RPC_TYPE_UINT32, npapi_version,
|
||||
RPC_TYPE_INVALID);
|
||||
|
||||
if (error != RPC_ERROR_NO_ERROR) {
|
||||
npw_perror("NP_Initialize() invoke", error);
|
||||
return NPERR_MODULE_LOAD_FAILED_ERROR;
|
||||
}
|
||||
|
||||
int32_t ret;
|
||||
error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_INT32, &ret, RPC_TYPE_INVALID);
|
||||
|
||||
if (error != RPC_ERROR_NO_ERROR) {
|
||||
npw_perror("NP_Initialize() wait for reply", error);
|
||||
return NPERR_MODULE_LOAD_FAILED_ERROR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
NPError
|
||||
NP_Initialize(NPNetscapeFuncs *moz_funcs, NPPluginFuncs *plugin_funcs)
|
||||
{
|
||||
|
@ -2378,26 +2607,9 @@ NP_Initialize(NPNetscapeFuncs *moz_funcs, NPPluginFuncs *plugin_funcs)
|
|||
|
||||
// pass down common NPAPI version supported by both the underlying
|
||||
// browser and the thunking capabilities of nspluginwrapper
|
||||
uint32_t version = min(moz_funcs->version, plugin_funcs->version);
|
||||
|
||||
int error = rpc_method_invoke(g_rpc_connection,
|
||||
RPC_METHOD_NP_INITIALIZE,
|
||||
RPC_TYPE_UINT32, (uint32_t)version,
|
||||
RPC_TYPE_INVALID);
|
||||
|
||||
if (error != RPC_ERROR_NO_ERROR) {
|
||||
npw_perror("NP_Initialize() invoke", error);
|
||||
return NPERR_MODULE_LOAD_FAILED_ERROR;
|
||||
}
|
||||
|
||||
int32_t ret;
|
||||
error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_INT32, &ret, RPC_TYPE_INVALID);
|
||||
|
||||
if (error != RPC_ERROR_NO_ERROR) {
|
||||
npw_perror("NP_Initialize() wait for reply", error);
|
||||
return NPERR_MODULE_LOAD_FAILED_ERROR;
|
||||
}
|
||||
npapi_version = min(moz_funcs->version, plugin_funcs->version);
|
||||
|
||||
NPError ret = invoke_NP_Initialize(npapi_version);
|
||||
D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret)));
|
||||
return ret;
|
||||
}
|
||||
|
@ -2542,17 +2754,18 @@ static void plugin_init(int is_NP_Initialize)
|
|||
}
|
||||
|
||||
// Initialize browser-side RPC communication channel
|
||||
if (rpc_add_np_marshalers() < 0) {
|
||||
npw_printf("ERROR: failed to initialize browser-side marshalers\n");
|
||||
return;
|
||||
}
|
||||
if ((g_rpc_connection = rpc_init_client(connection_path)) == NULL) {
|
||||
npw_printf("ERROR: failed to initialize plugin-side RPC client connection\n");
|
||||
return;
|
||||
}
|
||||
if (rpc_add_np_marshalers(g_rpc_connection) < 0) {
|
||||
npw_printf("ERROR: failed to initialize browser-side marshalers\n");
|
||||
return;
|
||||
}
|
||||
static const rpc_method_descriptor_t vtable[] = {
|
||||
{ RPC_METHOD_NPN_USER_AGENT, handle_NPN_UserAgent },
|
||||
{ RPC_METHOD_NPN_GET_VALUE, handle_NPN_GetValue },
|
||||
{ RPC_METHOD_NPN_SET_VALUE, handle_NPN_SetValue },
|
||||
{ RPC_METHOD_NPN_GET_URL, handle_NPN_GetURL },
|
||||
{ RPC_METHOD_NPN_GET_URL_NOTIFY, handle_NPN_GetURLNotify },
|
||||
{ RPC_METHOD_NPN_POST_URL, handle_NPN_PostURL },
|
||||
|
@ -2565,6 +2778,7 @@ static void plugin_init(int is_NP_Initialize)
|
|||
{ RPC_METHOD_NPN_WRITE, handle_NPN_Write },
|
||||
{ RPC_METHOD_NPN_PUSH_POPUPS_ENABLED_STATE, handle_NPN_PushPopupsEnabledState },
|
||||
{ RPC_METHOD_NPN_POP_POPUPS_ENABLED_STATE, handle_NPN_PopPopupsEnabledState },
|
||||
{ RPC_METHOD_NPN_INVALIDATE_RECT, handle_NPN_InvalidateRect },
|
||||
{ RPC_METHOD_NPN_CREATE_OBJECT, handle_NPN_CreateObject },
|
||||
{ RPC_METHOD_NPN_RETAIN_OBJECT, handle_NPN_RetainObject },
|
||||
{ RPC_METHOD_NPN_RELEASE_OBJECT, handle_NPN_ReleaseObject },
|
||||
|
@ -2592,7 +2806,7 @@ static void plugin_init(int is_NP_Initialize)
|
|||
{ RPC_METHOD_NPCLASS_SET_PROPERTY, npclass_handle_SetProperty },
|
||||
{ RPC_METHOD_NPCLASS_REMOVE_PROPERTY, npclass_handle_RemoveProperty },
|
||||
};
|
||||
if (rpc_method_add_callbacks(g_rpc_connection, vtable, sizeof(vtable) / sizeof(vtable[0])) < 0) {
|
||||
if (rpc_connection_add_method_descriptors(g_rpc_connection, vtable, sizeof(vtable) / sizeof(vtable[0])) < 0) {
|
||||
npw_printf("ERROR: failed to setup NPN method callbacks\n");
|
||||
return;
|
||||
}
|
||||
|
@ -2673,7 +2887,7 @@ static void plugin_exit(void)
|
|||
}
|
||||
|
||||
if (g_rpc_connection) {
|
||||
rpc_exit(g_rpc_connection);
|
||||
rpc_connection_unref(g_rpc_connection);
|
||||
g_rpc_connection = NULL;
|
||||
}
|
||||
|
||||
|
@ -2724,3 +2938,40 @@ static void __attribute__((destructor)) plugin_exit_sentinel(void)
|
|||
g_plugin.description = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static NPError plugin_restart(void)
|
||||
{
|
||||
if (g_plugin.is_wrapper)
|
||||
return NPERR_NO_ERROR;
|
||||
|
||||
// Shut it down
|
||||
plugin_exit();
|
||||
g_plugin.initialized = 0;
|
||||
g_plugin.viewer_pid = -1;
|
||||
g_plugin.is_wrapper = 0;
|
||||
|
||||
// And start it again
|
||||
plugin_init(1);
|
||||
if (g_plugin.initialized <= 0)
|
||||
return NPERR_MODULE_LOAD_FAILED_ERROR;
|
||||
|
||||
return invoke_NP_Initialize(npapi_version);
|
||||
}
|
||||
|
||||
static NPError plugin_restart_if_needed(void)
|
||||
{
|
||||
if (rpc_status(g_rpc_connection) != RPC_STATUS_ACTIVE) {
|
||||
static time_t last_restart = 0;
|
||||
time_t now = time(NULL);
|
||||
if (now - last_restart < MIN_RESTART_INTERVAL)
|
||||
return NPERR_GENERIC_ERROR;
|
||||
last_restart = now;
|
||||
|
||||
D(bug("Restart plugins viewer\n"));
|
||||
NPError ret = plugin_restart();
|
||||
D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret)));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
|
596
src/rpc.c
596
src/rpc.c
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include "sysdeps.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
|
@ -274,6 +275,135 @@ static inline int rpc_poll(int op, int socket, int timeout)
|
|||
return ret;
|
||||
}
|
||||
|
||||
// Hash tables (implemented as simple tables at this time)
|
||||
typedef void (*rpc_map_entry_destroy_func_t)(void *value);
|
||||
|
||||
typedef struct {
|
||||
void *value;
|
||||
int key;
|
||||
int use_count;
|
||||
} rpc_map_entry_t;
|
||||
|
||||
typedef struct {
|
||||
int n_entries;
|
||||
int n_entries_max;
|
||||
rpc_map_entry_t *entries;
|
||||
rpc_map_entry_destroy_func_t destroy_func;
|
||||
} rpc_map_t;
|
||||
|
||||
static rpc_map_t *rpc_map_new(void)
|
||||
{
|
||||
rpc_map_t *map = (rpc_map_t *)malloc(sizeof(*map));
|
||||
if (map == NULL)
|
||||
return NULL;
|
||||
map->entries = NULL;
|
||||
map->n_entries = 0;
|
||||
map->n_entries_max = 0;
|
||||
map->destroy_func = NULL;
|
||||
return map;
|
||||
}
|
||||
|
||||
static rpc_map_t *rpc_map_new_full(rpc_map_entry_destroy_func_t destroy_func)
|
||||
{
|
||||
rpc_map_t *map = rpc_map_new();
|
||||
if (map == NULL)
|
||||
return NULL;
|
||||
map->destroy_func = destroy_func;
|
||||
return map;
|
||||
}
|
||||
|
||||
static void rpc_map_destroy(rpc_map_t *map)
|
||||
{
|
||||
if (map == NULL)
|
||||
return;
|
||||
if (map->entries) {
|
||||
if (map->destroy_func) {
|
||||
for (int i = 0; i < map->n_entries; i++) {
|
||||
map->destroy_func(map->entries[i].value);
|
||||
map->entries[i].value = NULL;
|
||||
}
|
||||
}
|
||||
free(map->entries);
|
||||
map->entries = NULL;
|
||||
}
|
||||
free(map);
|
||||
}
|
||||
|
||||
static rpc_map_entry_t *_rpc_map_lookup(const rpc_map_t *map, int key)
|
||||
{
|
||||
assert(map != NULL);
|
||||
|
||||
if (map->entries == NULL)
|
||||
return NULL;
|
||||
|
||||
for (int i = 0; i < map->n_entries; i++)
|
||||
if (map->entries[i].key == key)
|
||||
return &map->entries[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *rpc_map_lookup(const rpc_map_t *map, int key)
|
||||
{
|
||||
rpc_map_entry_t *entry = _rpc_map_lookup(map, key);
|
||||
if (entry == NULL)
|
||||
return NULL;
|
||||
entry->use_count++;
|
||||
return entry->value;
|
||||
}
|
||||
|
||||
static int rpc_map_remove(rpc_map_t *map, int key)
|
||||
{
|
||||
assert(map != NULL);
|
||||
|
||||
rpc_map_entry_t *entry = _rpc_map_lookup(map, key);
|
||||
if (entry) {
|
||||
entry->key = -1;
|
||||
entry->value = 0;
|
||||
entry->use_count = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rpc_map_insert(rpc_map_t *map, int key, void *value)
|
||||
{
|
||||
assert(map != NULL);
|
||||
assert(value != NULL);
|
||||
|
||||
const int N_ENTRIES_ALLOC = 7;
|
||||
int i = map->n_entries_max;
|
||||
|
||||
// override any existing entry
|
||||
rpc_map_entry_t *entry = _rpc_map_lookup(map, key);
|
||||
if (entry) {
|
||||
entry->value = value;
|
||||
entry->use_count = 0;
|
||||
return RPC_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
// look for a free slot
|
||||
if (map->entries) {
|
||||
for (i = 0; i < map->n_entries_max; i++) {
|
||||
if (map->entries[i].value == NULL)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// none found, reallocate
|
||||
if (i >= map->n_entries_max) {
|
||||
if ((map->entries = (rpc_map_entry_t *)realloc(map->entries, (map->n_entries_max + N_ENTRIES_ALLOC) * sizeof(map->entries[0]))) == NULL)
|
||||
return RPC_ERROR_NO_MEMORY;
|
||||
i = map->n_entries;
|
||||
memset(&map->entries[i], 0, N_ENTRIES_ALLOC * sizeof(map->entries[0]));
|
||||
map->n_entries_max += N_ENTRIES_ALLOC;
|
||||
}
|
||||
|
||||
map->entries[i].key = key;
|
||||
map->entries[i].value = value;
|
||||
map->entries[i].use_count = 0;
|
||||
++map->n_entries;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* ====================================================================== */
|
||||
/* === RPC Connection Handling === */
|
||||
|
@ -286,19 +416,77 @@ enum {
|
|||
};
|
||||
|
||||
// Client / Server connection
|
||||
struct rpc_connection_t {
|
||||
struct rpc_connection {
|
||||
int type;
|
||||
int refcnt;
|
||||
int status;
|
||||
int socket;
|
||||
char *socket_path;
|
||||
int server_socket;
|
||||
int server_thread_active;
|
||||
pthread_t server_thread;
|
||||
rpc_method_descriptor_t *callbacks;
|
||||
int n_callbacks;
|
||||
int send_offset;
|
||||
char send_buffer[BUFSIZ];
|
||||
rpc_map_t *types;
|
||||
rpc_map_t *methods;
|
||||
};
|
||||
|
||||
// Increment connection reference count
|
||||
rpc_connection_t *rpc_connection_ref(rpc_connection_t *connection)
|
||||
{
|
||||
if (connection)
|
||||
++connection->refcnt;
|
||||
return connection;
|
||||
}
|
||||
|
||||
// Decrement connection reference count and destroy it if it reaches zero
|
||||
void rpc_connection_unref(rpc_connection_t *connection)
|
||||
{
|
||||
if (connection && --connection->refcnt == 0) {
|
||||
D(bug("Close unused connection\n"));
|
||||
rpc_exit(connection);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns connection status
|
||||
static inline int _rpc_status(rpc_connection_t *connection)
|
||||
{
|
||||
return connection->status;
|
||||
}
|
||||
|
||||
int rpc_status(rpc_connection_t *connection)
|
||||
{
|
||||
if (connection == NULL)
|
||||
return RPC_STATUS_BROKEN;
|
||||
return _rpc_status(connection);
|
||||
}
|
||||
|
||||
// Set connection status
|
||||
static void _rpc_set_status(rpc_connection_t *connection, int error)
|
||||
{
|
||||
if (connection->status == RPC_STATUS_ACTIVE) {
|
||||
switch (error) {
|
||||
case RPC_ERROR_NO_ERROR:
|
||||
connection->status = RPC_STATUS_ACTIVE;
|
||||
break;
|
||||
case RPC_ERROR_CONNECTION_CLOSED:
|
||||
connection->status = RPC_STATUS_CLOSED;
|
||||
break;
|
||||
default:
|
||||
connection->status = RPC_STATUS_BROKEN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline int rpc_error(rpc_connection_t *connection, int error)
|
||||
{
|
||||
// XXX: this function must be called only in case of error
|
||||
// (otherwise, it's an internal error)
|
||||
assert(error < 0);
|
||||
assert(connection != NULL);
|
||||
_rpc_set_status(connection, error);
|
||||
return error;
|
||||
}
|
||||
|
||||
// Returns socket fd or -1 if invalid connection
|
||||
int rpc_socket(rpc_connection_t *connection)
|
||||
{
|
||||
|
@ -374,10 +562,18 @@ rpc_connection_t *rpc_init_server(const char *ident)
|
|||
if (connection == NULL)
|
||||
return NULL;
|
||||
connection->type = RPC_CONNECTION_SERVER;
|
||||
connection->refcnt = 1;
|
||||
connection->status = RPC_STATUS_CLOSED;
|
||||
connection->socket = -1;
|
||||
connection->server_thread_active = 0;
|
||||
connection->callbacks = NULL;
|
||||
connection->n_callbacks = 0;
|
||||
if ((connection->types = rpc_map_new_full((free))) == NULL) {
|
||||
rpc_exit(connection);
|
||||
return NULL;
|
||||
}
|
||||
if ((connection->methods = rpc_map_new()) == NULL) {
|
||||
rpc_exit(connection);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((connection->server_socket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
|
||||
perror("server socket");
|
||||
|
@ -404,6 +600,7 @@ rpc_connection_t *rpc_init_server(const char *ident)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
connection->status = RPC_STATUS_ACTIVE;
|
||||
return connection;
|
||||
}
|
||||
|
||||
|
@ -423,9 +620,17 @@ rpc_connection_t *rpc_init_client(const char *ident)
|
|||
if (connection == NULL)
|
||||
return NULL;
|
||||
connection->type = RPC_CONNECTION_CLIENT;
|
||||
connection->refcnt = 1;
|
||||
connection->status = RPC_STATUS_CLOSED;
|
||||
connection->server_socket = -1;
|
||||
connection->callbacks = NULL;
|
||||
connection->n_callbacks = 0;
|
||||
if ((connection->types = rpc_map_new_full((free))) == NULL) {
|
||||
rpc_exit(connection);
|
||||
return NULL;
|
||||
}
|
||||
if ((connection->methods = rpc_map_new()) == NULL) {
|
||||
rpc_exit(connection);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((connection->socket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
|
||||
perror("client socket");
|
||||
|
@ -467,6 +672,7 @@ rpc_connection_t *rpc_init_client(const char *ident)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
connection->status = RPC_STATUS_ACTIVE;
|
||||
return connection;
|
||||
}
|
||||
|
||||
|
@ -507,9 +713,13 @@ int rpc_exit(rpc_connection_t *connection)
|
|||
}
|
||||
}
|
||||
|
||||
if (connection->callbacks) {
|
||||
free(connection->callbacks);
|
||||
connection->callbacks = NULL;
|
||||
if (connection->types) {
|
||||
rpc_map_destroy(connection->types);
|
||||
connection->types = NULL;
|
||||
}
|
||||
if (connection->methods) {
|
||||
rpc_map_destroy(connection->methods);
|
||||
connection->methods = NULL;
|
||||
}
|
||||
|
||||
free(connection);
|
||||
|
@ -611,66 +821,43 @@ enum {
|
|||
|
||||
// Message type
|
||||
struct rpc_message_t {
|
||||
const rpc_map_t *types;
|
||||
int socket;
|
||||
int offset;
|
||||
unsigned char buffer[BUFSIZ];
|
||||
};
|
||||
|
||||
// User-defined marshalers
|
||||
static struct {
|
||||
rpc_message_descriptor_t *descs;
|
||||
int last;
|
||||
int count;
|
||||
} g_message_descriptors = { NULL, 0, 0 };
|
||||
static pthread_mutex_t g_message_descriptors_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
// Add a user-defined marshaler
|
||||
static int rpc_message_add_callback(const rpc_message_descriptor_t *desc)
|
||||
int rpc_connection_add_message_descriptor(rpc_connection_t *connection, const rpc_message_descriptor_t *idesc)
|
||||
{
|
||||
D(bug("rpc_message_add_callback\n"));
|
||||
D(bug("rpc_connection_add_message_descriptor for type %d\n", idesc->id));
|
||||
|
||||
const int N_ENTRIES_ALLOC = 8;
|
||||
int error = RPC_ERROR_NO_ERROR;
|
||||
if (connection == NULL)
|
||||
return RPC_ERROR_CONNECTION_NULL;
|
||||
|
||||
pthread_mutex_lock(&g_message_descriptors_lock);
|
||||
if (g_message_descriptors.descs == NULL) {
|
||||
g_message_descriptors.count = N_ENTRIES_ALLOC;
|
||||
if ((g_message_descriptors.descs = (rpc_message_descriptor_t *)malloc(g_message_descriptors.count * sizeof(g_message_descriptors.descs[0]))) == NULL) {
|
||||
pthread_mutex_unlock(&g_message_descriptors_lock);
|
||||
return RPC_ERROR_NO_MEMORY;
|
||||
}
|
||||
g_message_descriptors.last = 0;
|
||||
}
|
||||
else if (g_message_descriptors.last >= g_message_descriptors.count) {
|
||||
g_message_descriptors.count += N_ENTRIES_ALLOC;
|
||||
if ((g_message_descriptors.descs = (rpc_message_descriptor_t *)realloc(g_message_descriptors.descs, g_message_descriptors.count * sizeof(g_message_descriptors.descs[0]))) == NULL) {
|
||||
pthread_mutex_unlock(&g_message_descriptors_lock);
|
||||
return RPC_ERROR_NO_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
// XXX only one callback per ID
|
||||
int i;
|
||||
for (i = 0; i < g_message_descriptors.last; i++) {
|
||||
if (g_message_descriptors.descs[i].id == desc->id) {
|
||||
pthread_mutex_unlock(&g_message_descriptors_lock);
|
||||
rpc_message_descriptor_t *desc;
|
||||
if ((desc = (rpc_message_descriptor_t *)rpc_map_lookup(connection->types, idesc->id)) != NULL) {
|
||||
if (memcmp(desc, idesc, sizeof(*desc)) == 0)
|
||||
return RPC_ERROR_NO_ERROR;
|
||||
}
|
||||
fprintf(stderr, "duplicate message type %d\n", desc->id);
|
||||
return RPC_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
g_message_descriptors.descs[g_message_descriptors.last++] = *desc;
|
||||
pthread_mutex_unlock(&g_message_descriptors_lock);
|
||||
return error;
|
||||
if ((desc = (rpc_message_descriptor_t *)malloc(sizeof(*desc))) == NULL)
|
||||
return RPC_ERROR_NO_MEMORY;
|
||||
memcpy(desc, idesc, sizeof(*desc));
|
||||
|
||||
return rpc_map_insert(connection->types, desc->id, desc);
|
||||
}
|
||||
|
||||
// Add user-defined marshalers
|
||||
int rpc_message_add_callbacks(const rpc_message_descriptor_t *descs, int n_descs)
|
||||
int rpc_connection_add_message_descriptors(rpc_connection_t *connection, const rpc_message_descriptor_t *descs, int n_descs)
|
||||
{
|
||||
D(bug("rpc_message_add_callbacks\n"));
|
||||
D(bug("rpc_connection_add_message_descriptors\n"));
|
||||
|
||||
int i, error;
|
||||
for (i = 0; i < n_descs; i++) {
|
||||
if ((error = rpc_message_add_callback(&descs[i])) < 0)
|
||||
for (int i = 0; i < n_descs; i++) {
|
||||
int error = rpc_connection_add_message_descriptor(connection, &descs[i]);
|
||||
if (error < 0)
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -678,17 +865,12 @@ int rpc_message_add_callbacks(const rpc_message_descriptor_t *descs, int n_descs
|
|||
}
|
||||
|
||||
// Find user-defined marshaler
|
||||
static rpc_message_descriptor_t *rpc_message_find_descriptor(int id)
|
||||
static inline rpc_message_descriptor_t *rpc_message_descriptor_lookup(rpc_message_t *message, int id)
|
||||
{
|
||||
D(bug("rpc_message_find_descriptor\n"));
|
||||
D(bug("rpc_message_descriptor_lookup\n"));
|
||||
|
||||
if (g_message_descriptors.descs) {
|
||||
int i;
|
||||
for (i = 0; i < g_message_descriptors.count; i++) {
|
||||
if (g_message_descriptors.descs[i].id == id)
|
||||
return &g_message_descriptors.descs[i];
|
||||
}
|
||||
}
|
||||
if (message && message->types)
|
||||
return (rpc_message_descriptor_t *)rpc_map_lookup(message->types, id);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -696,6 +878,7 @@ static rpc_message_descriptor_t *rpc_message_find_descriptor(int id)
|
|||
// Initialize message
|
||||
static inline void rpc_message_init(rpc_message_t *message, rpc_connection_t *connection)
|
||||
{
|
||||
message->types = connection->types;
|
||||
message->socket = connection->socket;
|
||||
message->offset = 0;
|
||||
}
|
||||
|
@ -897,29 +1080,12 @@ static int rpc_message_send_args(rpc_message_t *message, va_list args)
|
|||
break;
|
||||
}
|
||||
default:
|
||||
if ((desc = rpc_message_find_descriptor(array_type)) != NULL) {
|
||||
if (desc->size <= sizeof(void *)) { // arguments are passed by value
|
||||
switch (desc->size) {
|
||||
case sizeof(void *): {
|
||||
void **array = va_arg(args, void **);
|
||||
for (i = 0; i < array_size; i++) {
|
||||
if ((error = desc->send_callback(message, array[i])) < 0)
|
||||
break;
|
||||
}
|
||||
if ((desc = rpc_message_descriptor_lookup(message, array_type)) != NULL) {
|
||||
// arguments are passed by value (XXX: needs a way to differenciate reference/value)
|
||||
uint8_t *array = va_arg(args, uint8_t *);
|
||||
for (i = 0; i < array_size; i++) {
|
||||
if ((error = desc->send_callback(message, &array[i * desc->size])) < 0)
|
||||
break;
|
||||
}
|
||||
default:
|
||||
fprintf(stderr, "invalid argument passing by value with type size of %d bytes\n", desc->size);
|
||||
error = RPC_ERROR_MESSAGE_ARGUMENT_INVALID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else { // arguments are passed by reference
|
||||
uint8_t *array = va_arg(args, uint8_t *);
|
||||
for (i = 0; i < array_size; i++) {
|
||||
if ((error = desc->send_callback(message, &array[i * desc->size])) < 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -931,7 +1097,7 @@ static int rpc_message_send_args(rpc_message_t *message, va_list args)
|
|||
break;
|
||||
}
|
||||
default:
|
||||
if ((desc = rpc_message_find_descriptor(type)) != NULL)
|
||||
if ((desc = rpc_message_descriptor_lookup(message, type)) != NULL)
|
||||
error = desc->send_callback(message, va_arg(args, uint8_t *));
|
||||
else {
|
||||
fprintf(stderr, "unknown arg type %d to send\n", type);
|
||||
|
@ -1190,9 +1356,10 @@ static int rpc_message_recv_args(rpc_message_t *message, va_list args)
|
|||
break;
|
||||
}
|
||||
default:
|
||||
if ((desc = rpc_message_find_descriptor(array_type)) != NULL) {
|
||||
char *array;
|
||||
if ((array = (char *)malloc(array_size * desc->size)) == NULL)
|
||||
if ((desc = rpc_message_descriptor_lookup(message, array_type)) != NULL) {
|
||||
// arguments are passed by value (XXX: needs a way to differenciate reference/value)
|
||||
uint8_t *array;
|
||||
if ((array = (uint8_t *)malloc(array_size * desc->size)) == NULL)
|
||||
return RPC_ERROR_NO_MEMORY;
|
||||
for (i = 0; i < array_size; i++) {
|
||||
if ((error = desc->recv_callback(message, &array[i * desc->size])) < 0)
|
||||
|
@ -1209,7 +1376,7 @@ static int rpc_message_recv_args(rpc_message_t *message, va_list args)
|
|||
break;
|
||||
}
|
||||
default:
|
||||
if ((desc = rpc_message_find_descriptor(type)) != NULL)
|
||||
if ((desc = rpc_message_descriptor_lookup(message, type)) != NULL)
|
||||
error = desc->recv_callback(message, p_value);
|
||||
else {
|
||||
fprintf(stderr, "unknown arg type %d to send\n", type);
|
||||
|
@ -1266,16 +1433,9 @@ static int rpc_message_skip_arg(rpc_message_t *message, int type)
|
|||
return error;
|
||||
}
|
||||
|
||||
static rpc_method_callback_t rpc_lookup_callback(rpc_connection_t *connection, int method)
|
||||
static inline rpc_method_callback_t rpc_lookup_callback(rpc_connection_t *connection, int method)
|
||||
{
|
||||
if (connection->callbacks) {
|
||||
int i;
|
||||
for (i = 0; i < connection->n_callbacks; i++) {
|
||||
if (connection->callbacks[i].id == method)
|
||||
return connection->callbacks[i].callback;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
return (rpc_method_callback_t)rpc_map_lookup(connection->methods, method);
|
||||
}
|
||||
|
||||
// Dispatch message received in the server loop
|
||||
|
@ -1305,9 +1465,10 @@ static int _rpc_dispatch(rpc_connection_t *connection, rpc_message_t *message)
|
|||
|
||||
// call: <method>
|
||||
rpc_method_callback_t callback = rpc_lookup_callback(connection, method);
|
||||
if (callback == NULL)
|
||||
return RPC_ERROR_MESSAGE_HANDLER_INVALID;
|
||||
error = callback(connection);
|
||||
if (callback)
|
||||
error = callback(connection);
|
||||
else
|
||||
error = RPC_ERROR_MESSAGE_HANDLER_INVALID;
|
||||
if (error != RPC_ERROR_NO_ERROR) {
|
||||
int error_code = error;
|
||||
|
||||
|
@ -1344,11 +1505,14 @@ int rpc_dispatch(rpc_connection_t *connection)
|
|||
int32_t msg_tag;
|
||||
int error = rpc_message_recv_int32(&message, &msg_tag);
|
||||
if (error != RPC_ERROR_NO_ERROR)
|
||||
return error;
|
||||
return rpc_error(connection, error);
|
||||
if (msg_tag != RPC_MESSAGE_START)
|
||||
return RPC_ERROR_MESSAGE_TYPE_INVALID;
|
||||
return rpc_error(connection, RPC_ERROR_MESSAGE_TYPE_INVALID);
|
||||
|
||||
return _rpc_dispatch(connection, &message);
|
||||
int method = _rpc_dispatch(connection, &message);
|
||||
if (method < 0)
|
||||
return rpc_error(connection, method);
|
||||
return method;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1357,48 +1521,34 @@ int rpc_dispatch(rpc_connection_t *connection)
|
|||
/* ====================================================================== */
|
||||
|
||||
// Add a user-defined method callback (server side)
|
||||
static int rpc_method_add_callback(rpc_connection_t *connection, const rpc_method_descriptor_t *desc)
|
||||
int rpc_connection_add_method_descriptor(rpc_connection_t *connection, const rpc_method_descriptor_t *idesc)
|
||||
{
|
||||
const int N_ENTRIES_ALLOC = 8;
|
||||
int i;
|
||||
D(bug("rpc_connection_add_method_descriptor for method %d\n", idesc->id));
|
||||
|
||||
// pre-allocate up to N_ENTRIES_ALLOC entries
|
||||
if (connection->callbacks == NULL) {
|
||||
if ((connection->callbacks = (rpc_method_descriptor_t *)calloc(N_ENTRIES_ALLOC, sizeof(connection->callbacks[0]))) == NULL)
|
||||
return RPC_ERROR_NO_MEMORY;
|
||||
connection->n_callbacks = N_ENTRIES_ALLOC;
|
||||
if (connection == NULL)
|
||||
return RPC_ERROR_CONNECTION_NULL;
|
||||
|
||||
rpc_method_callback_t callback;
|
||||
if ((callback = (rpc_method_callback_t)rpc_map_lookup(connection->methods, idesc->id)) != NULL) {
|
||||
if (callback == idesc->callback)
|
||||
return RPC_ERROR_NO_ERROR;
|
||||
fprintf(stderr, "duplicate method %d\n", idesc->id);
|
||||
return RPC_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
// look for a free slot
|
||||
for (i = connection->n_callbacks - 1; i >= 0; i--) {
|
||||
if (connection->callbacks[i].callback == NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
// none found, reallocate
|
||||
if (i < 0) {
|
||||
if ((connection->callbacks = (rpc_method_descriptor_t *)realloc(connection->callbacks, (connection->n_callbacks + N_ENTRIES_ALLOC) * sizeof(connection->callbacks[0]))) == NULL)
|
||||
return RPC_ERROR_NO_MEMORY;
|
||||
i = connection->n_callbacks;
|
||||
memset(&connection->callbacks[i], 0, N_ENTRIES_ALLOC * sizeof(connection->callbacks[0]));
|
||||
connection->n_callbacks += N_ENTRIES_ALLOC;
|
||||
}
|
||||
|
||||
D(bug("rpc_method_add_callback for method %d in slot %d\n", desc->id, i));
|
||||
connection->callbacks[i] = *desc;
|
||||
return RPC_ERROR_NO_ERROR;
|
||||
return rpc_map_insert(connection->methods, idesc->id, (void *)idesc->callback);
|
||||
}
|
||||
|
||||
// Add user-defined method callbacks (server side)
|
||||
int rpc_method_add_callbacks(rpc_connection_t *connection, const rpc_method_descriptor_t *descs, int n_descs)
|
||||
int rpc_connection_add_method_descriptors(rpc_connection_t *connection, const rpc_method_descriptor_t *descs, int n_descs)
|
||||
{
|
||||
D(bug("rpc_method_add_callbacks\n"));
|
||||
D(bug("rpc_connection_add_method_descriptors\n"));
|
||||
|
||||
if (connection == NULL)
|
||||
return RPC_ERROR_CONNECTION_NULL;
|
||||
|
||||
while (--n_descs >= 0) {
|
||||
int error = rpc_method_add_callback(connection, &descs[n_descs]);
|
||||
int error = rpc_connection_add_method_descriptor(connection, &descs[n_descs]);
|
||||
if (error != RPC_ERROR_NO_ERROR)
|
||||
return error;
|
||||
}
|
||||
|
@ -1407,33 +1557,26 @@ int rpc_method_add_callbacks(rpc_connection_t *connection, const rpc_method_desc
|
|||
}
|
||||
|
||||
// Remove a user-defined method callback (common code)
|
||||
int rpc_method_remove_callback_id(rpc_connection_t *connection, int id)
|
||||
int rpc_connection_remove_method_descriptor(rpc_connection_t *connection, int id)
|
||||
{
|
||||
D(bug("rpc_method_remove_callback_id\n"));
|
||||
|
||||
if (connection->callbacks) {
|
||||
int i;
|
||||
for (i = 0; i < connection->n_callbacks; i++) {
|
||||
if (connection->callbacks[i].id == id) {
|
||||
connection->callbacks[i].callback = NULL;
|
||||
return RPC_ERROR_NO_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return RPC_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
// Remove user-defined method callbacks (server side)
|
||||
int rpc_method_remove_callbacks(rpc_connection_t *connection, const rpc_method_descriptor_t *callbacks, int n_callbacks)
|
||||
{
|
||||
D(bug("rpc_method_remove_callbacks\n"));
|
||||
D(bug("rpc_connection_remove_method_descriptor\n"));
|
||||
|
||||
if (connection == NULL)
|
||||
return RPC_ERROR_CONNECTION_NULL;
|
||||
|
||||
while (--n_callbacks >= 0) {
|
||||
int error = rpc_method_remove_callback_id(connection, callbacks[n_callbacks].id);
|
||||
return rpc_map_remove(connection->methods, id);
|
||||
}
|
||||
|
||||
// Remove user-defined method callbacks (server side)
|
||||
int rpc_connection_remove_method_descriptors(rpc_connection_t *connection, const rpc_method_descriptor_t *descs, int n_descs)
|
||||
{
|
||||
D(bug("rpc_connection_remove_method_descriptors\n"));
|
||||
|
||||
if (connection == NULL)
|
||||
return RPC_ERROR_CONNECTION_NULL;
|
||||
|
||||
while (--n_descs >= 0) {
|
||||
int error = rpc_connection_remove_method_descriptor(connection, descs[n_descs].id);
|
||||
if (error != RPC_ERROR_NO_ERROR)
|
||||
return error;
|
||||
}
|
||||
|
@ -1453,6 +1596,8 @@ int rpc_method_invoke(rpc_connection_t *connection, int method, ...)
|
|||
|
||||
if (connection == NULL)
|
||||
return RPC_ERROR_CONNECTION_NULL;
|
||||
if (_rpc_status(connection) == RPC_STATUS_CLOSED)
|
||||
return RPC_ERROR_CONNECTION_CLOSED;
|
||||
|
||||
rpc_message_t message;
|
||||
rpc_message_init(&message, connection);
|
||||
|
@ -1469,24 +1614,24 @@ int rpc_method_invoke(rpc_connection_t *connection, int method, ...)
|
|||
// send: <invoke> = MESSAGE_START <method-id> MESSAGE_END
|
||||
int error = rpc_message_send_int32(&message, RPC_MESSAGE_START);
|
||||
if (error != RPC_ERROR_NO_ERROR)
|
||||
return error;
|
||||
return rpc_error(connection, error);
|
||||
error = rpc_message_send_int32(&message, method);
|
||||
if (error != RPC_ERROR_NO_ERROR)
|
||||
return error;
|
||||
return rpc_error(connection, error);
|
||||
error = rpc_message_send_int32(&message, RPC_MESSAGE_END);
|
||||
if (error != RPC_ERROR_NO_ERROR)
|
||||
return error;
|
||||
return rpc_error(connection, error);
|
||||
error = rpc_message_flush(&message);
|
||||
if (error != RPC_ERROR_NO_ERROR)
|
||||
return error;
|
||||
return rpc_error(connection, error);
|
||||
|
||||
// wait: MESSAGE_ACK
|
||||
int32_t msg_tag;
|
||||
error = rpc_message_recv_int32(&message, &msg_tag);
|
||||
if (error != RPC_ERROR_NO_ERROR)
|
||||
return error;
|
||||
return rpc_error(connection, error);
|
||||
if (msg_tag != RPC_MESSAGE_ACK)
|
||||
return RPC_ERROR_MESSAGE_TYPE_INVALID;
|
||||
return rpc_error(connection, RPC_ERROR_MESSAGE_TYPE_INVALID);
|
||||
|
||||
// send optional arguments
|
||||
va_list args;
|
||||
|
@ -1500,19 +1645,19 @@ int rpc_method_invoke(rpc_connection_t *connection, int method, ...)
|
|||
error = rpc_message_send_args(&message, args);
|
||||
va_end(args);
|
||||
if (error != RPC_ERROR_NO_ERROR)
|
||||
return error;
|
||||
return rpc_error(connection, error);
|
||||
error = rpc_message_flush(&message);
|
||||
if (error != RPC_ERROR_NO_ERROR)
|
||||
return error;
|
||||
return rpc_error(connection, error);
|
||||
|
||||
// wait: MESSAGE_ACK
|
||||
error = rpc_message_recv_int32(&message, &msg_tag);
|
||||
if (error != RPC_ERROR_NO_ERROR)
|
||||
return error;
|
||||
return rpc_error(connection, error);
|
||||
if (msg_tag != RPC_MESSAGE_ACK)
|
||||
return RPC_ERROR_MESSAGE_TYPE_INVALID;
|
||||
return rpc_error(connection, RPC_ERROR_MESSAGE_TYPE_INVALID);
|
||||
}
|
||||
|
||||
|
||||
return RPC_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
|
@ -1523,6 +1668,8 @@ int rpc_method_get_args(rpc_connection_t *connection, ...)
|
|||
|
||||
if (connection == NULL)
|
||||
return RPC_ERROR_CONNECTION_NULL;
|
||||
if (_rpc_status(connection) == RPC_STATUS_CLOSED)
|
||||
return RPC_ERROR_CONNECTION_CLOSED;
|
||||
|
||||
rpc_message_t message;
|
||||
rpc_message_init(&message, connection);
|
||||
|
@ -1533,15 +1680,15 @@ int rpc_method_get_args(rpc_connection_t *connection, ...)
|
|||
int error = rpc_message_recv_args(&message, args);
|
||||
va_end(args);
|
||||
if (error != RPC_ERROR_NO_ERROR)
|
||||
return error;
|
||||
return rpc_error(connection, error);
|
||||
|
||||
// send: MESSAGE_ACK
|
||||
error = rpc_message_send_int32(&message, RPC_MESSAGE_ACK);
|
||||
if (error != RPC_ERROR_NO_ERROR)
|
||||
return error;
|
||||
return rpc_error(connection, error);
|
||||
error = rpc_message_flush(&message);
|
||||
if (error != RPC_ERROR_NO_ERROR)
|
||||
return error;
|
||||
return rpc_error(connection, error);
|
||||
|
||||
return RPC_ERROR_NO_ERROR;
|
||||
}
|
||||
|
@ -1551,17 +1698,14 @@ int rpc_method_wait_for_reply(rpc_connection_t *connection, ...)
|
|||
{
|
||||
D(bug("rpc_method_wait_for_reply\n"));
|
||||
|
||||
int error, type;
|
||||
va_list args;
|
||||
rpc_message_t message;
|
||||
|
||||
if (connection == NULL)
|
||||
return RPC_ERROR_CONNECTION_NULL;
|
||||
if (_rpc_status(connection) == RPC_STATUS_CLOSED)
|
||||
return RPC_ERROR_CONNECTION_CLOSED;
|
||||
|
||||
int error;
|
||||
rpc_message_t message;
|
||||
rpc_message_init(&message, connection);
|
||||
va_start(args, connection);
|
||||
type = va_arg(args, int);
|
||||
va_end(args);
|
||||
|
||||
// call: rpc_dispatch() (pending remote calls)
|
||||
int32_t msg_tag;
|
||||
|
@ -1569,11 +1713,11 @@ int rpc_method_wait_for_reply(rpc_connection_t *connection, ...)
|
|||
while (!done) {
|
||||
error = rpc_message_recv_int32(&message, &msg_tag);
|
||||
if (error != RPC_ERROR_NO_ERROR)
|
||||
return error;
|
||||
return rpc_error(connection, error);
|
||||
switch (msg_tag) {
|
||||
case RPC_MESSAGE_START:
|
||||
if ((error = _rpc_dispatch(connection, &message)) < 0)
|
||||
return error;
|
||||
return rpc_error(connection, error);
|
||||
break;
|
||||
case RPC_MESSAGE_REPLY:
|
||||
case RPC_MESSAGE_ACK:
|
||||
|
@ -1585,47 +1729,53 @@ int rpc_method_wait_for_reply(rpc_connection_t *connection, ...)
|
|||
int32_t error_code;
|
||||
error = rpc_message_recv_int32(&message, &error_code);
|
||||
if (error != RPC_ERROR_NO_ERROR)
|
||||
return error;
|
||||
return error_code;
|
||||
return rpc_error(connection, error);
|
||||
// return other-side error code
|
||||
return rpc_error(connection, error_code);
|
||||
}
|
||||
default:
|
||||
return RPC_ERROR_MESSAGE_TYPE_INVALID;
|
||||
return rpc_error(connection, RPC_ERROR_MESSAGE_TYPE_INVALID);
|
||||
}
|
||||
}
|
||||
|
||||
va_list args;
|
||||
va_start(args, connection);
|
||||
int type = va_arg(args, int);
|
||||
va_end(args);
|
||||
|
||||
if (type != RPC_TYPE_INVALID) {
|
||||
|
||||
// wait: <reply>
|
||||
if (msg_tag != RPC_MESSAGE_REPLY)
|
||||
return RPC_ERROR_MESSAGE_TYPE_INVALID;
|
||||
return rpc_error(connection, RPC_ERROR_MESSAGE_TYPE_INVALID);
|
||||
va_start(args, connection);
|
||||
error = rpc_message_recv_args(&message, args);
|
||||
va_end(args);
|
||||
if (error != RPC_ERROR_NO_ERROR)
|
||||
return error;
|
||||
return rpc_error(connection, error);
|
||||
error = rpc_message_recv_int32(&message, &msg_tag);
|
||||
if (error != RPC_ERROR_NO_ERROR)
|
||||
return error;
|
||||
return rpc_error(connection, error);
|
||||
if (msg_tag != RPC_MESSAGE_END)
|
||||
return RPC_ERROR_MESSAGE_TYPE_INVALID;
|
||||
return rpc_error(connection, RPC_ERROR_MESSAGE_TYPE_INVALID);
|
||||
|
||||
// send: MESSAGE_ACK
|
||||
error = rpc_message_send_int32(&message, RPC_MESSAGE_ACK);
|
||||
if (error != RPC_ERROR_NO_ERROR)
|
||||
return error;
|
||||
return rpc_error(connection, error);
|
||||
error = rpc_message_flush(&message);
|
||||
if (error != RPC_ERROR_NO_ERROR)
|
||||
return error;
|
||||
return rpc_error(connection, error);
|
||||
|
||||
// wait: MESSAGE_ACK (prepare for final ACK)
|
||||
error = rpc_message_recv_int32(&message, &msg_tag);
|
||||
if (error != RPC_ERROR_NO_ERROR)
|
||||
return error;
|
||||
return rpc_error(connection, error);
|
||||
}
|
||||
|
||||
// wait: MESSAGE_ACK
|
||||
if (msg_tag != RPC_MESSAGE_ACK)
|
||||
return RPC_ERROR_MESSAGE_TYPE_INVALID;
|
||||
return rpc_error(connection, RPC_ERROR_MESSAGE_TYPE_INVALID);
|
||||
|
||||
return RPC_ERROR_NO_ERROR;
|
||||
}
|
||||
|
@ -1636,7 +1786,9 @@ int rpc_method_send_reply(rpc_connection_t *connection, ...)
|
|||
D(bug("rpc_method_send_reply\n"));
|
||||
|
||||
if (connection == NULL)
|
||||
return RPC_ERROR_GENERIC;
|
||||
return RPC_ERROR_CONNECTION_NULL;
|
||||
if (_rpc_status(connection) == RPC_STATUS_CLOSED)
|
||||
return RPC_ERROR_CONNECTION_CLOSED;
|
||||
|
||||
rpc_message_t message;
|
||||
rpc_message_init(&message, connection);
|
||||
|
@ -1644,27 +1796,27 @@ int rpc_method_send_reply(rpc_connection_t *connection, ...)
|
|||
// send: <reply> = MESSAGE_REPLY [ <method-args> ] MESSAGE_END
|
||||
int error = rpc_message_send_int32(&message, RPC_MESSAGE_REPLY);
|
||||
if (error != RPC_ERROR_NO_ERROR)
|
||||
return error;
|
||||
return rpc_error(connection, error);
|
||||
va_list args;
|
||||
va_start(args, connection);
|
||||
error = rpc_message_send_args(&message, args);
|
||||
va_end(args);
|
||||
if (error != RPC_ERROR_NO_ERROR)
|
||||
return error;
|
||||
return rpc_error(connection, error);
|
||||
error = rpc_message_send_int32(&message, RPC_MESSAGE_END);
|
||||
if (error != RPC_ERROR_NO_ERROR)
|
||||
return error;
|
||||
return rpc_error(connection, error);
|
||||
error = rpc_message_flush(&message);
|
||||
if (error != RPC_ERROR_NO_ERROR)
|
||||
return error;
|
||||
return rpc_error(connection, error);
|
||||
|
||||
// wait: MESSAGE_ACK
|
||||
int32_t msg_tag;
|
||||
error = rpc_message_recv_int32(&message, &msg_tag);
|
||||
if (error != RPC_ERROR_NO_ERROR)
|
||||
return error;
|
||||
return rpc_error(connection, error);
|
||||
if (msg_tag != RPC_MESSAGE_ACK)
|
||||
return RPC_ERROR_MESSAGE_TYPE_INVALID;
|
||||
return rpc_error(connection, RPC_ERROR_MESSAGE_TYPE_INVALID);
|
||||
|
||||
return RPC_ERROR_NO_ERROR;
|
||||
}
|
||||
|
@ -1700,7 +1852,7 @@ static int do_send_point(rpc_message_t *message, void *p_value)
|
|||
{
|
||||
D(bug("do_send_point\n"));
|
||||
|
||||
struct Point *pt = p_value;
|
||||
struct Point *pt = (struct Point *)p_value;
|
||||
int error;
|
||||
|
||||
if ((error = rpc_message_send_int32(message, pt->x)) < 0)
|
||||
|
@ -1714,7 +1866,7 @@ static int do_recv_point(rpc_message_t *message, void *p_value)
|
|||
{
|
||||
D(bug("do_recv_point\n"));
|
||||
|
||||
struct Point *pt = p_value;
|
||||
struct Point *pt = (struct Point *)p_value;
|
||||
int error;
|
||||
int32_t value;
|
||||
|
||||
|
@ -1880,22 +2032,27 @@ static int run_server(void)
|
|||
g_server_pid = getpid();
|
||||
printf("Server PID: %d\n", g_server_pid);
|
||||
|
||||
if (rpc_message_add_callbacks(&point_desc, 1) < 0) {
|
||||
fprintf(stderr, "ERROR: failed to add Point marshaler\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((connection = rpc_init_server(g_npn_connection_path)) == NULL) {
|
||||
fprintf(stderr, "ERROR: failed to initialize RPC server connection to NPN\n");
|
||||
return 0;
|
||||
}
|
||||
g_npn_connection = connection;
|
||||
|
||||
if (rpc_connection_add_message_descriptors(g_npn_connection, &point_desc, 1) < 0) {
|
||||
fprintf(stderr, "ERROR: failed to add server-side Point marshaler\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((g_npp_connection = rpc_init_client(g_npp_connection_path)) == NULL) {
|
||||
fprintf(stderr, "ERROR: failed to initialize RPC server connection to NPP\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (rpc_connection_add_message_descriptors(g_npp_connection, &point_desc, 1) < 0) {
|
||||
fprintf(stderr, "ERROR: failed to add client-side Point marshaler\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const rpc_method_descriptor_t vtable1[] = {
|
||||
{ TEST_RPC_METHOD_ADD, handle_ADD },
|
||||
{ TEST_RPC_METHOD_ECHO, handle_ECHO },
|
||||
|
@ -1903,11 +2060,11 @@ static int run_server(void)
|
|||
{ TEST_RPC_METHOD_PID, handle_server_PID },
|
||||
{ TEST_RPC_METHOD_EXIT, handle_EXIT },
|
||||
};
|
||||
if (rpc_method_add_callbacks(connection, &vtable1[0], sizeof(vtable1) / sizeof(vtable1[0])) < 0) {
|
||||
if (rpc_connection_add_method_descriptors(connection, vtable1, sizeof(vtable1) / sizeof(vtable1[0])) < 0) {
|
||||
fprintf(stderr, "ERROR: failed to setup method callbacks\n");
|
||||
return 0;
|
||||
}
|
||||
if (rpc_method_remove_callback_id(connection, TEST_RPC_METHOD_PID) < 0) {
|
||||
if (rpc_connection_remove_method_descriptor(connection, TEST_RPC_METHOD_PID) < 0) {
|
||||
fprintf(stderr, "ERROR: failed to remove superfluous callback %d\n", TEST_RPC_METHOD_PID);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1916,7 +2073,7 @@ static int run_server(void)
|
|||
{ TEST_RPC_METHOD_STRINGS, handle_STRINGS },
|
||||
{ TEST_RPC_METHOD_POINTS, handle_POINTS },
|
||||
};
|
||||
if (rpc_method_add_callbacks(connection, &vtable2[0], sizeof(vtable2) / sizeof(vtable2[0])) < 0) {
|
||||
if (rpc_connection_add_method_descriptors(connection, vtable2, sizeof(vtable2) / sizeof(vtable2[0])) < 0) {
|
||||
fprintf(stderr, "ERROR: failed to setup method callbacks\n");
|
||||
return 0;
|
||||
}
|
||||
|
@ -1943,32 +2100,37 @@ static int run_server(void)
|
|||
static int run_client(void)
|
||||
{
|
||||
rpc_connection_t *connection;
|
||||
int i, error;
|
||||
int error;
|
||||
|
||||
g_client_pid = getpid();
|
||||
printf("Client PID: %d\n", g_client_pid);
|
||||
|
||||
if (rpc_message_add_callbacks(&point_desc, 1) < 0) {
|
||||
fprintf(stderr, "ERROR: failed to add Point marshaler\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((connection = rpc_init_client(g_npn_connection_path)) == NULL) {
|
||||
fprintf(stderr, "ERROR: failed to initialize RPC client connection to NPN\n");
|
||||
return 0;
|
||||
}
|
||||
g_npn_connection = connection;
|
||||
|
||||
if (rpc_connection_add_message_descriptors(g_npn_connection, &point_desc, 1) < 0) {
|
||||
fprintf(stderr, "ERROR: failed to add server-side Point marshaler\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((g_npp_connection = rpc_init_server(g_npp_connection_path)) == NULL) {
|
||||
fprintf(stderr, "ERROR: failed to initialize RPC server connection to NPP\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (rpc_connection_add_message_descriptors(g_npp_connection, &point_desc, 1) < 0) {
|
||||
fprintf(stderr, "ERROR: failed to add client-side Point marshaler\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const rpc_method_descriptor_t vtable[] = {
|
||||
{ TEST_RPC_METHOD_PID, handle_client_PID },
|
||||
{ TEST_RPC_METHOD_EXIT, handle_EXIT },
|
||||
};
|
||||
if (rpc_method_add_callbacks(g_npp_connection, &vtable[0], sizeof(vtable) / sizeof(vtable[0])) < 0) {
|
||||
if (rpc_connection_add_method_descriptors(g_npp_connection, vtable, sizeof(vtable) / sizeof(vtable[0])) < 0) {
|
||||
fprintf(stderr, "ERROR: failed to setup method callbacks\n");
|
||||
return 0;
|
||||
}
|
||||
|
@ -2035,7 +2197,7 @@ static int run_client(void)
|
|||
}
|
||||
printf(" done\n");
|
||||
|
||||
printf("Call STRINGS\n", str);
|
||||
printf("Call STRINGS\n");
|
||||
const char *strtab[] = { "un", "deux", "trois", "quatre" };
|
||||
if ((error = rpc_method_invoke(connection, TEST_RPC_METHOD_STRINGS, RPC_TYPE_ARRAY, RPC_TYPE_STRING, 4, strtab, RPC_TYPE_INVALID)) < 0) {
|
||||
fprintf(stderr, "ERROR: failed to send STRINGS message [%d]\n", error);
|
||||
|
@ -2047,7 +2209,7 @@ static int run_client(void)
|
|||
}
|
||||
printf(" done\n");
|
||||
|
||||
printf("Call POINTS\n", str);
|
||||
printf("Call POINTS\n");
|
||||
const struct Point pttab[] = {
|
||||
{ -1, 0 },
|
||||
{ 2, -1 },
|
||||
|
|
29
src/rpc.h
29
src/rpc.h
|
@ -21,6 +21,10 @@
|
|||
#ifndef RPC_H
|
||||
#define RPC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Error Types
|
||||
enum {
|
||||
RPC_ERROR_NO_ERROR = 0,
|
||||
|
@ -41,7 +45,10 @@ enum {
|
|||
extern const char *rpc_strerror(int error) attribute_hidden;
|
||||
|
||||
// Connection Handling
|
||||
typedef struct rpc_connection_t rpc_connection_t;
|
||||
typedef struct rpc_connection rpc_connection_t;
|
||||
extern rpc_connection_t *rpc_connection_ref(rpc_connection_t *connection) attribute_hidden;
|
||||
extern void rpc_connection_unref(rpc_connection_t *connection) attribute_hidden;
|
||||
|
||||
extern rpc_connection_t *rpc_init_server(const char *ident) attribute_hidden;
|
||||
extern rpc_connection_t *rpc_init_client(const char *ident) attribute_hidden;
|
||||
extern int rpc_exit(rpc_connection_t *connection) attribute_hidden;
|
||||
|
@ -51,6 +58,13 @@ extern int rpc_dispatch(rpc_connection_t *connection) attribute_hidden;
|
|||
extern int rpc_wait_dispatch(rpc_connection_t *connection, int timeout) attribute_hidden;
|
||||
extern int rpc_socket(rpc_connection_t *connection) attribute_hidden;
|
||||
|
||||
enum {
|
||||
RPC_STATUS_BROKEN = -1,
|
||||
RPC_STATUS_CLOSED = 0,
|
||||
RPC_STATUS_ACTIVE = 1,
|
||||
};
|
||||
extern int rpc_status(rpc_connection_t *connection) attribute_hidden;
|
||||
|
||||
// Message Passing
|
||||
enum {
|
||||
RPC_TYPE_INVALID = 0,
|
||||
|
@ -78,6 +92,7 @@ extern int rpc_message_recv_uint64(rpc_message_t *message, uint64_t *ret) attrib
|
|||
extern int rpc_message_recv_double(rpc_message_t *message, double *ret) attribute_hidden;
|
||||
extern int rpc_message_recv_string(rpc_message_t *message, char **ret) attribute_hidden;
|
||||
extern int rpc_message_recv_bytes(rpc_message_t *message, unsigned char *bytes, int count) attribute_hidden;
|
||||
|
||||
typedef int (*rpc_message_callback_t)(rpc_message_t *message, void *p_value);
|
||||
typedef struct {
|
||||
int id;
|
||||
|
@ -85,7 +100,8 @@ typedef struct {
|
|||
rpc_message_callback_t send_callback;
|
||||
rpc_message_callback_t recv_callback;
|
||||
} rpc_message_descriptor_t;
|
||||
extern int rpc_message_add_callbacks(const rpc_message_descriptor_t *descs, int n_descs) attribute_hidden;
|
||||
extern int rpc_connection_add_message_descriptor(rpc_connection_t *connection, const rpc_message_descriptor_t *desc) attribute_hidden;
|
||||
extern int rpc_connection_add_message_descriptors(rpc_connection_t *connection, const rpc_message_descriptor_t *descs, int n_descs) attribute_hidden;
|
||||
|
||||
// Method Callbacks Handling
|
||||
typedef int (*rpc_method_callback_t)(rpc_connection_t *connection);
|
||||
|
@ -93,9 +109,8 @@ typedef struct {
|
|||
int id;
|
||||
rpc_method_callback_t callback;
|
||||
} rpc_method_descriptor_t;
|
||||
extern int rpc_method_add_callbacks(rpc_connection_t *connection, const rpc_method_descriptor_t *descs, int n_descs) attribute_hidden;
|
||||
extern int rpc_method_remove_callback_id(rpc_connection_t *connection, int id) attribute_hidden;
|
||||
extern int rpc_method_remove_callbacks(rpc_connection_t *connection, const rpc_method_descriptor_t *descs, int n_descs) attribute_hidden;
|
||||
extern int rpc_connection_add_method_descriptor(rpc_connection_t *connection, const rpc_method_descriptor_t *desc) attribute_hidden;
|
||||
extern int rpc_connection_add_method_descriptors(rpc_connection_t *connection, const rpc_method_descriptor_t *descs, int n_descs) attribute_hidden;
|
||||
|
||||
// Remote Procedure Call (method invocation)
|
||||
extern int rpc_method_invoke(rpc_connection_t *connection, int method, ...) attribute_hidden;
|
||||
|
@ -103,4 +118,8 @@ extern int rpc_method_wait_for_reply(rpc_connection_t *connection, ...) attribut
|
|||
extern int rpc_method_get_args(rpc_connection_t *connection, ...) attribute_hidden;
|
||||
extern int rpc_method_send_reply(rpc_connection_t *connection, ...) attribute_hidden;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* RPC_H */
|
||||
|
|
|
@ -21,9 +21,11 @@
|
|||
#ifndef SYSDEPS_H
|
||||
#define SYSDEPS_H
|
||||
|
||||
#ifndef __cplusplus
|
||||
#if !defined(__STDC__) || (__STDC_VERSION__ < 199901L)
|
||||
#error "Your compiler is not ISO. Get a real one."
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
|
||||
|
@ -61,6 +63,8 @@ typedef struct __attribute__((packed)) {
|
|||
#define NPW_COMPONENT_NAME "Wrapper"
|
||||
#elif defined(BUILD_VIEWER)
|
||||
#define NPW_COMPONENT_NAME "Viewer "
|
||||
#elif defined(BUILD_PLAYER)
|
||||
#define NPW_COMPONENT_NAME "Player "
|
||||
#endif
|
||||
|
||||
// Boolean types
|
||||
|
|
|
@ -21,6 +21,10 @@
|
|||
#ifndef UTILS_H
|
||||
#define UTILS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Hashes
|
||||
extern bool id_init(void) attribute_hidden;
|
||||
extern void id_kill(void) attribute_hidden;
|
||||
|
@ -39,4 +43,8 @@ extern const char *string_of_NPStreamType(int stype) attribute_hidden;
|
|||
extern void npw_perror(const char *prefix, int error) attribute_hidden;
|
||||
extern const char *npw_strerror(int error) attribute_hidden;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* UTILS_H */
|
||||
|
|
Loading…
Reference in New Issue