summaryrefslogtreecommitdiff
path: root/imlibrenderer
diff options
context:
space:
mode:
Diffstat (limited to 'imlibrenderer')
-rw-r--r--imlibrenderer/Makefile5
-rw-r--r--imlibrenderer/dmyrenderer/dmyrenderer.h28
-rw-r--r--imlibrenderer/fbrenderer/fbrenderer.c375
-rw-r--r--imlibrenderer/fbrenderer/fbrenderer.h65
-rw-r--r--imlibrenderer/imlib.cc81
-rw-r--r--imlibrenderer/imlibrenderer.c906
-rw-r--r--imlibrenderer/imlibrenderer.h76
-rw-r--r--imlibrenderer/xrenderer/xrenderer.c296
-rw-r--r--imlibrenderer/xrenderer/xrenderer.h54
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(), &currentWidth, &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(), &currentWidth, &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(), &currentWidth, &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__