w3m

Unnamed repository; edit this file to name it for gitweb.
git clone https://logand.com/git/w3m.git/
Log | Files | Refs | README

x11_w3mimg.c (19449B)


      1 /* $Id$ */
      2 #include <stdio.h>
      3 #include <stdlib.h>
      4 #include <string.h>
      5 #include <ctype.h>
      6 #include "config.h"
      7 
      8 #if defined(USE_IMLIB)
      9 #include <Imlib.h>
     10 #elif defined(USE_IMLIB2)
     11 #include <X11/Xlib.h>
     12 #include <X11/Xutil.h>
     13 #include <Imlib2.h>
     14 #elif defined(USE_GDKPIXBUF)
     15 #if defined(USE_GTK2)
     16 #include <glib-object.h>
     17 #include <gdk/gdk.h>
     18 #include <gdk-pixbuf-xlib/gdk-pixbuf-xlib.h>
     19 #else
     20 #include <gdk-pixbuf/gdk-pixbuf-xlib.h>
     21 #endif
     22 #else
     23 #error no Imlib and GdkPixbuf support
     24 #endif
     25 
     26 #include "w3mimg/w3mimg.h"
     27 
     28 #define OFFSET_X	2
     29 #define OFFSET_Y	2
     30 
     31 struct x11_info {
     32     Display *display;
     33     Window window, parent;
     34     unsigned long background_pixel;
     35     GC imageGC;
     36 #if defined(USE_IMLIB)
     37     ImlibData *id;
     38 #elif defined(USE_GDKPIXBUF)
     39     int init_flag;
     40 #endif
     41 };
     42 
     43 #if defined(USE_GDKPIXBUF)
     44 struct x11_image {
     45     int total;
     46     int no;
     47     int wait;
     48     int delay;
     49     Pixmap *pixmap;
     50 };
     51 
     52 #if defined(USE_GTK2)
     53 static int
     54 get_animation_size(GdkPixbufAnimation * animation, int *w, int *h, int *delay)
     55 {
     56     GdkPixbufAnimationIter *iter;
     57     int n, i, d = -1;
     58     GTimeVal time;
     59 
     60     g_get_current_time(&time);
     61     iter = gdk_pixbuf_animation_get_iter(animation, &time);
     62     *w = gdk_pixbuf_animation_get_width(animation);
     63     *h = gdk_pixbuf_animation_get_height(animation);
     64     for (i = 1;
     65 	 gdk_pixbuf_animation_iter_on_currently_loading_frame(iter) != TRUE;
     66 	 i++) {
     67 	int tmp;
     68 	tmp = gdk_pixbuf_animation_iter_get_delay_time(iter);
     69 	g_time_val_add(&time, tmp * 1000);
     70 	if (tmp > d)
     71 	    d = tmp;
     72 	gdk_pixbuf_animation_iter_advance(iter, &time);
     73     }
     74     if (delay)
     75 	*delay = d;
     76     g_object_unref(G_OBJECT(iter));
     77     n = i;
     78     return n;
     79 }
     80 #else
     81 static int
     82 get_animation_size(GdkPixbufAnimation * animation, int *w, int *h, int *delay)
     83 {
     84     GList *frames;
     85     int iw, ih, n, i, d = -1;
     86 
     87     frames = gdk_pixbuf_animation_get_frames(animation);
     88     n = gdk_pixbuf_animation_get_num_frames(animation);
     89     *w = gdk_pixbuf_animation_get_width(animation);
     90     *h = gdk_pixbuf_animation_get_height(animation);
     91     for (i = 0; i < n; i++) {
     92 	GdkPixbufFrame *frame;
     93 	GdkPixbuf *pixbuf;
     94 	int tmp;
     95 
     96 	frame = (GdkPixbufFrame *) g_list_nth_data(frames, i);
     97 	tmp = gdk_pixbuf_frame_get_delay_time(frame);
     98 	if (tmp > d)
     99 	    d = tmp;
    100 	pixbuf = gdk_pixbuf_frame_get_pixbuf(frame);
    101 	iw = gdk_pixbuf_frame_get_x_offset(frame)
    102 	    + gdk_pixbuf_get_width(pixbuf);
    103 	ih = gdk_pixbuf_frame_get_y_offset(frame)
    104 	    + gdk_pixbuf_get_height(pixbuf);
    105 	if (iw > *w)
    106 	    *w = iw;
    107 	if (ih > *h)
    108 	    *h = ih;
    109     }
    110     if (delay)
    111 	*delay = d;
    112     return n;
    113 }
    114 #endif
    115 #endif
    116 
    117 static int
    118 x11_init(w3mimg_op * self)
    119 {
    120     struct x11_info *xi;
    121     if (self == NULL)
    122 	return 0;
    123     xi = (struct x11_info *)self->priv;
    124     if (xi == NULL)
    125 	return 0;
    126 #if defined(USE_IMLIB)
    127     if (!xi->id) {
    128 	xi->id = Imlib_init(xi->display);
    129 	if (!xi->id)
    130 	    return 0;
    131     }
    132 #elif defined(USE_GDKPIXBUF)
    133     if (!xi->init_flag) {
    134 #if defined(USE_GTK2)
    135 	g_type_init();
    136 #endif
    137 	gdk_pixbuf_xlib_init(xi->display, 0);
    138 	xi->init_flag = TRUE;
    139     }
    140 #endif
    141     if (!xi->imageGC) {
    142 	xi->imageGC = XCreateGC(xi->display, xi->parent, 0, NULL);
    143 	if (!xi->imageGC)
    144 	    return 0;
    145     }
    146     return 1;
    147 }
    148 
    149 static int
    150 x11_finish(w3mimg_op * self)
    151 {
    152     struct x11_info *xi;
    153     if (self == NULL)
    154 	return 0;
    155     xi = (struct x11_info *)self->priv;
    156     if (xi == NULL)
    157 	return 0;
    158     if (xi->imageGC) {
    159 	XFreeGC(xi->display, xi->imageGC);
    160 	xi->imageGC = NULL;
    161     }
    162     return 1;
    163 }
    164 
    165 static int
    166 x11_clear(w3mimg_op * self, int x, int y, int w, int h)
    167 {
    168     struct x11_info *xi;
    169     if (self == NULL)
    170 	return 0;
    171     xi = (struct x11_info *)self->priv;
    172     if (xi == NULL)
    173 	return 0;
    174 
    175     if (x < 0)
    176 	x = 0;
    177     if (y < 0)
    178 	y = 0;
    179 
    180     XClearArea(xi->display, xi->window, x, y, w, h, False);
    181     return 1;
    182 }
    183 
    184 static int
    185 x11_active(w3mimg_op * self)
    186 {
    187     struct x11_info *xi;
    188     if (self == NULL)
    189 	return 0;
    190     xi = (struct x11_info *)self->priv;
    191     if (xi == NULL)
    192 	return 0;
    193     if (!xi->imageGC)
    194 	return 0;
    195     return 1;
    196 }
    197 
    198 static void
    199 x11_set_background(w3mimg_op * self, char *background)
    200 {
    201     XColor screen_def, exact_def;
    202     struct x11_info *xi;
    203     if (self == NULL)
    204 	return;
    205     xi = (struct x11_info *)self->priv;
    206     if (xi == NULL)
    207 	return;
    208 
    209     if (background &&
    210 	XAllocNamedColor(xi->display, DefaultColormap(xi->display, 0),
    211 			 background, &screen_def, &exact_def))
    212 	xi->background_pixel = screen_def.pixel;
    213     else {
    214 	Pixmap p;
    215 	GC gc;
    216 	XImage *i;
    217 
    218 	p = XCreatePixmap(xi->display, xi->window, 1, 1,
    219 			  DefaultDepth(xi->display, 0));
    220 	gc = XCreateGC(xi->display, xi->window, 0, NULL);
    221 	if (!p || !gc)
    222 	    exit(1);		/* XXX */
    223 	XCopyArea(xi->display, xi->window, p, gc,
    224 		  (self->offset_x >= 1) ? (self->offset_x - 1) : 0,
    225 		  (self->offset_y >= 1) ? (self->offset_y - 1) : 0,
    226 		  1, 1, 0, 0);
    227 	i = XGetImage(xi->display, p, 0, 0, 1, 1, -1, ZPixmap);
    228 	if (!i)
    229 	    exit(1);
    230 	xi->background_pixel = XGetPixel(i, 0, 0);
    231 	XDestroyImage(i);
    232 	XFreeGC(xi->display, gc);
    233 	XFreePixmap(xi->display, p);
    234     }
    235 }
    236 
    237 static void
    238 x11_sync(w3mimg_op * self)
    239 {
    240     struct x11_info *xi;
    241     if (self == NULL)
    242 	return;
    243     xi = (struct x11_info *)self->priv;
    244     if (xi == NULL)
    245 	return;
    246     XSync(xi->display, False);
    247 }
    248 
    249 static void
    250 x11_close(w3mimg_op * self)
    251 {
    252     /* XCloseDisplay(xi->display); */
    253 }
    254 
    255 #if defined(USE_GDKPIXBUF)
    256 static struct x11_image *
    257 x11_img_new(struct x11_info *xi, int w, int h, int n)
    258 {
    259     struct x11_image *img = NULL;
    260     int i;
    261 
    262     img = malloc(sizeof(*img));
    263     if (!img)
    264 	goto ERROR;
    265 
    266     img->pixmap = calloc(n, sizeof(*(img->pixmap)));
    267     if (!img->pixmap)
    268 	goto ERROR;
    269 
    270     for (i = 0; i < n; i++) {
    271 	img->pixmap[i] = XCreatePixmap(xi->display, xi->parent, w, h,
    272 				       DefaultDepth(xi->display, 0));
    273 	if (!img->pixmap[i])
    274 	    goto ERROR;
    275 
    276 	XSetForeground(xi->display, xi->imageGC, xi->background_pixel);
    277 	XFillRectangle(xi->display, (Pixmap) img->pixmap[i], xi->imageGC, 0, 0,
    278 		       w, h);
    279     }
    280 
    281     img->no = 0;
    282     img->total = n;
    283     img->wait = 0;
    284     img->delay = -1;
    285 
    286     return img;
    287   ERROR:
    288     if (img) {
    289 	if (img->pixmap) {
    290 	    for (i = 0; i < n; i++) {
    291 		if (img->pixmap[i])
    292 		    XFreePixmap(xi->display, (Pixmap) img->pixmap[i]);
    293 	    }
    294 	    free(img->pixmap);
    295 	}
    296 	free(img);
    297     }
    298     return NULL;
    299 }
    300 
    301 static GdkPixbuf *
    302 resize_image(GdkPixbuf * pixbuf, int width, int height)
    303 {
    304     GdkPixbuf *resized_pixbuf;
    305     int w, h;
    306 
    307     if (pixbuf == NULL)
    308 	return NULL;
    309     w = gdk_pixbuf_get_width(pixbuf);
    310     h = gdk_pixbuf_get_height(pixbuf);
    311     if (width < 1 || height < 1)
    312 	return pixbuf;
    313     if (w == width && h == height)
    314 	return pixbuf;
    315     resized_pixbuf =
    316 	gdk_pixbuf_scale_simple(pixbuf, width, height, GDK_INTERP_BILINEAR);
    317     if (resized_pixbuf == NULL)
    318 	return NULL;
    319     return resized_pixbuf;
    320 }
    321 #endif
    322 
    323 static int
    324 x11_load_image(w3mimg_op * self, W3MImage * img, char *fname, int w, int h)
    325 {
    326     struct x11_info *xi;
    327 #if defined(USE_IMLIB)
    328     ImlibImage *im;
    329 #elif defined(USE_IMLIB2)
    330     Imlib_Image im;
    331 #elif defined(USE_GDKPIXBUF)
    332     GdkPixbufAnimation *animation;
    333     int j, iw, ih, n, frame_num, delay = -1, max_anim;
    334     double ratio_w, ratio_h;
    335     struct x11_image *ximg;
    336     Pixmap tmp_pixmap;
    337 #if defined(USE_GTK2)
    338     GdkPixbufAnimationIter *iter;
    339     GTimeVal time;
    340 #else
    341     int i;
    342     GList *frames;
    343 #endif
    344 #endif
    345 
    346     if (self == NULL)
    347 	return 0;
    348     xi = (struct x11_info *)self->priv;
    349     if (xi == NULL)
    350 	return 0;
    351 
    352 #if defined(USE_IMLIB)
    353     im = Imlib_load_image(xi->id, fname);
    354     if (!im)
    355 	return 0;
    356     if (w <= 0)
    357 	w = im->rgb_width;
    358     if (h <= 0)
    359 	h = im->rgb_height;
    360     img->pixmap = (void *)XCreatePixmap(xi->display, xi->parent, w, h,
    361 					DefaultDepth(xi->display, 0));
    362     if (!img->pixmap)
    363 	return 0;
    364     XSetForeground(xi->display, xi->imageGC, xi->background_pixel);
    365     XFillRectangle(xi->display, (Pixmap) img->pixmap, xi->imageGC, 0, 0, w, h);
    366     Imlib_paste_image(xi->id, im, (Pixmap) img->pixmap, 0, 0, w, h);
    367     Imlib_kill_image(xi->id, im);
    368 #elif defined(USE_IMLIB2)
    369     im = imlib_load_image(fname);
    370     if (!im)
    371 	return 0;
    372     imlib_context_set_image(im);
    373     if (w <= 0)
    374 	w = imlib_image_get_width();
    375     if (h <= 0)
    376 	h = imlib_image_get_height();
    377     img->pixmap = (void *)XCreatePixmap(xi->display, xi->parent, w, h,
    378 					DefaultDepth(xi->display, 0));
    379     if (!img->pixmap)
    380 	return 0;
    381     XSetForeground(xi->display, xi->imageGC, xi->background_pixel);
    382     XFillRectangle(xi->display, (Pixmap) img->pixmap, xi->imageGC, 0, 0, w, h);
    383     imlib_context_set_display(xi->display);
    384     imlib_context_set_visual(DefaultVisual(xi->display, 0));
    385     imlib_context_set_colormap(DefaultColormap(xi->display, 0));
    386     imlib_context_set_drawable((Drawable) img->pixmap);
    387     imlib_render_image_on_drawable_at_size(0, 0, w, h);
    388     imlib_free_image();
    389 #elif defined(USE_GDKPIXBUF)
    390     max_anim = self->max_anim;
    391 #if defined(USE_GTK2)
    392     animation = gdk_pixbuf_animation_new_from_file(fname, NULL);
    393 #else
    394     animation = gdk_pixbuf_animation_new_from_file(fname);
    395 #endif
    396     if (!animation)
    397 	return 0;
    398     frame_num = n = get_animation_size(animation, &iw, &ih, &delay);
    399     if (delay <= 0)
    400 	max_anim = -1;
    401 
    402     if (max_anim < 0) {
    403 	frame_num = (-max_anim > n) ? n : -max_anim;
    404     }
    405     else if (max_anim > 0) {
    406 	frame_num = n = (max_anim > n) ? n : max_anim;
    407     }
    408 
    409     if (w < 1 || h < 1) {
    410 	w = iw;
    411 	h = ih;
    412 	ratio_w = ratio_h = 1;
    413     }
    414     else {
    415 	ratio_w = 1.0 * w / iw;
    416 	ratio_h = 1.0 * h / ih;
    417     }
    418     tmp_pixmap = XCreatePixmap(xi->display, xi->parent, w, h,
    419 			       DefaultDepth(xi->display, 0));
    420     XSetForeground(xi->display, xi->imageGC, xi->background_pixel);
    421     XFillRectangle(xi->display, (Pixmap) tmp_pixmap, xi->imageGC, 0, 0, w, h);
    422     if (!tmp_pixmap) {
    423 #if defined(USE_GTK2)
    424 	g_object_unref(G_OBJECT(animation));
    425 #else
    426 	gdk_pixbuf_animation_unref(animation);
    427 #endif
    428 	return 0;
    429     }
    430     ximg = x11_img_new(xi, w, h, frame_num);
    431     if (!ximg) {
    432 	XFreePixmap(xi->display, tmp_pixmap);
    433 #if defined(USE_GTK2)
    434 	g_object_unref(G_OBJECT(animation));
    435 #else
    436 	gdk_pixbuf_animation_unref(animation);
    437 #endif
    438 	return 0;
    439     }
    440 #if defined(USE_GTK2)
    441     g_get_current_time(&time);
    442     iter = gdk_pixbuf_animation_get_iter(animation, &time);
    443 
    444    if (max_anim < 0 && n > -max_anim) {
    445 	max_anim = n + max_anim;
    446 	for (j = 0; j < max_anim; j++) {
    447 	    delay = gdk_pixbuf_animation_iter_get_delay_time(iter);
    448 	    g_time_val_add(&time, delay * 1000);
    449 	    gdk_pixbuf_animation_iter_advance(iter, &time);
    450 	}
    451     }
    452     for (j = 0; j < frame_num; j++) {
    453 	GdkPixbuf *org_pixbuf, *pixbuf;
    454 
    455 	org_pixbuf = gdk_pixbuf_animation_iter_get_pixbuf(iter);
    456 	delay = gdk_pixbuf_animation_iter_get_delay_time(iter);
    457 	pixbuf = resize_image(org_pixbuf, w, h);
    458 
    459 	if (delay > ximg->delay)
    460 	    ximg->delay = delay;
    461 
    462 	gdk_pixbuf_xlib_render_to_drawable_alpha(pixbuf,
    463 						 (Drawable) ximg->pixmap[j], 0,
    464 						 0, 0, 0, w, h,
    465 						 GDK_PIXBUF_ALPHA_BILEVEL, 1,
    466 						 XLIB_RGB_DITHER_NORMAL, 0, 0);
    467 	if (org_pixbuf != pixbuf)
    468 	    g_object_unref(G_OBJECT(pixbuf));
    469 	g_time_val_add(&time, delay * 1000);
    470 	gdk_pixbuf_animation_iter_advance(iter, &time);
    471     }
    472     XFreePixmap(xi->display, tmp_pixmap);
    473     g_object_unref(G_OBJECT(animation));
    474 
    475 #else
    476     frames = gdk_pixbuf_animation_get_frames(animation);
    477 
    478     for (j = 0; j < n; j++) {
    479 	GdkPixbufFrame *frame;
    480 	GdkPixbuf *org_pixbuf, *pixbuf;
    481 	int width, height, ofstx, ofsty;
    482 
    483 	if (max_anim < 0) {
    484 	    i = (j - n + frame_num > 0) ? (j - n + frame_num) : 0;
    485 	}
    486 	else {
    487 	    i = j;
    488 	}
    489 	frame = (GdkPixbufFrame *) g_list_nth_data(frames, j);
    490 	org_pixbuf = gdk_pixbuf_frame_get_pixbuf(frame);
    491 	ofstx = gdk_pixbuf_frame_get_x_offset(frame);
    492 	ofsty = gdk_pixbuf_frame_get_y_offset(frame);
    493 	delay = gdk_pixbuf_frame_get_delay_time(frame);
    494 	width = gdk_pixbuf_get_width(org_pixbuf);
    495 	height = gdk_pixbuf_get_height(org_pixbuf);
    496 
    497 	if (ofstx == 0 && ofsty == 0 && width == w && height == h) {
    498 	    pixbuf = resize_image(org_pixbuf, w, h);
    499 	}
    500 	else {
    501 	    pixbuf =
    502 		resize_image(org_pixbuf, width * ratio_w, height * ratio_h);
    503 	    ofstx *= ratio_w;
    504 	    ofsty *= ratio_h;
    505 	}
    506 	width = gdk_pixbuf_get_width(pixbuf);
    507 	height = gdk_pixbuf_get_height(pixbuf);
    508 
    509 	if (delay > ximg->delay)
    510 	    ximg->delay = delay;
    511 
    512 	XCopyArea(xi->display, tmp_pixmap, ximg->pixmap[i],
    513 		  xi->imageGC, 0, 0, w, h, 0, 0);
    514 	gdk_pixbuf_xlib_render_to_drawable_alpha(pixbuf,
    515 						 (Drawable) ximg->pixmap[i], 0,
    516 						 0, ofstx, ofsty, width,
    517 						 height,
    518 						 GDK_PIXBUF_ALPHA_BILEVEL, 1,
    519 						 XLIB_RGB_DITHER_NORMAL, 0, 0);
    520 
    521 	switch (gdk_pixbuf_frame_get_action(frame)) {
    522 	case GDK_PIXBUF_FRAME_RETAIN:
    523 	    XCopyArea(xi->display, ximg->pixmap[i], tmp_pixmap,
    524 		      xi->imageGC, 0, 0, w, h, 0, 0);
    525 	    break;
    526 	case GDK_PIXBUF_FRAME_DISPOSE:
    527 	    XSetForeground(xi->display, xi->imageGC, xi->background_pixel);
    528 	    XFillRectangle(xi->display, tmp_pixmap, xi->imageGC,
    529 			   0, 0, w, h);
    530 	    break;
    531 	case GDK_PIXBUF_FRAME_REVERT:
    532 	    XCopyArea(xi->display, ximg->pixmap[0], tmp_pixmap,
    533 		      xi->imageGC, 0, 0, w, h, 0, 0);
    534 	    break;
    535 	default:
    536 	    XCopyArea(xi->display, ximg->pixmap[0], tmp_pixmap,
    537 		      xi->imageGC, 0, 0, w, h, 0, 0);
    538 	    break;
    539 	}
    540 
    541 
    542 	if (org_pixbuf != pixbuf)
    543 	    gdk_pixbuf_finalize(pixbuf);
    544 
    545     }
    546     XFreePixmap(xi->display, tmp_pixmap);
    547     gdk_pixbuf_animation_unref(animation);
    548 #endif
    549     img->pixmap = ximg;
    550 #endif
    551 
    552     img->width = w;
    553     img->height = h;
    554     return 1;
    555 }
    556 
    557 static int
    558 x11_show_image(w3mimg_op * self, W3MImage * img, int sx, int sy, int sw,
    559 	       int sh, int x, int y)
    560 {
    561     struct x11_info *xi;
    562 #if defined(USE_GDKPIXBUF)
    563     struct x11_image *ximg = img->pixmap;
    564     int i;
    565 #endif
    566     if (self == NULL)
    567 	return 0;
    568 
    569     if (img->pixmap == NULL)
    570 	return 0;
    571 
    572     xi = (struct x11_info *)self->priv;
    573     if (xi == NULL)
    574 	return 0;
    575 
    576 #if defined(USE_IMLIB) || defined(USE_IMLIB2)
    577     XCopyArea(xi->display, (Pixmap) img->pixmap, xi->window, xi->imageGC,
    578 	      sx, sy,
    579 	      (sw ? sw : img->width),
    580 	      (sh ? sh : img->height), x + self->offset_x, y + self->offset_y);
    581 #elif defined(USE_GDKPIXBUF)
    582 #define WAIT_CNT 4
    583     if (ximg->delay <= 0)
    584 	i = ximg->total - 1;
    585     else
    586 	i = ximg->no;
    587     XCopyArea(xi->display, ximg->pixmap[i], xi->window, xi->imageGC,
    588 	      sx, sy,
    589 	      (sw ? sw : img->width),
    590 	      (sh ? sh : img->height), x + self->offset_x, y + self->offset_y);
    591     if (ximg->total > 1) {
    592 	if (ximg->wait > WAIT_CNT) {
    593 	    ximg->wait = 0;
    594 	    if (i < ximg->total - 1)
    595 		ximg->no = i + 1;
    596 	    else
    597 		ximg->no = 0;
    598 	}
    599 	ximg->wait += 1;
    600     }
    601 #endif
    602     return 1;
    603 }
    604 
    605 static void
    606 x11_free_image(w3mimg_op * self, W3MImage * img)
    607 {
    608     struct x11_info *xi;
    609     if (self == NULL)
    610 	return;
    611     xi = (struct x11_info *)self->priv;
    612     if (xi == NULL)
    613 	return;
    614 #if defined(USE_IMLIB) || defined(USE_IMLIB2)
    615     if (img && img->pixmap) {
    616 	XFreePixmap(xi->display, (Pixmap) img->pixmap);
    617 	img->pixmap = NULL;
    618 	img->width = 0;
    619 	img->height = 0;
    620     }
    621 #elif defined(USE_GDKPIXBUF)
    622     if (img && img->pixmap) {
    623 	struct x11_image *ximg = img->pixmap;
    624 	int i, n;
    625 	if (ximg->pixmap) {
    626 	    n = ximg->total;
    627 	    for (i = 0; i < n; i++) {
    628 		if (ximg->pixmap[i])
    629 		    XFreePixmap(xi->display, (Pixmap) ximg->pixmap[i]);
    630 	    }
    631 	    free(ximg->pixmap);
    632 	}
    633 	free(ximg);
    634 	img->pixmap = NULL;
    635 	img->width = 0;
    636 	img->height = 0;
    637     }
    638 #endif
    639 }
    640 
    641 static int
    642 x11_get_image_size(w3mimg_op * self, W3MImage * img, char *fname, int *w,
    643 		   int *h)
    644 {
    645     struct x11_info *xi;
    646 #if defined(USE_IMLIB)
    647     ImlibImage *im;
    648 #elif defined(USE_IMLIB2)
    649     Imlib_Image im;
    650 #elif defined(USE_GDKPIXBUF)
    651     GdkPixbufAnimation *animation;
    652 #endif
    653 
    654     if (self == NULL)
    655 	return 0;
    656     xi = (struct x11_info *)self->priv;
    657     if (xi == NULL)
    658 	return 0;
    659 
    660 #if defined(USE_IMLIB)
    661     im = Imlib_load_image(xi->id, fname);
    662     if (!im)
    663 	return 0;
    664 
    665     *w = im->rgb_width;
    666     *h = im->rgb_height;
    667     Imlib_kill_image(xi->id, im);
    668 #elif defined(USE_IMLIB2)
    669     im = imlib_load_image(fname);
    670     if (im == NULL)
    671 	return 0;
    672 
    673     imlib_context_set_image(im);
    674     *w = imlib_image_get_width();
    675     *h = imlib_image_get_height();
    676     imlib_free_image();
    677 #elif defined(USE_GDKPIXBUF)
    678 #if defined(USE_GTK2)
    679     animation = gdk_pixbuf_animation_new_from_file(fname, NULL);
    680 #else
    681     animation = gdk_pixbuf_animation_new_from_file(fname);
    682 #endif
    683     if (!animation)
    684 	return 0;
    685 
    686     get_animation_size(animation, w, h, NULL);
    687 #if defined(USE_GTK2)
    688     g_object_unref(G_OBJECT(animation));
    689 #else
    690     gdk_pixbuf_animation_unref(animation);
    691 #endif
    692 #endif
    693     return 1;
    694 }
    695 
    696 /* *INDENT-OFF* */
    697 /*
    698   xterm/kterm/hanterm/cxterm
    699     top window (WINDOWID)
    700       +- text window
    701            +- scrollbar
    702   rxvt/aterm/Eterm/wterm
    703     top window (WINDOWID)
    704       +- text window
    705       +- scrollbar
    706       +- menubar (etc.)
    707   gnome-terminal
    708     top window
    709       +- text window (WINDOWID)
    710       +- scrollbar
    711       +- menubar
    712   mlterm (-s)
    713     top window
    714       +- text window (WINDOWID)
    715       +- scrollbar
    716   mlterm
    717     top window = text window (WINDOWID)
    718 
    719   powershell
    720     top window
    721       +- window
    722       |    +- text window
    723       |    +- scrollbar
    724       +- menubar (etc.)
    725   dtterm
    726     top window
    727       +- window
    728            +- window
    729            |    +- window
    730            |         +- text window
    731            |         +- scrollbar
    732            +- menubar
    733   hpterm
    734     top window
    735       +- window
    736            +- text window
    737            +- scrollbar
    738            +- (etc.)
    739 */
    740 /* *INDENT-ON* */
    741 
    742 w3mimg_op *
    743 w3mimg_x11open()
    744 {
    745     w3mimg_op *wop = NULL;
    746     struct x11_info *xi = NULL;
    747     char *id;
    748     int revert, i;
    749     unsigned int nchildren;
    750     XWindowAttributes attr;
    751     Window root, *children;
    752 
    753     wop = (w3mimg_op *) malloc(sizeof(w3mimg_op));
    754     if (wop == NULL)
    755 	return NULL;
    756     memset(wop, 0, sizeof(w3mimg_op));
    757 
    758     xi = (struct x11_info *)malloc(sizeof(struct x11_info));
    759     if (xi == NULL)
    760 	goto error;
    761     memset(xi, 0, sizeof(struct x11_info));
    762 
    763     xi->display = XOpenDisplay(NULL);
    764     if (xi->display == NULL) {
    765 	goto error;
    766     }
    767     if ((id = getenv("WINDOWID")) != NULL)
    768 	xi->window = (Window) atoi(id);
    769     else
    770 	XGetInputFocus(xi->display, &xi->window, &revert);
    771     if (!xi->window)
    772 	exit(1);
    773 
    774     XGetWindowAttributes(xi->display, xi->window, &attr);
    775     wop->width = attr.width;
    776     wop->height = attr.height;
    777 
    778     while (1) {
    779 	Window p_window;
    780 
    781 	XQueryTree(xi->display, xi->window, &root, &xi->parent,
    782 		   &children, &nchildren);
    783 	p_window = xi->window;
    784 	for (i = 0; i < nchildren; i++) {
    785 	    XGetWindowAttributes(xi->display, children[i], &attr);
    786 	    if (attr.width > wop->width * 0.7 &&
    787 		attr.height > wop->height * 0.7) {
    788 		/* maybe text window */
    789 		wop->width = attr.width;
    790 		wop->height = attr.height;
    791 		xi->window = children[i];
    792 	    }
    793 	}
    794 	if (p_window == xi->window)
    795 	    break;
    796     }
    797     wop->offset_x = OFFSET_X;
    798     for (i = 0; i < nchildren; i++) {
    799 	XGetWindowAttributes(xi->display, children[i], &attr);
    800 	if (attr.x <= 0 && attr.width < 30 && attr.height > wop->height * 0.7) {
    801 	    /* scrollbar of xterm/kterm ? */
    802 	    wop->offset_x += attr.x + attr.width + attr.border_width * 2;
    803 	    break;
    804 	}
    805     }
    806     wop->offset_y = OFFSET_Y;
    807 
    808     wop->priv = xi;
    809 
    810     wop->init = x11_init;
    811     wop->finish = x11_finish;
    812     wop->active = x11_active;
    813     wop->set_background = x11_set_background;
    814     wop->sync = x11_sync;
    815     wop->close = x11_close;
    816     wop->clear = x11_clear;
    817 
    818     wop->load_image = x11_load_image;
    819     wop->show_image = x11_show_image;
    820     wop->free_image = x11_free_image;
    821     wop->get_image_size = x11_get_image_size;
    822 
    823     return wop;
    824   error:
    825     if (xi)
    826 	free(xi);
    827     free(wop);
    828     return NULL;
    829 }