You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kaffeine-mozilla/src/plugin.c

581 lines
14 KiB

/***************************************************************************
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>
#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;
}