aboutsummaryrefslogtreecommitdiffstats
path: root/w3mimg
diff options
context:
space:
mode:
authorIto Hiroyuki <ZXB01226@nifty.com>2010-12-21 10:13:55 +0000
committerIto Hiroyuki <ZXB01226@nifty.com>2010-12-21 10:13:55 +0000
commit40feb310a3399b674b4f8924465cee1ea441ffde (patch)
tree2df2f0c81b76925e8fbf681848cdd0d762e54d72 /w3mimg
parentadd documents about some options for w3mimgdisplay. (diff)
downloadw3m-40feb310a3399b674b4f8924465cee1ea441ffde.tar.gz
w3m-40feb310a3399b674b4f8924465cee1ea441ffde.zip
w3mimgdisplay supports Windows console (http://www.j10n.org/files/w3m-cvs-1.1040-misc.patch).
Diffstat (limited to '')
-rw-r--r--w3mimg/Makefile.in11
-rw-r--r--w3mimg/w3mimg.c6
-rw-r--r--w3mimg/w3mimg.h17
-rw-r--r--w3mimg/win/Makefile.in31
-rw-r--r--w3mimg/win/win_w3mimg.cpp1063
-rw-r--r--w3mimgdisplay.c4
6 files changed, 1124 insertions, 8 deletions
diff --git a/w3mimg/Makefile.in b/w3mimg/Makefile.in
index a197352..dfc550c 100644
--- a/w3mimg/Makefile.in
+++ b/w3mimg/Makefile.in
@@ -11,10 +11,11 @@ AR=ar
RANLIB=@RANLIB@
RM=rm
-IMGCFLAGS=@IMGX11CFLAGS@ @IMGFBCFLAGS@
+SUBDIRS=fb x11 win
+IMGCFLAGS=@IMGX11CFLAGS@ @IMGFBCFLAGS@ @IMGWINCFLAGS@
IMGOBJS=@IMGOBJS@
-.PHONY: fb x11
+.PHONY: $(SUBDIRS)
all: @IMGTARGETS@ w3mimg.a
w3mimg.a: $(IMGOBJS)
@@ -24,18 +25,18 @@ w3mimg.a: $(IMGOBJS)
w3mimg.o: w3mimg.c
$(CC) $(CFLAGS) -c $<
-fb x11:
+$(SUBDIRS):
cd $@ && $(MAKE) CC="$(CC)" OPTS="$(OPTS)"
clean:
@-$(RM) -f *.o
- @for dir in fb x11; do \
+ @for dir in $(SUBDIRS); do \
(cd $$dir && $(MAKE) clean RM=$(RM)); \
done
-$(RM) -f w3mimg.a
distclean: clean
- for subdir in fb x11; \
+ for subdir in $(SUBDIRS); \
do \
(cd $$subdir && $(MAKE) distclean); \
done
diff --git a/w3mimg/w3mimg.c b/w3mimg/w3mimg.c
index 144a2d9..46b5cac 100644
--- a/w3mimg/w3mimg.c
+++ b/w3mimg/w3mimg.c
@@ -1,4 +1,4 @@
-/* $Id: w3mimg.c,v 1.5 2002/11/06 03:50:49 ukai Exp $ */
+/* $Id: w3mimg.c,v 1.6 2010/12/21 10:13:55 htrb Exp $ */
#include <stdio.h>
#include <stdlib.h>
@@ -14,6 +14,10 @@ w3mimg_open()
uid_t runner_uid = getuid();
uid_t owner_uid = geteuid();
#endif
+#ifdef USE_W3MIMG_WIN
+ if (w_op == NULL)
+ w_op = w3mimg_winopen();
+#endif
#ifdef USE_W3MIMG_X11
#ifdef W3MIMGDISPLAY_SETUID
/* run in user privileges */
diff --git a/w3mimg/w3mimg.h b/w3mimg/w3mimg.h
index 3807ca5..f6415a9 100644
--- a/w3mimg/w3mimg.h
+++ b/w3mimg/w3mimg.h
@@ -1,6 +1,13 @@
-/* $Id: w3mimg.h,v 1.8 2003/07/13 16:19:10 ukai Exp $ */
+/* $Id: w3mimg.h,v 1.9 2010/12/21 10:13:55 htrb Exp $ */
+#ifndef W3MIMG_W3MIMG_H
+#define W3MIMG_W3MIMG_H
+
#include "config.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#ifdef USE_W3MIMG_FB
#include "w3mimg/fb/fb.h"
#include "w3mimg/fb/fb_img.h"
@@ -42,5 +49,13 @@ extern w3mimg_op *w3mimg_x11open();
#ifdef USE_W3MIMG_FB
extern w3mimg_op *w3mimg_fbopen();
#endif
+#ifdef USE_W3MIMG_WIN
+extern w3mimg_op *w3mimg_winopen();
+#endif
extern w3mimg_op *w3mimg_open();
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* W3MIMG_W3MIMG_H */
diff --git a/w3mimg/win/Makefile.in b/w3mimg/win/Makefile.in
new file mode 100644
index 0000000..b760a3d
--- /dev/null
+++ b/w3mimg/win/Makefile.in
@@ -0,0 +1,31 @@
+#
+# w3mimg/win/Makefile
+#
+#
+@SET_MAKE@
+SHELL=@SHELL@
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = $(srcdir):.
+CFLAGS=$(OPTS) -I../.. -I$(top_srcdir) -I$(srcdir) @CFLAGS@ @CPPFLAGS@ @DEFS@ $(IMGCFLAGS)
+RM=rm
+CC=@CC@
+CXX=@CXX@
+
+IMGCFLAGS=@IMGWINCFLAGS@
+OBJS=win_w3mimg.o
+
+all: win_w3mimg.o
+
+win_w3mimg.o: win_w3mimg.cpp
+ $(CXX) $(CFLAGS) -c $<
+
+clean:
+ @-$(RM) -f *.o
+
+distclean: clean
+ -$(RM) -f Makefile
+
+#
+
+
diff --git a/w3mimg/win/win_w3mimg.cpp b/w3mimg/win/win_w3mimg.cpp
new file mode 100644
index 0000000..1864fcb
--- /dev/null
+++ b/w3mimg/win/win_w3mimg.cpp
@@ -0,0 +1,1063 @@
+/* $Id: win_w3mimg.cpp,v 1.1 2010/12/21 10:13:55 htrb Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "config.h"
+#include <assert.h>
+#include <locale.h>
+
+#include <new>
+#include <algorithm>
+
+#include "w3mimg/w3mimg.h"
+#include <windows.h>
+#include <gdiplus.h>
+#include <unistd.h>
+#include <sys/cygwin.h>
+/* GDI+ can handle BMP, GIF, JPEG, PNG and TIFF by itself. */
+
+#define OFFSET_X 2
+#define OFFSET_Y 2
+#define DEBUG
+#define USE_GDIP_CACHED_BITMAP
+
+#ifdef DEBUG
+#define THROW_NONE throw()
+#else
+#define THROW_NONE
+#endif
+
+struct win_info {
+ HWND window;
+ Gdiplus::ARGB background_pixel;
+ ULONG_PTR gdiplus_token;
+ FILE *logfile;
+};
+
+struct window_list {
+ HWND *wnd;
+ size_t nwnd;
+ size_t capacity;
+};
+
+#ifdef USE_GDIP_CACHED_BITMAP
+typedef Gdiplus::CachedBitmap *cache_handle;
+#else
+typedef HBITMAP cache_handle;
+#endif
+class win_image {
+private:
+ win_image(const win_image &); // decl only
+ win_image &operator=(const win_image &); // decl only
+
+ Gdiplus::Bitmap *gpbitmap;
+ unsigned int nframe;
+ unsigned int current;
+ unsigned long tick;
+ unsigned long loopcount; // zero = infinite
+ unsigned long *delay; // unit: millisecond
+ cache_handle *cache;
+
+public:
+ win_image() THROW_NONE;
+ ~win_image() THROW_NONE;
+ int load(w3mimg_op *wop, Gdiplus::Bitmap **p_gpbitmap,
+ int *wreturn, int *hreturn) THROW_NONE;
+ int show(w3mimg_op *wop, int sx, int sy, int sw, int sh, int x, int y) THROW_NONE;
+ int animate(w3mimg_op *wop) THROW_NONE;
+};
+
+static int win_init(w3mimg_op * wop) THROW_NONE;
+static int win_finish(w3mimg_op * wop) THROW_NONE;
+static int win_active(w3mimg_op * wop) THROW_NONE;
+static void win_set_background(w3mimg_op * wop, char *background) THROW_NONE;
+static void win_sync(w3mimg_op * wop) THROW_NONE;
+static void win_close(w3mimg_op * wop) THROW_NONE;
+
+static int win_load_image(w3mimg_op * wop, W3MImage * img, char *fname,
+ int w, int h) THROW_NONE;
+static int win_show_image(w3mimg_op * wop, W3MImage * img,
+ int sx, int sy, int sw, int sh, int x, int y) THROW_NONE;
+static void win_free_image(w3mimg_op * wop, W3MImage * img) THROW_NONE;
+static int win_get_image_size(w3mimg_op * wop, W3MImage * img,
+ char *fname, int *w, int *h) THROW_NONE;
+static int win_clear(w3mimg_op * wop, int x, int y, int w, int h) THROW_NONE;
+
+static int window_alive(w3mimg_op *wop) THROW_NONE;
+static Gdiplus::Bitmap *read_image_file(w3mimg_op *wop, const char *fname) THROW_NONE;
+static BOOL CALLBACK store_to_window_list(HWND hWnd, LPARAM wndlist) THROW_NONE;
+static void clear_window_list(struct window_list *wl) THROW_NONE;
+static const char *gdip_strerror(Gdiplus::Status status) THROW_NONE;
+static void gdip_perror(w3mimg_op *wop, Gdiplus::Status status, const char *func) THROW_NONE;
+static char *win32_strerror_alloc(DWORD status) THROW_NONE;
+static void win32_perror(w3mimg_op *wop, DWORD status, const char *func) THROW_NONE;
+#if 0 /* unused */
+static WCHAR *mb2wstr_alloc(const char *) THROW_NONE;
+static char *wstr2mb_alloc(const WCHAR *) THROW_NONE;
+#endif
+
+#define PRELUDE(wop, xi) \
+ assert(wop); \
+ struct win_info *xi = static_cast<struct win_info *>(wop->priv); \
+ assert(xi)
+
+win_image::win_image() THROW_NONE
+ : gpbitmap(NULL), nframe(0)
+{}
+
+win_image::~win_image() THROW_NONE
+{
+ if (this->cache) {
+ for (size_t i = 0; i != this->nframe; ++i) {
+#ifdef USE_GDIP_CACHED_BITMAP
+ delete this->cache[i];
+#else
+ if (this->cache[i])
+ DeleteObject(this->cache[i]);
+#endif
+ }
+ delete[] this->cache;
+ }
+ delete[] this->delay;
+ delete this->gpbitmap;
+}
+
+int
+win_image::load(w3mimg_op *wop, Gdiplus::Bitmap **p_gpbitmap, int *wreturn, int *hreturn) THROW_NONE
+{
+ PRELUDE(wop, xi);
+ Gdiplus::Bitmap *gpbitmap = *p_gpbitmap;
+ assert(gpbitmap);
+ Gdiplus::Status status = Gdiplus::Ok;
+ int retval = 0;
+
+ Gdiplus::PropertyItem *loopcountbuf = NULL;
+ Gdiplus::PropertyItem *delaybuf = NULL;
+ unsigned long *delay = NULL;
+ cache_handle *cache = NULL;
+
+ if (xi->logfile) {
+ fprintf(xi->logfile, "win_image::load(%p, %p, %p, %p) start\n",
+ wop, gpbitmap, wreturn, hreturn);
+ }
+ {
+ unsigned int width = gpbitmap->GetWidth();
+ unsigned int height = gpbitmap->GetHeight();
+ unsigned int nframe = gpbitmap->GetFrameCount(&Gdiplus::FrameDimensionTime);
+ unsigned long loopcount = 0;
+
+ if (xi->logfile)
+ fprintf(xi->logfile, "win_image::load(): size[0]=%ux%u\n", width, height);
+ if (nframe == 0) {
+ // Not an animated picture
+ if (xi->logfile)
+ fprintf(xi->logfile, "win_image::load(): zero frame count\n");
+ nframe = 1;
+ delay = new(std::nothrow) unsigned long[1];
+ if (delay == NULL)
+ goto last;
+ delay[0] = 0;
+ } else {
+ unsigned int loopcountsize = gpbitmap->GetPropertyItemSize(PropertyTagLoopCount);
+ unsigned int delaysize = gpbitmap->GetPropertyItemSize(PropertyTagFrameDelay);
+
+ // Get loop count
+ if (loopcountsize != 0) {
+ loopcountbuf = (Gdiplus::PropertyItem *)malloc(loopcountsize);
+ if (loopcountbuf == NULL)
+ goto last;
+ status = gpbitmap->GetPropertyItem(PropertyTagLoopCount, loopcountsize, loopcountbuf);
+ if (status != Gdiplus::Ok)
+ goto gdip_error;
+ if (loopcountbuf->type == PropertyTagTypeShort &&
+ loopcountbuf->length >= sizeof(unsigned short)) {
+ loopcount = *(unsigned short *)loopcountbuf->value;
+ } else if (loopcountbuf->type == PropertyTagTypeLong &&
+ loopcountbuf->length >= sizeof(unsigned long)) {
+ loopcount = *(unsigned long *)loopcountbuf->value;
+ }
+ }
+ if (xi->logfile)
+ fprintf(xi->logfile, "win_image::load(): loopcount=%lu\n", loopcount);
+ // Get delay times
+ if (delaysize != 0) {
+ delaybuf = (Gdiplus::PropertyItem *)malloc(delaysize);
+ if (delaybuf == NULL)
+ goto last;
+ status = gpbitmap->GetPropertyItem(PropertyTagFrameDelay, delaysize, delaybuf);
+ if (status != Gdiplus::Ok)
+ goto gdip_error;
+ delay = new(std::nothrow) unsigned long[nframe];
+ if (delay == NULL)
+ goto last;
+ std::fill(delay, delay + nframe, 0);
+ if (delaybuf->type == PropertyTagTypeShort) {
+ unsigned int count = delaybuf->length / sizeof(unsigned short);
+ for (unsigned int i = 0; i != count; ++i)
+ delay[i] = ((unsigned short *)delaybuf->value)[i] * 10;
+ } else if (delaybuf->type == PropertyTagTypeLong) {
+ unsigned int count = delaybuf->length / sizeof(unsigned long);
+ for (unsigned int i = 0; i != count; ++i)
+ delay[i] = ((unsigned long *)delaybuf->value)[i] * 10;
+ }
+ }
+ if (xi->logfile) {
+ for (unsigned int i = 0; i != nframe; ++i)
+ fprintf(xi->logfile, "win_image::load(): delay[%u]=%lu\n", i, delay[i]);
+ }
+ // Get dimensions
+ for (unsigned int nextframe = 1; nextframe != nframe; ++nextframe) {
+ status = gpbitmap->SelectActiveFrame(&Gdiplus::FrameDimensionTime, nextframe);
+ if (status != Gdiplus::Ok) {
+ if (xi->logfile)
+ fprintf(xi->logfile, "win_image::load(): SelectActiveFrame() to %u failed = %d: %s\n",
+ nextframe, (int)status, gdip_strerror(status));
+ goto last;
+ }
+ unsigned int iw = gpbitmap->GetWidth();
+ unsigned int ih = gpbitmap->GetHeight();
+ if (iw > width)
+ width = iw;
+ if (ih > height)
+ height = ih;
+ if (xi->logfile)
+ fprintf(xi->logfile, "win_image::load(): size[%u]=%ux%u\n", nextframe, iw, ih);
+ }
+ // Back to the top
+ status = gpbitmap->SelectActiveFrame(&Gdiplus::FrameDimensionTime, 0);
+ if (status != Gdiplus::Ok) {
+ if (xi->logfile)
+ fprintf(xi->logfile, "win_image::load(): SelectActiveFrame() to %u frame = %d: %s\n",
+ 1U, (int)status, gdip_strerror(status));
+ goto last;
+ }
+ }
+ // Allocate cache array
+ cache = new(std::nothrow) cache_handle[nframe];
+ if (cache == NULL)
+ goto last;
+ std::fill(cache, cache + nframe, (cache_handle)NULL);
+ // Sanity check
+ if (width > SHRT_MAX || height > SHRT_MAX) {
+ if (xi->logfile)
+ fprintf(xi->logfile, "win_image::load(): too big image: %ux%u\n", width, height);
+ goto last;
+ }
+ // Store the results
+ if (wreturn)
+ *wreturn = (int)width;
+ if (hreturn)
+ *hreturn = (int)height;
+ this->gpbitmap = gpbitmap;
+ *p_gpbitmap = NULL; // ownership transfer
+ this->nframe = nframe;
+ this->current = 0;
+ this->tick = 0;
+ this->loopcount = loopcount;
+ this->delay = delay;
+ delay = NULL; // ownership transfer
+ this->cache = cache;
+ cache = NULL; // ownership transfer
+ retval = 1;
+ }
+ goto last;
+
+gdip_error:
+ gdip_perror(wop, status, "win_image::load");
+ goto last;
+last:
+ delete[] cache;
+ delete[] delay;
+ free(delaybuf);
+ free(loopcountbuf);
+ if (xi->logfile)
+ fprintf(xi->logfile, "win_image::load() = %d\n", retval);
+ return retval;
+}
+
+int
+win_image::show(w3mimg_op *wop, int sx, int sy, int sw, int sh, int x, int y) THROW_NONE
+{
+ PRELUDE(wop, xi);
+ int retval = 0;
+ Gdiplus::Status status = Gdiplus::Ok;
+ cache_handle newcache = NULL;
+#ifndef USE_GDIP_CACHED_BITMAP
+ HDC windc = NULL;
+ HDC memdc = NULL;
+#endif
+
+ if (xi->logfile)
+ fprintf(xi->logfile, "win_image::show(%p, %d, %d, %d, %d, %d, %d) start\n",
+ wop, sx, sy, sw, sh, x, y);
+ if (!window_alive(wop))
+ goto last;
+ {
+ int xx = x + wop->offset_x;
+ int yy = y + wop->offset_y;
+
+#ifdef USE_GDIP_CACHED_BITMAP
+ // Prepare the Graphics object for painting
+ Gdiplus::Graphics graphics(xi->window);
+ if ((status = graphics.GetLastStatus()) != Gdiplus::Ok)
+ goto gdip_error;
+ Gdiplus::Rect clip(xx, yy, sw, sh);
+ status = graphics.SetClip(clip);
+ if (status != Gdiplus::Ok)
+ goto gdip_error;
+
+ // Clear the area first as the picture may be transparent
+ status = graphics.Clear(Gdiplus::Color(xi->background_pixel));
+ if (status != Gdiplus::Ok)
+ goto gdip_error;
+
+ unsigned int retry_count = 2;
+ do {
+ if (this->cache[this->current] == NULL) {
+ // Cache the image
+ Gdiplus::CachedBitmap *newcache = new Gdiplus::CachedBitmap(this->gpbitmap, &graphics);
+ if (newcache == NULL)
+ goto last;
+ if ((status = newcache->GetLastStatus()) != Gdiplus::Ok)
+ goto gdip_error;
+ this->cache[this->current] = newcache;
+ newcache = NULL; // ownership transfer
+ --retry_count;
+ }
+ // Draw it
+ status = graphics.DrawCachedBitmap(this->cache[this->current], xx - sx, yy - sy);
+ if (status == Gdiplus::Ok)
+ break;
+ // maybe the user altered the display configuration
+ if (xi->logfile)
+ fprintf(xi->logfile, "win_image::show(): stale cache = %d: %s\n",
+ (int)status, gdip_strerror(status));
+ delete this->cache[this->current];
+ this->cache[this->current] = NULL;
+ if (retry_count == 0)
+ goto last;
+ } while (1);
+#else /* !USE_GDIP_CACHED_BITMAP */
+ // Prepare the GC for painting
+ windc = GetDC(xi->window);
+ if (windc == NULL)
+ goto win32_error;
+ // Prepare the GC for read/write access to the cached bitmap
+ memdc = CreateCompatibleDC(windc);
+ if (memdc == NULL)
+ goto win32_error;
+ unsigned int retry_count = 2;
+ do {
+ HGDIOBJ hbitmap_save;
+ if (this->cache[this->current] == NULL) {
+ unsigned int ow = gpbitmap->GetWidth();
+ unsigned int oh = gpbitmap->GetHeight();
+ // Cache the image
+ newcache = CreateCompatibleBitmap(windc, ow, oh);
+ if (newcache == NULL)
+ goto win32_error;
+ SetLastError(ERROR_SUCCESS); // SelectObject sometimes leave the error unchanged
+ hbitmap_save = SelectObject(memdc, newcache);
+ if (hbitmap_save == NULL || hbitmap_save == HGDI_ERROR)
+ goto win32_error;
+ Gdiplus::Graphics tmp_graphics(memdc);
+ if ((status = tmp_graphics.GetLastStatus()) != Gdiplus::Ok)
+ goto gdip_error;
+ status = tmp_graphics.Clear(Gdiplus::Color(xi->background_pixel));
+ if (status != Gdiplus::Ok)
+ goto gdip_error;
+ status = tmp_graphics.DrawImage(this->gpbitmap, 0, 0, ow, oh);
+ if (status != Gdiplus::Ok)
+ goto gdip_error;
+ this->cache[this->current] = newcache;
+ newcache = NULL; // ownership transfer
+ --retry_count;
+ } else {
+ SetLastError(ERROR_SUCCESS); // SelectObject sometimes leave the error unchanged
+ hbitmap_save = SelectObject(memdc, this->cache[this->current]);
+ if (hbitmap_save == NULL || hbitmap_save == HGDI_ERROR)
+ goto stale_cache;
+ }
+ // Draw it
+ if (BitBlt(windc, xx, yy, sw, sh, memdc, sx, sy, SRCCOPY))
+ break;
+ // maybe the user altered the display configuration
+stale_cache:
+ if (xi->logfile) {
+ DWORD ecode = GetLastError();
+ char *msg = win32_strerror_alloc(ecode);
+ fprintf(xi->logfile, "win_image::show(): stale cache = %u: %s\n",
+ (unsigned int)ecode, msg ? msg : "(unknown)");
+ LocalFree(msg);
+ }
+ SetLastError(ERROR_SUCCESS); // SelectObject sometimes leave the error unchanged
+ hbitmap_save = SelectObject(memdc, hbitmap_save);
+ if (hbitmap_save == NULL || hbitmap_save == HGDI_ERROR)
+ goto win32_error;
+ DeleteObject(this->cache[this->current]);
+ this->cache[this->current] = NULL;
+ if (retry_count == 0)
+ goto last;
+ } while (1);
+#endif /* !USE_GDIP_CACHED_BITMAP */
+
+ retval = 1;
+ }
+ goto last;
+#ifndef USE_GDIP_CACHED_BITMAP
+win32_error:
+ win32_perror(wop, GetLastError(), "win_image::show");
+ goto last;
+#endif
+gdip_error:
+ gdip_perror(wop, status, "win_image::show");
+ goto last;
+last:
+#ifdef USE_GDIP_CACHED_BITMAP
+ delete newcache;
+#else
+ if (memdc)
+ DeleteDC(memdc);
+ if (windc)
+ ReleaseDC(xi->window, windc);
+ if (newcache)
+ DeleteObject(newcache);
+#endif
+ if (xi->logfile)
+ fprintf(xi->logfile, "win_image::show() = %d\n", retval);
+ return retval;
+}
+
+int
+win_image::animate(w3mimg_op * wop) THROW_NONE
+{
+ PRELUDE(wop, xi);
+ int retval = 0;
+ Gdiplus::Status status = Gdiplus::Ok;
+
+ if (xi->logfile)
+ fprintf(xi->logfile, "win_image::animate(%p) start\n", wop);
+ {
+ if (this->nframe <= 1)
+ goto animation_end;
+#define UNIT_TICK 50
+#define MIN_DELAY (UNIT_TICK*2)
+ this->tick += UNIT_TICK;
+ if (this->tick >= MIN_DELAY && this->tick >= this->delay[this->current]) {
+ this->tick = 0;
+ unsigned int nextframe = this->current + 1;
+ if (nextframe >= this->nframe) {
+ if (this->loopcount == 1) // end of the loop
+ goto animation_end;
+ nextframe = 0;
+ }
+ status = this->gpbitmap->SelectActiveFrame(&Gdiplus::FrameDimensionTime, nextframe);
+ if (status != Gdiplus::Ok)
+ goto gdip_error;
+ this->current = nextframe;
+ if (nextframe == 0 && this->loopcount > 1)
+ --this->loopcount;
+ }
+animation_end:
+ retval = 1;
+ }
+ goto last;
+gdip_error:
+ gdip_perror(wop, status, "win_image::animate");
+ goto last;
+last:
+ if (xi->logfile)
+ fprintf(xi->logfile, "win_image::animate() = %d\n", retval);
+ return retval;
+}
+
+static int
+window_alive(w3mimg_op *wop) THROW_NONE
+{
+ PRELUDE(wop, xi);
+ if (xi->window == NULL)
+ return 0;
+ if (IsWindow(xi->window))
+ return 1;
+ xi->window = NULL;
+ fputs("w3mimgdisplay: target window disappeared\n", stderr);
+ if (xi->logfile)
+ fputs("w3mimgdisplay: target window disappeared\n", xi->logfile);
+ return 0;
+}
+
+static int
+win_init(w3mimg_op *) THROW_NONE
+{
+ // nothing to do
+ return 1;
+}
+
+static int
+win_finish(w3mimg_op *) THROW_NONE
+{
+ // nothing to do
+ return 1;
+}
+
+static int
+win_clear(w3mimg_op *wop, int x, int y, int w, int h) THROW_NONE
+{
+ PRELUDE(wop, xi);
+ Gdiplus::Status status = Gdiplus::Ok;
+ int retval = 0;
+
+ if (xi->logfile)
+ fprintf(xi->logfile, "win_clear(%p, %d, %d, %d, %d) start\n",
+ wop, x, y, w, h);
+ if (!window_alive(wop))
+ goto last;
+ {
+ if (x < 0)
+ x = 0;
+ if (y < 0)
+ y = 0;
+ Gdiplus::SolidBrush brush(Gdiplus::Color(xi->background_pixel));
+ if ((status = brush.GetLastStatus()) != Gdiplus::Ok)
+ goto gdip_error;
+ Gdiplus::Graphics graphics(xi->window);
+ if ((status = graphics.GetLastStatus()) != Gdiplus::Ok)
+ goto gdip_error;
+ status = graphics.FillRectangle(&brush, x + wop->offset_x, y + wop->offset_y, w, h);
+ if (status != Gdiplus::Ok)
+ goto gdip_error;
+ retval = 1;
+ }
+ goto last;
+gdip_error:
+ gdip_perror(wop, status, "win_clear");
+ goto last;
+last:
+ if (xi->logfile)
+ fprintf(xi->logfile, "win_clear() = %d\n", retval);
+ return retval;
+}
+
+static int
+win_active(w3mimg_op * wop) THROW_NONE
+{
+ return window_alive(wop);
+}
+
+static void
+win_set_background(w3mimg_op * wop, char *background) THROW_NONE
+{
+ PRELUDE(wop, xi);
+
+ HDC windc = NULL;
+
+ if (xi->logfile)
+ fprintf(xi->logfile, "win_set_background(%p, \"%s\")\n", wop, background ? background : "(auto)");
+ {
+ // Fallback value
+ // xi->background_pixel = Gdiplus::Color::White;
+ xi->background_pixel = Gdiplus::Color::Black;
+
+ // Explicit
+ if (background) {
+ unsigned int r, g, b;
+ if (sscanf(background, "#%02x%02x%02x", &r, &g, &b) == 3) {
+ xi->background_pixel = Gdiplus::Color::MakeARGB((BYTE)255, (BYTE)r, (BYTE)g, (BYTE)b);
+ goto last;
+ }
+ }
+
+ // Auto detect
+ if (xi->window == NULL || !IsWindow(xi->window))
+ goto last;
+ windc = GetDC(xi->window);
+ if (windc == NULL)
+ goto win32_error;
+ COLORREF c = GetPixel(windc,
+ (wop->offset_x >= 1) ? (wop->offset_x - 1) : 0,
+ (wop->offset_y >= 1) ? (wop->offset_y - 1) : 0);
+ xi->background_pixel = Gdiplus::Color::MakeARGB(
+ (BYTE)255, GetRValue(c), GetGValue(c), GetBValue(c));
+ }
+ goto last;
+win32_error:
+ win32_perror(wop, GetLastError(), "win_set_background");
+ goto last;
+last:
+ if (xi->logfile)
+ fprintf(xi->logfile, "win_set_background() result = #%06x\n",
+ (unsigned int)xi->background_pixel);
+ if (windc)
+ ReleaseDC(xi->window, windc);
+}
+
+static void
+win_sync(w3mimg_op *) THROW_NONE
+{
+ // nothing to do
+ return;
+}
+
+static void
+win_close(w3mimg_op * wop) THROW_NONE
+{
+ PRELUDE(wop, xi);
+
+ if (xi->gdiplus_token)
+ Gdiplus::GdiplusShutdown(xi->gdiplus_token);
+ if (xi->logfile) {
+ fprintf(xi->logfile, "win_close(%p)\n", wop);
+ fclose(xi->logfile);
+ }
+ delete xi;
+ delete wop;
+}
+
+static Gdiplus::Bitmap *
+read_image_file(w3mimg_op *wop, const char *fname) THROW_NONE
+{
+ PRELUDE(wop, xi);
+ Gdiplus::Status status = Gdiplus::Ok;
+ Gdiplus::Bitmap *retval = NULL;
+
+ WCHAR *wfname = NULL;
+ Gdiplus::Bitmap *gpbitmap = NULL;
+
+ if (xi->logfile)
+ fprintf(xi->logfile, "read_image_file(%p, \"%s\") start\n", wop, fname);
+ {
+ wfname = (WCHAR *)cygwin_create_path(CCP_POSIX_TO_WIN_W, fname);
+ if (wfname == NULL)
+ goto last;
+ gpbitmap = new Gdiplus::Bitmap(wfname);
+ if (gpbitmap == NULL)
+ goto last;
+ status = gpbitmap->GetLastStatus();
+ switch (status) {
+ case Gdiplus::Ok:
+ break;
+ case Gdiplus::UnknownImageFormat:
+ case Gdiplus::FileNotFound:
+ goto last; // fail silently
+ default:
+ goto gdip_error;
+ }
+ retval = gpbitmap;
+ gpbitmap = NULL; // ownership transfer
+ }
+ goto last;
+gdip_error:
+ gdip_perror(wop, status, "read_image_file");
+last:
+ delete gpbitmap;
+ free(wfname);
+ if (xi->logfile)
+ fprintf(xi->logfile, "read_image_file() = %p\n", retval);
+ return retval;
+}
+
+static int
+win_load_image(w3mimg_op * wop, W3MImage * img, char *fname, int w, int h) THROW_NONE
+{
+ PRELUDE(wop, xi);
+ int retval = 0;
+ Gdiplus::Bitmap *gpbitmap = NULL;
+ win_image *wimg = NULL;
+
+ assert(img);
+ if (xi->logfile) {
+ fprintf(xi->logfile, "win_load_image(%p, %p, \"%s\", %d, %d) start\n",
+ wop, img, fname, w, h);
+ }
+ {
+ gpbitmap = read_image_file(wop, fname);
+ if (gpbitmap == NULL)
+ goto last;
+ int iw, ih;
+ wimg = new(std::nothrow) win_image;
+ if (!wimg->load(wop, &gpbitmap, &iw, &ih))
+ goto last;
+ img->pixmap = wimg;
+ wimg = NULL; // ownership transfer
+ img->width = (0 <= w && w < iw) ? w : iw;
+ img->height = (0 <= h && h < ih) ? h : ih;
+ retval = 1;
+ }
+ goto last;
+last:
+ delete wimg;
+ delete gpbitmap;
+ if (xi->logfile)
+ fprintf(xi->logfile, "win_load_image() = %d\n", retval);
+ return retval;
+}
+
+static int
+win_show_image(w3mimg_op * wop, W3MImage * img, int sx, int sy, int sw,
+ int sh, int x, int y) THROW_NONE
+{
+ PRELUDE(wop, xi);
+ int retval = 0;
+
+ assert(img);
+ win_image *wimg = static_cast<win_image *>(img->pixmap);
+ assert(wimg);
+
+ if (xi->logfile)
+ fprintf(xi->logfile, "win_show_image(%p, %p, %d, %d, %d, %d, %d, %d) start\n",
+ wop, img, sx, sy, sw, sh, x, y);
+ int sww = sw ? sw : img->width;
+ int shh = sh ? sh : img->height;
+ retval = wimg->show(wop, sx, sy, sww, shh, x, y)
+ && wimg->animate(wop);
+ if (xi->logfile)
+ fprintf(xi->logfile, "win_show_image() = %d\n", retval);
+ return retval;
+}
+
+static void
+win_free_image(w3mimg_op * wop, W3MImage * img) THROW_NONE
+{
+ PRELUDE(wop, xi);
+
+ assert(img);
+ if (xi->logfile)
+ fprintf(xi->logfile, "win_free_image(%p, %p) pixmap=%p\n", wop, img, img->pixmap);
+ delete static_cast<win_image *>(img->pixmap);
+ img->pixmap = NULL;
+ img->width = 0;
+ img->height = 0;
+}
+
+static int
+win_get_image_size(w3mimg_op * wop, W3MImage *img_unused, char *fname, int *w, int *h) THROW_NONE
+{
+ PRELUDE(wop, xi);
+ int retval = 0;
+ Gdiplus::Bitmap *gpbitmap = NULL;
+ win_image *wimg = NULL;
+
+ if (xi->logfile) {
+ fprintf(xi->logfile, "win_get_image_size(%p, %p, \"%s\", %p, %p) start\n",
+ wop, img_unused, fname, w, h);
+ }
+ {
+ gpbitmap = read_image_file(wop, fname);
+ if (gpbitmap == NULL)
+ goto last;
+ wimg = new(std::nothrow) win_image;
+ if (wimg == NULL)
+ goto last;
+ retval = wimg->load(wop, &gpbitmap, w, h);;
+ }
+ goto last;
+last:
+ delete wimg;
+ delete gpbitmap;
+ if (xi->logfile)
+ fprintf(xi->logfile, "win_get_image_size() = %d\n", retval);
+ return retval;
+}
+
+extern "C" w3mimg_op *
+w3mimg_winopen()
+{
+ w3mimg_op *retval = NULL;
+ Gdiplus::Status status = Gdiplus::Ok;
+
+ w3mimg_op *wop = NULL;
+ struct win_info *xi = NULL;
+ struct window_list children = { NULL, 0, 0 };
+
+ {
+ // Quit if running on X
+ const char *display_name;
+ if ((display_name = getenv("DISPLAY")) != NULL &&
+ display_name[0] && strcmp(display_name, ":0") != 0)
+ return NULL;
+
+ // Allocate the context objects
+ wop = new(std::nothrow) w3mimg_op(); // call the default ctor instead of "new w3mimg_op;"
+ if (wop == NULL)
+ return NULL;
+ wop->priv = xi = new(std::nothrow) win_info();
+ if (xi == NULL)
+ goto last;
+
+ // Debug logging
+ const char *logging_dir;
+ if ((logging_dir = getenv("W3MIMG_LOGDIR")) != NULL &&
+ logging_dir[0]) {
+ size_t l = strlen(logging_dir) + sizeof "/w3mimgXXXXXXXXXX.log";
+ char *fname = (char *)malloc(l);
+ snprintf(fname, l, "%s/w3mimg%d.log", logging_dir, (int)getpid());
+ xi->logfile = fopen(fname, "a");
+ if (xi->logfile) {
+ setvbuf(xi->logfile, NULL, _IONBF, 0);
+ fprintf(xi->logfile, "\nw3mimg_winopen() start pid=%d\n", (int)getpid());
+ }
+ }
+
+ // Look for the window to draw the image
+ xi->window = NULL;
+ const char *windowid;
+ if ((windowid = getenv("WINDOWID")) != NULL)
+ xi->window = FindWindowA(windowid, NULL);
+ if (!xi->window)
+ xi->window = GetForegroundWindow();
+ if (!xi->window)
+ goto win32_error;
+
+ WINDOWINFO winfo = WINDOWINFO();
+ winfo.cbSize = sizeof winfo;
+ GetWindowInfo(xi->window, &winfo);
+ wop->width = (int)(winfo.rcClient.right - winfo.rcClient.left);
+ wop->height = (int)(winfo.rcClient.bottom - winfo.rcClient.top);
+
+ // Search decendant windows and find out which is the text window
+ while (1) {
+ HWND p_window = xi->window;
+
+ clear_window_list(&children);
+ EnumChildWindows(xi->window, &store_to_window_list, (LPARAM)&children);
+ for (unsigned int i = 0; i < children.nwnd; i++) {
+ int width, height;
+
+ GetWindowInfo(children.wnd[i], &winfo);
+ width = (int)(winfo.rcClient.right - winfo.rcClient.left);
+ height = (int)(winfo.rcClient.bottom - winfo.rcClient.top);
+ if (width > wop->width * 0.7 &&
+ height > wop->height * 0.7) {
+ /* maybe text window */
+ wop->width = width;
+ wop->height = height;
+ xi->window = children.wnd[i];
+ }
+ }
+ if (p_window == xi->window)
+ break;
+ }
+
+ // Terminal may leave some border pixels
+ wop->offset_x = OFFSET_X;
+ wop->offset_y = OFFSET_Y;
+
+ // Start up the GDI+
+ Gdiplus::GdiplusStartupInput startup_input; /// default ctor
+ status = Gdiplus::GdiplusStartup(&xi->gdiplus_token, &startup_input, NULL);
+ if (status != Gdiplus::Ok)
+ goto gdip_error;
+
+ // Fill the context object
+ wop->init = win_init;
+ wop->finish = win_finish;
+ wop->active = win_active;
+ wop->set_background = win_set_background;
+ wop->sync = win_sync;
+ wop->close = win_close;
+ wop->clear = win_clear;
+
+ wop->load_image = win_load_image;
+ wop->show_image = win_show_image;
+ wop->free_image = win_free_image;
+ wop->get_image_size = win_get_image_size;
+
+ retval = wop; // take care of the object lifetime
+ }
+ goto last;
+win32_error:
+ win32_perror(wop, GetLastError(), "w3mimg_winopen");
+ goto last;
+gdip_error:
+ gdip_perror(wop, status, "w3mimg_winopen");
+ goto last;
+last:
+ if (xi && xi->logfile)
+ fprintf(xi->logfile, "w3mimg_winopen() = %p\n", retval);
+ clear_window_list(&children);
+ if (!retval) {
+ if (xi) {
+ if (xi->gdiplus_token)
+ Gdiplus::GdiplusShutdown(xi->gdiplus_token);
+ if (xi->logfile)
+ fclose(xi->logfile);
+ delete xi;
+ }
+ delete wop;
+ }
+ return retval;
+}
+
+static BOOL CALLBACK
+store_to_window_list(HWND hWnd, LPARAM wndlist) THROW_NONE
+{
+ struct window_list *wl = (struct window_list *)wndlist;
+
+ if (wl->nwnd >= wl->capacity) {
+ size_t newsize = (wl->capacity < 4 ) ? 4 : (wl->capacity * 2);
+ HWND *newbuf = (HWND *)realloc(wl->wnd, newsize * sizeof newbuf[0]);
+ if (newbuf == NULL) {
+ clear_window_list(wl);
+ return FALSE;
+ }
+ wl->wnd = newbuf;
+ wl->capacity = newsize;
+ }
+ wl->wnd[wl->nwnd++] = hWnd;
+ return TRUE;
+}
+
+static void
+clear_window_list(struct window_list *wl) THROW_NONE
+{
+ free(wl->wnd);
+ wl->wnd = NULL;
+ wl->nwnd = 0;
+ wl->capacity = 0;
+}
+
+static const char *
+gdip_strerror(Gdiplus::Status status) THROW_NONE
+{
+ size_t i;
+ struct status_rec {
+ Gdiplus::Status code;
+ const char *str;
+ };
+ static const struct status_rec table[] = {
+#define ERRITEM(s) { Gdiplus::s, #s }
+ ERRITEM(Ok),
+ ERRITEM(GenericError),
+ ERRITEM(InvalidParameter),
+ ERRITEM(OutOfMemory),
+ ERRITEM(ObjectBusy),
+ ERRITEM(InsufficientBuffer),
+ ERRITEM(NotImplemented),
+ ERRITEM(Win32Error),
+ ERRITEM(WrongState),
+ ERRITEM(Aborted),
+ ERRITEM(FileNotFound),
+ ERRITEM(ValueOverflow),
+ ERRITEM(AccessDenied),
+ ERRITEM(UnknownImageFormat),
+ ERRITEM(FontFamilyNotFound),
+ ERRITEM(FontStyleNotFound),
+ ERRITEM(NotTrueTypeFont),
+ ERRITEM(UnsupportedGdiplusVersion),
+ ERRITEM(GdiplusNotInitialized),
+ ERRITEM(PropertyNotFound),
+ ERRITEM(PropertyNotSupported),
+ ERRITEM(ProfileNotFound),
+#undef ERRITEM
+ };
+ for (i = 0; i != sizeof table / sizeof table[0]; ++i)
+ if (table[i].code == status)
+ return table[i].str;
+ return "unknown";
+}
+
+static void
+gdip_perror(w3mimg_op *wop, Gdiplus::Status status, const char *func) THROW_NONE
+{
+ const char *s = gdip_strerror(status);
+ fprintf(stderr, "w3mimgdisplay: GDI+ error %d: %s\n", (int)status, s);
+ if (wop && wop->priv) {
+ struct win_info *xi = (struct win_info *)wop->priv;
+ if (xi->logfile) {
+ fprintf(xi->logfile, "%s(): GDI+ error %d: %s\n", func, (int)status, s);
+ }
+ }
+}
+
+// Don't free() the result; use LocalFree() instead
+static char *
+win32_strerror_alloc(DWORD status) THROW_NONE
+{
+ char *errbuf = NULL;
+
+ FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, status, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
+ (LPSTR)&errbuf, 0, NULL);
+ if (errbuf) {
+ size_t len = strlen(errbuf);
+ if (len > 0 && errbuf[len - 1] == '\n')
+ errbuf[len - 1] = '\0';
+ }
+ return errbuf;
+}
+
+static void
+win32_perror(w3mimg_op *wop, DWORD status, const char *func) THROW_NONE
+{
+ char *errbuf = win32_strerror_alloc(status);
+ const char *s = errbuf ? errbuf : "(unknown)";
+
+ fprintf(stderr, "w3mimgdisplay: Win32 error %u: %s\n", (unsigned int)status, s);
+ if (wop && wop->priv) {
+ struct win_info *xi = (struct win_info *)wop->priv;
+ if (xi->logfile) {
+ fprintf(xi->logfile, "%s(): Win32 error %u: %s\n",
+ func, (unsigned int)status, s);
+ }
+ }
+ LocalFree(errbuf);
+}
+
+#if 0 /* unused */
+static WCHAR *
+mb2wstr_alloc(const char *s) THROW_NONE
+{
+ int len;
+ WCHAR *buf = NULL;
+
+ len = MultiByteToWideChar(CP_OEMCP, MB_PRECOMPOSED, s, -1, NULL, 0);
+ if (len <= 0) {
+ fprintf(stderr, "w3mimgdisplay: unable to convert string ecode=%u\n",
+ (unsigned int)GetLastError());
+ goto error;
+ }
+ buf = (WCHAR *)malloc(len * sizeof(WCHAR)); /* including L'\0' */
+ if (!buf)
+ goto error;
+ len = MultiByteToWideChar(CP_OEMCP, MB_PRECOMPOSED, s, -1, buf, len);
+ if (len <= 0) {
+ fprintf(stderr, "w3mimgdisplay: unable to convert string ecode=%u\n",
+ (unsigned int)GetLastError());
+ goto error;
+ }
+ return buf;
+error:
+ free(buf);
+ return NULL;
+}
+
+static char *
+wstr2mb_alloc(const WCHAR *ws) THROW_NONE
+{
+ int len;
+ char *buf = NULL;
+
+ len = WideCharToMultiByte(CP_OEMCP, WC_COMPOSITECHECK, ws, -1, NULL, 0, NULL, NULL);
+ if (len <= 0) {
+ fprintf(stderr, "w3mimgdisplay: unable to convert string ecode=%u\n",
+ (unsigned int)GetLastError());
+ goto error;
+ }
+ buf = (char *)malloc(len); /* including '\0' */
+ if (!buf)
+ goto error;
+ len = WideCharToMultiByte(CP_OEMCP, WC_COMPOSITECHECK, ws, -1, buf, len, NULL, NULL);
+ if (len <= 0) {
+ fprintf(stderr, "w3mimgdisplay: unable to convert string ecode=%u\n",
+ (unsigned int)GetLastError());
+ goto error;
+ }
+ return buf;
+error:
+ free(buf);
+ return NULL;
+}
+#endif /* unused */
diff --git a/w3mimgdisplay.c b/w3mimgdisplay.c
index 78550e5..5486a47 100644
--- a/w3mimgdisplay.c
+++ b/w3mimgdisplay.c
@@ -1,4 +1,4 @@
-/* $Id: w3mimgdisplay.c,v 1.18 2003/07/13 16:20:42 ukai Exp $ */
+/* $Id: w3mimgdisplay.c,v 1.19 2010/12/21 10:13:55 htrb Exp $ */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
@@ -65,6 +65,7 @@ main(int argc, char **argv)
if (defined_test) {
printf("%d %d\n", w_op->width - w_op->offset_x,
w_op->height - w_op->offset_y);
+ w_op->close(w_op);
exit(0);
}
@@ -75,6 +76,7 @@ main(int argc, char **argv)
if (w_op->get_image_size(w_op, &img, defined_size, &w, &h))
printf("%d %d\n", w, h);
}
+ w_op->close(w_op);
exit(0);
}