diff options
Diffstat (limited to 'src/video_out/x11osd.c')
-rw-r--r-- | src/video_out/x11osd.c | 375 |
1 files changed, 375 insertions, 0 deletions
diff --git a/src/video_out/x11osd.c b/src/video_out/x11osd.c new file mode 100644 index 000000000..c94f2bd26 --- /dev/null +++ b/src/video_out/x11osd.c @@ -0,0 +1,375 @@ +/* + * Copyright (C) 2003 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * $Id: x11osd.c,v 1.1 2003/11/26 01:03:32 miguelfreitas Exp $ + * + * x11osd.c, use X11 Nonrectangular Window Shape Extension to draw xine OSD + * + * Nov 2003 - Miguel Freitas + * + * based on ideas and code of + * xosd Copyright (c) 2000 Andre Renaud (andre@ignavus.net) + */ + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> +#include <time.h> + +#include <assert.h> + +#include <netinet/in.h> + +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/extensions/shape.h> +#include <X11/Xatom.h> + +#include "xine_internal.h" +#include "alphablend.h" +#include "x11osd.h" + +struct x11osd +{ + Display *display; + int screen; + Window window; + Window parent_window; + unsigned int depth; + Pixmap mask_bitmap; + Pixmap bitmap; + Visual *visual; + Colormap cmap; + + GC gc; + GC mask_gc; + GC mask_gc_back; + + int width; + int height; + int x; + int y; + int clean; + int mapped; +}; + + +void +x11osd_expose (x11osd * osd) +{ + assert (osd); + + if( !osd->clean ) { + + XShapeCombineMask (osd->display, osd->window, ShapeBounding, 0, 0, + osd->mask_bitmap, ShapeSet); + + if( !osd->mapped ) + XMapRaised (osd->display, osd->window); + osd->mapped = 1; + + XCopyArea (osd->display, osd->bitmap, osd->window, osd->gc, 0, 0, + osd->width, osd->height, 0, 0); + } else { + if( osd->mapped ) + XUnmapWindow (osd->display, osd->window); + osd->mapped = 0; + } +} + + +void +x11osd_resize (x11osd * osd, int width, int height) +{ + assert (osd); + osd->width = width; + osd->height = height; + + XResizeWindow (osd->display, osd->window, osd->width, osd->height); + XFreePixmap (osd->display, osd->mask_bitmap); + osd->mask_bitmap = + XCreatePixmap (osd->display, osd->window, osd->width, osd->height, + 1); + XFillRectangle (osd->display, osd->mask_bitmap, osd->mask_gc_back, + 0, 0, osd->width, osd->height); + + XFreePixmap (osd->display, osd->bitmap); + osd->bitmap = + XCreatePixmap (osd->display, osd->window, osd->width, + osd->height, osd->depth); +} + +void +x11osd_drawable_changed (x11osd * osd, Window window) +{ + assert (osd); + +/* + Do I need to recreate the GC's?? + + XFreeGC (osd->display, osd->gc); + XFreeGC (osd->display, osd->mask_gc); + XFreeGC (osd->display, osd->mask_gc_back); +*/ + XFreePixmap (osd->display, osd->bitmap); + XFreePixmap (osd->display, osd->mask_bitmap); + XFreeColormap (osd->display, osd->cmap); + XDestroyWindow (osd->display, osd->window); + + + osd->parent_window = window; + osd->window = XCreateSimpleWindow (osd->display, + osd->parent_window, + 0, 0, + osd->width, osd->height, 1, + BlackPixel (osd->display, osd->screen), + BlackPixel (osd->display, osd->screen)); + + osd->mask_bitmap = + XCreatePixmap (osd->display, osd->window, osd->width, osd->height, + 1); + XFillRectangle (osd->display, osd->mask_bitmap, osd->mask_gc_back, + 0, 0, osd->width, osd->height); + + osd->bitmap = + XCreatePixmap (osd->display, osd->window, osd->width, + osd->height, osd->depth); + + osd->cmap = XCreateColormap(osd->display, osd->window, + osd->visual, AllocNone); + + XSelectInput (osd->display, osd->window, ExposureMask); +} + + +x11osd * +x11osd_create (Display *display, int screen, Window window) +{ + x11osd *osd; + int event_basep, error_basep; + + osd = malloc (sizeof (x11osd)); + memset (osd, 0, sizeof (x11osd)); + if (osd == NULL) + return NULL; + + osd->display = display; + osd->screen = screen; + osd->parent_window = window; + + if (!XShapeQueryExtension (osd->display, &event_basep, &error_basep)) + goto error2; + + osd->visual = DefaultVisual (osd->display, osd->screen); + osd->depth = DefaultDepth (osd->display, osd->screen); + osd->width = XDisplayWidth (osd->display, osd->screen); + osd->height = XDisplayHeight (osd->display, osd->screen); + + osd->window = XCreateSimpleWindow (osd->display, + osd->parent_window, + 0, 0, + osd->width, osd->height, 1, + BlackPixel (osd->display, osd->screen), + BlackPixel (osd->display, osd->screen)); + + osd->mask_bitmap = + XCreatePixmap (osd->display, osd->window, osd->width, osd->height, + 1); + osd->bitmap = + XCreatePixmap (osd->display, osd->window, osd->width, + osd->height, osd->depth); + + osd->gc = XCreateGC (osd->display, osd->window, 0, NULL); + osd->mask_gc = XCreateGC (osd->display, osd->mask_bitmap, 0, NULL); + osd->mask_gc_back = XCreateGC (osd->display, osd->mask_bitmap, 0, NULL); + + XSetForeground (osd->display, osd->mask_gc_back, + BlackPixel (osd->display, osd->screen)); + XSetBackground (osd->display, osd->mask_gc_back, + WhitePixel (osd->display, osd->screen)); + + XSetForeground (osd->display, osd->mask_gc, + WhitePixel (osd->display, osd->screen)); + XSetBackground (osd->display, osd->mask_gc, + BlackPixel (osd->display, osd->screen)); + + osd->cmap = XCreateColormap(osd->display, osd->window, + osd->visual, AllocNone); + + XSelectInput (osd->display, osd->window, ExposureMask); + + osd->clean = 0; + x11osd_clear(osd); + osd->mapped = 0; + x11osd_expose(osd); + + return osd; + +/* +error3: + XFreeGC (osd->display, osd->gc); + XFreeGC (osd->display, osd->mask_gc); + XFreeGC (osd->display, osd->mask_gc_back); + XFreePixmap (osd->display, osd->bitmap); + XFreePixmap (osd->display, osd->mask_bitmap); + XDestroyWindow (osd->display, osd->window); +*/ +error2: + free (osd); + return NULL; +} + +void +x11osd_destroy (x11osd * osd) +{ + + assert (osd); + + XFreeGC (osd->display, osd->gc); + XFreeGC (osd->display, osd->mask_gc); + XFreeGC (osd->display, osd->mask_gc_back); + XFreePixmap (osd->display, osd->bitmap); + XFreePixmap (osd->display, osd->mask_bitmap); + XFreeColormap (osd->display, osd->cmap); + XDestroyWindow (osd->display, osd->window); + + free (osd); +} + +void x11osd_clear(x11osd *osd) +{ + if( !osd->clean ) + XFillRectangle (osd->display, osd->mask_bitmap, osd->mask_gc_back, + 0, 0, osd->width, osd->height); + osd->clean = 1; +} + +#define TRANSPARENT 0xffffffff + +#define saturate(n, l, u) ((n) < (l) ? (l) : ((n) > (u) ? (u) : (n))) + +void x11osd_blend(x11osd *osd, vo_overlay_t *overlay) +{ + if (overlay->rle) { + int i, x, y, len, width; + int use_clip_palette, max_palette_colour[2]; + uint32_t palette[2][OVL_PALETTE_SIZE]; + + max_palette_colour[0] = -1; + max_palette_colour[1] = -1; + + for (i=0, x=0, y=0; i<overlay->num_rle; i++) { + len = overlay->rle[i].len; + + while (len > 0) { + use_clip_palette = 0; + if (len > overlay->width) { + width = overlay->width; + len -= overlay->width; + } + else { + width = len; + len = 0; + } + if ((y >= overlay->clip_top) && (y <= overlay->clip_bottom) && (x <= overlay->clip_right)) { + if ((x < overlay->clip_left) && (x + width - 1 >= overlay->clip_left)) { + width -= overlay->clip_left - x; + len += overlay->clip_left - x; + } + else if (x > overlay->clip_left) { + use_clip_palette = 1; + if (x + width - 1 > overlay->clip_right) { + width -= overlay->clip_right - x; + len += overlay->clip_right - x; + } + } + } + + if (overlay->rle[i].color > max_palette_colour[use_clip_palette]) { + int j; + clut_t *src_clut; + uint8_t *src_trans; + + if (use_clip_palette) { + src_clut = (clut_t *)&overlay->clip_color; + src_trans = (uint8_t *)&overlay->clip_trans; + } + else { + src_clut = (clut_t *)&overlay->color; + src_trans = (uint8_t *)&overlay->trans; + } + for (j=max_palette_colour[use_clip_palette]+1; j<=overlay->rle[i].color; j++) { + if (src_trans[j]) { + if (1) { + XColor xcolor; + int y, u, v, r, g, b; + + y = saturate(src_clut[j].y, 16, 235); + u = saturate(src_clut[j].cb, 16, 240); + v = saturate(src_clut[j].cr, 16, 240); + y = (9 * y) / 8; + r = y + (25 * v) / 16 - 218; + xcolor.red = (65536 * saturate(r, 0, 255)) / 256; + g = y + (-13 * v) / 16 + (-25 * u) / 64 + 136; + xcolor.green = (65536 * saturate(g, 0, 255)) / 256; + b = y + 2 * u - 274; + xcolor.blue = (65536 * saturate(b, 0, 255)) / 256; + + xcolor.flags = DoRed | DoBlue | DoGreen; + + XAllocColor(osd->display, osd->cmap, &xcolor); + + palette[use_clip_palette][j] = xcolor.pixel; + } + else { + if (src_clut[j].y > 127) { + palette[use_clip_palette][j] = WhitePixel(osd->display, osd->screen); + } + else { + palette[use_clip_palette][j] = BlackPixel(osd->display, osd->screen); + } + } + } + else { + palette[use_clip_palette][j] = TRANSPARENT; + } + } + max_palette_colour[use_clip_palette] = overlay->rle[i].color; + } + + if(palette[use_clip_palette][overlay->rle[i].color] != TRANSPARENT) { + XSetForeground(osd->display, osd->gc, palette[use_clip_palette][overlay->rle[i].color]); + XFillRectangle(osd->display, osd->bitmap, osd->gc, overlay->x + x, overlay->y + y, width, 1); + XFillRectangle(osd->display, osd->mask_bitmap, osd->mask_gc, overlay->x + x, overlay->y + y, width, 1); + } + + x += width; + if (x == overlay->width) { + x = 0; + y++; + } + } + } + } + osd->clean = 0; +} + |