2
* npw-viewer.c - Target plugin loader and viewer
4
* nspluginwrapper (C) 2005-2007 Gwenole Beauchesne
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
#define _GNU_SOURCE 1 /* RTLD_NEXT */
34
#include <X11/Xutil.h>
35
#include <X11/Intrinsic.h>
36
#include <X11/Shell.h>
37
#include <X11/StringDefs.h>
38
#include <X11/extensions/XShm.h>
51
#include "npruntime-impl.h"
57
// [UNIMPLEMENTED] Define to use XPCOM emulation
60
// Define to use XEMBED
63
// XXX define which widget to use
64
#define USE_GTK_TOOLKIT 1
65
#define USE_X11_TOOLKIT 0
67
// XXX unimplemented functions
68
#define UNIMPLEMENTED() npw_printf("WARNING: Unimplemented function %s at line %d\n", __func__, __LINE__)
71
// RPC global connections
72
rpc_connection_t *g_rpc_connection attribute_hidden = NULL;
74
// Instance state information about the plugin
75
typedef struct _PluginInstance {
80
uint32_t width, height;
83
Window old_focus_window;
85
GtkWidget *top_window;
93
// Browser side data for an NPStream instance
94
typedef struct _StreamInstance {
100
/* ====================================================================== */
101
/* === X Toolkit glue === */
102
/* ====================================================================== */
104
static Display *x_display;
105
static XtAppContext x_app_context;
107
typedef struct _XtTMRec {
108
XtTranslations translations; /* private to Translation Manager */
109
XtBoundActions proc_table; /* procedure bindings for actions */
110
struct _XtStateRec *current_state; /* Translation Manager state ptr */
111
unsigned long lastEventTime;
114
typedef struct _CorePart {
115
Widget self; /* pointer to widget itself */
116
WidgetClass widget_class; /* pointer to Widget's ClassRec */
117
Widget parent; /* parent widget */
118
XrmName xrm_name; /* widget resource name quarkified */
119
Boolean being_destroyed; /* marked for destroy */
120
XtCallbackList destroy_callbacks; /* who to call when widget destroyed */
121
XtPointer constraints; /* constraint record */
122
Position x, y; /* window position */
123
Dimension width, height; /* window dimensions */
124
Dimension border_width; /* window border width */
125
Boolean managed; /* is widget geometry managed? */
126
Boolean sensitive; /* is widget sensitive to user events*/
127
Boolean ancestor_sensitive; /* are all ancestors sensitive? */
128
XtEventTable event_table; /* private to event dispatcher */
129
XtTMRec tm; /* translation management */
130
XtTranslations accelerators; /* accelerator translations */
131
Pixel border_pixel; /* window border pixel */
132
Pixmap border_pixmap; /* window border pixmap or NULL */
133
WidgetList popup_list; /* list of popups */
134
Cardinal num_popups; /* how many popups */
135
String name; /* widget resource name */
136
Screen *screen; /* window's screen */
137
Colormap colormap; /* colormap */
138
Window window; /* window ID */
139
Cardinal depth; /* number of planes in window */
140
Pixel background_pixel; /* window background pixel */
141
Pixmap background_pixmap; /* window background pixmap or NULL */
142
Boolean visible; /* is window mapped and not occluded?*/
143
Boolean mapped_when_managed;/* map window if it's managed? */
146
typedef struct _WidgetRec {
148
} WidgetRec, CoreRec;
150
extern void XtResizeWidget(
152
_XtDimension /* width */,
153
_XtDimension /* height */,
154
_XtDimension /* border_width */
157
// Update focus to plugin window
158
// XXX I am not convinced this is the really corrent...
159
static void xt_client_focus_listener(Widget w, XtPointer user_data, XEvent *event, Boolean *cont)
161
PluginInstance *plugin = (PluginInstance *)user_data;
163
switch (event->type) {
165
if (plugin->focus_window != XtWindow(plugin->form)) {
166
XSetInputFocus(x_display, XtWindow(plugin->form), RevertToParent, event->xbutton.time);
167
plugin->focus_window = XtWindow(plugin->form);
168
XSync(x_display, False);
172
if (plugin->old_focus_window && plugin->focus_window != plugin->old_focus_window) {
173
XSetInputFocus(x_display, plugin->old_focus_window, RevertToParent, event->xcrossing.time);
174
plugin->focus_window = plugin->old_focus_window;
175
XSync(x_display, False);
182
/* ====================================================================== */
183
/* === XPCOM glue === */
184
/* ====================================================================== */
186
#if defined(__GNUC__) && (__GNUC__ > 2)
187
#define NS_LIKELY(x) (__builtin_expect((x), 1))
188
#define NS_UNLIKELY(x) (__builtin_expect((x), 0))
190
#define NS_LIKELY(x) (x)
191
#define NS_UNLIKELY(x) (x)
194
#define NS_FAILED(_nsresult) (NS_UNLIKELY((_nsresult) & 0x80000000))
195
#define NS_SUCCEEDED(_nsresult) (NS_LIKELY(!((_nsresult) & 0x80000000)))
197
typedef uint32 nsresult;
198
typedef struct nsIServiceManager nsIServiceManager;
199
extern nsresult NS_GetServiceManager(nsIServiceManager **result);
202
/* ====================================================================== */
203
/* === Window utilities === */
204
/* ====================================================================== */
206
// Reconstruct window attributes
207
static int create_window_attributes(NPWindow *window)
209
if (window == NULL || window->window == NULL)
211
if (window->ws_info == NULL) {
212
if ((window->ws_info = malloc(sizeof(NPSetWindowCallbackStruct))) == NULL) {
213
npw_printf("ERROR: could not allocate window attributes for NPWindow %p\n", window->window);
217
NPSetWindowCallbackStruct *ws_info = window->ws_info;
218
ws_info->type = 0; // should be NP_SETWINDOW but Mozilla sets it to 0
219
ws_info->display = x_display;
220
XWindowAttributes win_attr;
221
if (!XGetWindowAttributes(ws_info->display, (Window)window->window, &win_attr)) {
222
npw_printf("ERROR: could not reconstruct window attributes from NPWindow\n");
225
ws_info->visual = win_attr.visual;
226
ws_info->colormap = win_attr.colormap;
227
ws_info->depth = win_attr.depth;
231
// Destroy window attributes struct
232
static void destroy_window_attributes(NPWindow *window)
236
if (window->ws_info) {
237
free(window->ws_info);
238
window->ws_info = NULL;
242
// Fix size hints in NPWindow (Flash Player doesn't like null width)
243
static void fixup_size_hints(PluginInstance *plugin)
245
NPWindow *window = &plugin->window;
247
// check global hints (got through EMBED plugin args)
248
if (window->width == 0 || window->height == 0) {
249
if (plugin->width && plugin->height) {
250
window->width = plugin->width;
251
window->height = plugin->height;
256
// check actual window size and commit back to plugin data
257
if (window->width == 0 || window->height == 0) {
258
XWindowAttributes win_attr;
259
if (XGetWindowAttributes(x_display, (Window)window->window, &win_attr)) {
260
plugin->width = window->width = win_attr.width;
261
plugin->height = window->height = win_attr.height;
266
if (window->width == 0 || window->height == 0)
267
npw_printf("WARNING: grmpf, despite much effort, I could not determine the actual plugin area size...\n");
270
// Create a new window from NPWindow
271
static int create_window(PluginInstance *plugin, NPWindow *window)
273
// cache new window information
274
// XXX destroy previous window here?
275
memcpy(&plugin->window, window, sizeof(*window));
276
window = &plugin->window;
277
fixup_size_hints(plugin);
279
// reconstruct window attributes
280
if (create_window_attributes(window) < 0)
282
NPSetWindowCallbackStruct *ws_info = window->ws_info;
284
// create the new window
285
if (plugin->use_xembed)
288
plugin->top_window = gtk_plug_new(0);
289
gtk_window_resize(GTK_WINDOW(plugin->top_window), plugin->width, plugin->height);
290
gtk_widget_set_size_request(plugin->top_window, window->width, window->height);
291
gtk_widget_show(plugin->top_window);
293
GdkDrawable *win = GDK_DRAWABLE(plugin->top_window->window);
294
XReparentWindow(GDK_DRAWABLE_XDISPLAY(win),
295
GDK_DRAWABLE_XID(win),
296
(Window)window->window, 0, 0);
298
XMapWindow(GDK_DRAWABLE_XDISPLAY(win),
299
GDK_DRAWABLE_XID(win));
302
XSetWindowAttributes attr;
303
attr.bit_gravity = NorthWestGravity;
304
attr.colormap = ws_info->colormap;
314
StructureNotifyMask |
315
VisibilityChangeMask |
319
unsigned long mask = CWBitGravity | CWEventMask;
323
plugin->top_window = XCreateWindow(x_display, (Window)window->window,
324
0, 0, window->width, window->height,
325
0, ws_info->depth, InputOutput, ws_info->visual, mask, &attr);
327
XSelectInput(x_display, plugin->top_window, ExposureMask);
329
XMapWindow(x_display, plugin->top_window);
333
Widget top_widget = XtAppCreateShell("drawingArea", "npw-viewer", applicationShellWidgetClass, x_display, NULL, 0);
334
plugin->top_widget = top_widget;
335
XtResizeWidget(top_widget, window->width, window->height, 0);
337
Widget form = XtVaCreateWidget("form", compositeWidgetClass, top_widget,
338
XtNdepth, ws_info->depth,
339
XtNvisual, ws_info->visual,
340
XtNcolormap, ws_info->colormap,
343
XtResizeWidget(form, window->width, window->height, 0);
346
plugin->old_window = top_widget->core.window;
347
top_widget->core.window = GDK_WINDOW_XWINDOW(plugin->top_window->window);
348
XtRegisterDrawable(x_display, GDK_WINDOW_XWINDOW(plugin->top_window->window), top_widget);
350
plugin->old_window = top_widget->core.window;
351
top_widget->core.window = plugin->top_window;
352
XtRegisterDrawable(x_display, plugin->top_window, top_widget);
355
XtRealizeWidget(form);
359
plugin->old_focus_window = None;
360
XGetInputFocus(x_display, &plugin->old_focus_window, &revert_to);
361
XtAddEventHandler(form, (LeaveWindowMask | ButtonReleaseMask), True, xt_client_focus_listener, plugin);
362
plugin->focus_window = plugin->old_focus_window;
363
XSync(x_display, False);
365
window->window = (void *)XtWindow(form);
369
// Update window information from NPWindow
370
static int update_window(PluginInstance *plugin, NPWindow *window)
372
if (plugin->window.width != window->width || plugin->window.height != window->height) {
373
plugin->window.width = window->width;
374
plugin->window.height = window->height;
376
XtResizeWidget(plugin->form, plugin->window.width, plugin->window.height, 0);
377
if (plugin->top_widget)
378
XtResizeWidget(plugin->top_widget, plugin->window.width, plugin->window.height, 0);
384
static void destroy_window(PluginInstance *plugin)
386
if (plugin->old_focus_window) {
387
XtRemoveEventHandler(plugin->form, (LeaveWindowMask | ButtonReleaseMask), True, xt_client_focus_listener, plugin);
388
plugin->old_focus_window = None;
391
if (plugin->top_widget) {
392
XSync(x_display, False);
394
XtUnregisterDrawable(x_display, GDK_WINDOW_XWINDOW(plugin->top_window->window));
396
XtUnregisterDrawable(x_display, plugin->top_window);
398
XSync(x_display, False);
399
plugin->top_widget->core.window = plugin->old_window;
400
XtUnrealizeWidget(plugin->top_widget);
401
XtDestroyWidget(plugin->top_widget);
402
XSync(x_display, False);
403
plugin->top_widget = NULL;
406
if (plugin->top_window) {
408
gtk_widget_destroy((GtkWidget *)plugin->top_window);
409
plugin->top_window = NULL;
411
XDestroyWindow(x_display, plugin->top_window);
412
plugin->top_window = None;
414
XSync(x_display, False);
417
destroy_window_attributes(&plugin->window);
421
/* ====================================================================== */
422
/* === Browser side plug-in API === */
423
/* ====================================================================== */
425
static char *g_user_agent = NULL;
427
// Netscape exported functions
428
static NPNetscapeFuncs mozilla_funcs;
430
// Closes and deletes a stream
432
g_NPN_DestroyStream(NPP instance, NPStream *stream, NPError reason)
434
D(bug("NPN_DestroyStream instance=%p\n", instance));
438
return NPERR_GENERIC_ERROR;
441
// Forces a repaint message for a windowless plug-in
443
g_NPN_ForceRedraw(NPP instance)
445
D(bug("NPN_ForceRedraw instance=%p\n", instance));
450
// Asks the browser to create a stream for the specified URL
452
invoke_NPN_GetURL(NPP instance, const char *url, const char *target)
454
int error = rpc_method_invoke(g_rpc_connection,
455
RPC_METHOD_NPN_GET_URL,
456
RPC_TYPE_NPP, instance,
457
RPC_TYPE_STRING, url,
458
RPC_TYPE_STRING, target,
461
if (error != RPC_ERROR_NO_ERROR) {
462
npw_perror("NPN_GetURL() invoke", error);
463
return NPERR_GENERIC_ERROR;
467
error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_INT32, &ret, RPC_TYPE_INVALID);
469
if (error != RPC_ERROR_NO_ERROR) {
470
npw_perror("NPN_GetURL() wait for reply", error);
471
return NPERR_GENERIC_ERROR;
478
g_NPN_GetURL(NPP instance, const char *url, const char *target)
480
if (instance == NULL)
481
return NPERR_INVALID_INSTANCE_ERROR;
483
D(bug("NPN_GetURL instance=%p\n", instance));
484
NPError ret = invoke_NPN_GetURL(instance, url, target);
485
D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret)));
489
// Requests creation of a new stream with the contents of the specified URL
491
invoke_NPN_GetURLNotify(NPP instance, const char *url, const char *target, void *notifyData)
493
int error = rpc_method_invoke(g_rpc_connection,
494
RPC_METHOD_NPN_GET_URL_NOTIFY,
495
RPC_TYPE_NPP, instance,
496
RPC_TYPE_STRING, url,
497
RPC_TYPE_STRING, target,
498
RPC_TYPE_NP_NOTIFY_DATA, notifyData,
501
if (error != RPC_ERROR_NO_ERROR) {
502
npw_perror("NPN_GetURLNotify() invoke", error);
503
return NPERR_GENERIC_ERROR;
507
error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_INT32, &ret, RPC_TYPE_INVALID);
509
if (error != RPC_ERROR_NO_ERROR) {
510
npw_perror("NPN_GetURLNotify() wait for reply", error);
511
return NPERR_GENERIC_ERROR;
518
g_NPN_GetURLNotify(NPP instance, const char *url, const char *target, void *notifyData)
520
if (instance == NULL)
521
return NPERR_INVALID_INSTANCE_ERROR;
523
D(bug("NPN_GetURLNotify instance=%p\n", instance));
524
NPError ret = invoke_NPN_GetURLNotify(instance, url, target, notifyData);
525
D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret)));
529
// Allows the plug-in to query the browser for information
531
invoke_NPN_GetValue(NPP instance, NPNVariable variable, void *value)
533
int error = rpc_method_invoke(g_rpc_connection,
534
RPC_METHOD_NPN_GET_VALUE,
535
RPC_TYPE_NPP, instance,
536
RPC_TYPE_UINT32, variable,
539
if (error != RPC_ERROR_NO_ERROR) {
540
npw_perror("NPN_GetValue() invoke", error);
541
return NPERR_GENERIC_ERROR;
545
switch (rpc_type_of_NPNVariable(variable)) {
546
case RPC_TYPE_BOOLEAN:
549
error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_INT32, &ret, RPC_TYPE_BOOLEAN, &b, RPC_TYPE_INVALID);
550
if (error != RPC_ERROR_NO_ERROR) {
551
npw_perror("NPN_GetValue() wait for reply", error);
552
ret = NPERR_GENERIC_ERROR;
554
D(bug(" value: %s\n", b ? "true" : "false"));
555
*((PRBool *)value) = b ? PR_TRUE : PR_FALSE;
558
case RPC_TYPE_NP_OBJECT:
560
NPObject *npobj = NULL;
561
error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_INT32, &ret, RPC_TYPE_NP_OBJECT, &npobj, RPC_TYPE_INVALID);
562
if (error != RPC_ERROR_NO_ERROR) {
563
npw_perror("NPN_GetValue() wait for reply", error);
564
ret = NPERR_GENERIC_ERROR;
566
D(bug(" value: %p\n", npobj));
567
*((NPObject **)value) = npobj;
576
g_NPN_GetValue(NPP instance, NPNVariable variable, void *value)
578
D(bug("NPN_GetValue instance=%p, variable=%d [%08x]\n", instance, variable & 0xffff, variable));
582
*(void **)value = x_display;
584
case NPNVxtAppContext:
585
*(void **)value = XtDisplayToApplicationContext(x_display);
588
*(NPNToolkitType *)value = NPNVGtk2;
591
case NPNVserviceManager: {
592
nsIServiceManager *sm;
593
int ret = NS_GetServiceManager(&sm);
595
return NPERR_GENERIC_ERROR;
596
*(nsIServiceManager **)value = sm;
601
case NPNVSupportsXEmbedBool:
603
case NPNVWindowNPObject:
604
case NPNVPluginElementNPObject: {
605
int ret = invoke_NPN_GetValue(instance, variable, value);
606
if (ret == NPERR_NO_ERROR)
611
npw_printf("WARNING: unhandled variable %d in NPN_GetValue()\n", variable);
612
return NPERR_INVALID_PARAM;
615
return NPERR_NO_ERROR;
618
// Invalidates specified drawing area prior to repainting or refreshing a windowless plug-in
620
g_NPN_InvalidateRect(NPP instance, NPRect *invalidRect)
622
D(bug("NPN_InvalidateRect instance=%p\n", instance));
627
// Invalidates specified region prior to repainting or refreshing a windowless plug-in
629
g_NPN_InvalidateRegion(NPP instance, NPRegion invalidRegion)
631
D(bug("NPN_InvalidateRegion instance=%p\n", instance));
636
// Allocates memory from the browser's memory space
638
g_NPN_MemAlloc(uint32 size)
640
D(bug("NPN_MemAlloc size=%d\n", size));
645
// Requests that the browser free a specified amount of memory
647
g_NPN_MemFlush(uint32 size)
649
D(bug("NPN_MemFlush size=%d\n", size));
654
// Deallocates a block of allocated memory
656
g_NPN_MemFree(void *ptr)
658
D(bug("NPN_MemFree ptr=%p\n", ptr));
663
// Requests the creation of a new data stream produced by the plug-in and consumed by the browser
665
g_NPN_NewStream(NPP instance, NPMIMEType type, const char *target, NPStream **stream)
667
D(bug("NPN_NewStream instance=%p\n", instance));
671
return NPERR_GENERIC_ERROR;
674
// Posts data to a URL
676
invoke_NPN_PostURL(NPP instance, const char *url, const char *target, uint32 len, const char *buf, NPBool file)
678
int error = rpc_method_invoke(g_rpc_connection,
679
RPC_METHOD_NPN_POST_URL,
680
RPC_TYPE_NPP, instance,
681
RPC_TYPE_STRING, url,
682
RPC_TYPE_STRING, target,
683
RPC_TYPE_ARRAY, RPC_TYPE_CHAR, len, buf,
684
RPC_TYPE_BOOLEAN, file,
687
if (error != RPC_ERROR_NO_ERROR) {
688
npw_perror("NPN_PostURL() invoke", error);
689
return NPERR_GENERIC_ERROR;
693
error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_INT32, &ret, RPC_TYPE_INVALID);
695
if (error != RPC_ERROR_NO_ERROR) {
696
npw_perror("NPN_PostURL() wait for reply", error);
697
return NPERR_GENERIC_ERROR;
704
g_NPN_PostURL(NPP instance, const char *url, const char *target, uint32 len, const char *buf, NPBool file)
706
if (instance == NULL)
707
return NPERR_INVALID_INSTANCE_ERROR;
709
D(bug("NPN_PostURL instance=%p\n", instance));
710
NPError ret = invoke_NPN_PostURL(instance, url, target, len, buf, file);
711
D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret)));
715
// Posts data to a URL, and receives notification of the result
717
invoke_NPN_PostURLNotify(NPP instance, const char *url, const char *target, uint32 len, const char *buf, NPBool file, void *notifyData)
719
int error = rpc_method_invoke(g_rpc_connection,
720
RPC_METHOD_NPN_POST_URL_NOTIFY,
721
RPC_TYPE_NPP, instance,
722
RPC_TYPE_STRING, url,
723
RPC_TYPE_STRING, target,
724
RPC_TYPE_ARRAY, RPC_TYPE_CHAR, len, buf,
725
RPC_TYPE_BOOLEAN, file,
726
RPC_TYPE_NP_NOTIFY_DATA, notifyData,
729
if (error != RPC_ERROR_NO_ERROR) {
730
npw_perror("NPN_PostURLNotify() invoke", error);
731
return NPERR_GENERIC_ERROR;
735
error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_INT32, &ret, RPC_TYPE_INVALID);
737
if (error != RPC_ERROR_NO_ERROR) {
738
npw_perror("NPN_PostURLNotify() wait for reply", error);
739
return NPERR_GENERIC_ERROR;
746
g_NPN_PostURLNotify(NPP instance, const char *url, const char *target, uint32 len, const char *buf, NPBool file, void *notifyData)
748
if (instance == NULL)
749
return NPERR_INVALID_INSTANCE_ERROR;
751
D(bug("NPN_PostURLNotify instance=%p\n", instance));
752
NPError ret = invoke_NPN_PostURLNotify(instance, url, target, len, buf, file, notifyData);
753
D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret)));
757
// Posts data to a URL, and receives notification of the result
759
g_NPN_ReloadPlugins(NPBool reloadPages)
761
D(bug("NPN_ReloadPlugins reloadPages=%d\n", reloadPages));
766
// Returns the Java execution environment
768
g_NPN_GetJavaEnv(void)
770
D(bug("NPN_GetJavaEnv\n"));
775
// Returns the Java object associated with the plug-in instance
777
g_NPN_GetJavaPeer(NPP instance)
779
D(bug("NPN_GetJavaPeer instance=%p\n", instance));
784
// Requests a range of bytes for a seekable stream
786
invoke_NPN_RequestRead(NPStream *stream, NPByteRange *rangeList)
788
int error = rpc_method_invoke(g_rpc_connection,
789
RPC_METHOD_NPN_REQUEST_READ,
790
RPC_TYPE_NP_STREAM, stream,
791
RPC_TYPE_NP_BYTE_RANGE, rangeList,
794
if (error != RPC_ERROR_NO_ERROR) {
795
npw_perror("NPN_RequestRead() invoke", error);
796
return NPERR_GENERIC_ERROR;
800
error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_INT32, &ret, RPC_TYPE_INVALID);
802
if (error != RPC_ERROR_NO_ERROR) {
803
npw_perror("NPN_RequestRead() wait for reply", error);
804
return NPERR_GENERIC_ERROR;
811
g_NPN_RequestRead(NPStream *stream, NPByteRange *rangeList)
813
if (stream == NULL || stream->ndata == NULL || rangeList == NULL)
814
return NPERR_INVALID_PARAM;
816
D(bug("NPN_RequestRead stream=%p\n", stream));
817
NPError ret = invoke_NPN_RequestRead(stream, rangeList);
818
D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret)));
822
// Sets various modes of plug-in operation
824
g_NPN_SetValue(NPP instance, NPPVariable variable, void *value)
826
D(bug("NPN_SetValue instance=%p\n", instance));
830
return NPERR_GENERIC_ERROR;
833
// Displays a message on the status line of the browser window
835
invoke_NPN_Status(NPP instance, const char *message)
837
int error = rpc_method_invoke(g_rpc_connection,
838
RPC_METHOD_NPN_STATUS,
839
RPC_TYPE_NPP, instance,
840
RPC_TYPE_STRING, message,
843
if (error != RPC_ERROR_NO_ERROR) {
844
npw_perror("NPN_Status() invoke", error);
848
error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_INVALID);
850
if (error != RPC_ERROR_NO_ERROR) {
851
npw_perror("NPN_Status() wait for reply", error);
857
g_NPN_Status(NPP instance, const char *message)
859
D(bug("NPN_Status instance=%p\n", instance));
860
invoke_NPN_Status(instance, message);
864
// Returns the browser's user agent field
866
invoke_NPN_UserAgent(void)
868
int error = rpc_method_invoke(g_rpc_connection, RPC_METHOD_NPN_USER_AGENT, RPC_TYPE_INVALID);
869
if (error != RPC_ERROR_NO_ERROR) {
870
npw_perror("NPN_UserAgent() invoke", error);
875
error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_STRING, &user_agent, RPC_TYPE_INVALID);
876
if (error != RPC_ERROR_NO_ERROR) {
877
npw_perror("NPN_UserAgent() wait for reply", error);
885
g_NPN_UserAgent(NPP instance)
887
D(bug("NPN_UserAgent instance=%p\n", instance));
888
if (g_user_agent == NULL)
889
g_user_agent = invoke_NPN_UserAgent();
890
D(bug(" user_agent='%s'\n", g_user_agent));
894
// Pushes data into a stream produced by the plug-in and consumed by the browser
896
g_NPN_Write(NPP instance, NPStream *stream, int32 len, void *buf)
898
D(bug("NPN_Write instance=%d\n", instance));
906
/* ====================================================================== */
907
/* === NPRuntime glue === */
908
/* ====================================================================== */
910
// Allocates a new NPObject
912
invoke_NPN_CreateObject(NPP instance)
914
int error = rpc_method_invoke(g_rpc_connection,
915
RPC_METHOD_NPN_CREATE_OBJECT,
916
RPC_TYPE_NPP, instance,
919
if (error != RPC_ERROR_NO_ERROR) {
920
npw_perror("NPN_CreateObject() invoke", error);
924
uint32_t npobj_id = 0;
925
error = rpc_method_wait_for_reply(g_rpc_connection,
926
RPC_TYPE_UINT32, &npobj_id,
929
if (error != RPC_ERROR_NO_ERROR) {
930
npw_perror("NPN_CreateObject() wait for reply", error);
938
g_NPN_CreateObject(NPP instance, NPClass *class)
940
if (instance == NULL)
946
D(bug("NPN_CreateObject\n"));
947
uint32_t npobj_id = invoke_NPN_CreateObject(instance);
948
D(bug(" return: %d\n", npobj_id));
949
return npobject_new(npobj_id, instance, class);
952
// Increments the reference count of the given NPObject
954
invoke_NPN_RetainObject(NPObject *npobj)
956
int error = rpc_method_invoke(g_rpc_connection,
957
RPC_METHOD_NPN_RETAIN_OBJECT,
958
RPC_TYPE_NP_OBJECT, npobj,
961
if (error != RPC_ERROR_NO_ERROR) {
962
npw_perror("NPN_RetainObject() invoke", error);
963
return npobj->referenceCount;
967
error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_UINT32, &refcount, RPC_TYPE_INVALID);
969
if (error != RPC_ERROR_NO_ERROR) {
970
npw_perror("NPN_RetainObject() wait for reply", error);
971
return npobj->referenceCount;
978
g_NPN_RetainObject(NPObject *npobj)
983
D(bug("NPN_RetainObject %p\n", npobj));
984
uint32_t refcount = invoke_NPN_RetainObject(npobj);
985
D(bug(" return: %d\n", refcount));
986
npobj->referenceCount = refcount;
990
// Decrements the reference count of the give NPObject
992
invoke_NPN_ReleaseObject(NPObject *npobj)
994
int error = rpc_method_invoke(g_rpc_connection,
995
RPC_METHOD_NPN_RELEASE_OBJECT,
996
RPC_TYPE_NP_OBJECT, npobj,
999
if (error != RPC_ERROR_NO_ERROR) {
1000
npw_perror("NPN_ReleaseObject() invoke", error);
1001
return npobj->referenceCount;
1005
error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_UINT32, &refcount, RPC_TYPE_INVALID);
1007
if (error != RPC_ERROR_NO_ERROR) {
1008
npw_perror("NPN_ReleaseObject() wait for reply", error);
1009
return npobj->referenceCount;
1016
g_NPN_ReleaseObject(NPObject *npobj)
1021
D(bug("NPN_ReleaseObject %p\n", npobj));
1022
uint32_t refcount = invoke_NPN_ReleaseObject(npobj);
1023
D(bug(" return: %d\n", refcount));
1025
if ((npobj->referenceCount = refcount) == 0)
1026
npobject_destroy(npobj);
1029
// Invokes a method on the given NPObject
1031
invoke_NPN_Invoke(NPP instance, NPObject *npobj, NPIdentifier methodName,
1032
const NPVariant *args, uint32_t argCount, NPVariant *result)
1034
int error = rpc_method_invoke(g_rpc_connection,
1035
RPC_METHOD_NPN_INVOKE,
1036
RPC_TYPE_NPP, instance,
1037
RPC_TYPE_NP_OBJECT, npobj,
1038
RPC_TYPE_NP_IDENTIFIER, methodName,
1039
RPC_TYPE_ARRAY, RPC_TYPE_NP_VARIANT, argCount, args,
1042
if (error != RPC_ERROR_NO_ERROR) {
1043
npw_perror("NPN_Invoke() invoke", error);
1048
error = rpc_method_wait_for_reply(g_rpc_connection,
1049
RPC_TYPE_UINT32, &ret,
1050
RPC_TYPE_NP_VARIANT, result,
1053
if (error != RPC_ERROR_NO_ERROR) {
1054
npw_perror("NPN_Invoke() wait for reply", error);
1062
g_NPN_Invoke(NPP instance, NPObject *npobj, NPIdentifier methodName,
1063
const NPVariant *args, uint32_t argCount, NPVariant *result)
1065
if (!instance || !npobj || !npobj->_class || !npobj->_class->invoke)
1068
D(bug("NPN_Invoke instance=%p, npobj=%p\n", instance, npobj));
1069
bool ret = invoke_NPN_Invoke(instance, npobj, methodName, args, argCount, result);
1070
D(bug(" return: %d\n", ret));
1074
// Invokes the default method on the given NPObject
1076
invoke_NPN_InvokeDefault(NPP instance, NPObject *npobj,
1077
const NPVariant *args, uint32_t argCount, NPVariant *result)
1079
int error = rpc_method_invoke(g_rpc_connection,
1080
RPC_METHOD_NPN_INVOKE_DEFAULT,
1081
RPC_TYPE_NPP, instance,
1082
RPC_TYPE_NP_OBJECT, npobj,
1083
RPC_TYPE_ARRAY, RPC_TYPE_NP_VARIANT, argCount, args,
1086
if (error != RPC_ERROR_NO_ERROR) {
1087
npw_perror("NPN_InvokeDefault() invoke", error);
1092
error = rpc_method_wait_for_reply(g_rpc_connection,
1093
RPC_TYPE_UINT32, &ret,
1094
RPC_TYPE_NP_VARIANT, result,
1097
if (error != RPC_ERROR_NO_ERROR) {
1098
npw_perror("NPN_InvokeDefault() wait for reply", error);
1106
g_NPN_InvokeDefault(NPP instance, NPObject *npobj,
1107
const NPVariant *args, uint32_t argCount, NPVariant *result)
1109
if (!instance || !npobj || !npobj->_class || !npobj->_class->invokeDefault)
1112
D(bug("NPN_InvokeDefault instance=%p, npobj=%p\n", instance, npobj));
1113
bool ret = invoke_NPN_InvokeDefault(instance, npobj, args, argCount, result);
1114
D(bug(" return: %d\n", ret));
1118
// Evaluates a script on the scope of a given NPObject
1120
invoke_NPN_Evaluate(NPP instance, NPObject *npobj, NPString *script, NPVariant *result)
1122
int error = rpc_method_invoke(g_rpc_connection,
1123
RPC_METHOD_NPN_EVALUATE,
1124
RPC_TYPE_NPP, instance,
1125
RPC_TYPE_NP_OBJECT, npobj,
1126
RPC_TYPE_NP_STRING, script,
1129
if (error != RPC_ERROR_NO_ERROR) {
1130
npw_perror("NPN_Evaluate() invoke", error);
1135
error = rpc_method_wait_for_reply(g_rpc_connection,
1136
RPC_TYPE_UINT32, &ret,
1137
RPC_TYPE_NP_VARIANT, result,
1140
if (error != RPC_ERROR_NO_ERROR) {
1141
npw_perror("NPN_Evaluate() wait for reply", error);
1149
g_NPN_Evaluate(NPP instance, NPObject *npobj, NPString *script, NPVariant *result)
1151
if (!instance || !npobj)
1154
if (!script || !script->utf8length || !script->utf8characters)
1155
return true; // nothing to evaluate
1157
D(bug("NPN_Evaluate instance=%p, npobj=%p\n", instance, npobj));
1158
bool ret = invoke_NPN_Evaluate(instance, npobj, script, result);
1159
D(bug(" return: %d\n", ret));
1163
// Gets the value of a property on the given NPObject
1165
invoke_NPN_GetProperty(NPP instance, NPObject *npobj, NPIdentifier propertyName,
1168
int error = rpc_method_invoke(g_rpc_connection,
1169
RPC_METHOD_NPN_GET_PROPERTY,
1170
RPC_TYPE_NPP, instance,
1171
RPC_TYPE_NP_OBJECT, npobj,
1172
RPC_TYPE_NP_IDENTIFIER, propertyName,
1175
if (error != RPC_ERROR_NO_ERROR) {
1176
npw_perror("NPN_GetProperty() invoke", error);
1181
error = rpc_method_wait_for_reply(g_rpc_connection,
1182
RPC_TYPE_UINT32, &ret,
1183
RPC_TYPE_NP_VARIANT, result,
1186
if (error != RPC_ERROR_NO_ERROR) {
1187
npw_perror("NPN_GetProperty() wait for reply", error);
1195
g_NPN_GetProperty(NPP instance, NPObject *npobj, NPIdentifier propertyName,
1198
if (!instance || !npobj || !npobj->_class || !npobj->_class->getProperty)
1201
D(bug("NPN_GetProperty instance=%p, npobj=%p\n", instance, npobj));
1202
bool ret = invoke_NPN_GetProperty(instance, npobj, propertyName, result);
1203
D(bug(" return: %d\n", ret));
1207
// Sets the value of a property on the given NPObject
1209
invoke_NPN_SetProperty(NPP instance, NPObject *npobj, NPIdentifier propertyName,
1210
const NPVariant *value)
1212
int error = rpc_method_invoke(g_rpc_connection,
1213
RPC_METHOD_NPN_SET_PROPERTY,
1214
RPC_TYPE_NPP, instance,
1215
RPC_TYPE_NP_OBJECT, npobj,
1216
RPC_TYPE_NP_IDENTIFIER, propertyName,
1217
RPC_TYPE_NP_VARIANT, value,
1220
if (error != RPC_ERROR_NO_ERROR) {
1221
npw_perror("NPN_SetProperty() invoke", error);
1226
error = rpc_method_wait_for_reply(g_rpc_connection,
1227
RPC_TYPE_UINT32, &ret,
1230
if (error != RPC_ERROR_NO_ERROR) {
1231
npw_perror("NPN_SetProperty() wait for reply", error);
1239
g_NPN_SetProperty(NPP instance, NPObject *npobj, NPIdentifier propertyName,
1240
const NPVariant *value)
1242
if (!instance || !npobj || !npobj->_class || !npobj->_class->setProperty)
1245
D(bug("NPN_SetProperty instance=%p, npobj=%p\n", instance, npobj));
1246
bool ret = invoke_NPN_SetProperty(instance, npobj, propertyName, value);
1247
D(bug(" return: %d\n", ret));
1251
// Removes a property on the given NPObject
1253
invoke_NPN_RemoveProperty(NPP instance, NPObject *npobj, NPIdentifier propertyName)
1255
int error = rpc_method_invoke(g_rpc_connection,
1256
RPC_METHOD_NPN_REMOVE_PROPERTY,
1257
RPC_TYPE_NPP, instance,
1258
RPC_TYPE_NP_OBJECT, npobj,
1259
RPC_TYPE_NP_IDENTIFIER, propertyName,
1262
if (error != RPC_ERROR_NO_ERROR) {
1263
npw_perror("NPN_RemoveProperty() invoke", error);
1268
error = rpc_method_wait_for_reply(g_rpc_connection,
1269
RPC_TYPE_UINT32, &ret,
1272
if (error != RPC_ERROR_NO_ERROR) {
1273
npw_perror("NPN_RemoveProperty() wait for reply", error);
1281
g_NPN_RemoveProperty(NPP instance, NPObject *npobj, NPIdentifier propertyName)
1283
if (!instance || !npobj || !npobj->_class || !npobj->_class->removeProperty)
1286
D(bug("NPN_RemoveProperty instance=%p, npobj=%p\n", instance, npobj));
1287
bool ret = invoke_NPN_RemoveProperty(instance, npobj, propertyName);
1288
D(bug(" return: %d\n", ret));
1292
// Checks if a given property exists on the given NPObject
1294
invoke_NPN_HasProperty(NPP instance, NPObject *npobj, NPIdentifier propertyName)
1296
int error = rpc_method_invoke(g_rpc_connection,
1297
RPC_METHOD_NPN_HAS_PROPERTY,
1298
RPC_TYPE_NPP, instance,
1299
RPC_TYPE_NP_OBJECT, npobj,
1300
RPC_TYPE_NP_IDENTIFIER, propertyName,
1303
if (error != RPC_ERROR_NO_ERROR) {
1304
npw_perror("NPN_HasProperty() invoke", error);
1309
error = rpc_method_wait_for_reply(g_rpc_connection,
1310
RPC_TYPE_UINT32, &ret,
1313
if (error != RPC_ERROR_NO_ERROR) {
1314
npw_perror("NPN_HasProperty() wait for reply", error);
1322
g_NPN_HasProperty(NPP instance, NPObject *npobj, NPIdentifier propertyName)
1324
if (!instance || !npobj || !npobj->_class || !npobj->_class->hasProperty)
1327
D(bug("NPN_HasProperty instance=%p, npobj=%p\n", instance, npobj));
1328
bool ret = invoke_NPN_HasProperty(instance, npobj, propertyName);
1329
D(bug(" return: %d\n", ret));
1333
// Checks if a given method exists on the given NPObject
1335
invoke_NPN_HasMethod(NPP instance, NPObject *npobj, NPIdentifier methodName)
1337
int error = rpc_method_invoke(g_rpc_connection,
1338
RPC_METHOD_NPN_HAS_METHOD,
1339
RPC_TYPE_NPP, instance,
1340
RPC_TYPE_NP_OBJECT, npobj,
1341
RPC_TYPE_NP_IDENTIFIER, methodName,
1344
if (error != RPC_ERROR_NO_ERROR) {
1345
npw_perror("NPN_HasMethod() invoke", error);
1350
error = rpc_method_wait_for_reply(g_rpc_connection,
1351
RPC_TYPE_UINT32, &ret,
1354
if (error != RPC_ERROR_NO_ERROR) {
1355
npw_perror("NPN_HasMethod() wait for reply", error);
1363
g_NPN_HasMethod(NPP instance, NPObject *npobj, NPIdentifier methodName)
1365
if (!instance || !npobj || !npobj->_class || !npobj->_class->hasMethod)
1368
D(bug("NPN_HasMethod instance=%p, npobj=%p\n", instance, npobj));
1369
bool ret = invoke_NPN_HasMethod(instance, npobj, methodName);
1370
D(bug(" return: %d\n", ret));
1374
// Indicates that a call to one of the plugins NPObjects generated an error
1376
invoke_NPN_SetException(NPObject *npobj, const NPUTF8 *message)
1378
int error = rpc_method_invoke(g_rpc_connection,
1379
RPC_METHOD_NPN_SET_EXCEPTION,
1380
RPC_TYPE_NP_OBJECT, npobj,
1381
RPC_TYPE_STRING, message,
1384
if (error != RPC_ERROR_NO_ERROR) {
1385
npw_perror("NPN_SetException() invoke", error);
1389
error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_INVALID);
1391
if (error != RPC_ERROR_NO_ERROR) {
1392
npw_perror("NPN_SetException() wait for reply", error);
1398
g_NPN_SetException(NPObject *npobj, const NPUTF8 *message)
1400
D(bug("NPN_SetException npobj=%p, message='%s'\n", npobj, message));
1401
invoke_NPN_SetException(npobj, message);
1405
// Releases the value in the given variant
1407
g_NPN_ReleaseVariantValue(NPVariant *variant)
1409
D(bug("NPN_ReleaseVariantValue\n"));
1411
switch (variant->type) {
1412
case NPVariantType_String:
1414
NPString *s = &NPVARIANT_TO_STRING(*variant);
1415
if (s->utf8characters)
1416
free((void *)s->utf8characters);
1419
case NPVariantType_Object:
1421
NPObject *npobj = NPVARIANT_TO_OBJECT(*variant);
1423
g_NPN_ReleaseObject(npobj);
1431
// Returns an opaque identifier for the string that is passed in
1433
invoke_NPN_GetStringIdentifier(const NPUTF8 *name)
1435
int error = rpc_method_invoke(g_rpc_connection,
1436
RPC_METHOD_NPN_GET_STRING_IDENTIFIER,
1437
RPC_TYPE_STRING, name,
1440
if (error != RPC_ERROR_NO_ERROR) {
1441
npw_perror("NPN_GetStringIdentifier() invoke", error);
1446
error = rpc_method_wait_for_reply(g_rpc_connection,
1447
RPC_TYPE_NP_IDENTIFIER, &ident,
1450
if (error != RPC_ERROR_NO_ERROR) {
1451
npw_perror("NPN_GetStringIdentifier() wait for reply", error);
1459
g_NPN_GetStringIdentifier(const NPUTF8 *name)
1464
D(bug("NPN_GetStringIdentifier name='%s'\n", name));
1465
NPIdentifier ret = invoke_NPN_GetStringIdentifier(name);
1466
D(bug(" return: %p\n", ret));
1470
// Returns an array of opaque identifiers for the names that are passed in
1472
invoke_NPN_GetStringIdentifiers(const NPUTF8 **names, uint32_t nameCount, NPIdentifier *identifiers)
1474
int error = rpc_method_invoke(g_rpc_connection,
1475
RPC_METHOD_NPN_GET_STRING_IDENTIFIERS,
1476
RPC_TYPE_ARRAY, RPC_TYPE_STRING, nameCount, names,
1479
if (error != RPC_ERROR_NO_ERROR) {
1480
npw_perror("NPN_GetStringIdentifiers() invoke", error);
1485
NPIdentifier *idents;
1486
error = rpc_method_wait_for_reply(g_rpc_connection,
1487
RPC_TYPE_ARRAY, RPC_TYPE_NP_IDENTIFIER, &n_idents, &idents,
1490
if (error != RPC_ERROR_NO_ERROR) {
1491
npw_perror("NPN_GetStringIdentifiers() wait for reply", error);
1496
if (n_idents != nameCount) {
1497
npw_printf("ERROR: NPN_GetStringIdentifiers returned fewer NPIdentifiers than expected\n");
1498
if (n_idents > nameCount)
1499
n_idents = nameCount;
1501
for (int i = 0; i < n_idents; i++)
1502
identifiers[i] = idents[i];
1508
g_NPN_GetStringIdentifiers(const NPUTF8 **names, uint32_t nameCount, NPIdentifier *identifiers)
1513
if (identifiers == NULL)
1516
D(bug("NPN_GetStringIdentifiers names=%p\n", names));
1517
invoke_NPN_GetStringIdentifiers(names, nameCount, identifiers);
1521
// Returns an opaque identifier for the integer that is passed in
1523
invoke_NPN_GetIntIdentifier(int32_t intid)
1525
int error = rpc_method_invoke(g_rpc_connection,
1526
RPC_METHOD_NPN_GET_INT_IDENTIFIER,
1527
RPC_TYPE_INT32, intid,
1530
if (error != RPC_ERROR_NO_ERROR) {
1531
npw_perror("NPN_GetIntIdentifier() invoke", error);
1536
error = rpc_method_wait_for_reply(g_rpc_connection,
1537
RPC_TYPE_NP_IDENTIFIER, &ident,
1540
if (error != RPC_ERROR_NO_ERROR) {
1541
npw_perror("NPN_GetIntIdentifier() wait for reply", error);
1549
g_NPN_GetIntIdentifier(int32_t intid)
1551
D(bug("NPN_GetIntIdentifier intid=%d\n", intid));
1552
NPIdentifier ret = invoke_NPN_GetIntIdentifier(intid);
1553
D(bug(" return: %p\n", ret));
1557
// Returns true if the given identifier is a string identifier, or false if it is an integer identifier
1559
invoke_NPN_IdentifierIsString(NPIdentifier identifier)
1561
int error = rpc_method_invoke(g_rpc_connection,
1562
RPC_METHOD_NPN_IDENTIFIER_IS_STRING,
1563
RPC_TYPE_NP_IDENTIFIER, identifier,
1566
if (error != RPC_ERROR_NO_ERROR) {
1567
npw_perror("NPN_IdentifierIsString() invoke", error);
1572
error = rpc_method_wait_for_reply(g_rpc_connection,
1573
RPC_TYPE_UINT32, &ret,
1576
if (error != RPC_ERROR_NO_ERROR) {
1577
npw_perror("NPN_IdentifierIsString() wait for reply", error);
1585
g_NPN_IdentifierIsString(NPIdentifier identifier)
1587
D(bug("NPN_IdentifierIsString identifier=%p\n", identifier));
1588
bool ret = invoke_NPN_IdentifierIsString(identifier);
1589
D(bug(" return: %d\n", ret));
1593
// Returns a pointer to a UTF-8 string as a sequence of 8-bit units (NPUTF8)
1595
invoke_NPN_UTF8FromIdentifier(NPIdentifier identifier)
1597
int error = rpc_method_invoke(g_rpc_connection,
1598
RPC_METHOD_NPN_UTF8_FROM_IDENTIFIER,
1599
RPC_TYPE_NP_IDENTIFIER, identifier,
1602
if (error != RPC_ERROR_NO_ERROR) {
1603
npw_perror("NPN_UTF8FromIdentifier() invoke", error);
1608
error = rpc_method_wait_for_reply(g_rpc_connection,
1609
RPC_TYPE_STRING, &str,
1612
if (error != RPC_ERROR_NO_ERROR) {
1613
npw_perror("NPN_UTF8FromIdentifier() wait for reply", error);
1621
g_NPN_UTF8FromIdentifier(NPIdentifier identifier)
1623
D(bug("NPN_UTF8FromIdentifier identifier=%p\n", identifier));
1624
NPUTF8 *ret = invoke_NPN_UTF8FromIdentifier(identifier);
1625
D(bug(" return: '%s'\n", ret));
1629
// Returns the integer value for the given integer identifier
1630
// NOTE: if the given identifier is not a integer identifier, the behavior is undefined (we return -1)
1632
invoke_NPN_IntFromIdentifier(NPIdentifier identifier)
1634
int error = rpc_method_invoke(g_rpc_connection,
1635
RPC_METHOD_NPN_INT_FROM_IDENTIFIER,
1636
RPC_TYPE_NP_IDENTIFIER, identifier,
1639
if (error != RPC_ERROR_NO_ERROR) {
1640
npw_perror("NPN_IntFromIdentifier() invoke", error);
1645
error = rpc_method_wait_for_reply(g_rpc_connection,
1646
RPC_TYPE_INT32, &ret,
1649
if (error != RPC_ERROR_NO_ERROR) {
1650
npw_perror("NPN_IntFromIdentifier() wait for reply", error);
1658
g_NPN_IntFromIdentifier(NPIdentifier identifier)
1660
D(bug("NPN_IntFromIdentifier identifier=%p\n", identifier));
1661
int32_t ret = invoke_NPN_IntFromIdentifier(identifier);
1662
D(bug(" return: %d\n", ret));
1667
/* ====================================================================== */
1668
/* === Plug-in side data === */
1669
/* ====================================================================== */
1671
// Functions supplied by the plug-in
1672
static NPPluginFuncs plugin_funcs;
1674
// Allows the browser to query the plug-in supported formats
1675
typedef char * (*NP_GetMIMEDescriptionUPP)(void);
1676
static NP_GetMIMEDescriptionUPP g_NP_GetMIMEDescription = NULL;
1678
// Allows the browser to query the plug-in for information
1679
typedef NPError (*NP_GetValueUPP)(void *instance, NPPVariable variable, void *value);
1680
static NP_GetValueUPP g_NP_GetValue = NULL;
1682
// Provides global initialization for a plug-in
1683
typedef NPError (*NP_InitializeUPP)(NPNetscapeFuncs *moz_funcs, NPPluginFuncs *plugin_funcs);
1684
static NP_InitializeUPP g_NP_Initialize = NULL;
1686
// Provides global deinitialization for a plug-in
1687
typedef NPError (*NP_ShutdownUPP)(void);
1688
static NP_ShutdownUPP g_NP_Shutdown = NULL;
1691
/* ====================================================================== */
1692
/* === RPC communication === */
1693
/* ====================================================================== */
1695
// NP_GetMIMEDescription
1696
static int handle_NP_GetMIMEDescription(rpc_connection_t *connection)
1698
D(bug("handle_NP_GetMIMEDescription\n"));
1700
char *str = g_NP_GetMIMEDescription();
1701
return rpc_method_send_reply(connection, RPC_TYPE_STRING, str, RPC_TYPE_INVALID);
1705
static int handle_NP_GetValue(rpc_connection_t *connection)
1707
D(bug("handle_NP_GetValue\n"));
1710
int error = rpc_method_get_args(connection, RPC_TYPE_INT32, &variable, RPC_TYPE_INVALID);
1711
if (error != RPC_ERROR_NO_ERROR) {
1712
npw_perror("NP_GetValue() get args", error);
1717
NPError ret = g_NP_GetValue ? g_NP_GetValue(NULL, variable, (void *)&str) : NPERR_GENERIC_ERROR;
1718
return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_STRING, str, RPC_TYPE_INVALID);
1722
static int handle_NP_Initialize(rpc_connection_t *connection)
1724
D(bug("handle_NP_Initialize\n"));
1726
uint32_t has_npruntime = 0;
1727
int error = rpc_method_get_args(connection,
1728
RPC_TYPE_UINT32, &has_npruntime,
1731
if (error != RPC_ERROR_NO_ERROR) {
1732
npw_perror("NP_Initialize() get args", error);
1736
memset(&plugin_funcs, 0, sizeof(plugin_funcs));
1737
plugin_funcs.size = sizeof(plugin_funcs);
1739
memset(&mozilla_funcs, 0, sizeof(mozilla_funcs));
1740
mozilla_funcs.size = sizeof(mozilla_funcs);
1741
mozilla_funcs.version = (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR;
1742
mozilla_funcs.geturl = NewNPN_GetURLProc(g_NPN_GetURL);
1743
mozilla_funcs.posturl = NewNPN_PostURLProc(g_NPN_PostURL);
1744
mozilla_funcs.requestread = NewNPN_RequestReadProc(g_NPN_RequestRead);
1745
mozilla_funcs.newstream = NewNPN_NewStreamProc(g_NPN_NewStream);
1746
mozilla_funcs.write = NewNPN_WriteProc(g_NPN_Write);
1747
mozilla_funcs.destroystream = NewNPN_DestroyStreamProc(g_NPN_DestroyStream);
1748
mozilla_funcs.status = NewNPN_StatusProc(g_NPN_Status);
1749
mozilla_funcs.uagent = NewNPN_UserAgentProc(g_NPN_UserAgent);
1750
mozilla_funcs.memalloc = NewNPN_MemAllocProc(g_NPN_MemAlloc);
1751
mozilla_funcs.memfree = NewNPN_MemFreeProc(g_NPN_MemFree);
1752
mozilla_funcs.memflush = NewNPN_MemFlushProc(g_NPN_MemFlush);
1753
mozilla_funcs.reloadplugins = NewNPN_ReloadPluginsProc(g_NPN_ReloadPlugins);
1754
mozilla_funcs.getJavaEnv = NewNPN_GetJavaEnvProc(g_NPN_GetJavaEnv);
1755
mozilla_funcs.getJavaPeer = NewNPN_GetJavaPeerProc(g_NPN_GetJavaPeer);
1756
mozilla_funcs.geturlnotify = NewNPN_GetURLNotifyProc(g_NPN_GetURLNotify);
1757
mozilla_funcs.posturlnotify = NewNPN_PostURLNotifyProc(g_NPN_PostURLNotify);
1758
mozilla_funcs.getvalue = NewNPN_GetValueProc(g_NPN_GetValue);
1759
mozilla_funcs.setvalue = NewNPN_SetValueProc(g_NPN_SetValue);
1760
mozilla_funcs.invalidaterect = NewNPN_InvalidateRectProc(g_NPN_InvalidateRect);
1761
mozilla_funcs.invalidateregion = NewNPN_InvalidateRegionProc(g_NPN_InvalidateRegion);
1762
mozilla_funcs.forceredraw = NewNPN_ForceRedrawProc(g_NPN_ForceRedraw);
1764
npruntime_init_callbacks(&mozilla_funcs);
1766
if (has_npruntime && getenv("NPW_DISABLE_NPRUNTIME")) {
1767
D(bug(" user disabled npruntime support\n"));
1768
has_npruntime = false;
1771
if (has_npruntime) {
1772
D(bug(" browser supports scripting through npruntime\n"));
1773
mozilla_funcs.getstringidentifier = NewNPN_GetStringIdentifierProc(g_NPN_GetStringIdentifier);
1774
mozilla_funcs.getstringidentifiers = NewNPN_GetStringIdentifiersProc(g_NPN_GetStringIdentifiers);
1775
mozilla_funcs.getintidentifier = NewNPN_GetIntIdentifierProc(g_NPN_GetIntIdentifier);
1776
mozilla_funcs.identifierisstring = NewNPN_IdentifierIsStringProc(g_NPN_IdentifierIsString);
1777
mozilla_funcs.utf8fromidentifier = NewNPN_UTF8FromIdentifierProc(g_NPN_UTF8FromIdentifier);
1778
mozilla_funcs.intfromidentifier = NewNPN_IntFromIdentifierProc(g_NPN_IntFromIdentifier);
1779
mozilla_funcs.createobject = NewNPN_CreateObjectProc(g_NPN_CreateObject);
1780
mozilla_funcs.retainobject = NewNPN_RetainObjectProc(g_NPN_RetainObject);
1781
mozilla_funcs.releaseobject = NewNPN_ReleaseObjectProc(g_NPN_ReleaseObject);
1782
mozilla_funcs.invoke = NewNPN_InvokeProc(g_NPN_Invoke);
1783
mozilla_funcs.invokeDefault = NewNPN_InvokeDefaultProc(g_NPN_InvokeDefault);
1784
mozilla_funcs.evaluate = NewNPN_EvaluateProc(g_NPN_Evaluate);
1785
mozilla_funcs.getproperty = NewNPN_GetPropertyProc(g_NPN_GetProperty);
1786
mozilla_funcs.setproperty = NewNPN_SetPropertyProc(g_NPN_SetProperty);
1787
mozilla_funcs.removeproperty = NewNPN_RemovePropertyProc(g_NPN_RemoveProperty);
1788
mozilla_funcs.hasproperty = NewNPN_HasPropertyProc(g_NPN_HasProperty);
1789
mozilla_funcs.hasmethod = NewNPN_HasMethodProc(g_NPN_HasMethod);
1790
mozilla_funcs.releasevariantvalue = NewNPN_ReleaseVariantValueProc(g_NPN_ReleaseVariantValue);
1791
mozilla_funcs.setexception = NewNPN_SetExceptionProc(g_NPN_SetException);
1794
NPError ret = NPERR_NO_ERROR;
1796
if (!npobject_bridge_new())
1797
ret = NPERR_OUT_OF_MEMORY_ERROR;
1799
if (ret == NPERR_NO_ERROR)
1800
ret = g_NP_Initialize(&mozilla_funcs, &plugin_funcs);
1802
return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_INVALID);
1806
static int handle_NP_Shutdown(rpc_connection_t *connection)
1808
D(bug("handle_NP_Shutdown\n"));
1810
NPError ret = g_NP_Shutdown();
1812
npobject_bridge_destroy();
1815
return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_INVALID);
1819
static NPError g_NPP_New(NPMIMEType plugin_type, uint32_t instance_id,
1820
uint16_t mode, int16_t argc, char *argn[], char *argv[],
1823
PluginInstance *plugin = malloc(sizeof(*plugin));
1825
return NPERR_OUT_OF_MEMORY_ERROR;
1826
memset(plugin, 0, sizeof(*plugin));
1827
plugin->instance_id = instance_id;
1828
id_link(instance_id, plugin);
1830
NPP instance = malloc(sizeof(*instance));
1831
if (instance == NULL)
1832
return NPERR_OUT_OF_MEMORY_ERROR;
1833
memset(instance, 0, sizeof(*instance));
1834
instance->ndata = plugin;
1835
plugin->instance = instance;
1837
// check for size hints
1838
for (int i = 0; i < argc; i++) {
1839
if (argn[i] == NULL)
1841
if (strcasecmp(argn[i], "width") == 0) {
1842
if (i < argc && argv[i])
1843
plugin->width = atoi(argv[i]);
1845
else if (strcasecmp(argn[i], "height") == 0) {
1846
if (i < argc && argv[i])
1847
plugin->height = atoi(argv[i]);
1851
D(bug("NPP_New instance=%p\n", instance));
1852
NPError ret = plugin_funcs.newp(plugin_type, instance, mode, argc, argn, argv, saved);
1853
D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret)));
1855
// check if XEMBED is to be used
1856
PRBool supports_XEmbed = PR_FALSE;
1857
if (mozilla_funcs.getvalue) {
1858
NPError error = mozilla_funcs.getvalue(NULL, NPNVSupportsXEmbedBool, (void *)&supports_XEmbed);
1859
if (error == NPERR_NO_ERROR && plugin_funcs.getvalue) {
1860
PRBool needs_XEmbed = PR_FALSE;
1861
error = plugin_funcs.getvalue(instance, NPPVpluginNeedsXEmbed, (void *)&needs_XEmbed);
1862
if (error == NPERR_NO_ERROR)
1863
plugin->use_xembed = supports_XEmbed && needs_XEmbed;
1870
static int handle_NPP_New(rpc_connection_t *connection)
1872
D(bug("handle_NPP_New\n"));
1874
uint32_t instance_id;
1875
NPMIMEType plugin_type;
1877
int argn_count, argv_count;
1878
char **argn, **argv;
1880
int error = rpc_method_get_args(connection,
1881
RPC_TYPE_UINT32, &instance_id,
1882
RPC_TYPE_STRING, &plugin_type,
1883
RPC_TYPE_INT32, &mode,
1884
RPC_TYPE_ARRAY, RPC_TYPE_STRING, &argn_count, &argn,
1885
RPC_TYPE_ARRAY, RPC_TYPE_STRING, &argv_count, &argv,
1886
RPC_TYPE_NP_SAVED_DATA, &saved,
1889
if (error != RPC_ERROR_NO_ERROR) {
1890
npw_perror("NPP_New() get args", error);
1894
assert(argn_count == argv_count);
1895
NPError ret = g_NPP_New(plugin_type, instance_id, mode, argn_count, argn, argv, saved);
1900
for (int i = 0; i < argn_count; i++)
1905
for (int i = 0; i < argv_count; i++)
1910
return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_INVALID);
1914
static NPError g_NPP_Destroy(NPP instance, NPSavedData **sdata)
1916
if (instance == NULL)
1917
return NPERR_INVALID_INSTANCE_ERROR;
1922
D(bug("NPP_Destroy instance=%p\n", instance));
1923
NPError ret = plugin_funcs.destroy(instance, sdata);
1924
D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret)));
1926
PluginInstance *plugin = instance->ndata;
1928
destroy_window(plugin);
1929
id_remove(plugin->instance_id);
1937
static int handle_NPP_Destroy(rpc_connection_t *connection)
1941
error = rpc_method_get_args(connection, RPC_TYPE_NPP, &instance, RPC_TYPE_INVALID);
1943
if (error != RPC_ERROR_NO_ERROR) {
1944
npw_perror("NPP_Destroy() get args", error);
1948
NPSavedData *save_area;
1949
NPError ret = g_NPP_Destroy(instance, &save_area);
1950
return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_NP_SAVED_DATA, save_area, RPC_TYPE_INVALID);
1955
g_NPP_SetWindow(NPP instance, NPWindow *np_window)
1957
if (instance == NULL)
1958
return NPERR_INVALID_INSTANCE_ERROR;
1960
if (plugin_funcs.setwindow == NULL)
1961
return NPERR_INVALID_FUNCTABLE_ERROR;
1963
PluginInstance *plugin = instance->ndata;
1965
return NPERR_INVALID_INSTANCE_ERROR;
1967
NPWindow *window = np_window;
1969
if (plugin->top_window) {
1970
if (update_window(plugin, window) < 0)
1971
return NPERR_GENERIC_ERROR;
1974
if (create_window(plugin, window) < 0)
1975
return NPERR_GENERIC_ERROR;
1977
window = &plugin->window;
1980
D(bug("NPP_SetWindow instance=%p, window=%p\n", instance, window ? window->window : NULL));
1981
NPError ret = plugin_funcs.setwindow(instance, window);
1982
D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret)));
1984
if (np_window == NULL)
1985
destroy_window(plugin);
1990
static int handle_NPP_SetWindow(rpc_connection_t *connection)
1992
D(bug("handle_NPP_SetWindow\n"));
1998
error = rpc_method_get_args(connection,
1999
RPC_TYPE_NPP, &instance,
2000
RPC_TYPE_NP_WINDOW, &window,
2003
if (error != RPC_ERROR_NO_ERROR) {
2004
npw_perror("NPP_SetWindow() get args", error);
2008
NPError ret = g_NPP_SetWindow(instance, window);
2011
return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_INVALID);
2016
g_NPP_GetValue(NPP instance, NPPVariable variable, void *value)
2018
if (instance == NULL)
2019
return NPERR_INVALID_INSTANCE_ERROR;
2021
if (plugin_funcs.getvalue == NULL)
2022
return NPERR_INVALID_FUNCTABLE_ERROR;
2024
D(bug("NPP_GetValue instance=%p, variable=%d\n", instance, variable));
2025
NPError ret = plugin_funcs.getvalue(instance, variable, value);
2026
D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret)));
2030
static int handle_NPP_GetValue(rpc_connection_t *connection)
2036
error = rpc_method_get_args(connection,
2037
RPC_TYPE_NPP, &instance,
2038
RPC_TYPE_INT32, &variable,
2041
if (error != RPC_ERROR_NO_ERROR) {
2042
npw_printf("ERROR: could not get NPP_GetValue variable\n");
2046
NPError ret = NPERR_GENERIC_ERROR;
2047
int variable_type = rpc_type_of_NPPVariable(variable);
2049
switch (variable_type) {
2050
case RPC_TYPE_STRING:
2053
ret = g_NPP_GetValue(instance, variable, (void *)&str);
2054
return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_STRING, str, RPC_TYPE_INVALID);
2056
case RPC_TYPE_INT32:
2059
ret = g_NPP_GetValue(instance, variable, (void *)&n);
2060
return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_INT32, n, RPC_TYPE_INVALID);
2062
case RPC_TYPE_BOOLEAN:
2064
PRBool b = PR_FALSE;
2065
ret = g_NPP_GetValue(instance, variable, (void *)&b);
2066
return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_BOOLEAN, b, RPC_TYPE_INVALID);
2068
case RPC_TYPE_NP_OBJECT:
2070
NPObject *npobj = NULL;
2071
ret = g_NPP_GetValue(instance, variable, (void *)&npobj);
2072
return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_NP_OBJECT, npobj, RPC_TYPE_INVALID);
2081
g_NPP_URLNotify(NPP instance, const char *url, NPReason reason, void *notifyData)
2086
if (plugin_funcs.urlnotify == NULL)
2089
D(bug("NPP_URLNotify instance=%p, url='%s', reason=%s, notifyData=%p\n",
2090
instance, url, string_of_NPReason(reason), notifyData));
2091
plugin_funcs.urlnotify(instance, url, reason, notifyData);
2095
static int handle_NPP_URLNotify(rpc_connection_t *connection)
2103
error = rpc_method_get_args(connection,
2104
RPC_TYPE_NPP, &instance,
2105
RPC_TYPE_STRING, &url,
2106
RPC_TYPE_INT32, &reason,
2107
RPC_TYPE_NP_NOTIFY_DATA, ¬ifyData,
2110
if (error != RPC_ERROR_NO_ERROR) {
2111
npw_perror("NPP_URLNotify() get args", error);
2115
g_NPP_URLNotify(instance, url, reason, notifyData);
2120
return RPC_ERROR_NO_ERROR;
2125
g_NPP_NewStream(NPP instance, NPMIMEType type, NPStream *stream, NPBool seekable, uint16 *stype)
2127
if (instance == NULL)
2128
return NPERR_INVALID_INSTANCE_ERROR;
2130
if (plugin_funcs.newstream == NULL)
2131
return NPERR_INVALID_FUNCTABLE_ERROR;
2133
D(bug("NPP_NewStream instance=%p, stream=%p, type='%s', seekable=%d, stype=%s\n",
2134
instance, stream, type, seekable, string_of_NPStreamType(*stype)));
2135
NPError ret = plugin_funcs.newstream(instance, type, stream, seekable, stype);
2136
D(bug(" return: %d [%s], stype=%s\n", ret, string_of_NPError(ret), string_of_NPStreamType(*stype)));
2140
static int handle_NPP_NewStream(rpc_connection_t *connection)
2149
if ((stream = malloc(sizeof(*stream))) == NULL)
2150
return RPC_ERROR_NO_MEMORY;
2151
memset(stream, 0, sizeof(*stream));
2153
error = rpc_method_get_args(connection,
2154
RPC_TYPE_NPP, &instance,
2155
RPC_TYPE_STRING, &type,
2156
RPC_TYPE_UINT32, &stream_id,
2157
RPC_TYPE_STRING, &stream->url,
2158
RPC_TYPE_UINT32, &stream->end,
2159
RPC_TYPE_UINT32, &stream->lastmodified,
2160
RPC_TYPE_NP_NOTIFY_DATA, &stream->notifyData,
2161
RPC_TYPE_BOOLEAN, &seekable,
2164
if (error != RPC_ERROR_NO_ERROR) {
2165
npw_perror("NPP_NewStream() get args", error);
2169
StreamInstance *stream_ndata;
2170
if ((stream_ndata = malloc(sizeof(*stream_ndata))) == NULL)
2171
return RPC_ERROR_NO_MEMORY;
2172
stream->ndata = stream_ndata;
2173
memset(stream_ndata, 0, sizeof(*stream_ndata));
2174
stream_ndata->stream_id = stream_id;
2175
id_link(stream_id, stream_ndata);
2176
stream_ndata->stream = stream;
2178
uint16 stype = NP_NORMAL;
2179
NPError ret = g_NPP_NewStream(instance, type, stream, seekable, &stype);
2184
return rpc_method_send_reply(connection,
2185
RPC_TYPE_INT32, ret,
2186
RPC_TYPE_UINT32, (uint32_t)stype,
2187
RPC_TYPE_NP_NOTIFY_DATA, stream->notifyData,
2191
// NPP_DestroyStream
2193
g_NPP_DestroyStream(NPP instance, NPStream *stream, NPReason reason)
2195
if (instance == NULL)
2196
return NPERR_INVALID_INSTANCE_ERROR;
2198
if (plugin_funcs.destroystream == NULL)
2199
return NPERR_INVALID_FUNCTABLE_ERROR;
2202
return NPERR_INVALID_PARAM;
2204
D(bug("NPP_DestroyStream instance=%p, stream=%p, reason=%s\n",
2205
instance, stream, string_of_NPReason(reason)));
2206
NPError ret = plugin_funcs.destroystream(instance, stream, reason);
2207
D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret)));
2209
StreamInstance *stream_ndata = stream->ndata;
2211
id_remove(stream_ndata->stream_id);
2214
free((char *)stream->url);
2220
static int handle_NPP_DestroyStream(rpc_connection_t *connection)
2222
D(bug("handle_NPP_DestroyStream\n"));
2227
int error = rpc_method_get_args(connection,
2228
RPC_TYPE_NPP, &instance,
2229
RPC_TYPE_NP_STREAM, &stream,
2230
RPC_TYPE_INT32, &reason,
2233
if (error != RPC_ERROR_NO_ERROR) {
2234
npw_perror("NPP_DestroyStream() get args", error);
2238
NPError ret = g_NPP_DestroyStream(instance, stream, reason);
2239
return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_INVALID);
2244
g_NPP_WriteReady(NPP instance, NPStream *stream)
2246
if (instance == NULL)
2247
return NPERR_INVALID_INSTANCE_ERROR;
2249
if (plugin_funcs.writeready == NULL)
2250
return NPERR_INVALID_FUNCTABLE_ERROR;
2253
return NPERR_INVALID_PARAM;
2255
D(bug("NPP_WriteReady instance=%p, stream=%p\n", instance, stream));
2256
int32 ret = plugin_funcs.writeready(instance, stream);
2257
D(bug(" return: %d\n", ret));
2261
static int handle_NPP_WriteReady(rpc_connection_t *connection)
2263
D(bug("handle_NPP_WriteReady\n"));
2267
int error = rpc_method_get_args(connection,
2268
RPC_TYPE_NPP, &instance,
2269
RPC_TYPE_NP_STREAM, &stream,
2272
if (error != RPC_ERROR_NO_ERROR) {
2273
npw_perror("NPP_WriteReady() get args", error);
2277
int32 ret = g_NPP_WriteReady(instance, stream);
2279
return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_INVALID);
2284
g_NPP_Write(NPP instance, NPStream *stream, int32 offset, int32 len, void *buf)
2286
if (instance == NULL)
2289
if (plugin_funcs.write == NULL)
2295
D(bug("NPP_Write instance=%p, stream=%p, offset=%d, len=%d, buf=%p\n", instance, stream, offset, len, buf));
2296
int32 ret = plugin_funcs.write(instance, stream, offset, len, buf);
2297
D(bug(" return: %d\n", ret));
2301
static int handle_NPP_Write(rpc_connection_t *connection)
2306
int32_t offset, len;
2307
int error = rpc_method_get_args(connection,
2308
RPC_TYPE_NPP, &instance,
2309
RPC_TYPE_NP_STREAM, &stream,
2310
RPC_TYPE_INT32, &offset,
2311
RPC_TYPE_ARRAY, RPC_TYPE_CHAR, &len, &buf,
2314
if (error != RPC_ERROR_NO_ERROR) {
2315
npw_perror("NPP_Write() get args", error);
2319
int32 ret = g_NPP_Write(instance, stream, offset, len, buf);
2324
return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_INVALID);
2329
g_NPP_StreamAsFile(NPP instance, NPStream *stream, const char *fname)
2331
if (instance == NULL)
2334
if (plugin_funcs.asfile == NULL)
2340
D(bug("NPP_StreamAsFile instance=%p, stream=%p, fname='%s'\n", instance, stream, fname));
2341
plugin_funcs.asfile(instance, stream, fname);
2345
static int handle_NPP_StreamAsFile(rpc_connection_t *connection)
2350
int error = rpc_method_get_args(connection,
2351
RPC_TYPE_NPP, &instance,
2352
RPC_TYPE_NP_STREAM, &stream,
2353
RPC_TYPE_STRING, &fname,
2356
if (error != RPC_ERROR_NO_ERROR) {
2357
npw_perror("NPP_StreamAsFile() get args", error);
2361
g_NPP_StreamAsFile(instance, stream, fname);
2366
return RPC_ERROR_NO_ERROR;
2371
g_NPP_Print(NPP instance, NPPrint *printInfo)
2373
if (plugin_funcs.print == NULL)
2376
if (printInfo == NULL)
2379
D(bug("NPP_Print instance=%p, printInfo->mode=%d\n", instance, printInfo->mode));
2380
plugin_funcs.print(instance, printInfo);
2384
static void invoke_NPN_PrintData(PluginInstance *plugin, uint32_t platform_print_id, NPPrintData *printData)
2386
if (printData == NULL)
2389
int error = rpc_method_invoke(g_rpc_connection,
2390
RPC_METHOD_NPN_PRINT_DATA,
2391
RPC_TYPE_UINT32, platform_print_id,
2392
RPC_TYPE_NP_PRINT_DATA, printData,
2395
if (error != RPC_ERROR_NO_ERROR) {
2396
npw_perror("NPN_PrintData() invoke", error);
2400
error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_INVALID);
2402
if (error != RPC_ERROR_NO_ERROR) {
2403
npw_perror("NPN_PrintData() wait for reply", error);
2408
static int handle_NPP_Print(rpc_connection_t *connection)
2412
uint32_t platform_print_id;
2413
int error = rpc_method_get_args(connection,
2414
RPC_TYPE_NPP, &instance,
2415
RPC_TYPE_UINT32, &platform_print_id,
2416
RPC_TYPE_NP_PRINT, &printInfo,
2419
if (error != RPC_ERROR_NO_ERROR) {
2420
npw_perror("NPP_Print() get args", error);
2424
// reconstruct printer info
2425
NPPrintCallbackStruct printer;
2426
printer.type = NP_PRINT;
2427
printer.fp = platform_print_id ? tmpfile() : NULL;
2428
switch (printInfo.mode) {
2430
printInfo.print.fullPrint.platformPrint = &printer;
2433
printInfo.print.embedPrint.platformPrint = &printer;
2434
// XXX the window ID is unlikely to work here as is. The NPWindow
2435
// is probably only used as a bounding box?
2436
create_window_attributes(&printInfo.print.embedPrint.window);
2440
g_NPP_Print(instance, &printInfo);
2442
// send back the printed data
2444
long file_size = ftell(printer.fp);
2445
D(bug(" writeback data [%d bytes]\n", file_size));
2447
if (file_size > 0) {
2448
NPPrintData printData;
2449
const int printDataMaxSize = sizeof(printData.data);
2450
int n = file_size / printDataMaxSize;
2452
printData.size = printDataMaxSize;
2453
if (fread(&printData.data, sizeof(printData.data), 1, printer.fp) != 1) {
2454
npw_printf("ERROR: unexpected end-of-file or error condition in NPP_Print\n");
2457
invoke_NPN_PrintData(instance->ndata, platform_print_id, &printData);
2459
printData.size = file_size % printDataMaxSize;
2460
if (fread(&printData.data, printData.size, 1, printer.fp) != 1)
2461
npw_printf("ERROR: unexpected end-of-file or error condition in NPP_Print\n");
2462
invoke_NPN_PrintData(instance->ndata, platform_print_id, &printData);
2467
if (printInfo.mode == NP_EMBED)
2468
destroy_window_attributes(&printInfo.print.embedPrint.window);
2470
uint32_t plugin_printed = FALSE;
2471
if (printInfo.mode == NP_FULL)
2472
plugin_printed = printInfo.print.fullPrint.pluginPrinted;
2473
return rpc_method_send_reply(connection, RPC_TYPE_BOOLEAN, plugin_printed, RPC_TYPE_INVALID);
2477
/* ====================================================================== */
2478
/* === Events processing === */
2479
/* ====================================================================== */
2481
typedef gboolean (*GSourcePrepare)(GSource *, gint *);
2482
typedef gboolean (*GSourceCheckFunc)(GSource *);
2483
typedef gboolean (*GSourceDispatchFunc)(GSource *, GSourceFunc, gpointer);
2484
typedef void (*GSourceFinalizeFunc)(GSource *);
2487
static GPollFD xt_event_poll_fd;
2489
static gboolean xt_event_prepare(GSource *source, gint *timeout)
2491
int mask = XtAppPending(x_app_context);
2492
return mask & XtIMXEvent;
2495
static gboolean xt_event_check(GSource *source)
2497
if (xt_event_poll_fd.revents & G_IO_IN) {
2498
int mask = XtAppPending(x_app_context);
2499
if (mask & XtIMXEvent)
2505
static gboolean xt_event_dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
2508
for (i = 0; i < 5; i++) {
2509
int mask = XtAppPending(x_app_context);
2510
if ((mask & XtIMXEvent) == 0)
2512
XtAppProcessEvent(x_app_context, XtIMXEvent);
2517
static GSourceFuncs xt_event_funcs = {
2521
(GSourceFinalizeFunc)g_free,
2523
(GSourceDummyMarshal)NULL
2526
static gboolean xt_event_polling_timer_callback(gpointer user_data)
2529
for (i = 0; i < 5; i++) {
2530
if ((XtAppPending(x_app_context) & (XtIMAll & ~XtIMXEvent)) == 0)
2532
XtAppProcessEvent(x_app_context, XtIMAll & ~XtIMXEvent);
2538
static GPollFD rpc_event_poll_fd;
2540
static gboolean rpc_event_prepare(GSource *source, gint *timeout)
2546
static gboolean rpc_event_check(GSource *source)
2548
return rpc_wait_dispatch(g_rpc_connection, 0) > 0;
2551
static gboolean rpc_event_dispatch(GSource *source, GSourceFunc callback, gpointer connection)
2553
return rpc_dispatch(connection) != RPC_ERROR_CONNECTION_CLOSED;
2556
static GSourceFuncs rpc_event_funcs = {
2560
(GSourceFinalizeFunc)g_free,
2562
(GSourceDummyMarshal)NULL
2566
/* ====================================================================== */
2567
/* === Main program === */
2568
/* ====================================================================== */
2570
static int do_test(void);
2572
static int do_main(int argc, char **argv, const char *connection_path)
2576
if (connection_path == NULL) {
2577
npw_printf("ERROR: missing connection path argument\n");
2580
D(bug(" Plugin connection: %s\n", connection_path));
2582
// Cleanup environment, the program may fork/exec a native shell
2583
// script and having 32-bit libraries in LD_PRELOAD is not right,
2584
// though not a fatal error
2585
#if defined(__linux__)
2586
if (getenv("LD_PRELOAD"))
2587
unsetenv("LD_PRELOAD");
2590
// Xt and GTK initialization
2591
XtToolkitInitialize();
2592
x_app_context = XtCreateApplicationContext();
2593
x_display = XtOpenDisplay(x_app_context, NULL, "npw-viewer", "npw-viewer", NULL, 0, &argc, argv);
2594
gtk_init(&argc, &argv);
2596
// Initialize RPC communication channel
2597
if (rpc_add_np_marshalers() < 0) {
2598
npw_printf("ERROR: failed to initialize plugin-side marshalers\n");
2601
if ((g_rpc_connection = rpc_init_server(connection_path)) == NULL) {
2602
npw_printf("ERROR: failed to initialize plugin-side RPC server connection\n");
2605
static const rpc_method_descriptor_t vtable[] = {
2606
{ RPC_METHOD_NP_GET_MIME_DESCRIPTION, handle_NP_GetMIMEDescription },
2607
{ RPC_METHOD_NP_GET_VALUE, handle_NP_GetValue },
2608
{ RPC_METHOD_NP_INITIALIZE, handle_NP_Initialize },
2609
{ RPC_METHOD_NP_SHUTDOWN, handle_NP_Shutdown },
2610
{ RPC_METHOD_NPP_NEW, handle_NPP_New },
2611
{ RPC_METHOD_NPP_DESTROY, handle_NPP_Destroy },
2612
{ RPC_METHOD_NPP_GET_VALUE, handle_NPP_GetValue },
2613
{ RPC_METHOD_NPP_SET_WINDOW, handle_NPP_SetWindow },
2614
{ RPC_METHOD_NPP_URL_NOTIFY, handle_NPP_URLNotify },
2615
{ RPC_METHOD_NPP_NEW_STREAM, handle_NPP_NewStream },
2616
{ RPC_METHOD_NPP_DESTROY_STREAM, handle_NPP_DestroyStream },
2617
{ RPC_METHOD_NPP_WRITE_READY, handle_NPP_WriteReady },
2618
{ RPC_METHOD_NPP_WRITE, handle_NPP_Write },
2619
{ RPC_METHOD_NPP_STREAM_AS_FILE, handle_NPP_StreamAsFile },
2620
{ RPC_METHOD_NPP_PRINT, handle_NPP_Print },
2621
{ RPC_METHOD_NPCLASS_INVALIDATE, npclass_handle_Invalidate },
2622
{ RPC_METHOD_NPCLASS_HAS_METHOD, npclass_handle_HasMethod },
2623
{ RPC_METHOD_NPCLASS_INVOKE, npclass_handle_Invoke },
2624
{ RPC_METHOD_NPCLASS_INVOKE_DEFAULT, npclass_handle_InvokeDefault },
2625
{ RPC_METHOD_NPCLASS_HAS_PROPERTY, npclass_handle_HasProperty },
2626
{ RPC_METHOD_NPCLASS_GET_PROPERTY, npclass_handle_GetProperty },
2627
{ RPC_METHOD_NPCLASS_SET_PROPERTY, npclass_handle_SetProperty },
2628
{ RPC_METHOD_NPCLASS_REMOVE_PROPERTY, npclass_handle_RemoveProperty },
2630
if (rpc_method_add_callbacks(g_rpc_connection, vtable, sizeof(vtable) / sizeof(vtable[0])) < 0) {
2631
npw_printf("ERROR: failed to setup NPP method callbacks\n");
2637
// Initialize Xt events listener (integrate X events into GTK events loop)
2638
GSource *xt_source = g_source_new(&xt_event_funcs, sizeof(GSource));
2639
if (xt_source == NULL) {
2640
npw_printf("ERROR: failed to initialize Xt events listener\n");
2643
g_source_set_priority(xt_source, GDK_PRIORITY_EVENTS);
2644
g_source_set_can_recurse(xt_source, TRUE);
2645
g_source_attach(xt_source, NULL);
2646
xt_event_poll_fd.fd = ConnectionNumber(x_display);
2647
xt_event_poll_fd.events = G_IO_IN;
2648
xt_event_poll_fd.revents = 0;
2649
g_source_add_poll(xt_source, &xt_event_poll_fd);
2651
gint xt_polling_timer_id = g_timeout_add(25,
2652
xt_event_polling_timer_callback,
2655
// Initialize RPC events listener
2656
GSource *rpc_source = g_source_new(&rpc_event_funcs, sizeof(GSource));
2657
if (rpc_source == NULL) {
2658
npw_printf("ERROR: failed to initialize plugin-side RPC events listener\n");
2661
g_source_set_priority(rpc_source, GDK_PRIORITY_EVENTS);
2662
g_source_attach(rpc_source, NULL);
2663
rpc_event_poll_fd.fd = rpc_listen_socket(g_rpc_connection);
2664
rpc_event_poll_fd.events = G_IO_IN;
2665
rpc_event_poll_fd.revents = 0;
2666
g_source_set_callback(rpc_source, (GSourceFunc)rpc_dispatch, g_rpc_connection, NULL);
2667
g_source_add_poll(rpc_source, &rpc_event_poll_fd);
2670
D(bug("--- EXIT ---\n"));
2672
g_source_remove(xt_polling_timer_id);
2673
g_source_destroy(rpc_source);
2674
g_source_destroy(xt_source);
2678
if (g_rpc_connection)
2679
rpc_exit(g_rpc_connection);
2685
// Flash Player 9 beta 1 is not stable enough and will generally
2686
// freeze on NP_Shutdown when multiple Flash movies are active
2687
static int is_flash_player9_beta1(void)
2689
if (g_NP_GetValue) {
2690
const char *plugin_desc = NULL;
2691
if (g_NP_GetValue(NULL, NPPVpluginDescriptionString, &plugin_desc) == NPERR_NO_ERROR
2692
&& plugin_desc && strcmp(plugin_desc, "Shockwave Flash 9.0 d55") == 0) {
2693
npw_printf("WARNING: Flash Player 9 beta 1 detected and rejected\n");
2700
static int do_test(void)
2702
if (g_NP_GetMIMEDescription == NULL)
2704
if (g_NP_Initialize == NULL)
2706
if (g_NP_Shutdown == NULL)
2708
if (is_flash_player9_beta1())
2713
static int do_info(void)
2717
if (g_NP_GetValue == NULL)
2718
printf("0\n\n0\n\n");
2720
const char *plugin_name = NULL;
2721
if (g_NP_GetValue(NULL, NPPVpluginNameString, &plugin_name) == NPERR_NO_ERROR && plugin_name)
2722
printf("%zd\n%s\n", strlen(plugin_name) + 1, plugin_name);
2725
const char *plugin_desc = NULL;
2726
if (g_NP_GetValue(NULL, NPPVpluginDescriptionString, &plugin_desc) == NPERR_NO_ERROR && plugin_desc)
2727
printf("%zd\n%s\n", strlen(plugin_desc) + 1, plugin_desc);
2731
const char *mime_info = g_NP_GetMIMEDescription();
2733
printf("%zd\n%s\n", strlen(mime_info) + 1, mime_info);
2739
static int do_help(const char *prog)
2741
printf("%s, NPAPI plugin viewer. Version %s\n", NPW_VIEWER, NPW_VERSION);
2743
printf("usage: %s [GTK flags] [flags]\n", prog);
2744
printf(" -h --help print this message\n");
2745
printf(" -t --test check plugin is compatible\n");
2746
printf(" -i --info print plugin information\n");
2747
printf(" -p --plugin set plugin path\n");
2748
printf(" -c --connection set connection path\n");
2752
int main(int argc, char **argv)
2754
const char *plugin_path = NULL;
2755
const char *connection_path = NULL;
2765
// Parse command line arguments
2766
for (int i = 0; i < argc; i++) {
2767
const char *arg = argv[i];
2768
if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) {
2772
else if (strcmp(arg, "-t") == 0 || strcmp(arg, "--test") == 0) {
2776
else if (strcmp(arg, "-i") == 0 || strcmp(arg, "--info") == 0) {
2780
else if (strcmp(arg, "-p") == 0 || strcmp(arg, "--plugin") == 0) {
2783
plugin_path = argv[i];
2787
else if (strcmp(arg, "-c") == 0 || strcmp(arg, "--connection") == 0) {
2790
connection_path = argv[i];
2796
// Remove processed arguments
2797
for (int i = 1, j = 1, n = argc; i < n; i++) {
2799
argv[j++] = argv[i];
2804
// Open plug-in and get exported lib functions
2805
void *handle = NULL;
2806
if (plugin_path == NULL)
2810
D(bug(" %s\n", plugin_path));
2811
if ((handle = dlopen(plugin_path, RTLD_LAZY)) == NULL) {
2812
npw_printf("ERROR: %s\n", dlerror());
2816
g_NP_GetMIMEDescription = (NP_GetMIMEDescriptionUPP)dlsym(handle, "NP_GetMIMEDescription");
2817
if ((error = dlerror()) != NULL) {
2818
npw_printf("ERROR: %s\n", error);
2821
g_NP_Initialize = (NP_InitializeUPP)dlsym(handle, "NP_Initialize");
2822
if ((error = dlerror()) != NULL) {
2823
npw_printf("ERROR: %s\n", error);
2826
g_NP_Shutdown = (NP_ShutdownUPP)dlsym(handle, "NP_Shutdown");
2827
if ((error = dlerror()) != NULL) {
2828
npw_printf("ERROR: %s\n", error);
2831
g_NP_GetValue = (NP_GetValueUPP)dlsym(handle, "NP_GetValue");
2837
ret = do_main(argc, argv, connection_path);
2846
ret = do_help(argv[0]);