1 /* $Id: x11_w3mimg.c,v 1.29 2004/11/08 17:14:06 ukai Exp $ */
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-pixbuf/gdk-pixbuf.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
get_animation_size(GdkPixbufAnimation * animation,int * w,int * h,int * delay)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
get_animation_size(GdkPixbufAnimation * animation,int * w,int * h,int * delay)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
x11_init(w3mimg_op * self)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 defined(USE_IMLIB)
125     if (xi == NULL)
126 	return 0;
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) {
134 #if defined(USE_GTK2)
135 	g_type_init();
136 #endif
137     }
138     else if (!xi->init_flag) {
139 	XWindowAttributes attr;
140 #if defined(USE_GTK2)
141 	g_type_init();
142 #endif
143 	XGetWindowAttributes(xi->display, xi->parent, &attr);
144 	/* gdk_pixbuf_xlib_init_with_depth() ignores depth, sigh... */
145 	gdk_pixbuf_xlib_init_with_depth(xi->display, 0, attr.depth);
146 	xi->init_flag = TRUE;
147     }
148 #endif
149     if (xi && !xi->imageGC) {
150 	xi->imageGC = XCreateGC(xi->display, xi->parent, 0, NULL);
151 	if (!xi->imageGC)
152 	    return 0;
153     }
154     return 1;
155 }
156 
157 static int
x11_finish(w3mimg_op * self)158 x11_finish(w3mimg_op * self)
159 {
160     struct x11_info *xi;
161     if (self == NULL)
162 	return 0;
163     xi = (struct x11_info *)self->priv;
164     if (xi == NULL)
165 	return 0;
166     if (xi->imageGC) {
167 	XFreeGC(xi->display, xi->imageGC);
168 	xi->imageGC = NULL;
169     }
170     return 1;
171 }
172 
173 static int
x11_clear(w3mimg_op * self,int x,int y,int w,int h)174 x11_clear(w3mimg_op * self, int x, int y, int w, int h)
175 {
176     struct x11_info *xi;
177     if (self == NULL)
178 	return 0;
179     xi = (struct x11_info *)self->priv;
180     if (xi == NULL)
181 	return 0;
182 
183     if (x < 0)
184 	x = 0;
185     if (y < 0)
186 	y = 0;
187 
188     XClearArea(xi->display, xi->window, x, y, w, h, False);
189     return 1;
190 }
191 
192 static int
x11_active(w3mimg_op * self)193 x11_active(w3mimg_op * self)
194 {
195     struct x11_info *xi;
196     if (self == NULL)
197 	return 0;
198     xi = (struct x11_info *)self->priv;
199     if (xi == NULL)
200 	return 0;
201     if (!xi->imageGC)
202 	return 0;
203     return 1;
204 }
205 
206 static void
x11_set_background(w3mimg_op * self,char * background)207 x11_set_background(w3mimg_op * self, char *background)
208 {
209     XColor screen_def, exact_def;
210     struct x11_info *xi;
211     XWindowAttributes attr;
212     if (self == NULL)
213 	return;
214     xi = (struct x11_info *)self->priv;
215     if (xi == NULL)
216 	return;
217 
218     XGetWindowAttributes(xi->display, xi->window, &attr);
219     if (background &&
220 	XAllocNamedColor(xi->display, attr.colormap,
221 			 background, &screen_def, &exact_def))
222 	xi->background_pixel = screen_def.pixel;
223     else {
224 	Pixmap p;
225 	GC gc;
226 	XImage *i;
227 
228 	p = XCreatePixmap(xi->display, xi->window, 1, 1,
229 			  attr.depth);
230 	gc = XCreateGC(xi->display, xi->window, 0, NULL);
231 	if (!p || !gc)
232 	    exit(1);		/* XXX */
233 	XCopyArea(xi->display, xi->window, p, gc,
234 		  (self->offset_x >= 1) ? (self->offset_x - 1) : 0,
235 		  (self->offset_y >= 1) ? (self->offset_y - 1) : 0,
236 		  1, 1, 0, 0);
237 	i = XGetImage(xi->display, p, 0, 0, 1, 1, -1, ZPixmap);
238 	if (!i)
239 	    exit(1);
240 	xi->background_pixel = XGetPixel(i, 0, 0);
241 	XDestroyImage(i);
242 	XFreeGC(xi->display, gc);
243 	XFreePixmap(xi->display, p);
244     }
245 }
246 
247 static void
x11_sync(w3mimg_op * self)248 x11_sync(w3mimg_op * self)
249 {
250     struct x11_info *xi;
251     if (self == NULL)
252 	return;
253     xi = (struct x11_info *)self->priv;
254     if (xi == NULL)
255 	return;
256     XSync(xi->display, False);
257 }
258 
259 static void
x11_close(w3mimg_op * self)260 x11_close(w3mimg_op * self)
261 {
262     /* XCloseDisplay(xi->display); */
263 }
264 
265 #if defined(USE_GDKPIXBUF)
266 static struct x11_image *
x11_img_new(struct x11_info * xi,int w,int h,int n)267 x11_img_new(struct x11_info *xi, int w, int h, int n)
268 {
269     struct x11_image *img = NULL;
270     int i;
271     XWindowAttributes attr;
272 
273     img = malloc(sizeof(*img));
274     if (!img)
275 	goto ERROR;
276 
277     img->pixmap = calloc(n, sizeof(*(img->pixmap)));
278     if (!img->pixmap)
279 	goto ERROR;
280 
281     XGetWindowAttributes(xi->display, xi->window, &attr);
282     for (i = 0; i < n; i++) {
283 	img->pixmap[i] = XCreatePixmap(xi->display, xi->parent, w, h,
284 				       attr.depth);
285 	if (!img->pixmap[i])
286 	    goto ERROR;
287 
288 	XSetForeground(xi->display, xi->imageGC, xi->background_pixel);
289 	XFillRectangle(xi->display, (Pixmap) img->pixmap[i], xi->imageGC, 0, 0,
290 		       w, h);
291     }
292 
293     img->no = 0;
294     img->total = n;
295     img->wait = 0;
296     img->delay = -1;
297 
298     return img;
299   ERROR:
300     if (img) {
301 	if (img->pixmap) {
302 	    for (i = 0; i < n; i++) {
303 		if (img->pixmap[i])
304 		    XFreePixmap(xi->display, (Pixmap) img->pixmap[i]);
305 	    }
306 	    free(img->pixmap);
307 	}
308 	free(img);
309     }
310     return NULL;
311 }
312 
313 static GdkPixbuf *
resize_image(GdkPixbuf * pixbuf,int width,int height)314 resize_image(GdkPixbuf * pixbuf, int width, int height)
315 {
316     GdkPixbuf *resized_pixbuf;
317     int w, h;
318 
319     if (pixbuf == NULL)
320 	return NULL;
321     w = gdk_pixbuf_get_width(pixbuf);
322     h = gdk_pixbuf_get_height(pixbuf);
323     if (width < 1 || height < 1)
324 	return pixbuf;
325     if (w == width && h == height)
326 	return pixbuf;
327     resized_pixbuf =
328 	gdk_pixbuf_scale_simple(pixbuf, width, height, GDK_INTERP_BILINEAR);
329     if (resized_pixbuf == NULL)
330 	return NULL;
331     return resized_pixbuf;
332 }
333 
334 #if defined(USE_GTK2)
335 static void
render_pixbuf_to_pixmap_32(Display * display,GC gc,Pixmap pixmap,GdkPixbuf * pixbuf)336 render_pixbuf_to_pixmap_32(Display *display, GC gc, Pixmap pixmap, GdkPixbuf *  pixbuf)
337 {
338     unsigned int x, y, width, height, rowstride, bytes_per_pixel;
339     unsigned char *line;
340     XImage *image;
341 
342     width = gdk_pixbuf_get_width(pixbuf) ;
343     height = gdk_pixbuf_get_height(pixbuf) ;
344 
345     if (!(image = XGetImage(display, pixmap, 0, 0, width, height, AllPlanes, ZPixmap)))
346 	return ;
347 
348     bytes_per_pixel = (gdk_pixbuf_get_has_alpha(pixbuf)) ? 4 : 3;
349     rowstride = gdk_pixbuf_get_rowstride(pixbuf);
350     line = gdk_pixbuf_get_pixels(pixbuf);
351 
352     for (y = 0; y < height; y++) {
353 	u_char *pixel;
354 
355 	pixel = line;
356 	for (x = 0; x < width; x++) {
357 	    XPutPixel(image, x, y,
358 		(pixel[0] <<16) | (pixel[1] <<8) | pixel[2] | 0xff000000);
359 	    pixel += bytes_per_pixel;
360 	}
361 	line += rowstride;
362     }
363 
364     XPutImage(display, pixmap, gc, image, 0, 0, 0, 0, width, height);
365     XDestroyImage(image);
366 }
367 #endif
368 #endif
369 
370 static int
x11_load_image(w3mimg_op * self,W3MImage * img,char * fname,int w,int h)371 x11_load_image(w3mimg_op * self, W3MImage * img, char *fname, int w, int h)
372 {
373     struct x11_info *xi;
374 #if defined(USE_IMLIB)
375     ImlibImage *im;
376 #elif defined(USE_IMLIB2)
377     Imlib_Image im;
378 #elif defined(USE_GDKPIXBUF)
379     GdkPixbufAnimation *animation;
380     int j, iw, ih, n, frame_num, delay = -1, max_anim;
381     double ratio_w, ratio_h;
382     struct x11_image *ximg;
383     Pixmap tmp_pixmap;
384 #if defined(USE_GTK2)
385     GdkPixbufAnimationIter *iter;
386     GTimeVal time;
387 #else
388     int i;
389     GList *frames;
390 #endif
391 #endif
392     XWindowAttributes attr;
393 
394     if (self == NULL)
395 	return 0;
396     xi = (struct x11_info *)self->priv;
397     if (xi == NULL)
398 	return 0;
399 
400     XGetWindowAttributes(xi->display, xi->window, &attr);
401 #if defined(USE_IMLIB)
402     im = Imlib_load_image(xi->id, fname);
403     if (!im)
404 	return 0;
405     if (w <= 0)
406 	w = im->rgb_width;
407     if (h <= 0)
408 	h = im->rgb_height;
409     img->pixmap = (void *)XCreatePixmap(xi->display, xi->parent, w, h,
410 					attr.depth);
411     if (!img->pixmap)
412 	return 0;
413     XSetForeground(xi->display, xi->imageGC, xi->background_pixel);
414     XFillRectangle(xi->display, (Pixmap) img->pixmap, xi->imageGC, 0, 0, w, h);
415     Imlib_paste_image(xi->id, im, (Pixmap) img->pixmap, 0, 0, w, h);
416     Imlib_kill_image(xi->id, im);
417 #elif defined(USE_IMLIB2)
418     im = imlib_load_image(fname);
419     if (!im)
420 	return 0;
421     imlib_context_set_image(im);
422     if (w <= 0)
423 	w = imlib_image_get_width();
424     if (h <= 0)
425 	h = imlib_image_get_height();
426 
427     im = imlib_create_cropped_scaled_image(0, 0, imlib_image_get_width(), imlib_image_get_height(), w, h);
428     imlib_context_set_image(im);
429 
430     img->pixmap = (void *)XCreatePixmap(xi->display, xi->parent, w, h,
431 					attr.depth);
432     if (!img->pixmap)
433 	return 0;
434     XSetForeground(xi->display, xi->imageGC, xi->background_pixel);
435     XFillRectangle(xi->display, (Pixmap) img->pixmap, xi->imageGC, 0, 0, w, h);
436     imlib_context_set_display(xi->display);
437     imlib_context_set_visual(attr.visual);
438     imlib_context_set_colormap(attr.colormap);
439     imlib_context_set_drawable((Drawable) img->pixmap);
440     imlib_render_image_on_drawable(0, 0);
441     imlib_free_image();
442 #elif defined(USE_GDKPIXBUF)
443     max_anim = self->max_anim;
444 #if defined(USE_GTK2)
445     animation = gdk_pixbuf_animation_new_from_file(fname, NULL);
446 #else
447     animation = gdk_pixbuf_animation_new_from_file(fname);
448 #endif
449     if (!animation)
450 	return 0;
451     frame_num = n = get_animation_size(animation, &iw, &ih, &delay);
452     if (delay <= 0)
453 	max_anim = -1;
454 
455     if (max_anim < 0) {
456 	frame_num = (-max_anim > n) ? n : -max_anim;
457     }
458     else if (max_anim > 0) {
459 	frame_num = n = (max_anim > n) ? n : max_anim;
460     }
461 
462     if (w < 1 || h < 1) {
463 	w = iw;
464 	h = ih;
465 	ratio_w = ratio_h = 1;
466     }
467     else {
468 	ratio_w = 1.0 * w / iw;
469 	ratio_h = 1.0 * h / ih;
470     }
471     tmp_pixmap = XCreatePixmap(xi->display, xi->parent, w, h,
472 			       attr.depth);
473     XSetForeground(xi->display, xi->imageGC, xi->background_pixel);
474     XFillRectangle(xi->display, (Pixmap) tmp_pixmap, xi->imageGC, 0, 0, w, h);
475     if (!tmp_pixmap) {
476 #if defined(USE_GTK2)
477 	g_object_unref(G_OBJECT(animation));
478 #else
479 	gdk_pixbuf_animation_unref(animation);
480 #endif
481 	return 0;
482     }
483     ximg = x11_img_new(xi, w, h, frame_num);
484     if (!ximg) {
485 	XFreePixmap(xi->display, tmp_pixmap);
486 #if defined(USE_GTK2)
487 	g_object_unref(G_OBJECT(animation));
488 #else
489 	gdk_pixbuf_animation_unref(animation);
490 #endif
491 	return 0;
492     }
493 #if defined(USE_GTK2)
494     g_get_current_time(&time);
495     iter = gdk_pixbuf_animation_get_iter(animation, &time);
496 
497    if (max_anim < 0 && n > -max_anim) {
498 	max_anim = n + max_anim;
499 	for (j = 0; j < max_anim; j++) {
500 	    delay = gdk_pixbuf_animation_iter_get_delay_time(iter);
501 	    g_time_val_add(&time, delay * 1000);
502 	    gdk_pixbuf_animation_iter_advance(iter, &time);
503 	}
504     }
505     for (j = 0; j < frame_num; j++) {
506 	GdkPixbuf *org_pixbuf, *pixbuf;
507 
508 	org_pixbuf = gdk_pixbuf_animation_iter_get_pixbuf(iter);
509 	delay = gdk_pixbuf_animation_iter_get_delay_time(iter);
510 	pixbuf = resize_image(org_pixbuf, w, h);
511 
512 	if (delay > ximg->delay)
513 	    ximg->delay = delay;
514 
515 	if (attr.depth == 32)
516 	    render_pixbuf_to_pixmap_32(xi->display, xi->imageGC, ximg->pixmap[j], pixbuf);
517 	else
518 	    gdk_pixbuf_xlib_render_to_drawable_alpha(pixbuf,
519 						 (Drawable) ximg->pixmap[j], 0,
520 						 0, 0, 0, w, h,
521 						 GDK_PIXBUF_ALPHA_BILEVEL, 1,
522 						 XLIB_RGB_DITHER_NORMAL, 0, 0);
523 	if (org_pixbuf != pixbuf)
524 	    g_object_unref(G_OBJECT(pixbuf));
525 	g_time_val_add(&time, delay * 1000);
526 	gdk_pixbuf_animation_iter_advance(iter, &time);
527     }
528     XFreePixmap(xi->display, tmp_pixmap);
529     g_object_unref(G_OBJECT(animation));
530 
531 #else
532     frames = gdk_pixbuf_animation_get_frames(animation);
533 
534     for (j = 0; j < n; j++) {
535 	GdkPixbufFrame *frame;
536 	GdkPixbuf *org_pixbuf, *pixbuf;
537 	int width, height, ofstx, ofsty;
538 
539 	if (max_anim < 0) {
540 	    i = (j - n + frame_num > 0) ? (j - n + frame_num) : 0;
541 	}
542 	else {
543 	    i = j;
544 	}
545 	frame = (GdkPixbufFrame *) g_list_nth_data(frames, j);
546 	org_pixbuf = gdk_pixbuf_frame_get_pixbuf(frame);
547 	ofstx = gdk_pixbuf_frame_get_x_offset(frame);
548 	ofsty = gdk_pixbuf_frame_get_y_offset(frame);
549 	delay = gdk_pixbuf_frame_get_delay_time(frame);
550 	width = gdk_pixbuf_get_width(org_pixbuf);
551 	height = gdk_pixbuf_get_height(org_pixbuf);
552 
553 	if (ofstx == 0 && ofsty == 0 && width == w && height == h) {
554 	    pixbuf = resize_image(org_pixbuf, w, h);
555 	}
556 	else {
557 	    pixbuf =
558 		resize_image(org_pixbuf, width * ratio_w, height * ratio_h);
559 	    ofstx *= ratio_w;
560 	    ofsty *= ratio_h;
561 	}
562 	width = gdk_pixbuf_get_width(pixbuf);
563 	height = gdk_pixbuf_get_height(pixbuf);
564 
565 	if (delay > ximg->delay)
566 	    ximg->delay = delay;
567 
568 	XCopyArea(xi->display, tmp_pixmap, ximg->pixmap[i],
569 		  xi->imageGC, 0, 0, w, h, 0, 0);
570 	gdk_pixbuf_xlib_render_to_drawable_alpha(pixbuf,
571 						 (Drawable) ximg->pixmap[i], 0,
572 						 0, ofstx, ofsty, width,
573 						 height,
574 						 GDK_PIXBUF_ALPHA_BILEVEL, 1,
575 						 XLIB_RGB_DITHER_NORMAL, 0, 0);
576 
577 	switch (gdk_pixbuf_frame_get_action(frame)) {
578 	case GDK_PIXBUF_FRAME_RETAIN:
579 	    XCopyArea(xi->display, ximg->pixmap[i], tmp_pixmap,
580 		      xi->imageGC, 0, 0, w, h, 0, 0);
581 	    break;
582 	case GDK_PIXBUF_FRAME_DISPOSE:
583 	    XSetForeground(xi->display, xi->imageGC, xi->background_pixel);
584 	    XFillRectangle(xi->display, tmp_pixmap, xi->imageGC,
585 			   0, 0, w, h);
586 	    break;
587 	case GDK_PIXBUF_FRAME_REVERT:
588 	    XCopyArea(xi->display, ximg->pixmap[0], tmp_pixmap,
589 		      xi->imageGC, 0, 0, w, h, 0, 0);
590 	    break;
591 	default:
592 	    XCopyArea(xi->display, ximg->pixmap[0], tmp_pixmap,
593 		      xi->imageGC, 0, 0, w, h, 0, 0);
594 	    break;
595 	}
596 
597 
598 	if (org_pixbuf != pixbuf)
599 	    gdk_pixbuf_finalize(pixbuf);
600 
601     }
602     XFreePixmap(xi->display, tmp_pixmap);
603     gdk_pixbuf_animation_unref(animation);
604 #endif
605     img->pixmap = ximg;
606 #endif
607 
608     img->width = w;
609     img->height = h;
610     return 1;
611 }
612 
613 static int
x11_show_image(w3mimg_op * self,W3MImage * img,int sx,int sy,int sw,int sh,int x,int y)614 x11_show_image(w3mimg_op * self, W3MImage * img, int sx, int sy, int sw,
615 	       int sh, int x, int y)
616 {
617     struct x11_info *xi;
618 #if defined(USE_GDKPIXBUF)
619     struct x11_image *ximg = img->pixmap;
620     int i;
621 #endif
622     if (self == NULL)
623 	return 0;
624 
625     if (img->pixmap == NULL)
626 	return 0;
627 
628     xi = (struct x11_info *)self->priv;
629     if (xi == NULL)
630 	return 0;
631 
632 #if defined(USE_IMLIB) || defined(USE_IMLIB2)
633     XCopyArea(xi->display, (Pixmap) img->pixmap, xi->window, xi->imageGC,
634 	      sx, sy,
635 	      (sw ? sw : img->width),
636 	      (sh ? sh : img->height), x + self->offset_x, y + self->offset_y);
637 #elif defined(USE_GDKPIXBUF)
638 #define WAIT_CNT 4
639     if (ximg->delay <= 0)
640 	i = ximg->total - 1;
641     else
642 	i = ximg->no;
643     XCopyArea(xi->display, ximg->pixmap[i], xi->window, xi->imageGC,
644 	      sx, sy,
645 	      (sw ? sw : img->width),
646 	      (sh ? sh : img->height), x + self->offset_x, y + self->offset_y);
647     if (ximg->total > 1) {
648 	if (ximg->wait > WAIT_CNT) {
649 	    ximg->wait = 0;
650 	    if (i < ximg->total - 1)
651 		ximg->no = i + 1;
652 	    else
653 		ximg->no = 0;
654 	}
655 	ximg->wait += 1;
656     }
657 #endif
658     return 1;
659 }
660 
661 static void
x11_free_image(w3mimg_op * self,W3MImage * img)662 x11_free_image(w3mimg_op * self, W3MImage * img)
663 {
664     struct x11_info *xi;
665     if (self == NULL)
666 	return;
667     xi = (struct x11_info *)self->priv;
668     if (xi == NULL)
669 	return;
670 #if defined(USE_IMLIB) || defined(USE_IMLIB2)
671     if (img && img->pixmap) {
672 	XFreePixmap(xi->display, (Pixmap) img->pixmap);
673 	img->pixmap = NULL;
674 	img->width = 0;
675 	img->height = 0;
676     }
677 #elif defined(USE_GDKPIXBUF)
678     if (img && img->pixmap) {
679 	struct x11_image *ximg = img->pixmap;
680 	int i, n;
681 	if (ximg->pixmap) {
682 	    n = ximg->total;
683 	    for (i = 0; i < n; i++) {
684 		if (ximg->pixmap[i])
685 		    XFreePixmap(xi->display, (Pixmap) ximg->pixmap[i]);
686 	    }
687 	    free(ximg->pixmap);
688 	}
689 	free(ximg);
690 	img->pixmap = NULL;
691 	img->width = 0;
692 	img->height = 0;
693     }
694 #endif
695 }
696 
697 static int
x11_get_image_size(w3mimg_op * self,W3MImage * img,char * fname,int * w,int * h)698 x11_get_image_size(w3mimg_op * self, W3MImage * img, char *fname, int *w,
699 		   int *h)
700 {
701     struct x11_info *xi;
702 #if defined(USE_IMLIB)
703     ImlibImage *im;
704 #elif defined(USE_IMLIB2)
705     Imlib_Image im;
706 #elif defined(USE_GDKPIXBUF)
707     GdkPixbufAnimation *animation;
708 #endif
709 
710     if (self == NULL)
711 	return 0;
712 #if defined(USE_IMLIB) && defined(USE_IMLIB2)
713     xi = (struct x11_info *)self->priv;
714     if (xi == NULL)
715 	return 0;
716 #endif
717 
718 #if defined(USE_IMLIB)
719     im = Imlib_load_image(xi->id, fname);
720     if (!im)
721 	return 0;
722 
723     *w = im->rgb_width;
724     *h = im->rgb_height;
725     Imlib_kill_image(xi->id, im);
726 #elif defined(USE_IMLIB2)
727     im = imlib_load_image(fname);
728     if (im == NULL)
729 	return 0;
730 
731     imlib_context_set_image(im);
732     *w = imlib_image_get_width();
733     *h = imlib_image_get_height();
734     imlib_free_image();
735 #elif defined(USE_GDKPIXBUF)
736 #if defined(USE_GTK2)
737     animation = gdk_pixbuf_animation_new_from_file(fname, NULL);
738 #else
739     animation = gdk_pixbuf_animation_new_from_file(fname);
740 #endif
741     if (!animation)
742 	return 0;
743 
744     get_animation_size(animation, w, h, NULL);
745 #if defined(USE_GTK2)
746     g_object_unref(G_OBJECT(animation));
747 #else
748     gdk_pixbuf_animation_unref(animation);
749 #endif
750 #endif
751     return 1;
752 }
753 
754 /* *INDENT-OFF* */
755 /*
756   xterm/kterm/hanterm/cxterm
757     top window (WINDOWID)
758       +- text window
759            +- scrollbar
760   rxvt/aterm/Eterm/wterm
761     top window (WINDOWID)
762       +- text window
763       +- scrollbar
764       +- menubar (etc.)
765   gnome-terminal
766     top window
767       +- text window (WINDOWID)
768       +- scrollbar
769       +- menubar
770   mlterm (-s)
771     top window
772       +- text window (WINDOWID)
773       +- scrollbar
774   mlterm
775     top window = text window (WINDOWID)
776 
777   powershell
778     top window
779       +- window
780       |    +- text window
781       |    +- scrollbar
782       +- menubar (etc.)
783   dtterm
784     top window
785       +- window
786            +- window
787            |    +- window
788            |         +- text window
789            |         +- scrollbar
790            +- menubar
791   hpterm
792     top window
793       +- window
794            +- text window
795            +- scrollbar
796            +- (etc.)
797 */
798 /* *INDENT-ON* */
799 
800 w3mimg_op *
w3mimg_x11open()801 w3mimg_x11open()
802 {
803     w3mimg_op *wop = NULL;
804     struct x11_info *xi = NULL;
805     char *id;
806     int revert, i;
807     unsigned int nchildren;
808     XWindowAttributes attr;
809     Window root, *children;
810 
811     wop = (w3mimg_op *) malloc(sizeof(w3mimg_op));
812     if (wop == NULL)
813 	return NULL;
814     memset(wop, 0, sizeof(w3mimg_op));
815 
816     if (getenv("W3M_USE_REMOTE_IMAGE"))
817 	goto  end;
818 
819     xi = (struct x11_info *)malloc(sizeof(struct x11_info));
820     if (xi == NULL)
821 	goto error;
822     memset(xi, 0, sizeof(struct x11_info));
823 
824     xi->display = XOpenDisplay(NULL);
825     if (xi->display == NULL) {
826 	goto error;
827     }
828     if ((id = getenv("WINDOWID")) != NULL)
829 	xi->window = (Window) atoi(id);
830     else
831 	XGetInputFocus(xi->display, &xi->window, &revert);
832     if (!xi->window)
833 	exit(1);
834 
835     XGetWindowAttributes(xi->display, xi->window, &attr);
836     wop->width = attr.width;
837     wop->height = attr.height;
838 
839     while (1) {
840 	Window p_window;
841 
842 	XQueryTree(xi->display, xi->window, &root, &xi->parent,
843 		   &children, &nchildren);
844 	p_window = xi->window;
845 	for (i = 0; i < nchildren; i++) {
846 	    XGetWindowAttributes(xi->display, children[i], &attr);
847 	    if (attr.width > wop->width * 0.7 &&
848 		attr.height > wop->height * 0.7) {
849 		/* maybe text window */
850 		wop->width = attr.width;
851 		wop->height = attr.height;
852 		xi->window = children[i];
853 	    }
854 	}
855 	if (p_window == xi->window)
856 	    break;
857     }
858     wop->offset_x = OFFSET_X;
859     for (i = 0; i < nchildren; i++) {
860 	XGetWindowAttributes(xi->display, children[i], &attr);
861 	if (attr.x <= 0 && attr.width < 30 && attr.height > wop->height * 0.7) {
862 	    /* scrollbar of xterm/kterm ? */
863 	    wop->offset_x += attr.x + attr.width + attr.border_width * 2;
864 	    break;
865 	}
866     }
867     wop->offset_y = OFFSET_Y;
868 
869     wop->priv = xi;
870 
871   end:
872     wop->init = x11_init;
873     wop->finish = x11_finish;
874     wop->active = x11_active;
875     wop->set_background = x11_set_background;
876     wop->sync = x11_sync;
877     wop->close = x11_close;
878     wop->clear = x11_clear;
879 
880     wop->load_image = x11_load_image;
881     wop->show_image = x11_show_image;
882     wop->free_image = x11_free_image;
883     wop->get_image_size = x11_get_image_size;
884 
885     return wop;
886   error:
887     if (xi)
888 	free(xi);
889     free(wop);
890     return NULL;
891 }
892