diff options
Diffstat (limited to 'src/plugin.c')
-rw-r--r-- | src/plugin.c | 582 |
1 files changed, 582 insertions, 0 deletions
diff --git a/src/plugin.c b/src/plugin.c new file mode 100644 index 0000000..abab8ab --- /dev/null +++ b/src/plugin.c @@ -0,0 +1,582 @@ +/*************************************************************************** + plugin.c + A modified gxine mozilla plugin, + to start kaffeine instead of gxine :-) + ------------------- + begin : Wen Oct 30 2003 + revision : $Revision: 1.1.1.1 $ + last modified : $Date: 2004/05/12 08:12:52 $ + copyright : (C) 2003-2004 by J. Kofler + email : kaffeine@gmx.net + ***************************************************************************/ + + +/* + * Copyright (C) 2000-2004 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * + * Id: plugin.c,v 1.22 2003/04/08 22:07:47 guenter Exp + * + * xine plugin for mozilla + * + */ + + + + +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <dlfcn.h> +#include <errno.h> +#include <signal.h> +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xos.h> +#include <X11/Xatom.h> +#include <X11/StringDefs.h> +#include <X11/Intrinsic.h> +#include <X11/Shell.h> +#include <X11/Xaw/Box.h> +#include <X11/Xaw/Form.h> +#include <X11/Xaw/Label.h> +#include <X11/Xaw/Command.h> +#include <X11/Xaw/Text.h> +#include <X11/Xaw/AsciiText.h> + +#include <stdio.h> +#include <math.h> +#include <unistd.h> + + +#define XP_UNIX + +#include "npapi.h" +#include "plugin.h" + + +/* define LOG to write debug messages to /tmp/kaffeine_plugin.log */ +/* +#define LOG +*/ + + +#define STATUS_STR_SIZE 1024 + +static char IsInitialised=0; + +/* global */ +typedef struct { + + char *url; + int kaffeine_started; + +} plugin_global_t; + +static plugin_global_t globals; + +/* per-instance */ +typedef struct { + + Display *display; + Screen *screen; + Window window; + Widget top_level; + int width,height; + + int autostart; + int imageWindow; + + char status_str[STATUS_STR_SIZE]; + + Pixel black, white; + + int is_visible; +} plugin_instance_t; + + +static void xprintf (const char *format, ...) { + +#ifdef LOG + static FILE *log_fd=NULL; + + va_list argp; + + if (!log_fd) { + + log_fd = fopen ("/tmp/kaffeine_plugin.log", "a+"); + + if (log_fd) { + + setvbuf (log_fd, NULL, _IONBF, 0); + + fprintf (log_fd, "\n---------------------------------------------\n\n"); + + } + } + + va_start (argp, format); + + if (log_fd) vfprintf (log_fd, format, argp); + + va_end (argp); +#endif +} + +char *NPP_GetMIMEDescription(void) { + + xprintf("NPP_GetMIMEDescription:\n"); + + return "video/mpeg: mpeg, mpg, mpe: MPEG animation;" + "video/x-mpeg: mpeg, mpg, mpe: MPEG animation;" + "audio/mpeg2: mp2: MPEG audio;" + "audio/x-mpeg2: mp2: MPEG audio;" + "audio/mpeg3: mp3: MPEG audio;" + "audio/x-mpeg3: mp3: MPEG audio;" + "audio/mpeg: mpa,abs,mpega: MPEG audio;" + "audio/x-mpeg: mpa,abs,mpega: MPEG audio;" + "video/quicktime: mov,qt: Quicktime animation;" + "video/x-quicktime: mov,qt: Quicktime animation;" + "video/msvideo: avi: AVI animation;" + "video/x-msvideo: avi: AVI animation;" + "application/x-mplayer2: asf,asx,asp: mplayer2;" + "video/x-ms-asf-plugin: asf,asx,asp: mms animation;" + "audio/x-pn-realaudio-plugin: rpm: Real audio;" + "audio/x-ogg: ogg,ogm: OGG Media;" + "audio/x-scpls: pls: MPEG audio;" + "audio/x-ms-wma: wma: Microsoft Media Audio;" + "video/x-ms-wmv: wmv: Microsoft Media Video;" + "audio/x-mpegurl: m3u: Streaming-MPEG-Audio;" + ; +} + +NPError NPP_GetValue(void *future, NPPVariable variable, void *value){ + + NPError err = NPERR_NO_ERROR; + xprintf("NPP_GetValue: variable=%d\n", variable); + + switch (variable) { + case NPPVpluginNameString: + *((char **)value) = "Kaffeine Starter Plugin"; + break; + case NPPVpluginDescriptionString: + *((char **)value) = + "Will start external Kaffeine Media Player for embedded media streams."; + break; + default: + err = NPERR_GENERIC_ERROR; + } + return err; +} + +NPError NPP_Initialize(void) { + + xprintf("NPP_Initialize:\n"); + if(!IsInitialised){ + + IsInitialised=1; + + globals.url = NULL; + globals.kaffeine_started = 0; + + } + return NPERR_NO_ERROR; +} + + +void * NPP_GetJavaClass() { + xprintf("NPP_GetJavaClass:\n"); + return NULL; +} + +void NPP_Shutdown(void) { + xprintf("NPP_Shutdown:\n"); +} + +static void print_status (plugin_instance_t *this, const char *format, ...) { + + va_list argp; + + va_start (argp, format); + + vsnprintf (this->status_str, STATUS_STR_SIZE, format, argp); + + va_end (argp); + +#if 0 + paint_it (this); +#endif +} + +/* fork2() -- like fork, but the new process is immediately orphaned + * (won't leave a zombie when it exits) + * Returns 1 to the parent, not any meaningful pid. + * The parent cannot wait() for the new process (it's unrelated). + */ + +/* This version assumes that you *haven't* caught or ignored SIGCHLD. */ +/* If you have, then you should just be using fork() instead anyway. */ + +static int fork2() { + pid_t pid; + int status; + + sigset_t set,oset; + sigfillset(& set); + xprintf (">>>>>>>>Forking<<<<<<<<,\n"); + sigprocmask(SIG_SETMASK,&set,&oset); + + if (!(pid = fork())) { + xprintf ("child\n"); + switch (fork()) { + case 0: + xprintf ("child 2\n"); + sigprocmask(SIG_SETMASK,&oset,&set); + return 0; + case -1: + xprintf ("fork 2 failed!\n"); + _exit(errno); /* assumes all errnos are <256 */ + default: + xprintf ("parent 2\n"); + _exit(0); + } + } + + xprintf ("parent, child pid =%d\n", pid); + + if (pid < 0 || waitpid(pid,&status,0) < 0) { + xprintf ("waitpid failed! (pid==%d)\n", pid); + sigprocmask(SIG_SETMASK,&oset,&set); + return -1; + } + sigprocmask(SIG_SETMASK,&oset,&set); + + xprintf ("waitpid done\n"); + + if (WIFEXITED(status)) + if (WEXITSTATUS(status) == 0) { + xprintf ("fork 2 succeeded\n"); + return 1; + } else + errno = WEXITSTATUS(status); + else + errno = EINTR; /* well, sort of :-) */ + + xprintf ("parent done\n"); + + return -1; +} + +static void launch_kaffeine(plugin_instance_t *this) { + + if (!globals.url) { + xprintf ("launch_kaffeine: no url!\n"); + return; + } + + if (!fork2()) { + + xprintf ("launch_kaffeine: url = %s\n", globals.url); + + execlp("kaffeine","" , globals.url, NULL); + + if (execlp("kaffeine", NULL) == -1) { + perror("Error while launching Kaffeine"); + _exit(0); + } + } + + xprintf ("Kaffeine launched.\n"); + + globals.kaffeine_started = 1; +} + +static void got_url (const char *url_) { + + if (strstr (url_, ":/")) + globals.url = strdup (url_); + else + xprintf ("got_url: ignoring this url (%s) because it is a relative one.\n", + url_); + +} + +NPError NPP_New(NPMIMEType pluginType, NPP instance, + uint16 mode, + int16 argc, char* argn[], char* argv[], + NPSavedData* saved) { + + plugin_instance_t* this; + xprintf("NPP_New:\n"); + + if (instance == NULL) + return NPERR_INVALID_INSTANCE_ERROR; + + instance->pdata = NPN_MemAlloc(sizeof(plugin_instance_t)); + + this = (plugin_instance_t*) instance->pdata; + + globals.url = NULL; + this->autostart = 0; + this->imageWindow = 1; + + if (this != NULL) { + + int i; + + /* parse args */ + + for (i=0; i<argc; i++) { + + xprintf ("plugin: argument '%s'='%s'\n", + argn[i], argv[i]); + + if (!strcasecmp (argn[i], "href")) { + got_url (argv[i]); + xprintf ("got href url %s\n", globals.url); + } else if (!strcasecmp (argn[i], "src") && !globals.url) { + got_url (argv[i]); + xprintf ("got src url %s\n", globals.url); + } else if (!strcasecmp (argn[i], "autostart")) { + this->autostart = !strcasecmp (argv[i], "true"); + xprintf ("got autostart %d\n", this->autostart); + } else if (!strcasecmp (argn[i], "controls")) { + this->imageWindow = !strcasecmp (argv[i], "imagewindow"); + if (!this->imageWindow) + xprintf("This is no ImageWindow!\n"); + } + + } + + if ( globals.url && !globals.kaffeine_started && this->imageWindow ) + launch_kaffeine(this); + + xprintf ("plugin: NPP_New done\n"); + + return NPERR_NO_ERROR; + } else { + xprintf ("plugin: out of memory :(\n"); + + return NPERR_OUT_OF_MEMORY_ERROR; + } +} + + +NPError NPP_SetWindow(NPP instance, NPWindow* window) { + + plugin_instance_t* this; + Widget hello, box; + + xprintf("NPP_SetWindow: 42\n"); + + if (instance == NULL) { + xprintf("NPERR_INVALID_INSTANCE_ERROR\n"); + return NPERR_INVALID_INSTANCE_ERROR; + } + + if (window == NULL) { + xprintf("window == NULL, NPERR_NO_ERROR\n"); + return NPERR_NO_ERROR; + } + + this = (plugin_instance_t*) instance->pdata; + + this->display = ((NPSetWindowCallbackStruct *) window->ws_info)->display; + this->window = (Window) window->window; + this->width = window->width; + this->height = window->height; + this->top_level = XtWindowToWidget (this->display, this->window); + this->screen = XtScreen (this->top_level); + + xprintf("x=%lu, y=%lu, w=%lu, h=%lu\n", window->x, window->y, window->width, window->height); + xprintf("window = %lu NPERR_NO_ERROR\n", this->window); + + this->black = BlackPixelOfScreen (this->screen); + this->white = WhitePixelOfScreen (this->screen); + + XResizeWindow(this->display, + this->window, this->width, this->height); + /* XSetWindowBackground (this, this->window, this->black); */ + XSync (this->display, FALSE); + + + + box = XtVaCreateManagedWidget ("form", formWidgetClass, this->top_level, + XtNbackground, this->black, + XtNwidth, this->width, + XtNheight, this->height, NULL); + + if (this->imageWindow) { + hello = XtVaCreateManagedWidget ("Kaffeine Starter Plugin", labelWidgetClass, box, + XtNbackground, this->black, + XtNforeground, this->white, + XtNwidth, this->width, + XtNheight, this->height, NULL); } + + + XtRealizeWidget (box); + + + xprintf("NPP_SetWindow: done.\n"); + + return NPERR_NO_ERROR; +} + +NPError NPP_Destroy(NPP instance, NPSavedData** save) { + + plugin_instance_t* this; + xprintf("NPP_Destroy:\n"); + + if (instance == NULL) + return NPERR_INVALID_INSTANCE_ERROR; + + this = (plugin_instance_t*) instance->pdata; + + if (this != NULL) { + + NPN_MemFree(instance->pdata); + instance->pdata = NULL; + + } + + globals.kaffeine_started = FALSE; + + xprintf("NPP_Destroy: closed.\n"); + + return NPERR_NO_ERROR; +} + + +NPError NPP_NewStream (NPP instance, + NPMIMEType type, + NPStream *stream, + NPBool seekable, + uint16 *stype) { + + /* NPByteRange range; */ + plugin_instance_t *this; + + xprintf("NPP_NewStream:\n"); + + if (instance == NULL) + return NPERR_INVALID_INSTANCE_ERROR; + + this = (plugin_instance_t*) instance->pdata; + + xprintf("NPP_NewStream: url is %s \n", stream->url); + + + got_url (stream->url); + + if (!globals.kaffeine_started) { + + /* + * now start kaffeine as an orphaned child + */ + + launch_kaffeine(this); + xprintf ("NPP_NewStream: Kaffeine started successfully\n"); + + } + + xprintf ("NPP_NewStream: done\n"); + + return NPERR_NO_ERROR; +} + + +/* PLUGIN DEVELOPERS: + * These next 2 functions are directly relevant in a plug-in which + * handles the data in a streaming manner. If you want zero bytes + * because no buffer space is YET available, return 0. As long as + * the stream has not been written to the plugin, Navigator will + * continue trying to send bytes. If the plugin doesn't want them, + * just return some large number from NPP_WriteReady(), and + * ignore them in NPP_Write(). For a NP_ASFILE stream, they are + * still called but can safely be ignored using this strategy. + */ + +int32 STREAMBUFSIZE = 0X0FFFFFFF; /* If we are reading from a file in NPAsFile + * mode so we can take any size stream in our + * write call (since we ignore it) */ + +int32 NPP_WriteReady(NPP instance, NPStream *stream) { + + plugin_instance_t* this; + xprintf("NPP_WriteReady:\n"); + if (instance != NULL) + this = (plugin_instance_t*) instance->pdata; + + return STREAMBUFSIZE; +} + + +int32 NPP_Write(NPP instance, NPStream *stream, int32 offset, int32 len, void *buffer) { + + xprintf("NPP_Write:\n"); + /* + if (instance != NULL) { + plugin_instance_t* this = (plugin_instance_t*) instance->pdata; + } + */ + + return -1; /* close stream */ +} + + +NPError NPP_DestroyStream(NPP instance, NPStream *stream, NPError reason) { + + plugin_instance_t* this; + + xprintf("NPP_DestroyStream: \n"); + if (instance == NULL) + return NPERR_INVALID_INSTANCE_ERROR; + this = (plugin_instance_t*) instance->pdata; + + return NPERR_NO_ERROR; +} + + +void NPP_StreamAsFile(NPP instance, NPStream *stream, const char* fname) { + + plugin_instance_t* this; + + xprintf("NPP_StreamAsFile:\n"); + if (instance != NULL) + this = (plugin_instance_t*) instance->pdata; +} + + +void NPP_Print(NPP instance, NPPrint* printInfo) { + + xprintf("NPP_Print:\n"); + if(printInfo == NULL) + return; + + xprintf("NPP_Print: Not implemented. \n"); +} + +int16 NPP_HandleEvent(NPP instance, void* ev) { + + xprintf("NPP_HandleEvent\n"); + + return 1; +} |