nspluginwrapper-1.1.0

Taken from Ubuntu orig.tar.gz file.
This commit is contained in:
David Benjamin 2011-03-05 22:24:52 -05:00
parent e9ae927da7
commit 10bbf2f098
26 changed files with 5940 additions and 660 deletions

515
ChangeLog
View File

@ -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

View File

@ -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
View File

@ -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
View File

@ -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
View File

@ -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)

46
configure vendored
View File

@ -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

View File

@ -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" */

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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 */

546
src/glibcurl.c Normal file
View File

@ -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

82
src/glibcurl.h Normal file
View File

@ -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

View File

@ -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;
}

View File

@ -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>

35
src/libnoxshm.c Normal file
View File

@ -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);
}

2643
src/npw-player.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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]));
}

View File

@ -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 */

View File

@ -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;

View File

@ -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"

View File

@ -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
View File

@ -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 },

View File

@ -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 */

View File

@ -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

View File

@ -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 */