diff options
Diffstat (limited to 'imlibrenderer')
-rw-r--r-- | imlibrenderer/Makefile | 5 | ||||
-rw-r--r-- | imlibrenderer/dmyrenderer/dmyrenderer.h | 28 | ||||
-rw-r--r-- | imlibrenderer/fbrenderer/fbrenderer.c | 375 | ||||
-rw-r--r-- | imlibrenderer/fbrenderer/fbrenderer.h | 65 | ||||
-rw-r--r-- | imlibrenderer/imlib.cc | 81 | ||||
-rw-r--r-- | imlibrenderer/imlibrenderer.c | 906 | ||||
-rw-r--r-- | imlibrenderer/imlibrenderer.h | 76 | ||||
-rw-r--r-- | imlibrenderer/xrenderer/xrenderer.c | 296 | ||||
-rw-r--r-- | imlibrenderer/xrenderer/xrenderer.h | 54 |
9 files changed, 1886 insertions, 0 deletions
diff --git a/imlibrenderer/Makefile b/imlibrenderer/Makefile new file mode 100644 index 0000000..68e7227 --- /dev/null +++ b/imlibrenderer/Makefile @@ -0,0 +1,5 @@ + +LIBS += $(shell imlib2-config --libs) -ljpeg + +all: + g++ -ggdb -I ../ imlib.cc $(LIBS) -o imlibtest diff --git a/imlibrenderer/dmyrenderer/dmyrenderer.h b/imlibrenderer/dmyrenderer/dmyrenderer.h new file mode 100644 index 0000000..d95fd1c --- /dev/null +++ b/imlibrenderer/dmyrenderer/dmyrenderer.h @@ -0,0 +1,28 @@ +//*************************************************************************** +// Group VDR/GraphTFT +// File dmyrenderer.c +// Date 31.10.06 - Jörg Wendel +// This code is distributed under the terms and conditions of the +// GNU GENERAL PUBLIC LICENSE. See the file COPYING for details. +//-------------------------------------------------------------------------- +// Class DummyRenderer +//*************************************************************************** + +#ifndef __GTFT_DMYRENDERER_HPP__ +#define __GTFT_DMYRENDERER_HPP__ + +#include "imlibrenderer.h" + +class DummyRenderer : public ImlibRenderer +{ + public: + + DummyRenderer(int x, int y, int width, int height, string cfgPath, int utf, string thmPath) + : ImlibRenderer(x, y, width, height, cfgPath, utf, thmPath) { } + + int init(int lazy) { return ImlibRenderer::init(lazy); } + void deinit() { } +}; + +//*************************************************************************** +#endif // __GTFT_DMYRENDERER_HPP__ diff --git a/imlibrenderer/fbrenderer/fbrenderer.c b/imlibrenderer/fbrenderer/fbrenderer.c new file mode 100644 index 0000000..87e2cd5 --- /dev/null +++ b/imlibrenderer/fbrenderer/fbrenderer.c @@ -0,0 +1,375 @@ +/** + * GraphTFT plugin for the Video Disk Recorder + * + * fbrenderer.c - A plugin for the Video Disk Recorder + * + * (c) 2004 Lars Tegeler, Sascha Volkenandt + * + * This code is distributed under the terms and conditions of the + * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details. + * + * $Id: fbrenderer.c,v 1.4 2012/09/27 13:07:12 wendel Exp $ + * + **/ + +#include <sys/mman.h> +#include <sys/ioctl.h> + +#include <fbrenderer.h> + +#include <libavcodec/avcodec.h> + +#include <common.h> +#include <setup.h> + +static unsigned char* frame_buffer; +static struct fb_var_screeninfo fb_vinfo; + +typedef unsigned char UINT8; + +//*************************************************************************** +// Object +//*************************************************************************** + +FbRenderer::FbRenderer(int x, int y, int width, int height, + string cfgPath, int utf, string thmPath) + : ImlibRenderer(x, y, width, height, cfgPath, utf, thmPath) +{ + fb_dev_name = 0; + initialized = no; +} + +FbRenderer::~FbRenderer() +{ + deinit(); +} + +//*************************************************************************** +// +//*************************************************************************** + +void FbRenderer::deinit() +{ + if (!initialized) + return; + + fb_orig_vinfo.xoffset = fb_vinfo.xoffset; + fb_orig_vinfo.yoffset = fb_vinfo.yoffset; + + if (ioctl(fb_dev_fd, FBIOPUT_VSCREENINFO, &fb_orig_vinfo)) + tell(4, "Can't reset original fb_var_screeninfo: %s", strerror(errno)); + + ::close(fb_dev_fd); + + if (frame_buffer) + munmap(frame_buffer, fb_size); + + initialized = no; +} + +//*************************************************************************** +// +//*************************************************************************** + +#ifndef AV_PIX_FMT_RGB32 +# define AV_PIX_FMT_RGB32 PIX_FMT_RGB32 +# define AV_PIX_FMT_RGB24 PIX_FMT_RGB24 +# define AV_PIX_FMT_RGB565 PIX_FMT_RGB565 +#endif + +int FbRenderer::init(int lazy) +{ + asprintf(&fb_dev_name, "%s", devname); + + // open framebuffer + + tell(4 , "Using framebuffer device '%s'", fb_dev_name); + + if ((fb_dev_fd = open(fb_dev_name, O_RDWR)) == -1) + { + tell(0, "Opening framebuffer device '%s' faild, error was '%s'", + fb_dev_name, strerror(errno)); + return fail; + } + + // read VScreen info from fb + + if (ioctl(fb_dev_fd, FBIOGET_VSCREENINFO, &fb_vinfo)) + { + tell(0, "Can't get VSCREENINFO, %s", strerror(errno)); + return fail; + } + + // Save VScreen info and try to set virtual image + + fb_orig_vinfo = fb_vinfo; + fb_vinfo.xres_virtual = fb_vinfo.xres; + fb_vinfo.yres_virtual = fb_vinfo.yres; + + fb_vinfo.xoffset = 0; + fb_vinfo.yoffset = 0; + + // fb_vinfo.bits_per_pixel = 32; + + // write VScreen info + + if (ioctl(fb_dev_fd, FBIOPUT_VSCREENINFO, &fb_vinfo)) + tell(0, "Can't put VSCREENINFO, %s", strerror(errno)); + + // read VScreen info from fb (again) this will be the 'accepted' resolutions from the fb + + if (ioctl(fb_dev_fd, FBIOGET_VSCREENINFO, &fb_vinfo)) + { + tell(0, "Can't get VSCREENINFO, %s", strerror(errno)); + return fail; + } + + // read VScreen info from fb + + if (ioctl(fb_dev_fd, FBIOGET_FSCREENINFO, &fb_finfo)) + { + tell(0, "Can't get FSCREENINFO, %s", strerror(errno)); + return fail; + } + + tell(0, "fb settings are (%d/%d) with a color depth of (%d)", + fb_vinfo.xres, fb_vinfo.yres, fb_vinfo.bits_per_pixel); + + dspWidth = fb_vinfo.xres; + dspHeight = fb_vinfo.yres; + + y_offset = fb_vinfo.yoffset; + fb_line_len = fb_finfo.line_length; + fb_size = fb_finfo.smem_len; + frame_buffer = 0; + + switch (fb_vinfo.bits_per_pixel) + { + case 32: tell(4, "FB using 32 bit depth"); fb_type = AV_PIX_FMT_RGB32; break; + case 24: tell(4, "FB using 24 bit depth"); fb_type = AV_PIX_FMT_RGB24; break; + case 16: tell(4, "FB using 16 bit depth"); fb_type = AV_PIX_FMT_RGB565; break; + default: tell(4, "FB color depth not supported -> %i bits per pixel", + fb_vinfo.bits_per_pixel); + } + + if ((frame_buffer = (unsigned char*)mmap(0, fb_size, PROT_READ | PROT_WRITE, MAP_SHARED, fb_dev_fd, 0)) == (unsigned char*)-1) + { + tell(0, "FB Can't mmap %s: %s", fb_dev_name, strerror(errno)); + return fail; + } + + initialized = yes; + + ImlibRenderer::init(lazy); + + return success; +} + +//*************************************************************************** +// +//*************************************************************************** + +#ifndef use_asm + +void FbRenderer::fbdev_draw_32(unsigned char* frame, int force) +{ + memcpy(frame_buffer, frame, 4*fb_vinfo.yres*fb_vinfo.xres); +} + +#else + +/* FIXME evil hack */ + +static void fbdev32(unsigned char * frame) +{ + __asm__ __volatile__( + + " pushl %%esi \n\t" + " pushl %%edi \n\t" + " pushl %%eax \n\t" + " pushl %%ecx \n\t" + + " movl fb_vinfo,%%eax \n\t" // Height + " movl fb_vinfo+4,%%ecx \n\t" // width + " imul %%eax,%%ecx \n\t" // mul + " movl frame_buffer,%%edi \n\t" // fbdev mmap'd buffer + " movl 8(%%ebp), %%esi \n\t" // Imlib2 buffer (frame) + " rep movsl \n\t" // move all longs at a time (4 bytes) + + " popl %%ecx \n\t" + " popl %%eax \n\t" + " popl %%edi \n\t" + " popl %%esi \n\t" + + :/*no output*/:/*no input*/:"memory","cc"); +} + +void FbRenderer::fbdev_draw_32(unsigned char* frame, int force) +{ + fbdev32(frame); +} + +#endif + +//*************************************************************************** +// +//*************************************************************************** + +#ifndef use_asm + +void FbRenderer::fbdev_draw_24(unsigned char* frame, int force) +{ + unsigned int i,a,b,c,x, out_offset = 0, in_offset = 0; + + x = fb_vinfo.xres*4; + + for (i = 0; i < fb_vinfo.yres; ++i) + { + for (a=0, b=0, c=0; a < fb_vinfo.xres; ++a, b+=3, c+=4) + { + frame_buffer[out_offset + b +0] = frame[in_offset + c +0]; + frame_buffer[out_offset + b +1] = frame[in_offset + c +1]; + frame_buffer[out_offset + b +2] = frame[in_offset + c +2]; + } + + out_offset += fb_line_len; + in_offset += x; + } +} + +#else + +/* FIXME evil hack */ + +static void fbdev24(unsigned char* frame) +{ + __asm__ __volatile__( + + " pushl %%esi \n\t" + " pushl %%edi \n\t" + " pushl %%eax \n\t" + " pushl %%ebx \n\t" + " pushl %%ecx \n\t" + " pushl %%edx \n\t" + + " movl fb_vinfo,%%eax \n\t" // fbdev mmap'd buffer + " movl fb_vinfo+4,%%edx \n\t" // fbdev mmap'd buffer + " imul %%eax,%%edx \n\t" // fbdev mmap'd buffer + " movl 8(%%ebp), %%esi \n\t" // Imlib2 buffer (frame) + " movl frame_buffer,%%edi \n\t" // fbdev mmap'd buffer + + " .lop: \n\t" + " leal 3,%%ecx \n\t" // fbdev mmap'd buffer + " rep movsb \n\t" // move 3 bytes at a time + " inc %%esi \n\t" // increment one byte, bypass Alpha + " dec %%edx \n\t" // dec counter + " jnz .lop \n\t" // loop :) + + " popl %%edx \n\t" + " popl %%ecx \n\t" + " popl %%ebx \n\t" + " popl %%eax \n\t" + " popl %%edi \n\t" + " popl %%esi \n\t" + + :/*no output*/:/*no input*/:"memory","cc"); +} + +void FbRenderer::fbdev_draw_24(unsigned char* frame, int force) +{ + fbdev24(frame); +} + +#endif + +//*************************************************************************** +// fbdev draw 16 +//*************************************************************************** + +void FbRenderer::fbdev_draw_16(unsigned char* frame, int force) +{ + static unsigned short* tmp = 0; + static unsigned int size = fb_vinfo.yres * fb_vinfo.xres; + static unsigned short* fb = (unsigned short*)frame_buffer; + + if (!tmp) + tmp = (unsigned short*)calloc(sizeof(unsigned short), size); + + LogDuration ld("FbRenderer::fbdev_draw_16()"); + + unsigned char B, G, R; + unsigned int x, y; + unsigned short v; + unsigned int out_offset = 0, in_offset = 0; + + for (y = 0; y < fb_vinfo.yres; y++) + { + for (x = 0; x < fb_vinfo.xres; x++, out_offset++, in_offset+=4) + { + R = (frame[in_offset + 2] >> 3) & 0x1f; + G = (frame[in_offset + 1] >> 2) & 0x3f; + B = (frame[in_offset + 0] >> 3) & 0x1f; + + v = ((G << 5) | B) | ((R << 3) | (G >> 3)) << 8; + + if (force || tmp[out_offset] != v) + { + tmp[out_offset] = v; + fb[out_offset] = v; + } + } + } +} + +//*************************************************************************** +// Refresh +//*************************************************************************** + +void FbRenderer::refresh(int force) +{ + LogDuration ld("FbRenderer::refresh()"); + + // refresh + + ImlibRenderer::refresh(force); + + // copy to buffer + + imlib_context_set_image(*pImageToDisplay); + + if (GraphTFTSetup.flipOSD) + { + imlib_image_flip_vertical(); + imlib_image_flip_horizontal(); + } + + UINT8* dataptr = (UINT8*)imlib_image_get_data_for_reading_only(); + + tell(4, "copy image with a depth of (%d) to framebuffer", + fb_vinfo.bits_per_pixel); + + switch (fb_vinfo.bits_per_pixel) + { + case 16 : fbdev_draw_16(dataptr, force); break; + case 24 : fbdev_draw_24(dataptr, force); break; + case 32 : fbdev_draw_32(dataptr, force); break; + + default : tell(0, "fbdevout.c: color depth not supported " + "-> %i bits per pixel", fb_vinfo.bits_per_pixel); + } + +#ifdef PVRFB + + struct ivtvfb_ioctl_dma_host_to_ivtv_args prep; + prep.source = frame_buffer; + prep.dest_offset = 0; + prep.count = width * height * 4; + ioctl(fb_dev_fd, IVTVFB_IOCTL_PREP_FRAME, &prep); + +#endif +} + +void FbRenderer::clear() +{ + ImlibRenderer::clear(); +} diff --git a/imlibrenderer/fbrenderer/fbrenderer.h b/imlibrenderer/fbrenderer/fbrenderer.h new file mode 100644 index 0000000..9de636e --- /dev/null +++ b/imlibrenderer/fbrenderer/fbrenderer.h @@ -0,0 +1,65 @@ +/** + * GraphTFT plugin for the Video Disk Recorder + * + * fbrenderer.h - A plugin for the Video Disk Recorder + * + * (c) 2004 Lars Tegeler, Sascha Volkenandt + * + * This code is distributed under the terms and conditions of the + * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details. + * + * $Id: fbrenderer.h,v 1.4 2012/09/27 13:07:12 wendel Exp $ + * + **/ + +//The most part of this Code is from the MMS V.2 Project: + +#ifndef __GTFT_FBRENDERER_HPP +#define __GTFT_FBRENDERER_HPP + +#include <linux/fb.h> + +#include <imlibrenderer.h> + +//*************************************************************************** +// +//*************************************************************************** + +class FbRenderer : public ImlibRenderer +{ + + public: + + FbRenderer(int x, int y, int width, int height, + string cfgPath, int utf, string thmPath); + ~FbRenderer(); + + int init(int lazy); + void deinit(); + + void refresh(int force = no); + void clear(); + + private: + + void fbdev_draw_32(unsigned char* frame, int force); + void fbdev_draw_24(unsigned char* frame, int force); + void fbdev_draw_16(unsigned char* frame, int force); + + // data + + char* fb_dev_name; + int initialized; + Imlib_Image _resized; + + int fb_dev_fd; + int fb_type; + size_t fb_size; + int fb_line_len; + int y_offset; + + struct fb_var_screeninfo fb_orig_vinfo; + struct fb_fix_screeninfo fb_finfo; +}; + +#endif // __GTFT_FBRENDERER_H diff --git a/imlibrenderer/imlib.cc b/imlibrenderer/imlib.cc new file mode 100644 index 0000000..15148a4 --- /dev/null +++ b/imlibrenderer/imlib.cc @@ -0,0 +1,81 @@ +// +// Test +// + +#include <stdlib.h> +#include <stdio.h> + +#include <Imlib2.h> + +int text(int x, int y, const char* text, const char* fontName, int size); +Imlib_Image theImage; + +//----------------------------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------------------------- + +int main(int argc, char** argv) +{ + if (argc != 4) + { + printf("Usage: imlib <text> <font-with-path> <fontsize>\n"); + return -1; + } + + theImage = imlib_create_image(600, 100); + imlib_context_set_image(theImage); + + text(10, 10, argv[1], argv[2], atoi(argv[3])); + + text(10, 50, "Test1 \n Test2", argv[2], atoi(argv[3])); + + imlib_image_set_format("png"); + imlib_save_image("test.png"); + + imlib_free_image(); + + return 0; +} + +//----------------------------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------------------------- + +int text(int x, int y, const char* text, const char* fontName, int size) +{ + char* font; + Imlib_Font theFont; + int height, width; + + if (!text || !fontName || !size) + return -1; + + asprintf(&font, "%s/%d", fontName, size); + + if (!(theFont = imlib_load_font(font))) + { + printf("Loading font '%s' failed\n", font); + free(font); + + return -1; + } + + imlib_context_set_font(theFont); + imlib_context_set_image(theImage); + imlib_context_set_color(150, 150, 150, 255); + + imlib_get_text_size(text, &width, &height); + + printf("width (%d); height (%d)\n", width, height); + printf("Ascent=%d/%d Descent=%d/%d\n", imlib_get_font_ascent(), + imlib_get_maximum_font_ascent(), imlib_get_font_descent(), + imlib_get_maximum_font_descent()); + + imlib_text_draw(x, y, text); + + imlib_free_font(); + free(font); + + return 0; +} + diff --git a/imlibrenderer/imlibrenderer.c b/imlibrenderer/imlibrenderer.c new file mode 100644 index 0000000..7720594 --- /dev/null +++ b/imlibrenderer/imlibrenderer.c @@ -0,0 +1,906 @@ +/** + * GraphTFT plugin for the Video Disk Recorder + * + * imlibrenderer.c - A plugin for the Video Disk Recorder + * + * (c) 2004 Lars Tegeler, Sascha Volkenandt + * (c) 2006-2013 Jörg Wendel + * + * This code is distributed under the terms and conditions of the + * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details. + * + * $Id: imlibrenderer.c,v 1.10 2012/09/27 13:07:11 wendel Exp $ + * + **/ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <locale.h> + +#include <string> +#include <vector> +#include <sstream> + +#include <string> +#include <utility> +#include <iostream> + +#include <jpeglib.h> + +#include "imlibrenderer.h" +#include "theme.h" +#include "common.h" + +using std::string; +using std::cout; +using std::endl; + +//*************************************************************************** +// Object +//*************************************************************************** + +ImlibRenderer::ImlibRenderer(int x, int y, int width, int height, + string cfgPath, int utf, string thmPath) + : Renderer(x, y, width, height, cfgPath, utf, thmPath) +{ +// Imlib_Context ctx = imlib_context_new(); +// imlib_context_push(ctx); + + _render_image = 0; + _cur_image = 0; + pImageToDisplay = 0; +} + +ImlibRenderer::~ImlibRenderer() +{ + deinit(); +} + +//*************************************************************************** +// init / deinit +//*************************************************************************** + +int ImlibRenderer::init(int lazy) +{ + if (_render_image || _cur_image) + deinit(); + + // new image + + imlib_set_color_usage(256); + + _cur_image = imlib_create_image(themeWidth, themeHeight); + _render_image = imlib_create_image(dspWidth, dspHeight); + imlib_context_set_image(_cur_image); + + // cache + + imlib_set_cache_size(16 * 1024 * 1024); + imlib_set_font_cache_size(4 * 1024 * 1024); + + return success; +} + +void ImlibRenderer::deinit() +{ + pImageToDisplay = 0; + + if (_render_image) + { + imlib_context_set_image(_render_image); + imlib_free_image(); + _render_image = 0; + } + + if (_cur_image) + { + imlib_context_set_image(_cur_image); + imlib_free_image(); + _cur_image = 0; + } +} + +//*************************************************************************** +// +//*************************************************************************** + +void ImlibRenderer::flushCache() +{ + // flush the font cache + + imlib_flush_font_cache(); + + // and the image cache + + imlib_set_cache_size(0); + imlib_set_cache_size(16 * 1024 * 1024); +} + +//*************************************************************************** +// Set Font Path +//*************************************************************************** + +void ImlibRenderer::setFontPath(string fntPath) +{ + int e, s; + e = s = 0; + string p; + int count; + char* path; + const char** list; + + // first clear imlibs font path + + list = (const char**)imlib_list_font_path(&count); + + for (int i = 0; i < count; i++) + { + tell(3, "Info: Removing '%s' from font path", list[i]); + imlib_remove_path_from_font_path(list[i]); + } + + imlib_list_font_path(&count); + + // add all configured font paths + + tell(0, "Info: Font path configured to '%s'", fntPath.c_str()); + + do + { + e = fntPath.find(':', s); + p = fntPath.substr(s, e == na ? fntPath.length()-s : e-s); + + if (p[0] != '/') + { + // make path relative to the themes directory + + asprintf(&path, "%s/themes/%s/%s", + confPath.c_str(), themePath.c_str(), p.c_str()); + } + else + { + asprintf(&path, "%s", p.c_str()); + } + + tell(0, "Info: Adding font path '%s'", path); + + if (*path && fileExists(path)) + imlib_add_path_to_font_path(path); + else + tell(0, "Info: Font path '%s' not found, ignoring", path); + + free(path); + s = e+1; + + } while (s > 0); + + + // at least add the default path + + asprintf(&path, "%s/graphtftng/fonts/", confPath.c_str()); + tell(0, "Info: Adding font path '%s'", path); + imlib_add_path_to_font_path(path); + free(path); +} + +//*************************************************************************** +// Refresh +//*************************************************************************** + +void ImlibRenderer::refresh(int force) +{ + LogDuration ld("ImlibRenderer::refresh()"); + + if (!_cur_image) + return ; + + // resize only if needed ! + + if (xOffset || yOffset || xBorder || yBorder + || themeWidth != dspWidth || themeHeight != dspHeight) + { + tell(2, "scale image from (%d/%d) to (%d/%d)", + themeWidth, themeHeight, + dspWidth - xOffset - (2 * xBorder), + dspHeight - yOffset - (2 * yBorder)); + + imlib_context_set_image(_render_image); + + imlib_blend_image_onto_image(_cur_image, 0, + 0, 0, themeWidth, themeHeight, + xOffset + xBorder, yOffset + yBorder, + dspWidth - xOffset - (2 * xBorder), + dspHeight - yOffset - (2 * yBorder)); + + pImageToDisplay = &_render_image; + } + else + { + pImageToDisplay = &_cur_image; + } +} + +void ImlibRenderer::clear() +{ + if (!_cur_image) + return ; + + // clear the current image + + imlib_context_set_image(_cur_image); + imlib_free_image(); + _cur_image = imlib_create_image(themeWidth, themeHeight); + imlib_context_set_image(_cur_image); +} + +//*************************************************************************** +// Image +//*************************************************************************** + +void ImlibRenderer::image(const char* fname, + int x, int y, + int width, int height, + bool fit, bool aspectRatio, + int orientation) +{ + Imlib_Image new_image; + int imgWidth = 0; + int imgHeight = 0; + std::ostringstream path; + int areaWidth = width; + int areaHeight = height; + Imlib_Load_Error err; + int rotate = na; + int hflip = no; + + if (!_cur_image) + return ; + + if (x == na) x = 0; + if (y == na) y = 0; + + if (fname[0] == '/') + path << fname; + else + path << confPath << "/themes/" << themePath << "/" << fname; + + if (!fileExists(path.str().c_str())) + { + tell(0, "Image '%s' not found", path.str().c_str()); + return ; + } + + new_image = imlib_load_image_with_error_return(path.str().c_str(), &err); + + if (!new_image) + { + tell(0, "The image '%s' could not be loaded, error was '%s'", + path.str().c_str(), strerror(err)); + + return ; + } + + imlib_context_set_image(new_image); + + switch (orientation) + { + case 0: rotate = na; hflip = no; break; // 0: unknon + case 1: rotate = na; hflip = no; break; // 1: okay + case 2: rotate = na; hflip = yes; break; // 2: gespiegelt (not implemented yet) + case 3: rotate = 2; hflip = no; break; // 3: auf dem Kopf + case 4: rotate = 2; hflip = yes; break; // 4: auf dem Kopf (und gespiegelt -> not implemented yet) + case 5: rotate = 1; hflip = yes; break; // 5: 90° links (und gespiegelt -> not implemented yet) + case 6: rotate = 1; hflip = no; break; // 6: 90° links + case 7: rotate = 3; hflip = yes; break; // 7: 90° rechts (und gespiegelt -> not implemented yet) + case 8: rotate = 3; hflip = no; break; // 8: 90° rechts + } + + if (rotate != na) + imlib_image_orientate(rotate); + + if (hflip) + imlib_image_flip_horizontal(); + + imgWidth = imlib_image_get_width(); + imgHeight = imlib_image_get_height(); + + if (strstr(fname, "chg_")) + imlib_image_set_changes_on_disk(); + + imlib_context_set_image(_cur_image); + + if (fit) + { + if (aspectRatio) + { + double ratio = (double)imgWidth / (double)imgHeight; + + if ((double)width/(double)imgWidth < (double)height/(double)imgHeight) + { + height = (int)((double)width / ratio); + y += (areaHeight-height) / 2; + } + else + { + width = (int)((double)height * ratio); + x += (areaWidth-width) / 2; + } + } + + imlib_blend_image_onto_image(new_image, 0, 0, 0, + imgWidth, imgHeight, x, y, + width, height); + } + else + { + imlib_blend_image_onto_image(new_image, 0, 0, 0, + imgWidth, imgHeight, x, y, + imgWidth, imgHeight); + } + + imlib_context_set_image(new_image); + imlib_free_image(); + imlib_context_set_image(_cur_image); +} + +//*************************************************************************** +// Image Part +//*************************************************************************** + +void ImlibRenderer::imagePart(const char* fname, int x, int y, + int width, int height) +{ + Imlib_Image new_image; + std::ostringstream path; + Imlib_Load_Error err; + + if (!_cur_image) + return ; + + if (x == na) x = 0; + if (y == na) y = 0; + + if (fname[0] == '/') + path << fname; + else + path << confPath << "/themes/" << themePath << "/" << fname; + + if (!fileExists(path.str().c_str())) + { + tell(0, "Image '%s' not found", path.str().c_str()); + return ; + } + + // new_image = imlib_load_image(path.str().c_str()); + + new_image = imlib_load_image_with_error_return(path.str().c_str(), &err); + + if (!new_image) + { + tell(0, "The image '%s' could not be loaded, error was '%s'", + path.str().c_str(), strerror(err)); + + return ; + } + + imlib_context_set_image(_cur_image); + + imlib_blend_image_onto_image(new_image, 0, + x, y, width, height, + x, y, width, height); + + imlib_context_set_image(new_image); + imlib_free_image(); + imlib_context_set_image(_cur_image); +} + +//*************************************************************************** +// Text Width Of +//*************************************************************************** + +int ImlibRenderer::textWidthOf(const char* text, const char* fontName, + int fontSize, int& height) +{ + Imlib_Font font; + int width = 20; + char* fontNameSize = 0; + + fontSize = fontSize ? fontSize : 24; + height = fontSize * (5/3); + + if (!_cur_image) + return 0; + + if (!fontName || !text || !strlen(text)) + return 0; + + asprintf(&fontNameSize, "%s/%d", fontName, fontSize); + font = imlib_load_font(fontNameSize); + free(fontNameSize); + + if (font) + { + imlib_context_set_font(font); + imlib_context_set_image(_cur_image); + imlib_get_text_size(text, &width, &height); + imlib_free_font(); + } + else + tell(1, "The font '%s' could not be loaded.", fontName); + + return width; +} + +//*************************************************************************** +// Char Width Of +//*************************************************************************** + +int ImlibRenderer::charWidthOf(const char* fontName, int fontSize) +{ + Imlib_Font font; + int width = 20; + int height = 20; + char* fontNameSize = 0; + + if (!_cur_image) + return 30; + + const char* text = "We need here something like a " + "representive sentence WITH SOME UPPER CASE LETTERS"; + + if (!fontName) + { + imlib_get_text_size(text, &width, &height); + return width / strlen(text); + } + + asprintf(&fontNameSize, "%s/%d", fontName, fontSize); + font = imlib_load_font(fontNameSize); + free(fontNameSize); + + if (font) + { + imlib_context_set_font(font); + imlib_context_set_image(_cur_image); + imlib_get_text_size(text, &width, &height); + imlib_free_font(); + + width /= clen(text); + } + else + tell(1, "The font '%s' could not be loaded.", fontName); + + return width; +} + +//*************************************************************************** +// Line Count +//*************************************************************************** + +int ImlibRenderer::lineCount(const char* text, const char* font_name, + int size, int width) +{ + int count; + int lineHeight, textWidth, dummy; + string line; + string tmp = text; + Imlib_Font font; + int currentWidth; + int blankWidth, dotsWidth; + string::size_type pos = 0; + char* fontNameSize = 0; + + if (!_cur_image) + return 1; + + // load font + + asprintf(&fontNameSize, "%s/%d", font_name, size); + font = imlib_load_font(fontNameSize); + free(fontNameSize); + + if (width <= 0) + width = themeWidth; // ;) + + imlib_context_set_font(font); + imlib_context_set_image(_cur_image); + + imlib_get_text_size(tmp.c_str(), &textWidth, &lineHeight); + imlib_get_text_size(" ", &blankWidth, &dummy); + imlib_get_text_size("...", &dotsWidth, &dummy); + + for (count = 1; pos < tmp.length(); count++) + { + string token; + line = ""; + + currentWidth = 0; + + // fill next line ... + + while (pos < tmp.length()) + { + int tokenWidth; + int lf = no; + + string::size_type pA = tmp.find_first_of(" \n", pos); + + if (pA != string::npos && tmp[pA] == '\n') + { + lf = yes; + tmp[pA] = ' '; + } + + token = tmp.substr(pos, pA - pos); + + if (token == "") + { + line += " "; + pos++; + + if (lf) + break; + else + continue; + } + + imlib_get_text_size(token.c_str(), &tokenWidth, &dummy); + + if (currentWidth + (currentWidth ? blankWidth : 0) + tokenWidth > width) + { + // passt nicht mehr ganz rein + + if (!line.length()) + { + // alleinstehendes Wort -> noch zur Zeile rechnen + + pos += token.length(); + } + + break; + } + else + { + // passt noch rein + + line = line + token; + imlib_get_text_size(line.c_str(), ¤tWidth, &dummy); + pos += token.length(); + + if (lf) + break; + } + } + } + + imlib_free_font(); + + return count-1; +} + +//*************************************************************************** +// Draw Text +//*************************************************************************** + +int ImlibRenderer::text(const char* text, + const char* font_name, int size, + int align, int x, int y, + p_rgba rgba, // int r, int g, int b, + int width, int height, + int lines, int dots, int skipLines) +{ + string line; + string tmp; + int lineHeight, textWidth, dummy; + int blankWidth; + int dotsWidth; + string::size_type pos; + int currentWidth; + Imlib_Font font; + char* fontNameSize = 0; + + if (x == na) x = 0; + if (y == na) y = 0; + + if (!_cur_image) + return 0; + + if (Str::isEmpty(text)) + return 0; + + if (utf8) + { + const int maxBuf = 10000; + char out[maxBuf+TB]; + + if (toUTF8(out, maxBuf, text) == success) + tmp = out; + else + tmp = text; + } + else + tmp = text; + + // load font + + asprintf(&fontNameSize, "%s/%d", font_name, size); + font = imlib_load_font(fontNameSize); + free(fontNameSize); + + if (width <= 0) + width = themeWidth; // ;) + + imlib_context_set_font(font); + imlib_context_set_image(_cur_image); + imlib_context_set_color(rgba[rgbR], rgba[rgbG], rgba[rgbB], 255); + + imlib_get_text_size(tmp.c_str(), &textWidth, &lineHeight); + imlib_get_text_size(" ", &blankWidth, &dummy); + imlib_get_text_size("...", &dotsWidth, &dummy); + + if (!lines) + lines = height / lineHeight; + + if (lines <= 0) + lines = 1; + + pos = 0; + int tl = 1; + + for (int l = 1; l <= lines && pos < tmp.length(); l++, tl++) + { + int yPos = y + lineHeight * (l-1); + string token; + line = ""; + + currentWidth = 0; + + while (pos < tmp.length()) + { + int tokenWidth; + int lf = no; + + string::size_type pA = tmp.find_first_of(" \n", pos); + + if (pA != string::npos && tmp[pA] == '\n') + { + lf = yes; + tmp[pA] = ' '; + } + + token = tmp.substr(pos, pA - pos); + + if (token == "") + { + line += " "; + pos++; + + if (lf) + break; + else + continue; + } + + imlib_get_text_size(token.c_str(), &tokenWidth, &dummy); + + if (currentWidth + (currentWidth ? blankWidth : 0) + tokenWidth > width) + { + // passt nicht mehr ganz rein + + if (!line.length() || l == lines) + { + // alleinstehendes Wort oder letzte Zeile, + // daher Abgeschnitten anzeigen + + unsigned int i = 0; + + while (currentWidth + (dots ? dotsWidth : 0) < width && i <= token.length()) + { + line += token.substr(i++, 1); + imlib_get_text_size(line.c_str(), ¤tWidth, &dummy); + } + + // einer zuviel ! + + line = line.substr(0, line.length()-1); + + if (dots) + { + if (currentWidth + dotsWidth > width) + line = line.substr(0, line.length()-1); + + line += "..."; + } + + pos += token.length(); + } + + break; + } + else + { + // passt noch rein + + // currentWidth += blankWidth + tokenWidth; // nicht genau + // -> so ist's besser + + line = line + token; + imlib_get_text_size(line.c_str(), ¤tWidth, &dummy); + pos += token.length(); + + if (lf) + break; + } + } + + if (skipLines && tl <= skipLines) + { + l--; + continue; + } + + if (align != 0) + imlib_get_text_size(line.c_str(), &textWidth, &lineHeight); + + if (align == 0) // left + imlib_text_draw(x, yPos, line.c_str()); + else if (align == 1) // center + imlib_text_draw(x + (width - textWidth) / 2, yPos, line.c_str()); + else // right + imlib_text_draw(x + width - textWidth -2, yPos, line.c_str()); + } + + imlib_free_font(); + + return 0; +} + +//*************************************************************************** +// Draw Rectangle +//*************************************************************************** + +void ImlibRenderer::rectangle(int x, int y, + int width, int height, + p_rgba rgba) // int r, int g, int b, int alpha) +{ + if (x == na) x = 0; + if (y == na) y = 0; + + if (!_cur_image) + return ; + + imlib_context_set_image(_cur_image); + imlib_context_set_color(rgba[rgbR], rgba[rgbG], rgba[rgbB], rgba[rgbA]); + imlib_image_fill_rectangle(x, y, width, height); +} + +//*************************************************************************** +// Dump Image To File +//*************************************************************************** + +void ImlibRenderer::dumpImage2File(const char* fname, int dumpWidth, + int dumpHeight, const char* aPath) +{ + std::ostringstream path; + const char* format = 0; + + if (!_cur_image) + return ; + + if (aPath && *aPath) + path << aPath; + else if (*fname != '.' && *fname != '/') + path << "/tmp"; + + if (strchr(fname, '.')) + format = strchr(fname, '.') + 1; + + // check if local directory structure exist, else create it. + + if (!fileExists(path.str().c_str())) + mkdir(path.str().c_str(), 0777); + + // get width and heigt + + imlib_context_set_image(_cur_image); + int width = imlib_image_get_width(); + int height = imlib_image_get_height(); + + // create image + + Imlib_Image new_image = imlib_create_image(dumpWidth, dumpHeight); + + imlib_context_set_image(new_image); + imlib_blend_image_onto_image(_cur_image, 0, + 0, 0, width, height, + 0, 0, dumpWidth, dumpHeight); + + tell(1, "DUMP: From (%d/%d) to (%d/%d) '%s'", + width, height, dumpWidth, dumpHeight, fname); + + // save the image + + imlib_image_set_format(format && *format ? format : "png"); + path << "/" << fname; + imlib_save_image(path.str().c_str()); + + imlib_free_image(); + imlib_context_set_image(_cur_image); +} + +//*************************************************************************** +// To JPEG +//*************************************************************************** + +#ifndef WITH_TCPCOM + +long ImlibRenderer::toJpeg(unsigned char*& buffer, int quality) +{ + return 0; +} + +#else + +long ImlibRenderer::toJpeg(unsigned char*& buffer, int quality) +{ + struct jpeg_compress_struct cinfo = { 0 }; + struct jpeg_error_mgr jerr; + DATA32* ptr; + DATA8* buf; + unsigned long size; + + if (!_cur_image) + return 0; + + buffer = 0; + size = 0; + + cinfo.err = jpeg_std_error(&jerr); + + jpeg_create_compress(&cinfo); + jpeg_mem_dest(&cinfo, &buffer, &size); + + cinfo.image_width = imlib_image_get_width(); + cinfo.image_height = imlib_image_get_height(); + cinfo.input_components = 3; + cinfo.in_color_space = JCS_RGB; + + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, quality, TRUE); + jpeg_start_compress(&cinfo, TRUE); + + // get data pointer + + if (!(ptr = imlib_image_get_data_for_reading_only())) + return 0; + + // allocate a small buffer to convert image data */ + + buf = (DATA8*)malloc(imlib_image_get_width() * 3 * sizeof(DATA8)); + + while (cinfo.next_scanline < cinfo.image_height) + { + // convert scanline from ARGB to RGB packed + + for (int j = 0, i = 0; i < imlib_image_get_width(); i++) + { + buf[j++] = ((*ptr) >> 16) & 0xff; + buf[j++] = ((*ptr) >> 8) & 0xff; + buf[j++] = ((*ptr)) & 0xff; + + ptr++; + } + + // write scanline + + jpeg_write_scanlines(&cinfo, (JSAMPROW*)(&buf), 1); + } + + free(buf); + jpeg_finish_compress(&cinfo); + jpeg_destroy_compress(&cinfo); + + return size; +} +#endif diff --git a/imlibrenderer/imlibrenderer.h b/imlibrenderer/imlibrenderer.h new file mode 100644 index 0000000..5ef79ab --- /dev/null +++ b/imlibrenderer/imlibrenderer.h @@ -0,0 +1,76 @@ +/** + * GraphTFT plugin for the Video Disk Recorder + * + * imlibrenderer.h + * + * (c) 2004 Lars Tegeler, Sascha Volkenandt + * (c) 2006-2014 Jörg Wendel + * + * This code is distributed under the terms and conditions of the + * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details. + * + **/ + +#ifndef __GTFT_IMLIBRENDERER_HPP +#define __GTFT_IMLIBRENDERER_HPP + +#include "renderer.h" + +#ifndef WITH_X +# define X_DISPLAY_MISSING +#endif + +#include <Imlib2.h> + +#undef Status + +//*************************************************************************** +// Class ImlibRenderer +//*************************************************************************** + +class ImlibRenderer : public Renderer +{ + public: + + ImlibRenderer(int x, int y, int width, int height, string cfgPath, int utf, string thmPath); + virtual ~ImlibRenderer(); + + int init(int lazy); + void deinit(); + void flushCache(); + void setFontPath(string fntPath); + + long toJpeg(unsigned char*& buffer, int quality); + + virtual void refresh(int force = no); + virtual void clear(); + + int textWidthOf(const char* text, const char* fontName, int fontSize, int& height); + int charWidthOf(const char* fontName = 0, int fontSize = 0); + + void image(const char* fname, int x, int y, + int coverwidth, int coverheight, + bool fit = no, bool aspectRatio = no, + int orientation = 1); + void imagePart(const char* fname, int x, int y, int width, int height); + + int text(const char* text, const char* font_name, int size, int align, + int x, int y, + p_rgba rgba, // int r, int g, int b, + int width, int height,int lines, int dots = 0, int skipLines = 0); + + int lineCount(const char* text, const char* font_name, int size, int width); + + void rectangle(int x, int y, int width, int height, p_rgba rgba); + + void dumpImage2File(const char* fname, int dumpWidth, int dumpHeight, const char* aPath = 0); + + protected: + + Imlib_Image _cur_image; // the image you're working on + Imlib_Image _render_image; // the image buffer for scaling + Imlib_Image* pImageToDisplay; // pointer to the image for displaying +}; + +//*************************************************************************** +#endif // __GTFT_IMLIBRENDERER_H diff --git a/imlibrenderer/xrenderer/xrenderer.c b/imlibrenderer/xrenderer/xrenderer.c new file mode 100644 index 0000000..7dde32b --- /dev/null +++ b/imlibrenderer/xrenderer/xrenderer.c @@ -0,0 +1,296 @@ +//*************************************************************************** +// Group VDR/GraphTFT +// File xrenderer.c +// Date 16.02.14 - Jörg Wendel +// This code is distributed under the terms and conditions of the +// GNU GENERAL PUBLIC LICENSE. See the file COPYING for details. +//-------------------------------------------------------------------------- +// Class XRenderer +//*************************************************************************** + +#include <stdio.h> + +#include <X11/Xutil.h> +#include <X11/cursorfont.h> +#define XK_MISCELLANY +#include <X11/keysymdef.h> + +#include <common.h> +#include "xrenderer.h" + +//*************************************************************************** +// Object +//*************************************************************************** + +XRenderer::XRenderer(int x, int y, int width, int height, + string cfgPath, int utf, string thmPath) + : ImlibRenderer(x, y, width, height, cfgPath, utf, thmPath) +{ + disp = 0; + win = 0; + pix = 0; + screen = 0; + initialized = no; +} + +XRenderer::~XRenderer() +{ + deinit(); +} + +void XRenderer::setDisplaySize(int width, int height) +{ + if (dspWidth != width || dspHeight != height) + { + cMutexLock lock(&mutex); + + tell(0, "Changing display size to %dx%d", width, height); + deinit(); + dspWidth = width; + dspHeight = height; + init(no); + } +} + +//*************************************************************************** +// Init +//*************************************************************************** + +int XRenderer::init(int lazy) +{ + const char* appName = "graphtft-fe"; + + Visual* vis; + Colormap cm; + int depth; + XClassHint* classHint; + + cMutexLock lock(&mutex); + + ImlibRenderer::init(lazy); + + if (Str::isEmpty(devname)) + { + tell(0, "Can't open display 'null' continue in detached mode!"); + return fail; + } + + // init X + + if (!(disp = XOpenDisplay(devname))) + { + tell(0, "Can't open display '%s' continue in detached mode", devname); + return lazy ? success : fail; + } + + if (!XInitThreads()) + tell(0, "Can't initialize X11 thread support"); + + // init display + + screen = DefaultScreen(disp); + vis = DefaultVisual(disp, screen); + depth = DefaultDepth(disp, screen); + cm = DefaultColormap(disp, screen); + + // create simple window + + win = XCreateSimpleWindow(disp, DefaultRootWindow(disp), + 0, depth, dspWidth, dspHeight, 0, 0, 0); + + XSetStandardProperties(disp, win, appName, appName, None, 0, 0, 0); + XStoreName(disp, win, appName); + + /* set the name and class hints for the window manager to use */ + + classHint = XAllocClassHint(); + classHint->res_name = (char*)appName; + classHint->res_class = (char*)appName; + XSetClassHint(disp, win, classHint); + XFree(classHint); + + XSelectInput(disp, win, + ButtonPressMask | + ButtonReleaseMask | + PointerMotionMask | + KeyPressMask | + ClientMessage | + SubstructureNotifyMask | + ExposureMask); // events to receive + + XMapWindow(disp, win); // show + XFlush(disp); + + Screen* scn = DefaultScreenOfDisplay(disp); + pix = XCreatePixmap(disp, win, dspWidth, dspHeight, DefaultDepthOfScreen(scn)); + + imlib_context_set_dither(1); // dither for depths < 24bpp + imlib_context_set_display(disp); // set the display + imlib_context_set_visual(vis); // visual, + imlib_context_set_colormap(cm); // colormap + imlib_context_set_drawable(pix); // and drawable we are using + +// { +// XWindowAttributes windowAttributes; +// XGetWindowAttributes(disp, win, &windowAttributes); +// int w = windowAttributes.width; +// int h = windowAttributes.height; + +// tell(0, "Created window with (%d/%d) got (%d/%d)", dspWidth, dspHeight, w, h); +// } + + tell(0, "Connection to '%s' established", devname); + initialized = yes; + + return success; +} + +//*************************************************************************** +// Deinit +//*************************************************************************** + +void XRenderer::deinit() +{ + cMutexLock lock(&mutex); + + ImlibRenderer::deinit(); + + if (initialized) + { + imlib_context_disconnect_display(); + + if (win) XDestroyWindow(disp, win); + if (pix) XFreePixmap(disp, pix); + + XFlush(disp); + + if (XCloseDisplay(disp)) + tell(0, "Error closing display"); + + disp = 0; + win = 0; + pix = 0; + screen = 0; + initialized = no; + } + + tell(0, "Connection to '%s' closed, now detached", devname); +} + +//*************************************************************************** +// attach / detach +//*************************************************************************** + +int XRenderer::attach(const char* disp) +{ + if (initialized) + { + tell(0, "Already attached, trying detach first"); + detach(); + } + + if (!Str::isEmpty(disp)) + setDevName(disp); + + tell(0, "Try to attach to '%s'", devname); + + return init(no); +} + +int XRenderer::detach() +{ + if (!initialized) + { + tell(0, "Already detached"); + return done; + } + + tell(0, "Detach from '%s'", devname); + deinit(); + + return success; +} + +//*************************************************************************** +// X Pending +//*************************************************************************** + +int XRenderer::xPending() +{ + cMutexLock lock(&mutex); + XEvent ev; + + if (!initialized) + return success; + + while (XPending(disp)) + XNextEvent(disp, &ev); + + return success; +} + +//*************************************************************************** +// Refresh +//*************************************************************************** + +void XRenderer::refresh(int force) +{ + cMutexLock lock(&mutex); + + if (!force || !initialized) // don't need 'total' refresh every time since we refresh the areas + return; + + tell(2, "refresh all"); + + refreshPixmap(); + + XClearWindow(disp, win); +} + +void XRenderer::refreshArea(int x, int y, int width, int height) +{ + cMutexLock lock(&mutex); + + if (!initialized) + return ; + + refreshPixmap(); + + // scale coordinates from theme to display size + + double xScale = (double)dspWidth / (double)themeWidth; + double yScale = (double)dspHeight / (double)themeHeight; + + int xDsp = x * xScale; + int yDsp = y * yScale; + int widthDsp = width * xScale; + int heightDsp = height * yScale; + + tell(3, "Refresh area at %d/%d (%d/%d); scaled to %d/%d (%d/%d); scale %.2f/%.2f; dspSize (%d/%d)", + x, y, width, height, xDsp, yDsp, widthDsp, heightDsp, + xScale, yScale, dspWidth, dspHeight); + + XClearArea(disp, win, xDsp, yDsp, widthDsp, heightDsp, false); +} + +void XRenderer::refreshPixmap() +{ + // XWindowAttributes windowAttributes; + // XGetWindowAttributes(disp, win, &windowAttributes); + // int width = windowAttributes.width; + // int height = windowAttributes.height; + + imlib_context_set_image(_cur_image); + imlib_render_image_on_drawable_at_size(0, 0, dspWidth, dspHeight); + + XSetWindowBackgroundPixmap(disp, win, pix); +} + +void XRenderer::clear() +{ + if (!initialized) + return ; + + cMutexLock lock(&mutex); + ImlibRenderer::clear(); +} diff --git a/imlibrenderer/xrenderer/xrenderer.h b/imlibrenderer/xrenderer/xrenderer.h new file mode 100644 index 0000000..1add4d1 --- /dev/null +++ b/imlibrenderer/xrenderer/xrenderer.h @@ -0,0 +1,54 @@ +//*************************************************************************** +// Group VDR/GraphTFT +// File xrenderer.h +// Date 09.11.14 - Jörg Wendel +// This code is distributed under the terms and conditions of the +// GNU GENERAL PUBLIC LICENSE. See the file COPYING for details. +//-------------------------------------------------------------------------- +// Class XRenderer +//*************************************************************************** + +#ifndef __DXRENDERER_H__ +#define __DXRENDERER_H__ + +#include <X11/Xlib.h> + +#include <vdr/thread.h> +#include "imlibrenderer.h" + +//*************************************************************************** +// Class X Renderer +//*************************************************************************** + +class XRenderer : public ImlibRenderer +{ + public: + + XRenderer(int x, int y, int width, int height, string cfgPath, int utf, string thmPath); + ~XRenderer(); + + void setDisplaySize(int width, int height); + int init(int lazy); + void deinit(); + int xPending(); + void refresh(int force = no); + void refreshArea(int x, int y, int width, int height); + void clear(); + + virtual int attach(const char* disp = 0); + virtual int detach(); + + protected: + + void refreshPixmap(); + + Window win; + Display* disp; + int screen; + Pixmap pix; + cMutex mutex; + int initialized; +}; + +//*************************************************************************** +#endif // __DXRENDERER_H__ |