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