From 751418fc6730f1ec1270a0858772b6c9590b8b64 Mon Sep 17 00:00:00 2001 From: Miguel Freitas Date: Thu, 23 Jan 2003 18:46:56 +0000 Subject: updates (osd faq, plugin_info_t and Daniel's xinimin) CVS patchset: 3997 CVS date: 2003/01/23 18:46:56 --- doc/hackersguide/hackersguide.sgml | 735 +++++++++++++++++++++++++++++-------- 1 file changed, 582 insertions(+), 153 deletions(-) (limited to 'doc') diff --git a/doc/hackersguide/hackersguide.sgml b/doc/hackersguide/hackersguide.sgml index 90e45e561..f27ae3da6 100644 --- a/doc/hackersguide/hackersguide.sgml +++ b/doc/hackersguide/hackersguide.sgml @@ -567,17 +567,104 @@ renderer->render_text(osd, x1, y1, text, OSD_TEXT2 ); + + OSD text and palette FAQ + + Q: What is the format of the color palette entries? + + + A: It's the same as used by overlay blending code (YUV). + + + Q: What is the relation between a text palette and a palette + I set with xine_osd_set_palette? + + + A: xine_osd_set_palette will set the entire 256 color palette + to be used when we blend the osd image. + + "text palette" is a sequence of 11 colors from palette to be + used to render text. that is, by calling osd_render_text() + with color_base=100 will render text using colors 100-110. + + + Q: Can I render text with colors in my own palette? + + + A: Sure. just pass the color_base to osd_render_text() + + + Q: Has a text palette change effects on already drawed text? + + + A: osd_set_text_palette() will overwrite some colors on palette + with pre-defined ones. so yes, it will change the color + on already drawed text (if you do it before calling osd_show, + of course). + + if you don't want to change the colors of drawed text just + use different color_base values. + + + Q: What about the shadows of osd-objects? Can I turn them off + or are they hardcoded? + + + A: osd objects have no shadows by itself, but fonts use 11 + colors to produce an anti-aliased effect. + if you set a "text palette" with entries 0-9 being transparent + and 10 being foreground you will get rid of any borders or + anti-aliasing. + + Plugin architecture - xine plugins are built as shared libraries that export at least one - public function named init_type_plugin, where - type reflects the function of the plugin (video, - audio, etc). This function returns a pointer to freshly allocated (typically - via malloc()) structure containing mainly - function pointers; these are the "methods" of the plugin. + xine plugins are built as shared libraries that export a plugin info + record named xine_plugin_info. This is used by plugin + loader to identify the "virtual" plugin types inside the shared library. + + +plugin_info_t xine_plugin_info[] = { + /* type, API, "name", version, special_info, init_function */ + { PLUGIN_DEMUX, 20, "flac", XINE_VERSION_CODE, NULL, demux_flac_init_class }, + { PLUGIN_AUDIO_DECODER, 13, "flacdec", XINE_VERSION_CODE, &dec_info_audio, init_plugin }, + { PLUGIN_NONE, 0, "", 0, NULL, NULL } +}; + + + xine_plugin_info can contain any number of plugins + and must be terminated with a PLUGIN_NONE. Available plugin + types are: + + +#define PLUGIN_NONE 0 +#define PLUGIN_INPUT 1 +#define PLUGIN_DEMUX 2 +#define PLUGIN_AUDIO_DECODER 3 +#define PLUGIN_VIDEO_DECODER 4 +#define PLUGIN_SPU_DECODER 5 +#define PLUGIN_AUDIO_OUT 6 +#define PLUGIN_VIDEO_OUT 7 +#define PLUGIN_POST 8 + + + Every entry in xine_plugin_info has a class initialization + function. This function returns a pointer to freshly allocated (typically + via malloc()) structure containing mainly function + pointers; these are the "methods" of the plugin class. + + + The "plugin class" is not what we call to do the job yet (like decoding + a video or something), it must be instantiated. One reason for having the + class is to hold any global settings that must be accessed by every + instance. Remember that xine library is multistream capable: multible + videos can be decoded at the same time, thus several instances of the + same plugin are possible. + + If you think this is pretty much an object-oriented aproach, then you're right. @@ -601,8 +688,8 @@ typedef struct { /* public fields "inherited" from demux.h */ - demux_plugin_t demux_plugin; + xine_t *xine; int count; } demux_foo_t; @@ -622,43 +709,22 @@ Use an existing demuxer plugin, e.g. demux_mpeg_block as an example. - - Demuxers need to start/stop their own thread for performance reasons - (input plugins may block and if the demuxer runs in a seperate - thread other xine modules can work during blocking time). - - - Since xine 0.9.9 some important responsibilities were assigned to demuxers, like - providing precise information about pts discontinuities. Besides that it's up - to demuxer to tag buffer packets with the specified codec to use and provide control - buffers with start and stop information for the rest of the engine. - Demuxer API You need to implement all the functions given in demux.h: -struct demux_plugin_s -{ - /* - * plugin interface version, lower versions _may_ be supported - */ - int interface_version; +struct demux_plugin_s { /* - * ask demuxer to open the given stream (input-plugin) - * using the content-detection method specified in "stage" - * - * return values: - * DEMUX_CAN_HANDLE on success - * DEMUX_CANNOT_HANDLE on failure + * send headers, followed by BUF_CONTROL_HEADERS_DONE down the + * fifos, then return. do not start demux thread (yet) */ - int (*open) (demux_plugin_t *this, input_plugin_t *ip, - int stage); + void (*send_headers) (demux_plugin_t *this); /* - * start demux thread + * ask demux to seek * * for seekable streams, a start position can be specified * @@ -667,82 +733,89 @@ struct demux_plugin_s * * if both parameters are !=0 start_pos will be used * for non-seekable streams both values will be ignored + * + * returns the demux status (like get_status, but immediately after + * starting the demuxer) */ - void (*start) (demux_plugin_t *this, fifo_buffer_t *video_fifo, - fifo_buffer_t *audio_fifo, - off_t start_pos, int start_time); - + int (*seek) (demux_plugin_t *this, + off_t start_pos, int start_time); + /* - * ask running demux thread to seek - * - * for seekable streams, a start position can be specified + * send a chunk of data down to decoder fifos * - * start_pos : position in input source - * start_time : position measured in seconds from stream start + * the meaning of "chunk" is specific to every demux, usually + * it involves parsing one unit of data from stream. * - * if both parameters are !=0 start_pos will be used - * for non-seekable streams both values will be ignored + * this function will be called from demux loop and should return + * the demux current status */ - void (*seek) (demux_plugin_t *this, - off_t start_pos, int start_time); - + int (*send_chunk) (demux_plugin_t *this); + /* - * stop & kill demux thread, free resources associated with current - * input stream + * free resources */ - void (*stop) (demux_plugin_t *this) ; + void (*dispose) (demux_plugin_t *this) ; /* - * close demuxer, free all resources + * returns DEMUX_OK or DEMUX_FINISHED */ - void (*close) (demux_plugin_t *this) ; + int (*get_status) (demux_plugin_t *this) ; /* - * returns DEMUX_OK or DEMUX_FINISHED + * gets stream length in miliseconds (might be estimated) + * may return 0 for non-seekable streams */ - int (*get_status) (demux_plugin_t *this) ; + int (*get_stream_length) (demux_plugin_t *this); /* - * return human readable identifier for this plugin + * get audio/video frames + * + * experimental, function pointers can be NULL for now. */ - char* (*get_identifier) (void); - - /* - * return MIME types supported for this plugin + int (*get_video_frame) (demux_plugin_t *this, + int timestamp, /* msec */ + int *width, int *height, + int *ratio_code, + int *duration, /* msec */ + int *format, + uint8_t *img) ; + + /* called by video_out for every frame it receives */ + void (*got_video_frame_cb) (demux_plugin_t *this, + vo_frame_t *frame); + + /* + * return capabilities of demuxed stream */ - char* (*get_mimetypes) (void); + uint32_t (*get_capabilities) (demux_plugin_t *this); + /* - * estimate stream length in seconds - * may return 0 for non-seekable streams + * request optional data from input plugin. + */ + int (*get_optional_data) (demux_plugin_t *this, void *data, int data_type); + + /* + * "backwards" link to plugin class */ - int (*get_stream_length) (demux_plugin_t *this); + demux_class_t *demux_class; } ; - - Demuxer plugins export only one function: - - demux_plugin_t *init_demux_plugin (int iface_version, xine_t *xine); - - this is called on startup when the demuxer plugin is loaded. - The funtion should malloc() a demux_plugin_t* pointer, - fill in the function pointers and return the demux_plugin_t * pointer. - Buffer types Demuxer must send data to decoders using two fifo of buffers fifo_video - and audio_fifo. Both are passed on demuxer start() method. The following - code fragment shows how it's done. + and audio_fifo. Both are available at stream + struct. The following code fragment shows how it's done. buf_element_t *buf; @@ -924,48 +997,37 @@ struct demux_plugin_s be purely block based. - The input plugin should export at least the following function: - - - input_plugin_t *init_input_plugin (int iface, xine_t *xine) - - - The iface parameter is the input plugin interface - xine is requesting (as of writing this is '5'). The - xine parameter is a pointer to the global - xine_t for this session. - - - The function should return a pointer to an allocated - input_plugin_t (defined in - xine/input_plugin.h) which has the following + The plugin struct input_plugin_t (defined in + xine/input_plugin.h) has the following definition: -struct input_plugin_s -{ +struct input_plugin_s { /* - * plugin interface version, lower versions _may_ be supported - */ - int interface_version; - - /* - * return capabilities of input source + * return capabilities of the current playable entity. See + * get_current_pos below for a description of a "playable entity" + * Capabilities a created by "OR"ing a mask of constants listed + * below which start "INPUT_CAP". + * + * depending on the values set, some of the functions below + * will or will not get called or should (not) be able to + * do certain tasks. + * + * for example if INPUT_CAP_SEEKABLE is set, + * the seek() function is expected to work fully at any time. + * however, if the flag is not set, the seek() function should + * make a best-effort attempt to seek, e.g. at least + * relative forward seeking should work. */ - uint32_t (*get_capabilities) (input_plugin_t *this); - /* - * open input MRL - return 1 if succ - */ - int (*open) (input_plugin_t *this, char *mrl); - /* * read nlen bytes, return number of bytes read */ off_t (*read) (input_plugin_t *this, char *buf, off_t nlen); + /* * read one block, return newly allocated block (or NULL on failure) * for blocked input sources len must be == blocksize @@ -973,6 +1035,7 @@ struct input_plugin_s */ buf_element_t *(*read_block)(input_plugin_t *this, fifo_buffer_t *fifo, off_t len); + /* * seek position, return new position * @@ -980,85 +1043,75 @@ struct input_plugin_s */ off_t (*seek) (input_plugin_t *this, off_t offset, int origin); + /* * get current position in stream. * */ off_t (*get_current_pos) (input_plugin_t *this); + /* - * return length of input (-1 => unlimited, e.g. stream) + * return number of bytes in the next playable entity or -1 if the + * input is unlimited, as would be the case in a network stream. + * + * A "playable entity" tends to be the entities listed in a playback + * list or the units on which playback control generally works on. + * It might be the number of bytes in a VCD "segment" or "track" (if + * the track has no "entry" subdivisions), or the number of bytes in + * a PS (Program Segment or "Chapter") of a DVD. If there are no + * subdivisions of the input medium and it is considered one + * indivisible entity, it would be the byte count of that entity; + * for example, the length in bytes of an MPEG file. + + * This length information is used, for example when in setting the + * absolute or relative play position or possibly calculating the + * bit rate. */ off_t (*get_length) (input_plugin_t *this); - /* - * return block size of input source (if supported, 0 otherwise) - */ - uint32_t (*get_blocksize) (input_plugin_t *this); /* - * ls function - * return value: NULL => filename is a file, **char=> filename is a dir - */ - mrl_t** (*get_dir) (input_plugin_t *this, char *filename, int *nFiles); - - /* - * eject/load the media (if it's possible) + * return block size in bytes of next complete playable entity (if + * supported, 0 otherwise). See the description above under + * get_length for a description of a "complete playable entity". + * + * this block size is only used for mpeg streams stored on + * a block oriented storage media, e.g. DVDs and VCDs, to speed + * up the demuxing process. only set this (and the INPUT_CAP_BLOCK + * flag) if this is the case for your input plugin. * - * returns 0 for temporary failures + * make this function simply return 0 if unsure. */ - int (*eject_media) (input_plugin_t *this); + + uint32_t (*get_blocksize) (input_plugin_t *this); + /* * return current MRL */ char * (*get_mrl) (input_plugin_t *this); - /* - * stop input source - */ - void (*stop) (input_plugin_t *this); /* - * close input source + * request optional data from input plugin. */ - void (*close) (input_plugin_t *this); + int (*get_optional_data) (input_plugin_t *this, void *data, int data_type); - /* - * return human readable (verbose = 1 line) description for this plugin - */ - char* (*get_description) (input_plugin_t *this); /* - * return short, human readable identifier for this plugin - * this is used for GUI buttons, The identifier must have max. 4 characters - * characters (max. 5 including terminating \0) + * close stream, free instance resources */ - char* (*get_identifier) (input_plugin_t *this); + void (*dispose) (input_plugin_t *this); /* - * generate autoplay list - * return value: list of MRLs + * "backward" link to input plugin class struct */ - char** (*get_autoplay_list) (input_plugin_t *this, int *nFiles); - /* - * request optional data from input plugin. - */ - int (*get_optional_data) (input_plugin_t *this, void *data, int data_type); + input_class_t *input_class; - /* - * check if it is possible/valid to directly branch to this MRL - * optional: may be NULL - */ - - int (*is_branch_possible) (input_plugin_t *this, char *next_mrl); }; - - Typically the init_input_plugin function will - initialise all these parameters. - The get_capabilities parameter points to a function which returns a bit mask describing the input device's capabilities. @@ -1323,8 +1376,21 @@ struct vo_driver_s { /* display a given frame */ void (*display_frame) (vo_driver_t *this, vo_frame_t *vo_img); - /* overlay functions */ + /* overlay_begin and overlay_end are used by drivers suporting + * persistent overlays. they can be optimized to update only when + * overlay image has changed. + * + * sequence of operation (pseudo-code): + * overlay_begin(this,img,true_if_something_changed_since_last_blend ); + * while(visible_overlays) + * overlay_blend(this,img,overlay[i]); + * overlay_end(this,img); + * + * any function pointer from this group may be set to NULL. + */ + void (*overlay_begin) (vo_driver_t *this, vo_frame_t *vo_img, int changed); void (*overlay_blend) (vo_driver_t *this, vo_frame_t *vo_img, vo_overlay_t *overlay); + void (*overlay_end) (vo_driver_t *this, vo_frame_t *vo_img); /* * these can be used by the gui directly: @@ -1346,16 +1412,21 @@ struct vo_driver_s { int (*gui_data_exchange) (vo_driver_t *this, int data_type, void *data); - void (*exit) (vo_driver_t *this); - /* check if a redraw is needed (due to resize) * this is only used for still frames, normal video playback * must call that inside display_frame() function. */ int (*redraw_needed) (vo_driver_t *this); + /* + * free all resources, close driver + */ + + void (*dispose) (vo_driver_t *this); + + void *node; /* needed by plugin_loader */ }; - + The get_info field is simply a pointer to the get_video_out_plugin_info() function described @@ -1506,6 +1577,365 @@ struct vo_frame_s { Writing a new frontend to xine + + Source code of a simple X11 frontend + +/* +** Copyright (C) 2003 Daniel Caujolle-Bert <segfault@club-internet.fr> +** +** This program 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. +** +** This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +** +*/ +#include <stdio.h> +#include <string.h> +#include <math.h> + +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/keysym.h> +#include <X11/Xatom.h> +#include <X11/Xutil.h> +#include <X11/extensions/XShm.h> + +#include <xine.h> +#include <xine/xineutils.h> + +#ifndef XShmGetEventBase +extern int XShmGetEventBase(Display *); +#endif + +#define MWM_HINTS_DECORATIONS (1L << 1) +#define PROP_MWM_HINTS_ELEMENTS 5 +typedef struct { + uint32_t flags; + uint32_t functions; + uint32_t decorations; + int32_t input_mode; + uint32_t status; +} MWMHints; + +static xine_t *xine; +static xine_stream_t *stream; +static xine_video_port_t *vo_port; +static xine_audio_port_t *ao_port; +static xine_event_queue_t *event_queue; + +static Display *display; +static int screen; +static Window window[2]; +static int completion_event; +static int xpos, ypos, width, height, fullscreen; +static double pixel_aspect; + +static int running = 0; + + +static void dest_size_cb(void *data, int video_width, int video_height, double video_pixel_aspect, + int *dest_width, int *dest_height, double *dest_pixel_aspect) { + + if(!running) + return; + + *dest_width = width; + *dest_height = height; + *dest_pixel_aspect = pixel_aspect; +} + +static void frame_output_cb(void *data, int video_width, int video_height, + double video_pixel_aspect, int *dest_x, int *dest_y, + int *dest_width, int *dest_height, + double *dest_pixel_aspect, int *win_x, int *win_y) { + if(!running) + return; + + *dest_x = 0; + *dest_y = 0; + *win_x = xpos; + *win_y = ypos; + *dest_width = width; + *dest_height = height; + *dest_pixel_aspect = pixel_aspect; +} + +static void event_listener(void *user_data, const xine_event_t *event) { + switch(event->type) { + case XINE_EVENT_UI_PLAYBACK_FINISHED: + running = 0; + break; + + case XINE_EVENT_PROGRESS: + { + xine_progress_data_t *pevent = (xine_progress_data_t *) event->data; + + printf("%s [%d%%]\n", pevent->description, pevent->percent); + } + break; + + } +} + +int main(int argc, char **argv) { + char configfile[2048]; + x11_visual_t vis; + double res_h, res_v; + char *vo_driver = "auto"; + char *ao_driver = "auto"; + char *mrl; + int i; + Atom XA_NO_BORDER; + MWMHints mwmhints; + + if(argc <= 1) { + printf("specify an mrl\n"); + return 1; + } + + for(i = 1; i < argc; i++) { + if(!strcmp(argv[i], "-vo")) { + vo_driver = argv[++i]; + } + else if(!strcmp(argv[i], "-ao")) { + ao_driver = argv[++i]; + } + else + mrl = argv[i]; + } + + mrl = argv[1]; + printf("mrl: '%s'\n", mrl); + + if(!XInitThreads()) { + printf("XInitThreads() failed\n"); + return 1; + } + + xine = xine_new(); + sprintf(configfile, "%s%s", xine_get_homedir(), "/.xine/config2"); + xine_config_load(xine, configfile); + xine_init(xine); + + display = XOpenDisplay(NULL); + screen = XDefaultScreen(display); + xpos = 0; + ypos = 0; + width = 320; + height = 200; + + XLockDisplay(display); + fullscreen = 0; + window[0] = XCreateSimpleWindow(display, XDefaultRootWindow(display), + xpos, ypos, width, height, 1, 0, 0); + + window[1] = XCreateSimpleWindow(display, XDefaultRootWindow(display), + 0, 0, (DisplayWidth(display, screen)), + (DisplayHeight(display, screen)), 0, 0, 0); + + XSelectInput(display, window[0], (ExposureMask | ButtonPressMask | KeyPressMask | + ButtonMotionMask | StructureNotifyMask | + PropertyChangeMask | PointerMotionMask)); + + XSelectInput(display, window[1], (ExposureMask | ButtonPressMask | KeyPressMask | + ButtonMotionMask | StructureNotifyMask | + PropertyChangeMask | PointerMotionMask)); + + XA_NO_BORDER = XInternAtom(display, "_MOTIF_WM_HINTS", False); + mwmhints.flags = MWM_HINTS_DECORATIONS; + mwmhints.decorations = 0; + XChangeProperty(display, window[1], + XA_NO_BORDER, XA_NO_BORDER, 32, PropModeReplace, (unsigned char *) &mwmhints, + PROP_MWM_HINTS_ELEMENTS); + + if(XShmQueryExtension(display) == True) + completion_event = XShmGetEventBase(display) + ShmCompletion; + else + completion_event = -1; + + XMapRaised(display, window[fullscreen]); + + res_h = (DisplayWidth(display, screen) * 1000 / DisplayWidthMM(display, screen)); + res_v = (DisplayHeight(display, screen) * 1000 / DisplayHeightMM(display, screen)); + XSync(display, False); + XUnlockDisplay(display); + + vis.display = display; + vis.screen = screen; + vis.d = window[fullscreen]; + vis.dest_size_cb = dest_size_cb; + vis.frame_output_cb = frame_output_cb; + vis.user_data = NULL; + pixel_aspect = res_v / res_h; + + if(fabs(pixel_aspect - 1.0) < 0.01) + pixel_aspect = 1.0; + + vo_port = xine_open_video_driver(xine, vo_driver, XINE_VISUAL_TYPE_X11, (void *) &vis); + + ao_port = xine_open_audio_driver(xine , ao_driver, NULL); + + stream = xine_stream_new(xine, ao_port, vo_port); + event_queue = xine_event_new_queue(stream); + xine_event_create_listener_thread(event_queue, event_listener, NULL); + + xine_gui_send_vo_data(stream, XINE_GUI_SEND_DRAWABLE_CHANGED, (void *) window[fullscreen]); + xine_gui_send_vo_data(stream, XINE_GUI_SEND_VIDEOWIN_VISIBLE, (void *) 1); + + if((!xine_open(stream, mrl)) || (!xine_play(stream, 0, 0))) { + printf("Unable to open mrl '%s'\n", mrl); + return 1; + } + + running = 1; + + while(running) { + XEvent xevent; + + XNextEvent(display, &xevent); + + switch(xevent.type) { + + case KeyPress: + { + XKeyEvent kevent; + KeySym ksym; + char kbuf[256]; + int len; + + kevent = xevent.xkey; + + XLockDisplay(display); + len = XLookupString(&kevent, kbuf, sizeof(kbuf), &ksym, NULL); + XUnlockDisplay(display); + + switch (ksym) { + + case XK_q: + case XK_Q: + running = 0; + break; + + case XK_f: + case XK_F: + { + Window tmp_win; + + XLockDisplay(display); + XUnmapWindow(display, window[fullscreen]); + fullscreen = !fullscreen; + XMapRaised(display, window[fullscreen]); + XSync(display, False); + XTranslateCoordinates(display, window[fullscreen], + DefaultRootWindow(display), + 0, 0, &xpos, &ypos, &tmp_win); + XUnlockDisplay(display); + + xine_gui_send_vo_data(stream, XINE_GUI_SEND_DRAWABLE_CHANGED, + (void*) window[fullscreen]); + } + break; + + case XK_Up: + xine_set_param(stream, XINE_PARAM_AUDIO_VOLUME, + (xine_get_param(stream, XINE_PARAM_AUDIO_VOLUME) + 1)); + break; + + case XK_Down: + xine_set_param(stream, XINE_PARAM_AUDIO_VOLUME, + (xine_get_param(stream, XINE_PARAM_AUDIO_VOLUME) - 1)); + break; + + case XK_plus: + xine_set_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL, + (xine_get_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL) + 1)); + break; + + case XK_minus: + xine_set_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL, + (xine_get_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL) - 1)); + break; + + case XK_space: + if(xine_get_param(stream, XINE_PARAM_SPEED) != XINE_SPEED_PAUSE) + xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE); + else + xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_NORMAL); + break; + + } + } + break; + + case Expose: + if(xevent.xexpose.count != 0) + break; + xine_gui_send_vo_data(stream, XINE_GUI_SEND_EXPOSE_EVENT, &xevent); + break; + + case ConfigureNotify: + { + XConfigureEvent *cev = (XConfigureEvent *) &xevent; + Window tmp_win; + + width = cev->width; + height = cev->height; + + if((cev->x == 0) && (cev->y == 0)) { + XLockDisplay(display); + XTranslateCoordinates(display, cev->window, + DefaultRootWindow(cev->display), + 0, 0, &xpos, &ypos, &tmp_win); + XUnlockDisplay(display); + } + else { + xpos = cev->x; + ypos = cev->y; + } + } + break; + + } + + if(xevent.type == completion_event) + xine_gui_send_vo_data(stream, XINE_GUI_SEND_COMPLETION_EVENT, &xevent); + } + + xine_close(stream); + xine_event_dispose_queue(event_queue); + xine_dispose(stream); + xine_close_audio_driver(xine, ao_port); + xine_close_video_driver(xine, vo_port); + xine_exit(xine); + + XLockDisplay(display); + XUnmapWindow(display, window[fullscreen]); + XDestroyWindow(display, window[0]); + XDestroyWindow(display, window[1]); + XUnlockDisplay(display); + + XCloseDisplay (display); + + return 1; +} + +/* + * Local variables: + * compile-command: "gcc -Wall -O2 `xine-config --cflags` `xine-config --libs` -lX11 -lm -o xinimin xinimin.c" + * End: + */ + + @@ -1584,4 +2014,3 @@ struct vo_frame_s { - -- cgit v1.2.3