File indexing completed on 2024-04-14 15:01:14
0001 /* 0002 * Copyright (C) 2007 Koos Vriezen <koos.vriezen@gmail.com> 0003 * 0004 * This library is free software; you can redistribute it and/or 0005 * modify it under the terms of the GNU Lesser General Public 0006 * License as published by the Free Software Foundation; either 0007 * version 2 of the License, or (at your option) any later version. 0008 * 0009 * This library is distributed in the hope that it will be useful, 0010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 * Lesser General Public License for more details. 0013 * 0014 * You should have received a copy of the GNU Lesser General Public 0015 * License along with this library; if not, write to the Free Software 0016 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 0017 */ 0018 0019 /* gcc -o knpplayer `pkg-config --libs --cflags gtk+-x11-2.0` `pkg-config --libs --cflags dbus-glib-1` `pkg-config --libs --cflags gthread-2.0` npplayer.c 0020 0021 http://devedge-temp.mozilla.org/library/manuals/2002/plugin/1.0/ 0022 http://dbus.freedesktop.org/doc/dbus/libdbus-tutorial.html 0023 */ 0024 extern "C" { 0025 #include <unistd.h> 0026 #include <string.h> 0027 #include <stdio.h> 0028 #include <stdarg.h> 0029 #include <stdlib.h> 0030 #include <sys/types.h> 0031 #include <sys/time.h> 0032 #include <fcntl.h> 0033 0034 #include <glib/gprintf.h> 0035 #include <glib.h> 0036 #include <gdk/gdkx.h> 0037 #include <gtk/gtk.h> 0038 0039 #include <dbus/dbus-glib-lowlevel.h> 0040 #define DBUS_API_SUBJECT_TO_CHANGE 0041 #include <dbus/dbus.h> 0042 #include <dbus/dbus-glib.h> 0043 0044 #define XP_UNIX 0045 #define MOZ_X11 0046 #include "moz-sdk/npapi.h" 0047 #include "moz-sdk/npruntime.h" 0048 #include "moz-sdk/npfunctions.h" 0049 #include "moz-sdk/prtypes.h" 0050 0051 #define INITIAL_WINDOW_WIDTH 1920 0052 0053 typedef const char* (* NP_LOADDS NP_GetMIMEDescriptionUPP)(); 0054 typedef NPError (* NP_GetValueUPP)(void *inst, NPPVariable var, void *value); 0055 typedef NPError (* NP_InitializeUPP)(NPNetscapeFuncs*, NPPluginFuncs*); 0056 typedef NPError (* NP_ShutdownUPP)(void); 0057 0058 static gchar *plugin; 0059 static gchar *object_url; 0060 static gchar *mimetype; 0061 0062 static DBusConnection *dbus_connection; 0063 static DBusObjectPathVTable stream_vtable; 0064 static char *service_name; 0065 static gchar *callback_service; 0066 static gchar *callback_path; 0067 static GModule *library; 0068 static GtkWidget *xembed; 0069 static Window socket_id; 0070 static Window parent_id; 0071 static int top_w, top_h; 0072 static int update_dimension_timer; 0073 static int stdin_read_watch; 0074 0075 static NPNetscapeFuncs ns_funcs; 0076 static NPPluginFuncs np_funcs; /* plugin functions */ 0077 static NPP npp; /* single instance of the plugin */ 0078 static NPWindow np_window; 0079 static NPSetWindowCallbackStruct ws_info; 0080 static NPObject *js_window; 0081 static NPSavedData *saved_data; 0082 static NPClass js_class; 0083 static GTree *stream_list; 0084 static gpointer current_stream_id; 0085 static uint32_t stream_chunk_size; 0086 static char stream_buf[64 * 1024]; 0087 static unsigned int stream_buf_pos; 0088 static int stream_id_counter; 0089 static GTree *identifiers; 0090 typedef struct _StreamInfo { 0091 NPStream np_stream; 0092 /*unsigned int stream_buf_pos;*/ 0093 unsigned int stream_pos; 0094 unsigned int total; 0095 unsigned int reason; 0096 unsigned int post_len; 0097 char *url; 0098 char *mimetype; 0099 char *target; 0100 char *post; 0101 char *headers; 0102 bool notify; 0103 bool called_plugin; 0104 bool destroyed; 0105 } StreamInfo; 0106 struct JsObject { 0107 NPObject npobject; 0108 struct JsObject * parent; 0109 char * name; 0110 }; 0111 0112 static NP_GetMIMEDescriptionUPP npGetMIMEDescription; 0113 static NP_GetValueUPP npGetValue; 0114 static NP_InitializeUPP npInitialize; 0115 static NP_ShutdownUPP npShutdown; 0116 0117 static const char *iface_stream = "org.kde.kmplayer.stream"; 0118 static const char *iface_callback = "org.kde.kmplayer.callback"; 0119 static void callFunction(int stream, const char *iface, const char *func, int first_arg_type, ...); 0120 static void readStdin (gpointer d, gint src, GdkInputCondition cond); 0121 static char *evaluate (const char *script, bool store); 0122 0123 static 0124 DBusHandlerResult dbusStreamMessage(DBusConnection *c, DBusMessage *m, void *u); 0125 static void dbusStreamUnregister (DBusConnection *conn, void *user_data); 0126 0127 /*----------------%<---------------------------------------------------------*/ 0128 0129 static void print (const char * format, ...) { 0130 va_list vl; 0131 va_start (vl, format); 0132 vfprintf (stderr, format, vl); 0133 va_end (vl); 0134 fflush (stderr); 0135 } 0136 0137 static void *nsAlloc (uint32 size) { 0138 return g_malloc (size); 0139 } 0140 0141 static void nsMemFree (void* ptr) { 0142 g_free (ptr); 0143 } 0144 0145 static void createPath (int stream, char *buf, int buf_len) { 0146 strncpy (buf, callback_path, buf_len -1); 0147 buf [buf_len -1] = 0; 0148 if (stream > -1) { 0149 int len = strlen (buf); 0150 snprintf (buf + len, buf_len - len, "/stream_%d", stream); 0151 } 0152 } 0153 0154 /*----------------%<---------------------------------------------------------*/ 0155 0156 static gint streamCompare (gconstpointer a, gconstpointer b) { 0157 return (long)a - (long)b; 0158 } 0159 0160 static void freeStream (StreamInfo *si) { 0161 char stream_name[64]; 0162 sprintf (stream_name, "/stream_%d", (int)(long) si->np_stream.ndata); 0163 if (!g_tree_remove (stream_list, si->np_stream.ndata)) 0164 print ("WARNING freeStream not in tree\n"); 0165 else 0166 dbus_connection_unregister_object_path (dbus_connection, stream_name); 0167 g_free (si->url); 0168 if (si->mimetype) 0169 g_free (si->mimetype); 0170 if (si->target) 0171 g_free (si->target); 0172 if (si->post) 0173 nsMemFree (si->post); 0174 if (si->headers) 0175 nsMemFree (si->headers); 0176 nsMemFree (si); 0177 } 0178 0179 static gboolean requestStream (void * p) { 0180 StreamInfo *si = (StreamInfo *) g_tree_lookup (stream_list, p); 0181 if (si) { 0182 char *path = (char *)nsAlloc (64); 0183 char *target = si->target ? si->target : g_strdup (""); 0184 if (!callback_service) 0185 current_stream_id = p; 0186 if (!stdin_read_watch) 0187 stdin_read_watch = gdk_input_add (0, GDK_INPUT_READ, readStdin, NULL); 0188 createPath ((int)(long)p, path, 64); 0189 0190 char cb_path[64]; 0191 createPath (-1, cb_path, sizeof (cb_path)); 0192 print ("call %s.%s()\n", cb_path, "request_stream"); 0193 if (callback_service) { 0194 DBusMessageIter it, ait; 0195 DBusMessage *msg = dbus_message_new_method_call ( 0196 callback_service, 0197 cb_path, 0198 "org.kde.kmplayer.callback", 0199 "request_stream"); 0200 dbus_message_iter_init_append (msg, &it); 0201 dbus_message_iter_append_basic (&it, DBUS_TYPE_STRING, &path); 0202 dbus_message_iter_append_basic (&it, DBUS_TYPE_STRING, &si->url); 0203 dbus_message_iter_append_basic (&it, DBUS_TYPE_STRING, &target); 0204 dbus_message_iter_open_container (&it, DBUS_TYPE_ARRAY, "y", &ait); 0205 if (si->post_len) 0206 dbus_message_iter_append_fixed_array (&ait, 0207 DBUS_TYPE_BYTE, &si->post, si->post_len); 0208 dbus_message_iter_close_container(&it, &ait); 0209 dbus_message_set_no_reply (msg, TRUE); 0210 dbus_connection_send (dbus_connection, msg, NULL); 0211 dbus_message_unref (msg); 0212 dbus_connection_flush (dbus_connection); 0213 } 0214 0215 nsMemFree (path); 0216 if (!si->target) 0217 g_free (target); 0218 } else { 0219 print ("requestStream %d not found", (long) p); 0220 } 0221 return 0; /* single shot */ 0222 } 0223 0224 static gboolean destroyStream (void * p) { 0225 StreamInfo *si = (StreamInfo *) g_tree_lookup (stream_list, p); 0226 if (si) { 0227 si->destroyed = true; 0228 callFunction ((int)(long)p, iface_stream, "destroy", DBUS_TYPE_INVALID); 0229 } 0230 return 0; /* single shot */ 0231 } 0232 0233 static void removeStream (void * p) { 0234 StreamInfo *si = (StreamInfo *) g_tree_lookup (stream_list, p); 0235 0236 if (si) { 0237 print ("removeStream %d rec:%d reason %d %dx%d\n", (long) p, si->stream_pos, si->reason, top_w, top_h); 0238 if (!si->destroyed) { 0239 if (si->called_plugin && !si->target) { 0240 si->np_stream.end = si->total; 0241 np_funcs.destroystream (npp, &si->np_stream, si->reason); 0242 } 0243 if (si->notify) 0244 np_funcs.urlnotify (npp, 0245 si->url, si->reason, si->np_stream.notifyData); 0246 } 0247 freeStream (si); 0248 } 0249 } 0250 0251 static int32_t writeStream (gpointer p, char *buf, uint32_t count) { 0252 int32_t sz = -1; 0253 StreamInfo *si = (StreamInfo *) g_tree_lookup (stream_list, p); 0254 /*print ("writeStream found %d count %d\n", !!si, count);*/ 0255 if (si) { 0256 if (si->reason > NPERR_NO_ERROR || si->destroyed) { 0257 sz = count; /* stream closed, skip remainings */ 0258 } else { 0259 if (!si->called_plugin) { 0260 uint16 stype = NP_NORMAL; 0261 NPError err = np_funcs.newstream (npp, si->mimetype 0262 ? si->mimetype 0263 : (char *)"text/plain", 0264 &si->np_stream, 0, &stype); 0265 if (err != NPERR_NO_ERROR) { 0266 g_printerr ("newstream error %d\n", err); 0267 destroyStream (p); 0268 return count; /* stream not accepted, skip remainings */ 0269 } 0270 print ("newStream %d type:%d\n", (long) p, stype); 0271 si->called_plugin = true; 0272 } 0273 if (count) /* urls with a target returns zero bytes */ 0274 sz = np_funcs.writeready (npp, &si->np_stream); 0275 if (sz > 0) { 0276 sz = np_funcs.write (npp, &si->np_stream, si->stream_pos, 0277 (int32_t) count > sz ? sz : (int32_t) count, buf); 0278 if (sz < 0) { /*FIXME plugin destroys stream here*/ 0279 si->reason = NPERR_INVALID_PLUGIN_ERROR; 0280 destroyStream ((gpointer)p); 0281 return count; /* stream not accepted, skip remainings */ 0282 } 0283 } else { 0284 sz = 0; 0285 } 0286 si->stream_pos += sz; 0287 if (si->stream_pos == si->total) { 0288 if (si->stream_pos || !count) { 0289 si->reason = NPRES_DONE; 0290 removeStream (p); 0291 } else { 0292 g_timeout_add (0, destroyStream, p); 0293 } 0294 } 0295 } 0296 } 0297 return sz; 0298 } 0299 0300 static StreamInfo *addStream (const char *url, const char *mime, const char *target, int len, const char *post, void *notify_data, bool notify) { 0301 StreamInfo *si = (StreamInfo *) nsAlloc (sizeof (StreamInfo)); 0302 char stream_name[64]; 0303 0304 memset (si, 0, sizeof (StreamInfo)); 0305 si->url = g_strdup (url); 0306 si->np_stream.url = si->url; 0307 if (mime) 0308 si->mimetype = g_strdup (mime); 0309 if (target) 0310 si->target = g_strdup (target); 0311 if (len && post) { 0312 si->post_len = len; 0313 si->post = (char *) nsAlloc (len); 0314 memcpy (si->post, post, len); 0315 } 0316 si->np_stream.notifyData = notify_data; 0317 si->notify = notify; 0318 si->np_stream.ndata = (void *) (long) (stream_id_counter++); 0319 print ("add stream %d\n", (long) si->np_stream.ndata); 0320 sprintf (stream_name, "/stream_%d", (int)(long) si->np_stream.ndata); 0321 if (!dbus_connection_register_object_path (dbus_connection, stream_name, 0322 &stream_vtable, si)) 0323 g_printerr ("dbus_connection_register_object_path error\n"); 0324 g_tree_insert (stream_list, si->np_stream.ndata, si); 0325 0326 g_timeout_add (0, requestStream, si->np_stream.ndata); 0327 0328 return si; 0329 } 0330 0331 /*----------------%<---------------------------------------------------------*/ 0332 0333 static void createJsName (JsObject * obj, char **name, uint32_t * len) { 0334 int slen = strlen (obj->name); 0335 if (obj->parent) { 0336 *len += slen + 1; 0337 createJsName (obj->parent, name, len); 0338 } else { 0339 *name = (char *) nsAlloc (*len + slen + 1); 0340 *(*name + *len + slen) = 0; 0341 *len = 0; 0342 } 0343 if (obj->parent) { 0344 *(*name + *len) = '.'; 0345 *len += 1; 0346 } 0347 memcpy (*name + *len, obj->name, slen); 0348 *len += slen; 0349 } 0350 0351 static char *nsVariant2Str (const NPVariant *value) { 0352 char *str; 0353 switch (value->type) { 0354 case NPVariantType_String: 0355 str = (char *) nsAlloc (value->value.stringValue.utf8length + 3); 0356 str[0] = str[value->value.stringValue.utf8length + 1] = '\''; 0357 strncpy (str + 1, value->value.stringValue.utf8characters, 0358 value->value.stringValue.utf8length); 0359 str[value->value.stringValue.utf8length + 2] = 0; 0360 break; 0361 case NPVariantType_Int32: 0362 str = (char *) nsAlloc (16); 0363 snprintf (str, 15, "%d", value->value.intValue); 0364 break; 0365 case NPVariantType_Double: 0366 str = (char *) nsAlloc (64); 0367 snprintf (str, 63, "%f", value->value.doubleValue); 0368 break; 0369 case NPVariantType_Bool: 0370 str = strdup (value->value.boolValue ? "true" : "false"); 0371 break; 0372 case NPVariantType_Null: 0373 str = strdup ("null"); 0374 break; 0375 case NPVariantType_Object: 0376 if (&js_class == value->value.objectValue->_class) { 0377 JsObject *jv = (JsObject *) value->value.objectValue; 0378 char *val; 0379 uint32_t vlen = 0; 0380 createJsName (jv, &val, &vlen); 0381 str = strdup (val); 0382 nsMemFree (val); 0383 } else { 0384 str = strdup ("null"); /* TODO track plugin objects */ 0385 } 0386 break; 0387 default: 0388 str = strdup (""); 0389 break; 0390 } 0391 return str; 0392 } 0393 0394 /*----------------%<---------------------------------------------------------*/ 0395 0396 static NPObject * nsCreateObject (NPP instance, NPClass *aClass) { 0397 NPObject *obj; 0398 if (aClass && aClass->allocate) { 0399 obj = aClass->allocate (instance, aClass); 0400 } else { 0401 obj = (NPObject *) nsAlloc (sizeof (NPObject)); 0402 memset (obj, 0, sizeof (NPObject)); 0403 obj->_class = aClass; 0404 /*obj = js_class.allocate (instance, &js_class);/ *add null class*/ 0405 print ("NPN_CreateObject\n"); 0406 } 0407 obj->referenceCount = 1; 0408 return obj; 0409 } 0410 0411 static NPObject *nsRetainObject (NPObject *npobj) { 0412 /*print( "nsRetainObject %p\n", npobj);*/ 0413 npobj->referenceCount++; 0414 return npobj; 0415 } 0416 0417 static void nsReleaseObject (NPObject *obj) { 0418 /*print ("NPN_ReleaseObject\n");*/ 0419 if (! (--obj->referenceCount)) 0420 obj->_class->deallocate (obj); 0421 } 0422 0423 static NPError nsGetURL (NPP instance, const char* url, const char* target) { 0424 (void)instance; 0425 print ("nsGetURL %s %s\n", url, target ? target : ""); 0426 addStream (url, 0L, target, 0, NULL, 0L, false); 0427 return NPERR_NO_ERROR; 0428 } 0429 0430 static NPError nsPostURL (NPP instance, const char *url, 0431 const char *target, uint32 len, const char *buf, NPBool file) { 0432 (void)instance; (void)file; 0433 print ("nsPostURL %s %s\n", url, target ? target : ""); 0434 addStream (url, 0L, target, len, buf, 0L, false); 0435 return NPERR_NO_ERROR; 0436 } 0437 0438 static NPError nsRequestRead (NPStream *stream, NPByteRange *rangeList) { 0439 (void)stream; (void)rangeList; 0440 print ("nsRequestRead\n"); 0441 return NPERR_NO_ERROR; 0442 } 0443 0444 static NPError nsNewStream (NPP instance, NPMIMEType type, 0445 const char *target, NPStream **stream) { 0446 (void)instance; (void)type; (void)stream; (void)target; 0447 print ("nsNewStream\n"); 0448 return NPERR_NO_ERROR; 0449 } 0450 0451 static int32 nsWrite (NPP instance, NPStream* stream, int32 len, void *buf) { 0452 (void)instance; (void)len; (void)buf; (void)stream; 0453 print ("nsWrite\n"); 0454 return 0; 0455 } 0456 0457 static NPError nsDestroyStream (NPP instance, NPStream *stream, NPError reason) { 0458 StreamInfo *si = (StreamInfo *) g_tree_lookup (stream_list, stream->ndata); 0459 (void)instance; 0460 print ("nsDestroyStream\n"); 0461 if (si) { 0462 si->reason = reason; 0463 si->destroyed = true; 0464 g_timeout_add (0, destroyStream, stream->ndata); 0465 return NPERR_NO_ERROR; 0466 } 0467 return NPERR_NO_DATA; 0468 } 0469 0470 static void nsStatus (NPP instance, const char* message) { 0471 (void)instance; 0472 print ("NPN_Status %s\n", message ? message : "-"); 0473 } 0474 0475 static const char* nsUserAgent (NPP instance) { 0476 (void)instance; 0477 print ("NPN_UserAgent\n"); 0478 return ""; 0479 } 0480 0481 static uint32 nsMemFlush (uint32 size) { 0482 (void)size; 0483 print ("NPN_MemFlush\n"); 0484 return 0; 0485 } 0486 0487 static void nsReloadPlugins (NPBool reloadPages) { 0488 (void)reloadPages; 0489 print ("NPN_ReloadPlugins\n"); 0490 } 0491 0492 /*static JRIEnv* nsGetJavaEnv () { 0493 print ("NPN_GetJavaEnv\n"); 0494 return NULL; 0495 }*/ 0496 0497 static void *nsGetJavaEnv () { 0498 print ("NPN_GetJavaEnv\n"); 0499 return NULL; 0500 } 0501 0502 /*static jref nsGetJavaPeer (NPP instance) { 0503 (void)instance; 0504 print ("NPN_GetJavaPeer\n"); 0505 return NULL; 0506 }*/ 0507 0508 static void *nsGetJavaPeer (NPP instance) { 0509 (void)instance; 0510 print ("NPN_GetJavaPeer\n"); 0511 return NULL; 0512 } 0513 0514 static NPError nsGetURLNotify (NPP instance, const char* url, const char* target, void *notify) { 0515 (void)instance; 0516 print ("NPN_GetURLNotify %s %s\n", url, target ? target : ""); 0517 addStream (url, 0L, target, 0, NULL, notify, true); 0518 return NPERR_NO_ERROR; 0519 } 0520 0521 static NPError nsPostURLNotify (NPP instance, const char* url, const char* target, uint32 len, const char* buf, NPBool file, void *notify) { 0522 (void)instance; (void)file; 0523 print ("NPN_PostURLNotify\n"); 0524 addStream (url, 0L, target, len, buf, notify, true); 0525 return NPERR_NO_ERROR; 0526 } 0527 0528 static NPError nsGetValue (NPP instance, NPNVariable variable, void *value) { 0529 print ("NPN_GetValue %d\n", variable & ~NP_ABI_MASK); 0530 switch (variable) { 0531 case NPNVxDisplay: 0532 *(void**)value = (void*)(long) gdk_x11_get_default_xdisplay (); 0533 break; 0534 case NPNVxtAppContext: 0535 *(void**)value = NULL; 0536 break; 0537 case NPNVnetscapeWindow: 0538 print ("NPNVnetscapeWindow\n"); 0539 break; 0540 case NPNVjavascriptEnabledBool: 0541 *(NPBool*)value = 1; 0542 break; 0543 case NPNVasdEnabledBool: 0544 *(NPBool*)value = 0; 0545 break; 0546 case NPNVisOfflineBool: 0547 *(NPBool*)value = 0; 0548 break; 0549 case NPNVserviceManager: 0550 *(void**)value = NULL; 0551 return NPERR_GENERIC_ERROR; 0552 /* *(int*)value = 0;*/ 0553 break; 0554 case NPNVToolkit: 0555 *(int*)value = NPNVGtk2; 0556 break; 0557 case NPNVSupportsXEmbedBool: 0558 *(NPBool*)value = 1; 0559 break; 0560 case NPNVSupportsWindowless: 0561 *(NPBool*)value = 0; 0562 break; 0563 case NPNVprivateModeBool: 0564 *(NPBool*)value = 0; 0565 break; 0566 case NPNVWindowNPObject: 0567 if (!js_window) { 0568 JsObject *jo = (JsObject*) nsCreateObject (instance, &js_class); 0569 jo->name = g_strdup ("window"); 0570 js_window = (NPObject *) jo; 0571 } 0572 *(NPObject**)value = nsRetainObject (js_window); 0573 break; 0574 case NPNVPluginElementNPObject: { 0575 JsObject * obj = (JsObject *) nsCreateObject (instance, &js_class); 0576 obj->name = g_strdup ("this"); 0577 *(NPObject**)value = (NPObject *) obj; 0578 break; 0579 } 0580 default: 0581 print ("unknown value\n"); 0582 return NPERR_GENERIC_ERROR; 0583 } 0584 return NPERR_NO_ERROR; 0585 } 0586 0587 static NPError nsSetValue (NPP instance, NPPVariable variable, void *value) { 0588 /* NPPVpluginWindowBool */ 0589 (void)instance; (void)value; 0590 print ("NPN_SetValue %d\n", variable & ~NP_ABI_MASK); 0591 return NPERR_NO_ERROR; 0592 } 0593 0594 static void nsInvalidateRect (NPP instance, NPRect *invalidRect) { 0595 (void)instance; (void)invalidRect; 0596 print ("NPN_InvalidateRect\n"); 0597 } 0598 0599 static void nsInvalidateRegion (NPP instance, NPRegion invalidRegion) { 0600 (void)instance; (void)invalidRegion; 0601 print ("NPN_InvalidateRegion\n"); 0602 } 0603 0604 static void nsForceRedraw (NPP instance) { 0605 (void)instance; 0606 print ("NPN_ForceRedraw\n"); 0607 } 0608 0609 static NPIdentifier nsGetStringIdentifier (const NPUTF8* name) { 0610 /*print ("NPN_GetStringIdentifier %s\n", name);*/ 0611 gpointer id = g_tree_lookup (identifiers, name); 0612 if (!id) { 0613 id = strdup (name); 0614 g_tree_insert (identifiers, id, id); 0615 } 0616 return id; 0617 } 0618 0619 static void nsGetStringIdentifiers (const NPUTF8** names, int32_t nameCount, 0620 NPIdentifier* ids) { 0621 (void)names; (void)nameCount; (void)ids; 0622 print ("NPN_GetStringIdentifiers\n"); 0623 } 0624 0625 static NPIdentifier nsGetIntIdentifier (int32_t intid) { 0626 print ("NPN_GetIntIdentifier %d\n", intid); 0627 return (NPIdentifier) (long) intid; 0628 } 0629 0630 static bool nsIdentifierIsString (NPIdentifier name) { 0631 print ("NPN_IdentifierIsString\n"); 0632 return !!g_tree_lookup (identifiers, name); 0633 } 0634 0635 static NPUTF8 * nsUTF8FromIdentifier (NPIdentifier name) { 0636 char *str = (char *)g_tree_lookup (identifiers, name); 0637 print ("NPN_UTF8FromIdentifier %s\n", str ? str : "not found"); 0638 if (str) 0639 return strdup (str); 0640 return NULL; 0641 } 0642 0643 static int32_t nsIntFromIdentifier (NPIdentifier identifier) { 0644 print ("NPN_IntFromIdentifier\n"); 0645 return (int32_t) (long) identifier; 0646 } 0647 0648 static bool nsInvoke (NPP instance, NPObject * npobj, NPIdentifier method, 0649 const NPVariant *args, uint32_t arg_count, NPVariant *result) { 0650 (void)instance; 0651 /*print ("NPN_Invoke %s\n", id);*/ 0652 return npobj->_class->invoke (npobj, method, args, arg_count, result); 0653 } 0654 0655 static bool nsInvokeDefault (NPP instance, NPObject * npobj, 0656 const NPVariant * args, uint32_t arg_count, NPVariant * result) { 0657 (void)instance; 0658 return npobj->_class->invokeDefault (npobj,args, arg_count, result); 0659 } 0660 0661 static bool str2NPVariant (NPP instance, const char *str, NPVariant *result) { 0662 if (!str || !*str) 0663 return false; 0664 if (!strncmp (str, "o:", 2)) { 0665 JsObject *jo = (JsObject *)nsCreateObject (instance, &js_class); 0666 result->type = NPVariantType_Object; 0667 jo->name = g_strdup (str + 2); 0668 result->value.objectValue = (NPObject *)jo; 0669 print ("object\n"); 0670 } else if (!strncmp (str, "s:", 2)) { 0671 result->type = NPVariantType_String; 0672 result->value.stringValue.utf8characters= g_strdup(str+2); 0673 result->value.stringValue.utf8length = strlen (str) - 2; 0674 print ("string %s\n", str + 2); 0675 } else if (!strncmp (str, "u:", 2)) { 0676 result->type = NPVariantType_Null; 0677 print ("null\n"); 0678 } else if (!strncmp (str, "n:", 2)) { 0679 char *eptr; 0680 long l = strtol (str + 2, &eptr, 10); 0681 if (*eptr && *eptr == '.') { 0682 result->type = NPVariantType_Double; 0683 result->value.doubleValue = strtod (str + 2, NULL); 0684 print ("double %f\n", result->value.doubleValue); 0685 } else if (eptr != str + 2) { 0686 result->type = NPVariantType_Int32; 0687 result->value.intValue = (int)l; 0688 print ("int32 %d\n", l); 0689 } else { 0690 result->type = NPVariantType_Null; 0691 return false; 0692 } 0693 } else if (!strncmp (str, "b:", 2)) { 0694 result->type = NPVariantType_Bool; 0695 if (!strcasecmp (str + 2, "true")) { 0696 result->value.boolValue = true; 0697 } else { 0698 char *eptr; 0699 long l = strtol (str + 2, &eptr, 10); 0700 result->value.boolValue = eptr != str ? !!l : false; 0701 } 0702 print ("bool %d\n", result->value.boolValue); 0703 } else { 0704 return false; 0705 } 0706 return true; 0707 } 0708 0709 static bool doEvaluate (NPP instance, NPObject * npobj, NPString * script, 0710 NPVariant * result) { 0711 char *result_string; 0712 bool success = false; 0713 (void) npobj; /*FIXME scope, search npobj window*/ 0714 0715 result_string = evaluate (script->utf8characters, true); 0716 0717 if (result_string) { 0718 success = str2NPVariant (instance, result_string, result); 0719 g_free (result_string); 0720 } 0721 0722 return success; 0723 } 0724 0725 static bool nsEvaluate (NPP instance, NPObject * npobj, NPString * script, 0726 NPVariant * result) { 0727 NPString str; 0728 char *jsscript; 0729 char *escaped; 0730 bool res; 0731 0732 print ("NPN_Evaluate:"); 0733 escaped = g_strescape (script->utf8characters, ""); 0734 str.utf8length = strlen (escaped) + 9; 0735 jsscript = (char *) nsAlloc (str.utf8length); 0736 sprintf (jsscript, "eval(\"%s\")", escaped); 0737 str.utf8characters = jsscript; 0738 0739 res = doEvaluate (instance, npobj, &str, result); 0740 0741 nsMemFree (jsscript); 0742 g_free (escaped); 0743 0744 return res; 0745 } 0746 0747 static bool nsGetProperty (NPP instance, NPObject * npobj, 0748 NPIdentifier property, NPVariant * result) { 0749 (void)instance; 0750 return npobj->_class->getProperty (npobj, property, result); 0751 } 0752 0753 static bool nsSetProperty (NPP instance, NPObject * npobj, 0754 NPIdentifier property, const NPVariant *value) { 0755 (void)instance; 0756 return npobj->_class->setProperty (npobj, property, value); 0757 } 0758 0759 static bool nsRemoveProperty (NPP inst, NPObject * npobj, NPIdentifier prop) { 0760 (void)inst; 0761 return npobj->_class->removeProperty (npobj, prop); 0762 } 0763 0764 static bool nsHasProperty (NPP instance, NPObject * npobj, NPIdentifier prop) { 0765 (void)instance; 0766 return npobj->_class->hasProperty (npobj, prop); 0767 } 0768 0769 static bool nsHasMethod (NPP instance, NPObject * npobj, NPIdentifier method) { 0770 (void)instance; 0771 return npobj->_class->hasMethod (npobj, method); 0772 } 0773 0774 static void nsReleaseVariantValue (NPVariant * variant) { 0775 /*print ("NPN_ReleaseVariantValue\n");*/ 0776 switch (variant->type) { 0777 case NPVariantType_String: 0778 if (variant->value.stringValue.utf8characters) 0779 g_free ((char *) variant->value.stringValue.utf8characters); 0780 break; 0781 case NPVariantType_Object: 0782 if (variant->value.objectValue) 0783 nsReleaseObject (variant->value.objectValue); 0784 break; 0785 default: 0786 break; 0787 } 0788 variant->type = NPVariantType_Null; 0789 } 0790 0791 static void nsSetException (NPObject *npobj, const NPUTF8 *message) { 0792 (void)npobj; 0793 print ("NPN_SetException %s\n", message ? message : "-"); 0794 } 0795 0796 static bool nsPushPopupsEnabledState (NPP instance, NPBool enabled) { 0797 (void)instance; 0798 print ("NPN_PushPopupsEnabledState %d\n", enabled); 0799 return false; 0800 } 0801 0802 static bool nsPopPopupsEnabledState (NPP instance) { 0803 (void)instance; 0804 print ("NPN_PopPopupsEnabledState\n"); 0805 return false; 0806 } 0807 0808 static bool nsEnumerate (NPP npp, NPObject *obj, NPIdentifier **identifier, uint32_t *count) { 0809 (void)npp; (void)obj; (void)identifier; (void)count; 0810 print ("NPN_Enumerate\n"); 0811 return false; 0812 } 0813 0814 typedef struct _AsyncCall { 0815 void (*func)(void *); 0816 void *arg; 0817 } AsyncCall; 0818 0819 static gboolean asyncCall (gpointer data) { 0820 AsyncCall *ac = (AsyncCall *) data; 0821 print ("NPN_PluginThreadAsyncCall %p\n", ac->func); 0822 ac->func (ac->arg); 0823 nsMemFree (ac); 0824 return FALSE; 0825 } 0826 0827 static void nsPluginThreadAsyncCall (NPP instance, void (*func)(void *), void *userData) { 0828 (void)instance; 0829 if (func) { 0830 AsyncCall *ac = (AsyncCall *) nsAlloc (sizeof (AsyncCall) ); 0831 ac->func = func; 0832 ac->arg = userData; 0833 g_idle_add (asyncCall, ac); 0834 } 0835 } 0836 0837 static bool nsConstruct (NPP npp, NPObject* obj, const NPVariant *args, uint32_t argCount, NPVariant *result) { 0838 (void)npp; (void)obj; (void)args; (void)argCount; (void)result; 0839 print ("NPN_Construct\n"); 0840 return FALSE; 0841 } 0842 0843 static NPError nsGetValueForURL (NPP npp, NPNURLVariable variable, const char *url, char **value, uint32_t *len) { 0844 (void)npp; 0845 print ("NPN_GetValueForURL\n"); 0846 switch (variable) { 0847 case NPNURLVCookie: 0848 if (callback_service) { 0849 DBusMessage *rmsg; 0850 DBusMessage *msg = dbus_message_new_method_call ( 0851 callback_service, 0852 callback_path, 0853 "org.kde.kmplayer.callback", 0854 "cookie"); 0855 dbus_message_append_args (msg, 0856 DBUS_TYPE_STRING, &url, 0857 DBUS_TYPE_INVALID); 0858 rmsg = dbus_connection_send_with_reply_and_block (dbus_connection, 0859 msg, 2000, NULL); 0860 if (rmsg) { 0861 DBusMessageIter it; 0862 if (dbus_message_iter_init (rmsg, &it) && 0863 DBUS_TYPE_STRING == dbus_message_iter_get_arg_type (&it)) { 0864 char *cookies; 0865 dbus_message_iter_get_basic (&it, &cookies); 0866 *value = g_strdup (cookies); 0867 *len = strlen (cookies); 0868 print ("cookie %s => %s\n", url, cookies); 0869 } 0870 dbus_message_unref (rmsg); 0871 break; 0872 } else { 0873 print ("cookie no reply\n"); 0874 } 0875 } 0876 case NPNURLVProxy: 0877 default: 0878 *value = (char *) nsAlloc (1); 0879 (*value)[0] = 0; 0880 *len = 0; 0881 } 0882 return NPERR_NO_ERROR; 0883 } 0884 0885 static NPError nsSetValueForURL (NPP npp, NPNURLVariable variable, const char *url, const char *value, uint32_t len) { 0886 (void)npp; (void)variable; (void)url; (void)value; (void)len; 0887 print ("NPN_SetValueForURL\n"); 0888 return NPERR_NO_ERROR; 0889 } 0890 0891 static NPError nsGetAuthenticationInfo (NPP npp, const char *protocol, const char *host, int32_t port, const char *scheme, const char *realm, char **username, uint32_t *ulen, char **password, uint32_t *plen) { 0892 (void)npp; 0893 (void)protocol; (void)host; (void)port; (void)scheme; (void)realm; 0894 print ("NPN_GetAuthenticationInfo\n"); 0895 *username = NULL; 0896 *ulen = 0; 0897 *password = NULL; 0898 *plen = 0; 0899 return NPERR_NO_ERROR; 0900 } 0901 0902 /*----------------%<---------------------------------------------------------*/ 0903 0904 static bool doInvoke (uint32_t obj, const char *func, GSList *arglst, 0905 uint32_t arg_count, char **resultstring) { 0906 NPObject *npobj; 0907 NPVariant result; 0908 NPVariant *args = NULL; 0909 0910 *resultstring = NULL; 0911 if (!obj && npp) { /*TODO NPObject tracking */ 0912 NPError np_err = np_funcs.getvalue (npp, 0913 NPPVpluginScriptableNPObject, (void*)&npobj); 0914 if (np_err == NPERR_NO_ERROR && npobj) { 0915 NPIdentifier method = nsGetStringIdentifier (func); 0916 0917 if (nsHasMethod (npp, npobj, method)) { 0918 GSList *sl; 0919 int i; 0920 if (arg_count) { 0921 args = (NPVariant *) nsAlloc (arg_count * sizeof (NPVariant)); 0922 memset (args, 0, arg_count * sizeof (NPVariant)); 0923 for (sl = arglst, i = 0; sl; sl = sl->next, i++) 0924 str2NPVariant (npp, (const char *) sl->data, args + i); 0925 } 0926 if (nsInvoke (npp, npobj, method, args, arg_count, &result)) { 0927 *resultstring = nsVariant2Str (&result); 0928 nsReleaseVariantValue (&result); 0929 print ("nsInvoke succes %s\n", *resultstring); 0930 } else { 0931 print ("nsInvoke failure\n"); 0932 } 0933 if (args) { 0934 for (sl = arglst, i = 0; sl; sl = sl->next, i++) 0935 nsReleaseVariantValue (args + i); 0936 nsMemFree (args); 0937 } 0938 } 0939 nsReleaseObject (npobj); 0940 } else { 0941 print("no obj %d\n", obj); 0942 } 0943 } 0944 if (!*resultstring) { 0945 *resultstring = g_strdup ("error"); 0946 return false; 0947 } 0948 return true; 0949 } 0950 0951 static bool doGet (uint32_t obj, const char *prop, char **resultstring) { 0952 NPObject *npobj; 0953 NPVariant result; 0954 0955 *resultstring = NULL; 0956 if (!obj && npp) { /*TODO NPObject tracking */ 0957 NPError np_err = np_funcs.getvalue (npp, 0958 NPPVpluginScriptableNPObject, (void*)&npobj); 0959 if (np_err == NPERR_NO_ERROR && npobj) { 0960 NPIdentifier identifier = nsGetStringIdentifier (prop); 0961 0962 if (nsHasMethod (npp, npobj, identifier)) { 0963 *resultstring = g_strdup ("o:function"); 0964 } else if (nsHasMethod (npp, npobj, identifier)) { 0965 if (nsGetProperty (npp, npobj, identifier, &result)) { 0966 *resultstring = nsVariant2Str (&result); 0967 nsReleaseVariantValue (&result); 0968 } 0969 } 0970 nsReleaseObject (npobj); 0971 } 0972 } 0973 if (!*resultstring) { 0974 *resultstring = g_strdup ("error"); 0975 return false; 0976 } 0977 return true; 0978 } 0979 0980 /*----------------%<---------------------------------------------------------*/ 0981 0982 static NPObject * windowClassAllocate (NPP instance, NPClass *aClass) { 0983 (void)instance; 0984 /*print ("windowClassAllocate\n");*/ 0985 JsObject * jo = (JsObject *) nsAlloc (sizeof (JsObject)); 0986 memset (jo, 0, sizeof (JsObject)); 0987 jo->npobject._class = aClass; 0988 return (NPObject *) jo; 0989 } 0990 0991 static void windowClassDeallocate (NPObject *npobj) { 0992 JsObject *jo = (JsObject *) npobj; 0993 /*print ("windowClassDeallocate\n");*/ 0994 if (jo->parent) { 0995 nsReleaseObject ((NPObject *) jo->parent); 0996 } else if (jo->name && !strncmp (jo->name, "this.__kmplayer__obj_", 21)) { 0997 char *script = (char *) nsAlloc (strlen (jo->name) + 7); 0998 char *result; 0999 sprintf (script, "%s=null;", jo->name); 1000 result = evaluate (script, false); 1001 nsMemFree (script); 1002 g_free (result); 1003 } 1004 if (jo->name) 1005 g_free (jo->name); 1006 if (npobj == js_window) { 1007 print ("WARNING deleting window object\n"); 1008 js_window = NULL; 1009 } 1010 nsMemFree (npobj); 1011 } 1012 1013 static void windowClassInvalidate (NPObject *npobj) { 1014 (void)npobj; 1015 print ("windowClassInvalidate\n"); 1016 } 1017 1018 static bool windowClassHasMethod (NPObject *npobj, NPIdentifier name) { 1019 (void)npobj; (void)name; 1020 print ("windowClassHasMehtod\n"); 1021 return false; 1022 } 1023 1024 static bool windowClassInvoke (NPObject *npobj, NPIdentifier method, 1025 const NPVariant *args, uint32_t arg_count, NPVariant *result) { 1026 JsObject * jo = (JsObject *) npobj; 1027 NPString str = { NULL, 0 }; 1028 char buf[4096]; 1029 int pos, i; 1030 bool res; 1031 char * id = (char *) g_tree_lookup (identifiers, method); 1032 /*print ("windowClassInvoke\n");*/ 1033 1034 result->type = NPVariantType_Null; 1035 result->value.objectValue = NULL; 1036 1037 if (!id) { 1038 print ("Invoke invalid id\n"); 1039 return false; 1040 } 1041 print ("Invoke %s\n", id); 1042 createJsName (jo, (char **)&str.utf8characters, &str.utf8length); 1043 pos = snprintf (buf, sizeof (buf), "%s.%s(", str.utf8characters, id); 1044 nsMemFree ((char *) str.utf8characters); 1045 for (i = 0; i < (int)arg_count; i++) { 1046 char *arg = nsVariant2Str (args + i); 1047 pos += snprintf (buf + pos, 1048 sizeof (buf) - pos, i ? ",%s" : "%s", *arg ? arg : "undefined"); 1049 nsMemFree (arg); 1050 } 1051 pos += snprintf (buf + pos, sizeof (buf) - pos, ")"); 1052 1053 str.utf8characters = buf; 1054 str.utf8length = pos; 1055 res = doEvaluate (npp, npobj, &str, result); 1056 1057 return res; 1058 } 1059 1060 static bool windowClassInvokeDefault (NPObject *npobj, 1061 const NPVariant *args, uint32_t arg_count, NPVariant *result) { 1062 (void)npobj; (void)args; (void)arg_count; (void)result; 1063 print ("windowClassInvokeDefault\n"); 1064 return false; 1065 } 1066 1067 static bool windowClassHasProperty (NPObject *npobj, NPIdentifier name) { 1068 (void)npobj; (void)name; 1069 print ("windowClassHasProperty\n"); 1070 return false; 1071 } 1072 1073 static bool windowClassGetProperty (NPObject *npobj, NPIdentifier property, 1074 NPVariant *result) { 1075 char * id = (char *) g_tree_lookup (identifiers, property); 1076 JsObject jo; 1077 NPString fullname = { NULL, 0 }; 1078 bool res; 1079 1080 print ("GetProperty %s\n", id); 1081 result->type = NPVariantType_Null; 1082 result->value.objectValue = NULL; 1083 1084 if (!id) 1085 return false; 1086 1087 if (!strcmp (((JsObject *) npobj)->name, "window") && 1088 !strcmp (id, "top")) { 1089 result->type = NPVariantType_Object; 1090 result->value.objectValue = nsRetainObject (js_window); 1091 return true; 1092 } 1093 1094 jo.name = id; 1095 jo.parent = (JsObject *) npobj; 1096 createJsName (&jo, (char **)&fullname.utf8characters, &fullname.utf8length); 1097 1098 res = doEvaluate (npp, npobj, &fullname, result); 1099 1100 nsMemFree ((char *) fullname.utf8characters); 1101 1102 return res; 1103 } 1104 1105 static bool windowClassSetProperty (NPObject *npobj, NPIdentifier property, 1106 const NPVariant *value) { 1107 char *id = (char *) g_tree_lookup (identifiers, property); 1108 char *script, *var_name, *var_val, *res; 1109 JsObject jo; 1110 uint32_t len = 0; 1111 1112 if (!id) 1113 return false; 1114 1115 jo.name = id; 1116 jo.parent = (JsObject *) npobj; 1117 createJsName (&jo, &var_name, &len); 1118 1119 var_val = nsVariant2Str (value); 1120 script = (char *) nsAlloc (len + strlen (var_val) + 3); 1121 sprintf (script, "%s=%s;", var_name, var_val); 1122 nsMemFree (var_name); 1123 nsMemFree (var_val); 1124 print ("SetProperty %s\n", script); 1125 1126 res = evaluate (script, false); 1127 if (res) 1128 g_free (res); 1129 nsMemFree (script); 1130 1131 1132 return true; 1133 } 1134 1135 static bool windowClassRemoveProperty (NPObject *npobj, NPIdentifier name) { 1136 (void)npobj; (void)name; 1137 print ("windowClassRemoveProperty\n"); 1138 return false; 1139 } 1140 1141 1142 /*----------------%<---------------------------------------------------------*/ 1143 1144 static void shutDownPlugin() { 1145 if (npShutdown) { 1146 if (npp) { 1147 np_funcs.destroy (npp, &saved_data); 1148 nsMemFree (npp); 1149 npp = 0L; 1150 } 1151 npShutdown(); 1152 npShutdown = 0; 1153 } 1154 } 1155 1156 static void readStdin (gpointer p, gint src, GdkInputCondition cond) { 1157 char *buf_ptr = stream_buf; 1158 gsize bytes_read = read (src, 1159 stream_buf + stream_buf_pos, 1160 sizeof (stream_buf) - stream_buf_pos); 1161 (void)cond; (void)p; 1162 if (bytes_read > 0) 1163 stream_buf_pos += bytes_read; 1164 1165 /*print ("readStdin %d\n", bytes_read);*/ 1166 while (buf_ptr < stream_buf + stream_buf_pos) { 1167 uint32_t write_len; 1168 int32_t bytes_written; 1169 1170 if (callback_service && !stream_chunk_size) { 1171 /* read header info */ 1172 if (stream_buf + stream_buf_pos < buf_ptr + 2 * sizeof (uint32_t)) 1173 break; /* need more data */ 1174 current_stream_id = (gpointer)(long)*(uint32_t*)(buf_ptr); 1175 stream_chunk_size = *((uint32_t *)(buf_ptr + sizeof (uint32_t))); 1176 /*print ("header %d %d\n",(long)current_stream_id, stream_chunk_size);*/ 1177 buf_ptr += 2 * sizeof (uint32_t); 1178 if (stream_chunk_size && stream_buf + stream_buf_pos == buf_ptr) { 1179 stream_buf_pos = 0; 1180 break; /* only read the header for chunk with data */ 1181 } 1182 } 1183 /* feed it to the stream */ 1184 write_len = stream_buf + stream_buf_pos - buf_ptr; 1185 if (callback_service && write_len > stream_chunk_size) 1186 write_len = stream_chunk_size; 1187 bytes_written = writeStream (current_stream_id, buf_ptr, write_len); 1188 if (bytes_written < 0) { 1189 print ("couldn't write to stream %d\n", (long)current_stream_id); 1190 bytes_written = write_len; /* assume stream destroyed, skip */ 1191 } 1192 1193 /* update chunk status */ 1194 if (bytes_written > 0) { 1195 buf_ptr += bytes_written; 1196 /*print ("update chunk %d %d\n", bytes_written, stream_chunk_size);*/ 1197 stream_chunk_size -= bytes_written; 1198 } else { 1199 /* FIXME if plugin didn't accept the data retry later, suspend stdin reading */ 1200 break; 1201 } 1202 1203 } 1204 /* update buffer */ 1205 /*print ("buffer written:%d bufpos:%d\n", buf_ptr-stream_buf, stream_buf_pos);*/ 1206 if (stream_buf + stream_buf_pos == buf_ptr) { 1207 stream_buf_pos = 0; 1208 } else { 1209 g_assert (buf_ptr < stream_buf + stream_buf_pos); 1210 stream_buf_pos -= (stream_buf + stream_buf_pos - buf_ptr); 1211 memmove (stream_buf, buf_ptr, stream_buf_pos); 1212 } 1213 if (bytes_read <= 0) { /* eof of stdin, only for 'cat foo | knpplayer' */ 1214 StreamInfo*si=(StreamInfo*)g_tree_lookup(stream_list,current_stream_id); 1215 si->reason = NPRES_DONE; 1216 removeStream (current_stream_id); 1217 if (stdin_read_watch) { 1218 gdk_input_remove (stdin_read_watch); 1219 stdin_read_watch = 0; 1220 } 1221 } 1222 } 1223 1224 static int initPlugin (const char *plugin_lib) { 1225 NPError np_err; 1226 char *pname; 1227 1228 print ("starting %s\n", plugin_lib); 1229 library = g_module_open (plugin_lib, G_MODULE_BIND_LAZY); 1230 if (!library) { 1231 print ("failed to load %s %s\n", plugin_lib, g_module_error ()); 1232 return -1; 1233 } 1234 if (!g_module_symbol (library, 1235 "NP_GetMIMEDescription", (gpointer *)&npGetMIMEDescription)) { 1236 print ("undefined reference to load NP_GetMIMEDescription\n"); 1237 return -1; 1238 } 1239 if (!g_module_symbol (library, 1240 "NP_GetValue", (gpointer *)&npGetValue)) { 1241 print ("undefined reference to load NP_GetValue\n"); 1242 } 1243 if (!g_module_symbol (library, 1244 "NP_Initialize", (gpointer *)&npInitialize)) { 1245 print ("undefined reference to load NP_Initialize\n"); 1246 return -1; 1247 } 1248 if (!g_module_symbol (library, 1249 "NP_Shutdown", (gpointer *)&npShutdown)) { 1250 print ("undefined reference to load NP_Shutdown\n"); 1251 return -1; 1252 } 1253 print ("startup succeeded %s\n", npGetMIMEDescription ()); 1254 memset (&ns_funcs, 0, sizeof (NPNetscapeFuncs)); 1255 ns_funcs.size = sizeof (NPNetscapeFuncs); 1256 ns_funcs.version = (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR; 1257 ns_funcs.geturl = nsGetURL; 1258 ns_funcs.posturl = nsPostURL; 1259 ns_funcs.requestread = nsRequestRead; 1260 ns_funcs.newstream = nsNewStream; 1261 ns_funcs.write = nsWrite; 1262 ns_funcs.destroystream = nsDestroyStream; 1263 ns_funcs.status = nsStatus; 1264 ns_funcs.uagent = nsUserAgent; 1265 ns_funcs.memalloc = nsAlloc; 1266 ns_funcs.memfree = nsMemFree; 1267 ns_funcs.memflush = nsMemFlush; 1268 ns_funcs.reloadplugins = nsReloadPlugins; 1269 ns_funcs.getJavaEnv = nsGetJavaEnv; 1270 ns_funcs.getJavaPeer = nsGetJavaPeer; 1271 ns_funcs.geturlnotify = nsGetURLNotify; 1272 ns_funcs.posturlnotify = nsPostURLNotify; 1273 ns_funcs.getvalue = nsGetValue; 1274 ns_funcs.setvalue = nsSetValue; 1275 ns_funcs.invalidaterect = nsInvalidateRect; 1276 ns_funcs.invalidateregion = nsInvalidateRegion; 1277 ns_funcs.forceredraw = nsForceRedraw; 1278 ns_funcs.getstringidentifier = nsGetStringIdentifier; 1279 ns_funcs.getstringidentifiers = nsGetStringIdentifiers; 1280 ns_funcs.getintidentifier = nsGetIntIdentifier; 1281 ns_funcs.identifierisstring = nsIdentifierIsString; 1282 ns_funcs.utf8fromidentifier = nsUTF8FromIdentifier; 1283 ns_funcs.intfromidentifier = nsIntFromIdentifier; 1284 ns_funcs.createobject = nsCreateObject; 1285 ns_funcs.retainobject = nsRetainObject; 1286 ns_funcs.releaseobject = nsReleaseObject; 1287 ns_funcs.invoke = nsInvoke; 1288 ns_funcs.invokeDefault = nsInvokeDefault; 1289 ns_funcs.evaluate = nsEvaluate; 1290 ns_funcs.getproperty = nsGetProperty; 1291 ns_funcs.setproperty = nsSetProperty; 1292 ns_funcs.removeproperty = nsRemoveProperty; 1293 ns_funcs.hasproperty = nsHasProperty; 1294 ns_funcs.hasmethod = nsHasMethod; 1295 ns_funcs.releasevariantvalue = nsReleaseVariantValue; 1296 ns_funcs.setexception = nsSetException; 1297 ns_funcs.pushpopupsenabledstate = nsPushPopupsEnabledState; 1298 ns_funcs.poppopupsenabledstate = nsPopPopupsEnabledState; 1299 ns_funcs.enumerate = nsEnumerate; 1300 ns_funcs.pluginthreadasynccall = nsPluginThreadAsyncCall; 1301 ns_funcs.construct = nsConstruct; 1302 ns_funcs.getvalueforurl = nsGetValueForURL; 1303 ns_funcs.setvalueforurl = nsSetValueForURL; 1304 ns_funcs.getauthenticationinfo = nsGetAuthenticationInfo; 1305 1306 js_class.structVersion = NP_CLASS_STRUCT_VERSION; 1307 js_class.allocate = windowClassAllocate; 1308 js_class.deallocate = windowClassDeallocate; 1309 js_class.invalidate = windowClassInvalidate; 1310 js_class.hasMethod = windowClassHasMethod; 1311 js_class.invoke = windowClassInvoke; 1312 js_class.invokeDefault = windowClassInvokeDefault; 1313 js_class.hasProperty = windowClassHasProperty; 1314 js_class.getProperty = windowClassGetProperty; 1315 js_class.setProperty = windowClassSetProperty; 1316 js_class.removeProperty = windowClassRemoveProperty; 1317 1318 np_funcs.size = sizeof (NPPluginFuncs); 1319 1320 np_err = npInitialize (&ns_funcs, &np_funcs); 1321 if (np_err != NPERR_NO_ERROR) { 1322 print ("NP_Initialize failure %d\n", np_err); 1323 npShutdown = 0; 1324 return -1; 1325 } 1326 np_err = npGetValue (NULL, NPPVpluginNameString, &pname); 1327 if (np_err == NPERR_NO_ERROR) 1328 print ("NP_GetValue Name %s\n", pname); 1329 np_err = npGetValue (NULL, NPPVpluginDescriptionString, &pname); 1330 if (np_err == NPERR_NO_ERROR) 1331 print ("NP_GetValue Description %s\n", pname); 1332 return 0; 1333 } 1334 1335 static int newPlugin (NPMIMEType mime, int16 argc, char *argn[], char *argv[]) { 1336 NPError np_err; 1337 Display *display; 1338 int screen; 1339 int i; 1340 int needs_xembed; 1341 uint32_t width = 0, height = 0; 1342 1343 for (i = 0; i < argc; i++) { 1344 if (!strcasecmp (argn[i], "width")) 1345 width = strtol (argv[i], 0L, 10); 1346 else if (!strcasecmp (argn[i], "height")) 1347 height = strtol (argv[i], 0L, 10); 1348 } 1349 /*if (width > 0 && height > 0) 1350 callFunction (-1, "dimension", 1351 DBUS_TYPE_INT32, &width, DBUS_TYPE_INT32, &height, 1352 DBUS_TYPE_INVALID);*/ 1353 1354 npp = (NPP_t*)nsAlloc (sizeof (NPP_t)); 1355 memset (npp, 0, sizeof (NPP_t)); 1356 np_err = np_funcs.newp (mime, npp, NP_EMBED, argc, argn, argv, saved_data); 1357 if (np_err != NPERR_NO_ERROR) { 1358 print ("NPP_New failure %d %p %p\n", np_err, np_funcs, np_funcs.newp); 1359 return -1; 1360 } 1361 if (np_funcs.getvalue) { 1362 char *pname; 1363 void *iid; 1364 np_err = np_funcs.getvalue (npp, 1365 NPPVpluginNameString, (void*)&pname); 1366 if (np_err == NPERR_NO_ERROR) 1367 print ("plugin name %s\n", pname); 1368 np_err = np_funcs.getvalue (npp, 1369 NPPVpluginNeedsXEmbed, (void*)&needs_xembed); 1370 if (np_err != NPERR_NO_ERROR || !needs_xembed) { 1371 print ("NPP_GetValue NPPVpluginNeedsXEmbed failure %d\n", np_err); 1372 shutDownPlugin(); 1373 return -1; 1374 } 1375 np_err = np_funcs.getvalue (npp, 1376 NPPVpluginScriptableIID, (void*)&iid); 1377 } 1378 memset (&np_window, 0, sizeof (NPWindow)); 1379 display = gdk_x11_get_default_xdisplay (); 1380 np_window.x = 0; 1381 np_window.y = 0; 1382 np_window.width = INITIAL_WINDOW_WIDTH; 1383 np_window.height = 1200; 1384 np_window.window = (void*)socket_id; 1385 np_window.type = NPWindowTypeWindow; 1386 ws_info.type = NP_SETWINDOW; 1387 screen = DefaultScreen (display); 1388 ws_info.display = display; 1389 ws_info.visual = DefaultVisual (display, screen); 1390 ws_info.colormap = DefaultColormap (display, screen); 1391 ws_info.depth = DefaultDepth (display, screen); 1392 print ("display %u %dx%d\n", socket_id, width, height); 1393 np_window.ws_info = (void*)&ws_info; 1394 1395 GtkAllocation allocation; 1396 allocation.x = 0; 1397 allocation.y = 0; 1398 allocation.width = np_window.width; 1399 allocation.height = np_window.height; 1400 gtk_widget_size_allocate (xembed, &allocation); 1401 1402 np_err = np_funcs.setwindow (npp, &np_window); 1403 1404 return 0; 1405 } 1406 1407 static bool startPlugin (const char *mime, 1408 int argc, char *argn[], char *argv[]) { 1409 if (!npp && (initPlugin (plugin) || newPlugin (mimetype, argc, argn, argv))) 1410 return false; 1411 return true; 1412 } 1413 1414 /*----------------%<---------------------------------------------------------*/ 1415 1416 static StreamInfo *getStreamInfo (const char *path, gpointer *stream_id) { 1417 const char *p = strrchr (path, '_'); 1418 *stream_id = p ? (gpointer) strtol (p+1, NULL, 10) : NULL; 1419 return (StreamInfo *) g_tree_lookup (stream_list, *stream_id); 1420 } 1421 1422 static void defaultReply (DBusConnection *conn, DBusMessage *msg) { 1423 if (!dbus_message_get_no_reply (msg)) { 1424 DBusMessage *rmsg = dbus_message_new_method_return (msg); 1425 dbus_connection_send (conn, rmsg, NULL); 1426 dbus_connection_flush (conn); 1427 dbus_message_unref (rmsg); 1428 } 1429 } 1430 1431 static bool dbusMsgIterGet (DBusMessage *msg, DBusMessageIter *it, 1432 int arg_type, void *p, bool first) { 1433 if (((first && dbus_message_iter_init (msg, it)) || 1434 (!first && dbus_message_iter_has_next (it) && 1435 dbus_message_iter_next (it))) && 1436 dbus_message_iter_get_arg_type (it) == arg_type) { 1437 dbus_message_iter_get_basic (it, p); 1438 return true; 1439 } 1440 return false; 1441 } 1442 1443 static DBusHandlerResult dbusStreamMessage (DBusConnection *conn, 1444 DBusMessage *msg, void *user_data) { 1445 DBusMessageIter args; 1446 const char *iface = "org.kde.kmplayer.backend"; 1447 gpointer stream_id; 1448 StreamInfo *si; 1449 (void)user_data; 1450 1451 print ("dbusStreamMessage %s %s %s\n", dbus_message_get_interface (msg), 1452 dbus_message_get_member (msg), dbus_message_get_signature (msg)); 1453 if (dbus_message_is_method_call (msg, iface, "redirected")) { 1454 char *url = 0; 1455 si = getStreamInfo(dbus_message_get_path (msg), &stream_id); 1456 if (dbusMsgIterGet (msg, &args, DBUS_TYPE_STRING, &url, true)) { 1457 if (si) { 1458 dbus_message_iter_get_basic (&args, &url); 1459 nsMemFree (si->url); 1460 si->url = g_strdup (url); 1461 si->np_stream.url = si->url; 1462 print ("redirect %d (had data %d) to %s\n", (long)stream_id, si->called_plugin, url); 1463 } else { 1464 print ("redirect %d not found\n", (long)stream_id); 1465 } 1466 } 1467 defaultReply (conn, msg); 1468 } else if (dbus_message_is_method_call (msg, iface, "eof")) { 1469 unsigned int total; 1470 if (dbusMsgIterGet (msg, &args, DBUS_TYPE_UINT32, &total, true)) { 1471 unsigned int reason; 1472 if (dbusMsgIterGet (msg, &args, DBUS_TYPE_UINT32, &reason, false)) { 1473 si = getStreamInfo(dbus_message_get_path (msg), &stream_id); 1474 if (si) { 1475 si->total = total; 1476 si->reason = reason; 1477 print ("eof %d bytes:%d reason:%d\n", (long)stream_id, si->total, si->reason); 1478 if (si->stream_pos == si->total || si->destroyed) 1479 removeStream (stream_id); 1480 } else { 1481 print ("stream %d not found\n", stream_id); 1482 } 1483 } 1484 } 1485 defaultReply (conn, msg); 1486 } else if (dbus_message_is_method_call (msg, iface, "streamInfo")) { 1487 const char *mime; 1488 if (dbusMsgIterGet (msg, &args, DBUS_TYPE_STRING, &mime, true)) { 1489 const char *headers; 1490 uint32_t length; 1491 si = getStreamInfo(dbus_message_get_path (msg), &stream_id); 1492 if (si && *mime) { 1493 if (si->mimetype) 1494 g_free (si->mimetype); 1495 si->mimetype = g_strdup (mime); 1496 } 1497 if (dbusMsgIterGet (msg, &args, DBUS_TYPE_UINT32, &length, false)) { 1498 if (si) 1499 si->np_stream.end = length; 1500 if (dbusMsgIterGet (msg, &args, DBUS_TYPE_STRING, &headers, false)) { 1501 if (si && *headers) { 1502 si->headers = g_strdup (headers); 1503 si->np_stream.headers = si->headers; 1504 } 1505 } 1506 } 1507 print ("streamInfo %d size:%d mime:%s headers %s\n", (long)stream_id, 1508 length, mime ? mime : "", headers ? headers : ""); 1509 } 1510 defaultReply (conn, msg); 1511 } 1512 return DBUS_HANDLER_RESULT_HANDLED; 1513 } 1514 1515 static void dbusStreamUnregister (DBusConnection *conn, void *user_data) { 1516 (void)conn; (void)user_data; 1517 print( "dbusStreamUnregister\n"); 1518 } 1519 1520 static void dbusPluginUnregister (DBusConnection *conn, void *user_data) { 1521 (void)conn; (void)user_data; 1522 print( "dbusPluginUnregister\n"); 1523 } 1524 1525 static const char *plugin_inspect = 1526 "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"" 1527 " \"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">" 1528 "<node>" 1529 " <interface name=\"org.freedesktop.DBus.Introspectable\">" 1530 " <method name=\"Introspect\">" 1531 " <arg name=\"xml_data\" type=\"s\" direction=\"out\"/>" 1532 " </method>" 1533 " </interface>" 1534 " <interface name=\"org.kde.kmplayer.backend\">" 1535 " <method name=\"setup\">" 1536 " <arg name=\"mimetype\" type=\"s\" direction=\"in\"/>" 1537 " <arg name=\"plugin\" type=\"s\" direction=\"in\"/>" 1538 " <arg name=\"arguments\" type=\"a{sv}\" direction=\"in\"/>" 1539 " </method>" 1540 " <method name=\"play\">" 1541 " <arg name=\"url\" type=\"s\" direction=\"in\"/>" 1542 " </method>" 1543 " </interface>" 1544 "</node>"; 1545 1546 static DBusHandlerResult dbusPluginMessage (DBusConnection *conn, 1547 DBusMessage *msg, void *user_data) { 1548 1549 DBusMessageIter args; 1550 const char *iface = "org.kde.kmplayer.backend"; 1551 (void) user_data; 1552 1553 print ("dbusPluginMessage %s %s %s\n", dbus_message_get_interface (msg), 1554 dbus_message_get_member (msg), dbus_message_get_signature (msg)); 1555 if (dbus_message_is_method_call (msg, 1556 "org.freedesktop.DBus.Introspectable", "Introspect")) { 1557 DBusMessage * rmsg = dbus_message_new_method_return (msg); 1558 dbus_message_append_args (rmsg, 1559 DBUS_TYPE_STRING, &plugin_inspect, DBUS_TYPE_INVALID); 1560 dbus_connection_send (conn, rmsg, NULL); 1561 dbus_connection_flush (conn); 1562 dbus_message_unref (rmsg); 1563 } else if (dbus_message_is_method_call (msg, iface, "setup")) { 1564 DBusMessageIter ait; 1565 char *param = 0; 1566 unsigned int params = 0; 1567 char **argn = NULL; 1568 char **argv = NULL; 1569 GSList *arglst = NULL; 1570 if (!dbusMsgIterGet (msg, &args, DBUS_TYPE_STRING, ¶m, true)) { 1571 g_printerr ("missing mimetype arg"); 1572 return DBUS_HANDLER_RESULT_HANDLED; 1573 } 1574 mimetype = g_strdup (param); 1575 if (!dbusMsgIterGet (msg, &args, DBUS_TYPE_STRING, ¶m, false)) { 1576 g_printerr ("missing plugin arg"); 1577 return DBUS_HANDLER_RESULT_HANDLED; 1578 } 1579 plugin = g_strdup (param); 1580 if (!dbus_message_iter_next (&args) || 1581 DBUS_TYPE_ARRAY != dbus_message_iter_get_arg_type (&args)) { 1582 g_printerr ("missing params array"); 1583 return DBUS_HANDLER_RESULT_HANDLED; 1584 } 1585 dbus_message_iter_recurse (&args, &ait); 1586 do { 1587 char *key, *value; 1588 DBusMessageIter di; 1589 int arg_type; 1590 if (dbus_message_iter_get_arg_type (&ait) != DBUS_TYPE_DICT_ENTRY) 1591 break; 1592 dbus_message_iter_recurse (&ait, &di); 1593 if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type (&di)) 1594 break; 1595 dbus_message_iter_get_basic (&di, &key); 1596 if (!dbus_message_iter_next (&di)) 1597 break; 1598 arg_type = dbus_message_iter_get_arg_type (&di); 1599 if (DBUS_TYPE_STRING == arg_type) { 1600 dbus_message_iter_get_basic (&di, &value); 1601 } else if (DBUS_TYPE_VARIANT == arg_type) { 1602 DBusMessageIter vi; 1603 dbus_message_iter_recurse (&di, &vi); 1604 if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type (&vi)) 1605 break; 1606 dbus_message_iter_get_basic (&vi, &value); 1607 } else { 1608 break; 1609 } 1610 arglst = g_slist_append (arglst, g_strdup (key)); 1611 arglst = g_slist_append (arglst, g_strdup (value)); 1612 params++; 1613 print ("param %d:%s='%s'\n", params, key, value); 1614 } while (dbus_message_iter_has_next (&ait) && 1615 dbus_message_iter_next (&ait)); 1616 if (params > 0 && params < 100) { 1617 int i; 1618 GSList *sl = arglst; 1619 argn = (char**) nsAlloc (params * sizeof (char *)); 1620 argv = (char**) nsAlloc (params * sizeof (char *)); 1621 for (i = 0; sl; i++) { 1622 argn[i] = (gchar *)sl->data; 1623 sl = sl->next; 1624 argv[i] = (gchar *)sl->data; 1625 sl = sl->next; 1626 } 1627 g_slist_free (arglst); 1628 } 1629 print ("setup %s %s params:%d\n", 1630 mimetype ? mimetype : "", plugin, params); 1631 startPlugin (mimetype, params, argn, argv); 1632 defaultReply (conn, msg); 1633 } else if (dbus_message_is_method_call (msg, iface, "play")) { 1634 char *param = 0; 1635 if (!dbusMsgIterGet (msg, &args, DBUS_TYPE_STRING, ¶m, true)) { 1636 g_printerr ("missing url arg"); 1637 return DBUS_HANDLER_RESULT_HANDLED; 1638 } 1639 object_url = g_strdup (param); 1640 print ("play %s\n", object_url); 1641 if (mimetype && strncmp (mimetype, "application/x-java", 18)) 1642 addStream (object_url, mimetype, 0L, 0, NULL, 0L, false); 1643 defaultReply (conn, msg); 1644 } else if (dbus_message_is_method_call (msg, iface, "get")) { 1645 DBusMessage * rmsg; 1646 uint32_t object; 1647 char *prop; 1648 if (dbusMsgIterGet (msg, &args, DBUS_TYPE_UINT32, &object, true) && 1649 dbusMsgIterGet (msg, &args, DBUS_TYPE_STRING, &prop, false)) { 1650 char *result = NULL; 1651 doGet (object, prop, &result); 1652 print ("get %s => %s\n", prop, result ? result : "NULL"); 1653 rmsg = dbus_message_new_method_return (msg); 1654 dbus_message_append_args (rmsg, 1655 DBUS_TYPE_STRING, &result, DBUS_TYPE_INVALID); 1656 dbus_connection_send (conn, rmsg, NULL); 1657 dbus_connection_flush (conn); 1658 dbus_message_unref (rmsg); 1659 g_free (result); 1660 } 1661 } else if (dbus_message_is_method_call (msg, iface, "call")) { 1662 DBusMessage * rmsg; 1663 DBusMessageIter ait; 1664 uint32_t object; 1665 char *func; 1666 GSList *arglst = NULL; 1667 GSList *sl; 1668 uint32_t arg_count = 0; 1669 char *result = NULL; 1670 if (dbusMsgIterGet (msg, &args, DBUS_TYPE_UINT32, &object, true) && 1671 dbusMsgIterGet (msg, &args, DBUS_TYPE_STRING, &func, false)) { 1672 if (!dbus_message_iter_next (&args) || 1673 DBUS_TYPE_ARRAY != dbus_message_iter_get_arg_type (&args)) { 1674 g_printerr ("missing arguments array"); 1675 return DBUS_HANDLER_RESULT_HANDLED; 1676 } 1677 dbus_message_iter_recurse (&args, &ait); 1678 print ("call %d:%s(", object, func); 1679 do { 1680 char *arg; 1681 if (dbus_message_iter_get_arg_type (&ait) != DBUS_TYPE_STRING) 1682 break; 1683 dbus_message_iter_get_basic (&ait, &arg); 1684 print ("%s, ", arg); 1685 arglst = g_slist_append (arglst, g_strdup (arg)); 1686 arg_count++; 1687 } while (dbus_message_iter_has_next (&ait) && 1688 dbus_message_iter_next (&ait)); 1689 doInvoke (object, func, arglst, arg_count, &result); 1690 print (") %s\n", result ? result : "NULL"); 1691 rmsg = dbus_message_new_method_return (msg); 1692 dbus_message_append_args (rmsg, 1693 DBUS_TYPE_STRING, &result, DBUS_TYPE_INVALID); 1694 dbus_connection_send (conn, rmsg, NULL); 1695 dbus_connection_flush (conn); 1696 dbus_message_unref (rmsg); 1697 g_free (result); 1698 if (arglst) { 1699 for (sl = arglst; sl; sl = sl->next) 1700 g_free ((char *)sl->data); 1701 g_slist_free (arglst); 1702 } 1703 } 1704 } else if (dbus_message_is_method_call (msg, iface, "quit")) { 1705 print ("quit\n"); 1706 shutDownPlugin(); 1707 defaultReply (conn, msg); 1708 gtk_main_quit(); 1709 } 1710 return DBUS_HANDLER_RESULT_HANDLED; 1711 } 1712 1713 static void callFunction(int stream, const char *iface, const char *func, int first_arg_type, ...) 1714 { 1715 char path[64]; 1716 createPath (stream, path, sizeof (path)); 1717 print ("call %s.%s()\n", path, func); 1718 if (callback_service) { 1719 va_list var_args; 1720 DBusMessage *msg = dbus_message_new_method_call ( 1721 callback_service, 1722 path, 1723 iface, 1724 func); 1725 if (first_arg_type != DBUS_TYPE_INVALID) { 1726 va_start (var_args, first_arg_type); 1727 dbus_message_append_args_valist (msg, first_arg_type, var_args); 1728 va_end (var_args); 1729 } 1730 dbus_message_set_no_reply (msg, TRUE); 1731 dbus_connection_send (dbus_connection, msg, NULL); 1732 dbus_message_unref (msg); 1733 dbus_connection_flush (dbus_connection); 1734 } 1735 } 1736 1737 static char *evaluate (const char *script, bool store) { 1738 char * ret = NULL; 1739 print ("evaluate %s", script); 1740 if (callback_service) { 1741 DBusMessage *rmsg; 1742 DBusMessage *msg = dbus_message_new_method_call ( 1743 callback_service, 1744 callback_path, 1745 "org.kde.kmplayer.callback", 1746 "evaluate"); 1747 int bool_val = store; 1748 dbus_message_append_args (msg, 1749 DBUS_TYPE_STRING, &script, 1750 DBUS_TYPE_BOOLEAN, &bool_val, 1751 DBUS_TYPE_INVALID); 1752 rmsg = dbus_connection_send_with_reply_and_block (dbus_connection, 1753 msg, 2000, NULL); 1754 if (rmsg) { 1755 DBusMessageIter it; 1756 if (dbus_message_iter_init (rmsg, &it) && 1757 DBUS_TYPE_STRING == dbus_message_iter_get_arg_type (&it)) { 1758 char * param; 1759 dbus_message_iter_get_basic (&it, ¶m); 1760 ret = g_strdup (param); 1761 } 1762 dbus_message_unref (rmsg); 1763 print (" => %s\n", ret); 1764 } 1765 dbus_message_unref (msg); 1766 } else { 1767 print (" => NA\n"); 1768 } 1769 return ret; 1770 } 1771 1772 /*----------------%<---------------------------------------------------------*/ 1773 1774 static void pluginAdded (GtkSocket *socket, gpointer d) { 1775 /*(void)socket;*/ (void)d; 1776 print ("pluginAdded\n"); 1777 if (socket->plug_window) { 1778 gpointer user_data = NULL; 1779 gdk_window_get_user_data (socket->plug_window, &user_data); 1780 if (!user_data) { 1781 /** 1782 * GtkSocket resets plugins XSelectInput in 1783 * _gtk_socket_add_window 1784 * _gtk_socket_windowing_select_plug_window_input 1785 **/ 1786 XSelectInput (gdk_x11_get_default_xdisplay (), 1787 gdk_x11_drawable_get_xid (socket->plug_window), 1788 KeyPressMask | KeyReleaseMask | 1789 ButtonPressMask | ButtonReleaseMask | 1790 KeymapStateMask | 1791 ButtonMotionMask | 1792 PointerMotionMask | 1793 /*EnterWindowMask | LeaveWindowMask |*/ 1794 FocusChangeMask | 1795 ExposureMask | 1796 StructureNotifyMask | SubstructureNotifyMask | 1797 /*SubstructureRedirectMask |*/ 1798 PropertyChangeMask 1799 ); 1800 } 1801 } 1802 callFunction (-1, iface_callback, "plugged", DBUS_TYPE_INVALID); 1803 } 1804 1805 static gboolean pluginRemoved (GtkSocket *socket, gpointer d) { 1806 (void)socket; (void)d; 1807 return TRUE; 1808 } 1809 1810 static void windowCreatedEvent (GtkWidget *w, gpointer d) { 1811 (void)d; 1812 print ("windowCreatedEvent\n"); 1813 socket_id = gtk_socket_get_id (GTK_SOCKET (xembed)); 1814 if (parent_id) { 1815 print ("windowCreatedEvent %p\n", GTK_PLUG (w)->socket_window); 1816 /*if (!GTK_PLUG (w)->socket_window) 1817 gtk_plug_construct (GTK_PLUG (w), parent_id); 1818 gdk_window_reparent( w->window, 1819 GTK_PLUG (w)->socket_window 1820 ? GTK_PLUG (w)->socket_window 1821 : gdk_window_foreign_new (parent_id), 1822 0, 0);*/ 1823 XReparentWindow (gdk_x11_drawable_get_xdisplay (w->window), 1824 gdk_x11_drawable_get_xid (w->window), 1825 parent_id, 1826 0, 0); 1827 gtk_widget_show_all (w); 1828 } 1829 if (!callback_service) { 1830 char *argn[] = { g_strdup("WIDTH"), g_strdup("HEIGHT"), g_strdup("debug"), g_strdup("SRC") }; 1831 char *argv[] = { g_strdup("440"), g_strdup("330"), g_strdup("yes"), g_strdup(object_url) }; 1832 if (startPlugin (mimetype, 4, argn, argv)) 1833 addStream (object_url, mimetype, 0L, 0, NULL, 0L, false); 1834 } 1835 } 1836 1837 static void embeddedEvent (GtkPlug *plug, gpointer d) { 1838 (void)plug; (void)d; 1839 print ("embeddedEvent\n"); 1840 } 1841 1842 static gboolean updateDimension (void * p) { 1843 (void)p; 1844 if (np_window.window) { 1845 if ((int)np_window.width != top_w || (int)np_window.height != top_h) { 1846 np_window.width = top_w; 1847 np_window.height = top_h; 1848 np_funcs.setwindow (npp, &np_window); 1849 } 1850 update_dimension_timer = 0; 1851 return 0; /* single shot */ 1852 } else { 1853 return 1; 1854 } 1855 } 1856 1857 static gboolean configureEvent(GtkWidget *w, GdkEventConfigure *e, gpointer d) { 1858 static int first_configure_pre_size; 1859 (void)w; (void)d; 1860 print("configureEvent %dx%d\n", e->width, e->height); 1861 if (!first_configure_pre_size && e->width == INITIAL_WINDOW_WIDTH) { 1862 first_configure_pre_size = 1; 1863 return FALSE; 1864 } 1865 if (e->width != top_w || e->height != top_h) { 1866 top_w = e->width; 1867 top_h = e->height; 1868 if (!update_dimension_timer) 1869 update_dimension_timer = g_timeout_add (100, updateDimension, NULL); 1870 } 1871 return FALSE; 1872 } 1873 1874 static gboolean windowCloseEvent (GtkWidget *w, GdkEvent *e, gpointer d) { 1875 (void)w; (void)e; (void)d; 1876 shutDownPlugin(); 1877 return FALSE; 1878 } 1879 1880 static void windowDestroyEvent (GtkWidget *w, gpointer d) { 1881 (void)w; (void)d; 1882 gtk_main_quit(); 1883 } 1884 1885 static gboolean initPlayer (void * p) { 1886 static DBusObjectPathVTable pluginVTable; 1887 GtkWidget *window; 1888 GdkColormap *color_map; 1889 GdkColor bg_color; 1890 (void)p; 1891 1892 window = /*callback_service 1893 ? gtk_plug_new (parent_id) 1894 :*/ gtk_window_new (GTK_WINDOW_TOPLEVEL); 1895 g_signal_connect (G_OBJECT (window), "delete_event", 1896 G_CALLBACK (windowCloseEvent), NULL); 1897 g_signal_connect (G_OBJECT (window), "destroy", 1898 G_CALLBACK (windowDestroyEvent), NULL); 1899 g_signal_connect_after (G_OBJECT (window), "realize", 1900 GTK_SIGNAL_FUNC (windowCreatedEvent), NULL); 1901 g_signal_connect (G_OBJECT (window), "configure-event", 1902 GTK_SIGNAL_FUNC (configureEvent), NULL); 1903 1904 xembed = gtk_socket_new(); 1905 g_signal_connect (G_OBJECT (xembed), "plug-added", 1906 GTK_SIGNAL_FUNC (pluginAdded), NULL); 1907 g_signal_connect (G_OBJECT (xembed), "plug-removed", 1908 GTK_SIGNAL_FUNC (pluginRemoved), NULL); 1909 1910 color_map = gdk_colormap_get_system(); 1911 gdk_colormap_query_color (color_map, 0, &bg_color); 1912 gtk_widget_modify_bg (xembed, GTK_STATE_NORMAL, &bg_color); 1913 1914 gtk_container_add (GTK_CONTAINER (window), xembed); 1915 1916 if (!parent_id) { 1917 gtk_widget_set_size_request (window, 440, 330); 1918 gtk_widget_show_all (window); 1919 } else { 1920 g_signal_connect (G_OBJECT (window), "embedded", 1921 GTK_SIGNAL_FUNC (embeddedEvent), NULL); 1922 gtk_widget_set_size_request (window, INITIAL_WINDOW_WIDTH, 1200); 1923 gtk_widget_realize (window); 1924 } 1925 1926 if (callback_service && callback_path) { 1927 DBusError dberr; 1928 char myname[64]; 1929 1930 dbus_error_init (&dberr); 1931 dbus_connection = dbus_bus_get (DBUS_BUS_SESSION, &dberr); 1932 if (!dbus_connection) { 1933 g_printerr ("Failed to open connection to bus: %s\n", 1934 dberr.message); 1935 exit (1); 1936 } 1937 g_sprintf (myname, "org.kde.kmplayer.npplayer-%d", getpid ()); 1938 service_name = g_strdup (myname); 1939 print ("using service %s was '%s'\n", service_name, dbus_bus_get_unique_name (dbus_connection)); 1940 dbus_connection_setup_with_g_main (dbus_connection, 0L); 1941 dbus_bus_request_name (dbus_connection, service_name, 1942 DBUS_NAME_FLAG_REPLACE_EXISTING, &dberr); 1943 if (dbus_error_is_set (&dberr)) { 1944 g_printerr ("Failed to register name: %s\n", dberr.message); 1945 dbus_connection_unref (dbus_connection); 1946 return -1; 1947 } 1948 1949 pluginVTable.unregister_function = dbusPluginUnregister; 1950 pluginVTable.message_function = dbusPluginMessage; 1951 if (!dbus_connection_register_object_path (dbus_connection, "/plugin", 1952 &pluginVTable, NULL)) 1953 g_printerr ("dbus_connection_register_object_path error\n"); 1954 1955 1956 /* TODO: remove DBUS_BUS_SESSION and create a private connection */ 1957 //callFunction (-1, "running", 1958 // DBUS_TYPE_STRING, &service_name, DBUS_TYPE_INVALID); 1959 1960 dbus_connection_flush (dbus_connection); 1961 1962 fprintf (stdout, "NPP_DBUS_SRV=%s\n", service_name); 1963 fflush (stdout); 1964 } 1965 return 0; /* single shot */ 1966 } 1967 1968 int main (int argc, char **argv) { 1969 int i; 1970 1971 g_thread_init (NULL); 1972 gtk_init (&argc, &argv); 1973 1974 for (i = 1; i < argc; i++) { 1975 if (!strcmp (argv[i], "-p") && ++i < argc) { 1976 plugin = g_strdup (argv[i]); 1977 } else if (!strcmp (argv[i], "-cb") && ++i < argc) { 1978 gchar *cb = g_strdup (argv[i]); 1979 gchar *path = strchr(cb, '/'); 1980 if (path) { 1981 callback_path = g_strdup (path); 1982 *path = 0; 1983 } 1984 callback_service = g_strdup (cb); 1985 g_free (cb); 1986 } else if (!strcmp (argv[i], "-m") && ++i < argc) { 1987 mimetype = g_strdup (argv[i]); 1988 } else if (!strcmp (argv [i], "-wid") && ++i < argc) { 1989 parent_id = strtol (argv[i], 0L, 10); 1990 } else 1991 object_url = g_strdup (argv[i]); 1992 } 1993 if (!callback_service && !(object_url && mimetype && plugin)) { 1994 g_fprintf(stderr, "Usage: %s <-m mimetype -p plugin url|-cb service -wid id>\n", argv[0]); 1995 return 1; 1996 } 1997 1998 identifiers = g_tree_new ((GCompareFunc)strcmp); 1999 stream_list = g_tree_new (streamCompare); 2000 stream_vtable.unregister_function = dbusStreamUnregister; 2001 stream_vtable.message_function = dbusStreamMessage; 2002 2003 g_timeout_add (0, initPlayer, NULL); 2004 2005 fcntl (0, F_SETFL, fcntl (0, F_GETFL) | O_NONBLOCK); 2006 2007 print ("entering gtk_main\n"); 2008 2009 gtk_main(); 2010 2011 if (dbus_connection) 2012 dbus_connection_unref (dbus_connection); 2013 2014 return 0; 2015 } 2016 }