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