Mercurial > hg > xemacs-beta
comparison src/glyphs-gtk.c @ 462:0784d089fdc9 r21-2-46
Import from CVS: tag r21-2-46
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:44:37 +0200 |
parents | |
children | 183866b06e0b |
comparison
equal
deleted
inserted
replaced
461:120ed4009e51 | 462:0784d089fdc9 |
---|---|
1 /* X-specific Lisp objects. | |
2 Copyright (C) 1993, 1994 Free Software Foundation, Inc. | |
3 Copyright (C) 1995 Board of Trustees, University of Illinois. | |
4 Copyright (C) 1995 Tinker Systems | |
5 Copyright (C) 1995, 1996 Ben Wing | |
6 Copyright (C) 1995 Sun Microsystems | |
7 | |
8 This file is part of XEmacs. | |
9 | |
10 XEmacs is free software; you can redistribute it and/or modify it | |
11 under the terms of the GNU General Public License as published by the | |
12 Free Software Foundation; either version 2, or (at your option) any | |
13 later version. | |
14 | |
15 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
17 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
18 for more details. | |
19 | |
20 You should have received a copy of the GNU General Public License | |
21 along with XEmacs; see the file COPYING. If not, write to | |
22 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
23 Boston, MA 02111-1307, USA. */ | |
24 | |
25 /* Synched up with: Not in FSF. */ | |
26 | |
27 /* Original author: Jamie Zawinski for 19.8 | |
28 font-truename stuff added by Jamie Zawinski for 19.10 | |
29 subwindow support added by Chuck Thompson | |
30 additional XPM support added by Chuck Thompson | |
31 initial X-Face support added by Stig | |
32 rewritten/restructured by Ben Wing for 19.12/19.13 | |
33 GIF/JPEG support added by Ben Wing for 19.14 | |
34 PNG support added by Bill Perry for 19.14 | |
35 Improved GIF/JPEG support added by Bill Perry for 19.14 | |
36 Cleanup/simplification of error handling by Ben Wing for 19.14 | |
37 Pointer/icon overhaul, more restructuring by Ben Wing for 19.14 | |
38 GIF support changed to external GIFlib 3.1 by Jareth Hein for 21.0 | |
39 Many changes for color work and optimizations by Jareth Hein for 21.0 | |
40 Switch of GIF/JPEG/PNG to new EImage intermediate code by Jareth Hein for 21.0 | |
41 TIFF code by Jareth Hein for 21.0 | |
42 GIF/JPEG/PNG/TIFF code moved to new glyph-eimage.c for 21.0 | |
43 Gtk version by William Perry for 21.1 | |
44 | |
45 TODO: | |
46 Support the GrayScale, StaticColor and StaticGray visual classes. | |
47 Convert images.el to C and stick it in here? | |
48 */ | |
49 | |
50 #include <config.h> | |
51 #include "lisp.h" | |
52 #include "lstream.h" | |
53 #include "console-gtk.h" | |
54 #include "glyphs.h" | |
55 #include "glyphs-gtk.h" | |
56 #include "objects-gtk.h" | |
57 #include "gui-gtk.h" | |
58 #include "ui-gtk.h" | |
59 | |
60 #include "buffer.h" | |
61 #include "window.h" | |
62 #include "frame.h" | |
63 #include "insdel.h" | |
64 #include "opaque.h" | |
65 #include "faces.h" | |
66 | |
67 #include "imgproc.h" | |
68 | |
69 #include "sysfile.h" | |
70 | |
71 #include <setjmp.h> | |
72 | |
73 #ifdef FILE_CODING | |
74 #include "file-coding.h" | |
75 #endif | |
76 | |
77 #if INTBITS == 32 | |
78 # define FOUR_BYTE_TYPE unsigned int | |
79 #elif LONGBITS == 32 | |
80 # define FOUR_BYTE_TYPE unsigned long | |
81 #elif SHORTBITS == 32 | |
82 # define FOUR_BYTE_TYPE unsigned short | |
83 #else | |
84 #error What kind of strange-ass system are we running on? | |
85 #endif | |
86 | |
87 DECLARE_IMAGE_INSTANTIATOR_FORMAT (nothing); | |
88 DECLARE_IMAGE_INSTANTIATOR_FORMAT (string); | |
89 DECLARE_IMAGE_INSTANTIATOR_FORMAT (formatted_string); | |
90 DECLARE_IMAGE_INSTANTIATOR_FORMAT (inherit); | |
91 #ifdef HAVE_JPEG | |
92 DECLARE_IMAGE_INSTANTIATOR_FORMAT (jpeg); | |
93 #endif | |
94 #ifdef HAVE_TIFF | |
95 DECLARE_IMAGE_INSTANTIATOR_FORMAT (tiff); | |
96 #endif | |
97 #ifdef HAVE_PNG | |
98 DECLARE_IMAGE_INSTANTIATOR_FORMAT (png); | |
99 #endif | |
100 #ifdef HAVE_GIF | |
101 DECLARE_IMAGE_INSTANTIATOR_FORMAT (gif); | |
102 #endif | |
103 | |
104 #ifdef HAVE_XFACE | |
105 DEFINE_DEVICE_IIFORMAT (gtk, xface); | |
106 Lisp_Object Qxface; | |
107 #endif | |
108 | |
109 #ifdef HAVE_XPM | |
110 DEFINE_DEVICE_IIFORMAT (gtk, xpm); | |
111 #endif | |
112 | |
113 DEFINE_DEVICE_IIFORMAT (gtk, xbm); | |
114 DEFINE_DEVICE_IIFORMAT (gtk, subwindow); | |
115 | |
116 DEFINE_IMAGE_INSTANTIATOR_FORMAT (cursor_font); | |
117 Lisp_Object Qcursor_font; | |
118 | |
119 DEFINE_IMAGE_INSTANTIATOR_FORMAT (font); | |
120 | |
121 DEFINE_IMAGE_INSTANTIATOR_FORMAT (autodetect); | |
122 | |
123 #ifdef HAVE_WIDGETS | |
124 DECLARE_IMAGE_INSTANTIATOR_FORMAT (layout); | |
125 DEFINE_DEVICE_IIFORMAT (gtk, widget); | |
126 DEFINE_DEVICE_IIFORMAT (gtk, native_layout); | |
127 DEFINE_DEVICE_IIFORMAT (gtk, button); | |
128 DEFINE_DEVICE_IIFORMAT (gtk, progress_gauge); | |
129 DEFINE_DEVICE_IIFORMAT (gtk, edit_field); | |
130 DEFINE_DEVICE_IIFORMAT (gtk, combo_box); | |
131 DEFINE_DEVICE_IIFORMAT (gtk, tab_control); | |
132 DEFINE_DEVICE_IIFORMAT (gtk, label); | |
133 #endif | |
134 | |
135 static void update_widget_face (GtkWidget *w, Lisp_Image_Instance *ii, | |
136 Lisp_Object domain); | |
137 static void cursor_font_instantiate (Lisp_Object image_instance, | |
138 Lisp_Object instantiator, | |
139 Lisp_Object pointer_fg, | |
140 Lisp_Object pointer_bg, | |
141 int dest_mask, | |
142 Lisp_Object domain); | |
143 | |
144 static gint cursor_name_to_index (const char *name); | |
145 | |
146 #ifndef BitmapSuccess | |
147 #define BitmapSuccess 0 | |
148 #define BitmapOpenFailed 1 | |
149 #define BitmapFileInvalid 2 | |
150 #define BitmapNoMemory 3 | |
151 #endif | |
152 | |
153 #include "bitmaps.h" | |
154 | |
155 DEFINE_IMAGE_INSTANTIATOR_FORMAT (gtk_resource); | |
156 Lisp_Object Q_resource_type, Q_resource_id; | |
157 Lisp_Object Qgtk_resource; | |
158 #ifdef HAVE_WIDGETS | |
159 Lisp_Object Qgtk_widget_instantiate_internal, Qgtk_widget_property_internal; | |
160 Lisp_Object Qgtk_widget_redisplay_internal, Qgtk_widget_set_style; | |
161 #endif | |
162 | |
163 #define CONST const | |
164 | |
165 | |
166 /************************************************************************/ | |
167 /* image instance methods */ | |
168 /************************************************************************/ | |
169 | |
170 /************************************************************************/ | |
171 /* convert from a series of RGB triples to an XImage formated for the */ | |
172 /* proper display */ | |
173 /************************************************************************/ | |
174 static GdkImage * | |
175 convert_EImage_to_GDKImage (Lisp_Object device, int width, int height, | |
176 unsigned char *pic, unsigned long **pixtbl, | |
177 int *npixels) | |
178 { | |
179 GdkColormap *cmap; | |
180 GdkVisual *vis; | |
181 GdkImage *outimg; | |
182 int depth, byte_cnt, i, j; | |
183 int rd,gr,bl,q; | |
184 unsigned char *data, *ip, *dp = NULL; | |
185 quant_table *qtable = NULL; | |
186 union { | |
187 FOUR_BYTE_TYPE val; | |
188 char cp[4]; | |
189 } conv; | |
190 | |
191 cmap = DEVICE_GTK_COLORMAP (XDEVICE(device)); | |
192 vis = DEVICE_GTK_VISUAL (XDEVICE(device)); | |
193 depth = DEVICE_GTK_DEPTH(XDEVICE(device)); | |
194 | |
195 if (vis->type == GDK_VISUAL_GRAYSCALE || vis->type == GDK_VISUAL_STATIC_COLOR || | |
196 vis->type == GDK_VISUAL_STATIC_GRAY) | |
197 { | |
198 /* #### Implement me!!! */ | |
199 return NULL; | |
200 } | |
201 | |
202 if (vis->type == GDK_VISUAL_PSEUDO_COLOR) | |
203 { | |
204 /* Quantize the image and get a histogram while we're at it. | |
205 Do this first to save memory */ | |
206 qtable = build_EImage_quantable(pic, width, height, 256); | |
207 if (qtable == NULL) return NULL; | |
208 } | |
209 | |
210 /* The first parameter (GdkWindow *) is allowed to be NULL if we | |
211 ** specify the depth */ | |
212 outimg = gdk_image_new (GDK_IMAGE_FASTEST, vis, width, height); | |
213 | |
214 if (!outimg) return NULL; | |
215 | |
216 byte_cnt = outimg->bpp; | |
217 | |
218 data = (unsigned char *) outimg->mem; | |
219 | |
220 if (!data) | |
221 { | |
222 gdk_image_destroy (outimg); | |
223 return NULL; | |
224 } | |
225 | |
226 if (vis->type == GDK_VISUAL_PSEUDO_COLOR) | |
227 { | |
228 unsigned long pixarray[256]; | |
229 int pixcount, n; | |
230 /* use our quantize table to allocate the colors */ | |
231 pixcount = 32; | |
232 *pixtbl = xnew_array (unsigned long, pixcount); | |
233 *npixels = 0; | |
234 | |
235 /* ### should implement a sort by popularity to assure proper allocation */ | |
236 n = *npixels; | |
237 for (i = 0; i < qtable->num_active_colors; i++) | |
238 { | |
239 GdkColor color; | |
240 int res; | |
241 | |
242 color.red = qtable->rm[i] ? qtable->rm[i] << 8 : 0; | |
243 color.green = qtable->gm[i] ? qtable->gm[i] << 8 : 0; | |
244 color.blue = qtable->bm[i] ? qtable->bm[i] << 8 : 0; | |
245 res = allocate_nearest_color (cmap, vis, &color); | |
246 if (res > 0 && res < 3) | |
247 { | |
248 DO_REALLOC(*pixtbl, pixcount, n+1, unsigned long); | |
249 (*pixtbl)[n] = color.pixel; | |
250 n++; | |
251 } | |
252 pixarray[i] = color.pixel; | |
253 } | |
254 *npixels = n; | |
255 ip = pic; | |
256 for (i = 0; i < height; i++) | |
257 { | |
258 dp = data + (i * outimg->bpl); | |
259 for (j = 0; j < width; j++) | |
260 { | |
261 rd = *ip++; | |
262 gr = *ip++; | |
263 bl = *ip++; | |
264 conv.val = pixarray[QUANT_GET_COLOR(qtable,rd,gr,bl)]; | |
265 #if WORDS_BIGENDIAN | |
266 if (outimg->byte_order == GDK_MSB_FIRST) | |
267 for (q = 4-byte_cnt; q < 4; q++) *dp++ = conv.cp[q]; | |
268 else | |
269 for (q = 3; q >= 4-byte_cnt; q--) *dp++ = conv.cp[q]; | |
270 #else | |
271 if (outimg->byte_order == GDK_MSB_FIRST) | |
272 for (q = byte_cnt-1; q >= 0; q--) *dp++ = conv.cp[q]; | |
273 else | |
274 for (q = 0; q < byte_cnt; q++) *dp++ = conv.cp[q]; | |
275 #endif | |
276 } | |
277 } | |
278 xfree(qtable); | |
279 } else { | |
280 unsigned long rshift,gshift,bshift,rbits,gbits,bbits,junk; | |
281 junk = vis->red_mask; | |
282 rshift = 0; | |
283 while ((junk & 0x1) == 0) | |
284 { | |
285 junk = junk >> 1; | |
286 rshift ++; | |
287 } | |
288 rbits = 0; | |
289 while (junk != 0) | |
290 { | |
291 junk = junk >> 1; | |
292 rbits++; | |
293 } | |
294 junk = vis->green_mask; | |
295 gshift = 0; | |
296 while ((junk & 0x1) == 0) | |
297 { | |
298 junk = junk >> 1; | |
299 gshift ++; | |
300 } | |
301 gbits = 0; | |
302 while (junk != 0) | |
303 { | |
304 junk = junk >> 1; | |
305 gbits++; | |
306 } | |
307 junk = vis->blue_mask; | |
308 bshift = 0; | |
309 while ((junk & 0x1) == 0) | |
310 { | |
311 junk = junk >> 1; | |
312 bshift ++; | |
313 } | |
314 bbits = 0; | |
315 while (junk != 0) | |
316 { | |
317 junk = junk >> 1; | |
318 bbits++; | |
319 } | |
320 ip = pic; | |
321 for (i = 0; i < height; i++) | |
322 { | |
323 dp = data + (i * outimg->bpl); | |
324 for (j = 0; j < width; j++) | |
325 { | |
326 if (rbits > 8) | |
327 rd = *ip++ << (rbits - 8); | |
328 else | |
329 rd = *ip++ >> (8 - rbits); | |
330 if (gbits > 8) | |
331 gr = *ip++ << (gbits - 8); | |
332 else | |
333 gr = *ip++ >> (8 - gbits); | |
334 if (bbits > 8) | |
335 bl = *ip++ << (bbits - 8); | |
336 else | |
337 bl = *ip++ >> (8 - bbits); | |
338 | |
339 conv.val = (rd << rshift) | (gr << gshift) | (bl << bshift); | |
340 #if WORDS_BIGENDIAN | |
341 if (outimg->byte_order == GDK_MSB_FIRST) | |
342 for (q = 4-byte_cnt; q < 4; q++) *dp++ = conv.cp[q]; | |
343 else | |
344 for (q = 3; q >= 4-byte_cnt; q--) *dp++ = conv.cp[q]; | |
345 #else | |
346 if (outimg->byte_order == GDK_MSB_FIRST) | |
347 for (q = byte_cnt-1; q >= 0; q--) *dp++ = conv.cp[q]; | |
348 else | |
349 for (q = 0; q < byte_cnt; q++) *dp++ = conv.cp[q]; | |
350 #endif | |
351 } | |
352 } | |
353 } | |
354 return outimg; | |
355 } | |
356 | |
357 static void | |
358 gtk_print_image_instance (struct Lisp_Image_Instance *p, | |
359 Lisp_Object printcharfun, | |
360 int escapeflag) | |
361 { | |
362 char buf[100]; | |
363 | |
364 switch (IMAGE_INSTANCE_TYPE (p)) | |
365 { | |
366 case IMAGE_MONO_PIXMAP: | |
367 case IMAGE_COLOR_PIXMAP: | |
368 case IMAGE_POINTER: | |
369 sprintf (buf, " (0x%lx", (unsigned long) IMAGE_INSTANCE_GTK_PIXMAP (p)); | |
370 write_c_string (buf, printcharfun); | |
371 if (IMAGE_INSTANCE_GTK_MASK (p)) | |
372 { | |
373 sprintf (buf, "/0x%lx", (unsigned long) IMAGE_INSTANCE_GTK_MASK (p)); | |
374 write_c_string (buf, printcharfun); | |
375 } | |
376 write_c_string (")", printcharfun); | |
377 break; | |
378 #if HAVE_SUBWINDOWS | |
379 case IMAGE_SUBWINDOW: | |
380 /* #### implement me */ | |
381 #endif | |
382 default: | |
383 break; | |
384 } | |
385 } | |
386 | |
387 static void | |
388 gtk_finalize_image_instance (struct Lisp_Image_Instance *p) | |
389 { | |
390 if (!p->data) | |
391 return; | |
392 | |
393 if (DEVICE_LIVE_P (XDEVICE (p->device))) | |
394 { | |
395 if (0) | |
396 ; | |
397 #ifdef HAVE_WIDGETS | |
398 if (IMAGE_INSTANCE_TYPE (p) == IMAGE_WIDGET) | |
399 { | |
400 if (IMAGE_INSTANCE_SUBWINDOW_ID (p)) | |
401 { | |
402 gtk_widget_destroy (IMAGE_INSTANCE_SUBWINDOW_ID (p)); | |
403 | |
404 /* We can release the callbacks again. */ | |
405 /* #### FIXME! */ | |
406 /* ungcpro_popup_callbacks (...); */ | |
407 | |
408 /* IMAGE_INSTANCE_GTK_WIDGET_ID (p) = 0; */ | |
409 IMAGE_INSTANCE_GTK_CLIPWIDGET (p) = 0; | |
410 } | |
411 } | |
412 #endif | |
413 else if (IMAGE_INSTANCE_TYPE (p) == IMAGE_SUBWINDOW) | |
414 { | |
415 abort(); | |
416 } | |
417 else | |
418 { | |
419 int i; | |
420 if (IMAGE_INSTANCE_PIXMAP_TIMEOUT (p)) | |
421 disable_glyph_animated_timeout (IMAGE_INSTANCE_PIXMAP_TIMEOUT (p)); | |
422 | |
423 if (IMAGE_INSTANCE_GTK_MASK (p) && | |
424 IMAGE_INSTANCE_GTK_MASK (p) != IMAGE_INSTANCE_GTK_PIXMAP (p)) | |
425 gdk_pixmap_unref (IMAGE_INSTANCE_GTK_MASK (p)); | |
426 IMAGE_INSTANCE_PIXMAP_MASK (p) = 0; | |
427 | |
428 if (IMAGE_INSTANCE_GTK_PIXMAP_SLICES (p)) | |
429 { | |
430 for (i = 0; i < IMAGE_INSTANCE_PIXMAP_MAXSLICE (p); i++) | |
431 if (IMAGE_INSTANCE_GTK_PIXMAP_SLICE (p,i)) | |
432 { | |
433 gdk_pixmap_unref (IMAGE_INSTANCE_GTK_PIXMAP_SLICE (p,i)); | |
434 IMAGE_INSTANCE_GTK_PIXMAP_SLICE (p, i) = 0; | |
435 } | |
436 xfree (IMAGE_INSTANCE_GTK_PIXMAP_SLICES (p)); | |
437 IMAGE_INSTANCE_GTK_PIXMAP_SLICES (p) = 0; | |
438 } | |
439 | |
440 if (IMAGE_INSTANCE_GTK_CURSOR (p)) | |
441 { | |
442 gdk_cursor_destroy (IMAGE_INSTANCE_GTK_CURSOR (p)); | |
443 IMAGE_INSTANCE_GTK_CURSOR (p) = 0; | |
444 } | |
445 } | |
446 | |
447 #if 0 | |
448 /* #### BILL!!! */ | |
449 if (IMAGE_INSTANCE_GTK_NPIXELS (p) != 0) | |
450 { | |
451 XFreeColors (dpy, | |
452 IMAGE_INSTANCE_GTK_COLORMAP (p), | |
453 IMAGE_INSTANCE_GTK_PIXELS (p), | |
454 IMAGE_INSTANCE_GTK_NPIXELS (p), 0); | |
455 IMAGE_INSTANCE_GTK_NPIXELS (p) = 0; | |
456 } | |
457 #endif | |
458 } | |
459 | |
460 if (IMAGE_INSTANCE_TYPE (p) != IMAGE_WIDGET | |
461 && IMAGE_INSTANCE_TYPE (p) != IMAGE_SUBWINDOW | |
462 && IMAGE_INSTANCE_GTK_PIXELS (p)) | |
463 { | |
464 xfree (IMAGE_INSTANCE_GTK_PIXELS (p)); | |
465 IMAGE_INSTANCE_GTK_PIXELS (p) = 0; | |
466 } | |
467 | |
468 xfree (p->data); | |
469 p->data = 0; | |
470 } | |
471 | |
472 static int | |
473 gtk_image_instance_equal (struct Lisp_Image_Instance *p1, | |
474 struct Lisp_Image_Instance *p2, int depth) | |
475 { | |
476 switch (IMAGE_INSTANCE_TYPE (p1)) | |
477 { | |
478 case IMAGE_MONO_PIXMAP: | |
479 case IMAGE_COLOR_PIXMAP: | |
480 case IMAGE_POINTER: | |
481 if (IMAGE_INSTANCE_GTK_COLORMAP (p1) != IMAGE_INSTANCE_GTK_COLORMAP (p2) || | |
482 IMAGE_INSTANCE_GTK_NPIXELS (p1) != IMAGE_INSTANCE_GTK_NPIXELS (p2)) | |
483 return 0; | |
484 #if HAVE_SUBWINDOWS | |
485 case IMAGE_SUBWINDOW: | |
486 /* #### implement me */ | |
487 #endif | |
488 break; | |
489 default: | |
490 break; | |
491 } | |
492 | |
493 return 1; | |
494 } | |
495 | |
496 static unsigned long | |
497 gtk_image_instance_hash (struct Lisp_Image_Instance *p, int depth) | |
498 { | |
499 switch (IMAGE_INSTANCE_TYPE (p)) | |
500 { | |
501 case IMAGE_MONO_PIXMAP: | |
502 case IMAGE_COLOR_PIXMAP: | |
503 case IMAGE_POINTER: | |
504 return IMAGE_INSTANCE_GTK_NPIXELS (p); | |
505 #if HAVE_SUBWINDOWS | |
506 case IMAGE_SUBWINDOW: | |
507 /* #### implement me */ | |
508 return 0; | |
509 #endif | |
510 default: | |
511 return 0; | |
512 } | |
513 } | |
514 | |
515 /* Set all the slots in an image instance structure to reasonable | |
516 default values. This is used somewhere within an instantiate | |
517 method. It is assumed that the device slot within the image | |
518 instance is already set -- this is the case when instantiate | |
519 methods are called. */ | |
520 | |
521 static void | |
522 gtk_initialize_pixmap_image_instance (struct Lisp_Image_Instance *ii, | |
523 int slices, | |
524 enum image_instance_type type) | |
525 { | |
526 ii->data = xnew_and_zero (struct gtk_image_instance_data); | |
527 IMAGE_INSTANCE_PIXMAP_MAXSLICE (ii) = slices; | |
528 IMAGE_INSTANCE_GTK_PIXMAP_SLICES (ii) = | |
529 xnew_array_and_zero (GdkPixmap *, slices); | |
530 IMAGE_INSTANCE_TYPE (ii) = type; | |
531 IMAGE_INSTANCE_PIXMAP_FILENAME (ii) = Qnil; | |
532 IMAGE_INSTANCE_PIXMAP_MASK_FILENAME (ii) = Qnil; | |
533 IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii) = Qnil; | |
534 IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii) = Qnil; | |
535 IMAGE_INSTANCE_PIXMAP_FG (ii) = Qnil; | |
536 IMAGE_INSTANCE_PIXMAP_BG (ii) = Qnil; | |
537 } | |
538 | |
539 | |
540 /************************************************************************/ | |
541 /* pixmap file functions */ | |
542 /************************************************************************/ | |
543 | |
544 /* Where bitmaps are; initialized from resource database */ | |
545 Lisp_Object Vgtk_bitmap_file_path; | |
546 | |
547 #ifndef BITMAPDIR | |
548 #define BITMAPDIR "/usr/include/X11/bitmaps" | |
549 #endif | |
550 | |
551 /* Given a pixmap filename, look through all of the "standard" places | |
552 where the file might be located. Return a full pathname if found; | |
553 otherwise, return Qnil. */ | |
554 | |
555 static Lisp_Object | |
556 gtk_locate_pixmap_file (Lisp_Object name) | |
557 { | |
558 /* This function can GC if IN_REDISPLAY is false */ | |
559 | |
560 /* Check non-absolute pathnames with a directory component relative to | |
561 the search path; that's the way Xt does it. */ | |
562 /* #### Unix-specific */ | |
563 if (XSTRING_BYTE (name, 0) == '/' || | |
564 (XSTRING_BYTE (name, 0) == '.' && | |
565 (XSTRING_BYTE (name, 1) == '/' || | |
566 (XSTRING_BYTE (name, 1) == '.' && | |
567 (XSTRING_BYTE (name, 2) == '/'))))) | |
568 { | |
569 if (!NILP (Ffile_readable_p (name))) | |
570 return name; | |
571 else | |
572 return Qnil; | |
573 } | |
574 | |
575 if (NILP (Vdefault_gtk_device)) | |
576 /* This may occur during intialization. */ | |
577 return Qnil; | |
578 | |
579 if (NILP (Vgtk_bitmap_file_path)) | |
580 { | |
581 Vgtk_bitmap_file_path = nconc2 (Vgtk_bitmap_file_path, | |
582 (decode_path (BITMAPDIR))); | |
583 } | |
584 | |
585 { | |
586 Lisp_Object found; | |
587 if (locate_file (Vgtk_bitmap_file_path, name, Qnil, &found, R_OK) < 0) | |
588 { | |
589 Lisp_Object temp = list1 (Vdata_directory); | |
590 struct gcpro gcpro1; | |
591 | |
592 GCPRO1 (temp); | |
593 locate_file (temp, name, Qnil, &found, R_OK); | |
594 UNGCPRO; | |
595 } | |
596 | |
597 return found; | |
598 } | |
599 } | |
600 | |
601 static Lisp_Object | |
602 locate_pixmap_file (Lisp_Object name) | |
603 { | |
604 return gtk_locate_pixmap_file (name); | |
605 } | |
606 | |
607 | |
608 /************************************************************************/ | |
609 /* cursor functions */ | |
610 /************************************************************************/ | |
611 | |
612 /* Check that this server supports cursors of size WIDTH * HEIGHT. If | |
613 not, signal an error. INSTANTIATOR is only used in the error | |
614 message. */ | |
615 | |
616 static void | |
617 check_pointer_sizes (unsigned int width, unsigned int height, | |
618 Lisp_Object instantiator) | |
619 { | |
620 /* #### BILL!!! There is no way to call XQueryBestCursor from Gdk! */ | |
621 #if 0 | |
622 unsigned int best_width, best_height; | |
623 if (! XQueryBestCursor (DisplayOfScreen (xs), RootWindowOfScreen (xs), | |
624 width, height, &best_width, &best_height)) | |
625 /* this means that an X error of some sort occurred (we trap | |
626 these so they're not fatal). */ | |
627 signal_simple_error ("XQueryBestCursor() failed?", instantiator); | |
628 | |
629 if (width > best_width || height > best_height) | |
630 error_with_frob (instantiator, | |
631 "pointer too large (%dx%d): " | |
632 "server requires %dx%d or smaller", | |
633 width, height, best_width, best_height); | |
634 #endif | |
635 } | |
636 | |
637 static void | |
638 generate_cursor_fg_bg (Lisp_Object device, Lisp_Object *foreground, | |
639 Lisp_Object *background, GdkColor *xfg, GdkColor *xbg) | |
640 { | |
641 if (!NILP (*foreground) && !COLOR_INSTANCEP (*foreground)) | |
642 *foreground = | |
643 Fmake_color_instance (*foreground, device, | |
644 encode_error_behavior_flag (ERROR_ME)); | |
645 if (COLOR_INSTANCEP (*foreground)) | |
646 *xfg = * COLOR_INSTANCE_GTK_COLOR (XCOLOR_INSTANCE (*foreground)); | |
647 else | |
648 { | |
649 xfg->pixel = 0; | |
650 xfg->red = xfg->green = xfg->blue = 0; | |
651 } | |
652 | |
653 if (!NILP (*background) && !COLOR_INSTANCEP (*background)) | |
654 *background = | |
655 Fmake_color_instance (*background, device, | |
656 encode_error_behavior_flag (ERROR_ME)); | |
657 if (COLOR_INSTANCEP (*background)) | |
658 *xbg = * COLOR_INSTANCE_GTK_COLOR (XCOLOR_INSTANCE (*background)); | |
659 else | |
660 { | |
661 xbg->pixel = 0; | |
662 xbg->red = xbg->green = xbg->blue = ~0; | |
663 } | |
664 } | |
665 | |
666 static void | |
667 maybe_recolor_cursor (Lisp_Object image_instance, Lisp_Object foreground, | |
668 Lisp_Object background) | |
669 { | |
670 #if 0 | |
671 /* #### BILL!!! */ | |
672 Lisp_Object device = XIMAGE_INSTANCE_DEVICE (image_instance); | |
673 GdkColor xfg, xbg; | |
674 | |
675 generate_cursor_fg_bg (device, &foreground, &background, &xfg, &xbg); | |
676 if (!NILP (foreground) || !NILP (background)) | |
677 { | |
678 XRecolorCursor (DEVICE_X_DISPLAY (XDEVICE (device)), | |
679 XIMAGE_INSTANCE_GTK_CURSOR (image_instance), | |
680 &xfg, &xbg); | |
681 XIMAGE_INSTANCE_PIXMAP_FG (image_instance) = foreground; | |
682 XIMAGE_INSTANCE_PIXMAP_BG (image_instance) = background; | |
683 } | |
684 #else | |
685 /* stderr_out ("Don't know how to recolor cursors in Gtk!\n"); */ | |
686 #endif | |
687 } | |
688 | |
689 | |
690 /************************************************************************/ | |
691 /* color pixmap functions */ | |
692 /************************************************************************/ | |
693 | |
694 /* Initialize an image instance from an XImage. | |
695 | |
696 DEST_MASK specifies the mask of allowed image types. | |
697 | |
698 PIXELS and NPIXELS specify an array of pixels that are used in | |
699 the image. These need to be kept around for the duration of the | |
700 image. When the image instance is freed, XFreeColors() will | |
701 automatically be called on all the pixels specified here; thus, | |
702 you should have allocated the pixels yourself using XAllocColor() | |
703 or the like. The array passed in is used directly without | |
704 being copied, so it should be heap data created with xmalloc(). | |
705 It will be freed using xfree() when the image instance is | |
706 destroyed. | |
707 | |
708 If this fails, signal an error. INSTANTIATOR is only used | |
709 in the error message. | |
710 | |
711 #### This should be able to handle conversion into `pointer'. | |
712 Use the same code as for `xpm'. */ | |
713 | |
714 static void | |
715 init_image_instance_from_gdk_image (struct Lisp_Image_Instance *ii, | |
716 GdkImage *gdk_image, | |
717 int dest_mask, | |
718 GdkColormap *cmap, | |
719 unsigned long *pixels, | |
720 int npixels, | |
721 int slices, | |
722 Lisp_Object instantiator) | |
723 { | |
724 Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii); | |
725 GdkGC *gc; | |
726 GdkWindow *d; | |
727 GdkPixmap *pixmap; | |
728 | |
729 if (!DEVICE_GTK_P (XDEVICE (device))) | |
730 signal_simple_error ("Not a Gtk device", device); | |
731 | |
732 d = GET_GTK_WIDGET_WINDOW (DEVICE_GTK_APP_SHELL (XDEVICE (device))); | |
733 | |
734 if (!(dest_mask & IMAGE_COLOR_PIXMAP_MASK)) | |
735 incompatible_image_types (instantiator, dest_mask, | |
736 IMAGE_COLOR_PIXMAP_MASK); | |
737 | |
738 pixmap = gdk_pixmap_new (d, gdk_image->width, gdk_image->height, gdk_image->depth); | |
739 if (!pixmap) | |
740 signal_simple_error ("Unable to create pixmap", instantiator); | |
741 | |
742 gc = gdk_gc_new (pixmap); | |
743 if (!gc) | |
744 { | |
745 gdk_pixmap_unref (pixmap); | |
746 signal_simple_error ("Unable to create GC", instantiator); | |
747 } | |
748 | |
749 gdk_draw_image (GDK_DRAWABLE (pixmap), gc, gdk_image, | |
750 0, 0, 0, 0, gdk_image->width, gdk_image->height); | |
751 | |
752 gdk_gc_destroy (gc); | |
753 | |
754 gtk_initialize_pixmap_image_instance (ii, slices, IMAGE_COLOR_PIXMAP); | |
755 | |
756 IMAGE_INSTANCE_PIXMAP_FILENAME (ii) = | |
757 find_keyword_in_vector (instantiator, Q_file); | |
758 | |
759 IMAGE_INSTANCE_GTK_PIXMAP (ii) = pixmap; | |
760 IMAGE_INSTANCE_GTK_MASK (ii) = 0; | |
761 IMAGE_INSTANCE_PIXMAP_WIDTH (ii) = gdk_image->width; | |
762 IMAGE_INSTANCE_PIXMAP_HEIGHT (ii) = gdk_image->height; | |
763 IMAGE_INSTANCE_PIXMAP_DEPTH (ii) = gdk_image->depth; | |
764 IMAGE_INSTANCE_GTK_COLORMAP (ii) = cmap; | |
765 IMAGE_INSTANCE_GTK_PIXELS (ii) = pixels; | |
766 IMAGE_INSTANCE_GTK_NPIXELS (ii) = npixels; | |
767 } | |
768 | |
769 #if 0 | |
770 void init_image_instance_from_gdk_pixmap (struct Lisp_Image_Instance *ii, | |
771 struct device *device, | |
772 GdkPixmap *gdk_pixmap, | |
773 int dest_mask, | |
774 Lisp_Object instantiator) | |
775 { | |
776 GdkWindow *d; | |
777 gint width, height, depth; | |
778 | |
779 if (!DEVICE_GTK_P (device)) | |
780 abort (); | |
781 | |
782 IMAGE_INSTANCE_DEVICE (ii) = device; | |
783 IMAGE_INSTANCE_TYPE (ii) = IMAGE_COLOR_PIXMAP; | |
784 | |
785 d = GET_GTK_WIDGET_WINDOW (DEVICE_GTK_APP_SHELL (device)); | |
786 | |
787 if (!(dest_mask & IMAGE_COLOR_PIXMAP_MASK)) | |
788 incompatible_image_types (instantiator, dest_mask, | |
789 IMAGE_COLOR_PIXMAP_MASK); | |
790 | |
791 gtk_initialize_pixmap_image_instance (ii, IMAGE_COLOR_PIXMAP); | |
792 | |
793 gdk_window_get_geometry (gdk_pixmap, NULL, NULL, &width, &height, &depth); | |
794 | |
795 IMAGE_INSTANCE_PIXMAP_FILENAME (ii) = Qnil; | |
796 IMAGE_INSTANCE_GTK_PIXMAP (ii) = gdk_pixmap; | |
797 IMAGE_INSTANCE_GTK_MASK (ii) = 0; | |
798 IMAGE_INSTANCE_PIXMAP_WIDTH (ii) = width; | |
799 IMAGE_INSTANCE_PIXMAP_HEIGHT (ii) = height; | |
800 IMAGE_INSTANCE_PIXMAP_DEPTH (ii) = depth; | |
801 IMAGE_INSTANCE_GTK_COLORMAP (ii) = gdk_window_get_colormap (gdk_pixmap); | |
802 IMAGE_INSTANCE_GTK_PIXELS (ii) = 0; | |
803 IMAGE_INSTANCE_GTK_NPIXELS (ii) = 0; | |
804 } | |
805 #endif | |
806 | |
807 static void | |
808 image_instance_add_gdk_image (Lisp_Image_Instance *ii, | |
809 GdkImage *gdk_image, | |
810 int slice, | |
811 Lisp_Object instantiator) | |
812 { | |
813 Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii); | |
814 GdkWindow *d; | |
815 GdkPixmap *pixmap; | |
816 GdkGC *gc; | |
817 | |
818 d = GET_GTK_WIDGET_WINDOW (DEVICE_GTK_APP_SHELL (XDEVICE (device))); | |
819 | |
820 pixmap = gdk_pixmap_new (d, gdk_image->width, gdk_image->height, gdk_image->depth); | |
821 | |
822 if (!pixmap) | |
823 signal_simple_error ("Unable to create pixmap", instantiator); | |
824 | |
825 gc = gdk_gc_new (pixmap); | |
826 | |
827 if (!gc) | |
828 { | |
829 gdk_pixmap_unref (pixmap); | |
830 signal_simple_error ("Unable to create GC", instantiator); | |
831 } | |
832 | |
833 gdk_draw_image (GDK_DRAWABLE (pixmap), gc, gdk_image, 0, 0, 0, 0, | |
834 gdk_image->width, gdk_image->height); | |
835 | |
836 gdk_gc_destroy (gc); | |
837 | |
838 IMAGE_INSTANCE_GTK_PIXMAP_SLICE (ii, slice) = pixmap; | |
839 } | |
840 | |
841 static void | |
842 gtk_init_image_instance_from_eimage (struct Lisp_Image_Instance *ii, | |
843 int width, int height, | |
844 int slices, | |
845 unsigned char *eimage, | |
846 int dest_mask, | |
847 Lisp_Object instantiator, | |
848 Lisp_Object domain) | |
849 { | |
850 Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii); | |
851 GdkColormap *cmap = DEVICE_GTK_COLORMAP (XDEVICE(device)); | |
852 unsigned long *pixtbl = NULL; | |
853 int npixels = 0; | |
854 int slice; | |
855 GdkImage* gdk_image; | |
856 | |
857 | |
858 for (slice = 0; slice < slices; slice++) | |
859 { | |
860 gdk_image = convert_EImage_to_GDKImage (device, width, height, eimage, | |
861 &pixtbl, &npixels); | |
862 if (!gdk_image) | |
863 { | |
864 if (pixtbl) xfree (pixtbl); | |
865 signal_image_error("EImage to GdkImage conversion failed", instantiator); | |
866 } | |
867 | |
868 if (slice == 0) | |
869 /* Now create the pixmap and set up the image instance */ | |
870 init_image_instance_from_gdk_image (ii, gdk_image, dest_mask, | |
871 cmap, pixtbl, npixels, slices, | |
872 instantiator); | |
873 else | |
874 image_instance_add_gdk_image (ii, gdk_image, slice, instantiator); | |
875 | |
876 if (gdk_image) | |
877 { | |
878 gdk_image_destroy (gdk_image); | |
879 } | |
880 gdk_image = 0; | |
881 } | |
882 } | |
883 | |
884 /* Given inline data for a mono pixmap, create and return the | |
885 corresponding X object. */ | |
886 | |
887 static GdkPixmap * | |
888 pixmap_from_xbm_inline (Lisp_Object device, int width, int height, | |
889 /* Note that data is in ext-format! */ | |
890 CONST Extbyte *bits) | |
891 { | |
892 return (gdk_bitmap_create_from_data (GET_GTK_WIDGET_WINDOW (DEVICE_GTK_APP_SHELL (XDEVICE (device))), | |
893 (char *) bits, width, height)); | |
894 } | |
895 | |
896 /* Given inline data for a mono pixmap, initialize the given | |
897 image instance accordingly. */ | |
898 | |
899 static void | |
900 init_image_instance_from_xbm_inline (struct Lisp_Image_Instance *ii, | |
901 int width, int height, | |
902 /* Note that data is in ext-format! */ | |
903 CONST char *bits, | |
904 Lisp_Object instantiator, | |
905 Lisp_Object pointer_fg, | |
906 Lisp_Object pointer_bg, | |
907 int dest_mask, | |
908 GdkPixmap *mask, | |
909 Lisp_Object mask_filename) | |
910 { | |
911 Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii); | |
912 Lisp_Object foreground = find_keyword_in_vector (instantiator, Q_foreground); | |
913 Lisp_Object background = find_keyword_in_vector (instantiator, Q_background); | |
914 GdkColor fg; | |
915 GdkColor bg; | |
916 enum image_instance_type type; | |
917 GdkWindow *draw = GET_GTK_WIDGET_WINDOW (DEVICE_GTK_APP_SHELL (XDEVICE (device))); | |
918 GdkColormap *cmap = DEVICE_GTK_COLORMAP (XDEVICE(device)); | |
919 GdkColor black; | |
920 GdkColor white; | |
921 | |
922 gdk_color_black(cmap, &black); | |
923 gdk_color_white(cmap, &white); | |
924 | |
925 if (!DEVICE_GTK_P (XDEVICE (device))) | |
926 signal_simple_error ("Not a Gtk device", device); | |
927 | |
928 if ((dest_mask & IMAGE_MONO_PIXMAP_MASK) && | |
929 (dest_mask & IMAGE_COLOR_PIXMAP_MASK)) | |
930 { | |
931 if (!NILP (foreground) || !NILP (background)) | |
932 type = IMAGE_COLOR_PIXMAP; | |
933 else | |
934 type = IMAGE_MONO_PIXMAP; | |
935 } | |
936 else if (dest_mask & IMAGE_MONO_PIXMAP_MASK) | |
937 type = IMAGE_MONO_PIXMAP; | |
938 else if (dest_mask & IMAGE_COLOR_PIXMAP_MASK) | |
939 type = IMAGE_COLOR_PIXMAP; | |
940 else if (dest_mask & IMAGE_POINTER_MASK) | |
941 type = IMAGE_POINTER; | |
942 else | |
943 incompatible_image_types (instantiator, dest_mask, | |
944 IMAGE_MONO_PIXMAP_MASK | IMAGE_COLOR_PIXMAP_MASK | |
945 | IMAGE_POINTER_MASK); | |
946 | |
947 gtk_initialize_pixmap_image_instance (ii, 1, type); | |
948 IMAGE_INSTANCE_PIXMAP_WIDTH (ii) = width; | |
949 IMAGE_INSTANCE_PIXMAP_HEIGHT (ii) = height; | |
950 IMAGE_INSTANCE_PIXMAP_FILENAME (ii) = | |
951 find_keyword_in_vector (instantiator, Q_file); | |
952 | |
953 switch (type) | |
954 { | |
955 case IMAGE_MONO_PIXMAP: | |
956 { | |
957 IMAGE_INSTANCE_GTK_PIXMAP (ii) = | |
958 pixmap_from_xbm_inline (device, width, height, (Extbyte *) bits); | |
959 } | |
960 break; | |
961 | |
962 case IMAGE_COLOR_PIXMAP: | |
963 { | |
964 gint d = DEVICE_GTK_DEPTH (XDEVICE(device)); | |
965 | |
966 if (!NILP (foreground) && !COLOR_INSTANCEP (foreground)) | |
967 foreground = | |
968 Fmake_color_instance (foreground, device, | |
969 encode_error_behavior_flag (ERROR_ME)); | |
970 | |
971 if (COLOR_INSTANCEP (foreground)) | |
972 fg = * COLOR_INSTANCE_GTK_COLOR (XCOLOR_INSTANCE (foreground)); | |
973 | |
974 if (!NILP (background) && !COLOR_INSTANCEP (background)) | |
975 background = | |
976 Fmake_color_instance (background, device, | |
977 encode_error_behavior_flag (ERROR_ME)); | |
978 | |
979 if (COLOR_INSTANCEP (background)) | |
980 bg = * COLOR_INSTANCE_GTK_COLOR (XCOLOR_INSTANCE (background)); | |
981 | |
982 /* We used to duplicate the pixels using XAllocColor(), to protect | |
983 against their getting freed. Just as easy to just store the | |
984 color instances here and GC-protect them, so this doesn't | |
985 happen. */ | |
986 IMAGE_INSTANCE_PIXMAP_FG (ii) = foreground; | |
987 IMAGE_INSTANCE_PIXMAP_BG (ii) = background; | |
988 IMAGE_INSTANCE_GTK_PIXMAP (ii) = | |
989 gdk_pixmap_create_from_data (draw, (char *) bits, width, height, d, &fg, &bg); | |
990 IMAGE_INSTANCE_PIXMAP_DEPTH (ii) = d; | |
991 } | |
992 break; | |
993 | |
994 case IMAGE_POINTER: | |
995 { | |
996 GdkColor fg_color, bg_color; | |
997 GdkPixmap *source; | |
998 | |
999 check_pointer_sizes (width, height, instantiator); | |
1000 | |
1001 source = gdk_pixmap_create_from_data (draw, (char *) bits, width, height, 1, &black, &white); | |
1002 | |
1003 if (NILP (foreground)) | |
1004 foreground = pointer_fg; | |
1005 if (NILP (background)) | |
1006 background = pointer_bg; | |
1007 generate_cursor_fg_bg (device, &foreground, &background, | |
1008 &fg_color, &bg_color); | |
1009 | |
1010 IMAGE_INSTANCE_PIXMAP_FG (ii) = foreground; | |
1011 IMAGE_INSTANCE_PIXMAP_BG (ii) = background; | |
1012 IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii) = | |
1013 find_keyword_in_vector (instantiator, Q_hotspot_x); | |
1014 IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii) = | |
1015 find_keyword_in_vector (instantiator, Q_hotspot_y); | |
1016 IMAGE_INSTANCE_GTK_CURSOR (ii) = | |
1017 gdk_cursor_new_from_pixmap (source, mask, &fg_color, &bg_color, | |
1018 !NILP (IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii)) ? | |
1019 XINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii)) : 0, | |
1020 !NILP (IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii)) ? | |
1021 XINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii)) : 0); | |
1022 } | |
1023 break; | |
1024 | |
1025 default: | |
1026 abort (); | |
1027 } | |
1028 } | |
1029 | |
1030 static void | |
1031 xbm_instantiate_1 (Lisp_Object image_instance, Lisp_Object instantiator, | |
1032 Lisp_Object pointer_fg, Lisp_Object pointer_bg, | |
1033 int dest_mask, int width, int height, | |
1034 /* Note that data is in ext-format! */ | |
1035 CONST char *bits) | |
1036 { | |
1037 Lisp_Object mask_data = find_keyword_in_vector (instantiator, Q_mask_data); | |
1038 Lisp_Object mask_file = find_keyword_in_vector (instantiator, Q_mask_file); | |
1039 struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance); | |
1040 GdkPixmap *mask = 0; | |
1041 CONST char *gcc_may_you_rot_in_hell; | |
1042 | |
1043 if (!NILP (mask_data)) | |
1044 { | |
1045 TO_EXTERNAL_FORMAT (LISP_STRING, XCAR (XCDR (XCDR (mask_data))), | |
1046 C_STRING_ALLOCA, gcc_may_you_rot_in_hell, | |
1047 Qfile_name); | |
1048 mask = | |
1049 pixmap_from_xbm_inline (IMAGE_INSTANCE_DEVICE (ii), | |
1050 XINT (XCAR (mask_data)), | |
1051 XINT (XCAR (XCDR (mask_data))), | |
1052 (CONST unsigned char *) | |
1053 gcc_may_you_rot_in_hell); | |
1054 } | |
1055 | |
1056 init_image_instance_from_xbm_inline (ii, width, height, bits, | |
1057 instantiator, pointer_fg, pointer_bg, | |
1058 dest_mask, mask, mask_file); | |
1059 } | |
1060 | |
1061 /* Instantiate method for XBM's. */ | |
1062 | |
1063 static void | |
1064 gtk_xbm_instantiate (Lisp_Object image_instance, Lisp_Object instantiator, | |
1065 Lisp_Object pointer_fg, Lisp_Object pointer_bg, | |
1066 int dest_mask, Lisp_Object domain) | |
1067 { | |
1068 Lisp_Object data = find_keyword_in_vector (instantiator, Q_data); | |
1069 CONST char *gcc_go_home; | |
1070 | |
1071 assert (!NILP (data)); | |
1072 | |
1073 TO_EXTERNAL_FORMAT (LISP_STRING, XCAR (XCDR (XCDR (data))), | |
1074 C_STRING_ALLOCA, gcc_go_home, | |
1075 Qbinary); | |
1076 | |
1077 xbm_instantiate_1 (image_instance, instantiator, pointer_fg, | |
1078 pointer_bg, dest_mask, XINT (XCAR (data)), | |
1079 XINT (XCAR (XCDR (data))), gcc_go_home); | |
1080 } | |
1081 | |
1082 | |
1083 #ifdef HAVE_XPM | |
1084 /********************************************************************** | |
1085 * XPM * | |
1086 **********************************************************************/ | |
1087 static void | |
1088 write_lisp_string_to_temp_file (Lisp_Object string, char *filename_out) | |
1089 { | |
1090 Lisp_Object instream, outstream; | |
1091 Lstream *istr, *ostr; | |
1092 char tempbuf[1024]; /* some random amount */ | |
1093 int fubar = 0; | |
1094 FILE *tmpfil; | |
1095 static Extbyte_dynarr *conversion_out_dynarr; | |
1096 Bytecount bstart, bend; | |
1097 struct gcpro gcpro1, gcpro2; | |
1098 #ifdef FILE_CODING | |
1099 Lisp_Object conv_out_stream; | |
1100 Lstream *costr; | |
1101 struct gcpro gcpro3; | |
1102 #endif | |
1103 | |
1104 /* This function can GC */ | |
1105 if (!conversion_out_dynarr) | |
1106 conversion_out_dynarr = Dynarr_new (Extbyte); | |
1107 else | |
1108 Dynarr_reset (conversion_out_dynarr); | |
1109 | |
1110 /* Create the temporary file ... */ | |
1111 sprintf (filename_out, "/tmp/emacs%d.XXXXXX", (int) getpid ()); | |
1112 mktemp (filename_out); | |
1113 tmpfil = fopen (filename_out, "w"); | |
1114 if (!tmpfil) | |
1115 { | |
1116 if (tmpfil) | |
1117 { | |
1118 int old_errno = errno; | |
1119 fclose (tmpfil); | |
1120 unlink (filename_out); | |
1121 errno = old_errno; | |
1122 } | |
1123 report_file_error ("Creating temp file", | |
1124 list1 (build_string (filename_out))); | |
1125 } | |
1126 | |
1127 CHECK_STRING (string); | |
1128 get_string_range_byte (string, Qnil, Qnil, &bstart, &bend, | |
1129 GB_HISTORICAL_STRING_BEHAVIOR); | |
1130 instream = make_lisp_string_input_stream (string, bstart, bend); | |
1131 istr = XLSTREAM (instream); | |
1132 /* setup the out stream */ | |
1133 outstream = make_dynarr_output_stream((unsigned_char_dynarr *)conversion_out_dynarr); | |
1134 ostr = XLSTREAM (outstream); | |
1135 #ifdef FILE_CODING | |
1136 /* setup the conversion stream */ | |
1137 conv_out_stream = make_encoding_output_stream (ostr, Fget_coding_system(Qbinary)); | |
1138 costr = XLSTREAM (conv_out_stream); | |
1139 GCPRO3 (instream, outstream, conv_out_stream); | |
1140 #else | |
1141 GCPRO2 (instream, outstream); | |
1142 #endif | |
1143 | |
1144 /* Get the data while doing the conversion */ | |
1145 while (1) | |
1146 { | |
1147 int size_in_bytes = Lstream_read (istr, tempbuf, sizeof (tempbuf)); | |
1148 if (!size_in_bytes) | |
1149 break; | |
1150 /* It does seem the flushes are necessary... */ | |
1151 #ifdef FILE_CODING | |
1152 Lstream_write (costr, tempbuf, size_in_bytes); | |
1153 Lstream_flush (costr); | |
1154 #else | |
1155 Lstream_write (ostr, tempbuf, size_in_bytes); | |
1156 #endif | |
1157 Lstream_flush (ostr); | |
1158 if (fwrite ((unsigned char *)Dynarr_atp(conversion_out_dynarr, 0), | |
1159 Dynarr_length(conversion_out_dynarr), 1, tmpfil) != 1) | |
1160 { | |
1161 fubar = 1; | |
1162 break; | |
1163 } | |
1164 /* reset the dynarr */ | |
1165 Lstream_rewind(ostr); | |
1166 } | |
1167 | |
1168 if (fclose (tmpfil) != 0) | |
1169 fubar = 1; | |
1170 Lstream_close (istr); | |
1171 #ifdef FILE_CODING | |
1172 Lstream_close (costr); | |
1173 #endif | |
1174 Lstream_close (ostr); | |
1175 | |
1176 UNGCPRO; | |
1177 Lstream_delete (istr); | |
1178 Lstream_delete (ostr); | |
1179 #ifdef FILE_CODING | |
1180 Lstream_delete (costr); | |
1181 #endif | |
1182 | |
1183 if (fubar) | |
1184 report_file_error ("Writing temp file", | |
1185 list1 (build_string (filename_out))); | |
1186 } | |
1187 | |
1188 struct color_symbol | |
1189 { | |
1190 char* name; | |
1191 GdkColor color; | |
1192 }; | |
1193 | |
1194 static struct color_symbol* | |
1195 extract_xpm_color_names (Lisp_Object device, | |
1196 Lisp_Object domain, | |
1197 Lisp_Object color_symbol_alist, | |
1198 int* nsymbols) | |
1199 { | |
1200 /* This function can GC */ | |
1201 Lisp_Object rest; | |
1202 Lisp_Object results = Qnil; | |
1203 int i, j; | |
1204 struct color_symbol *colortbl; | |
1205 struct gcpro gcpro1, gcpro2; | |
1206 | |
1207 GCPRO2 (results, device); | |
1208 | |
1209 /* We built up results to be (("name" . #<color>) ...) so that if an | |
1210 error happens we don't lose any malloc()ed data, or more importantly, | |
1211 leave any pixels allocated in the server. */ | |
1212 i = 0; | |
1213 LIST_LOOP (rest, color_symbol_alist) | |
1214 { | |
1215 Lisp_Object cons = XCAR (rest); | |
1216 Lisp_Object name = XCAR (cons); | |
1217 Lisp_Object value = XCDR (cons); | |
1218 if (NILP (value)) | |
1219 continue; | |
1220 if (STRINGP (value)) | |
1221 value = | |
1222 Fmake_color_instance | |
1223 (value, device, encode_error_behavior_flag (ERROR_ME_NOT)); | |
1224 else | |
1225 { | |
1226 assert (COLOR_SPECIFIERP (value)); | |
1227 value = Fspecifier_instance (value, domain, Qnil, Qnil); | |
1228 } | |
1229 if (NILP (value)) | |
1230 continue; | |
1231 results = noseeum_cons (noseeum_cons (name, value), results); | |
1232 i++; | |
1233 } | |
1234 UNGCPRO; /* no more evaluation */ | |
1235 | |
1236 *nsymbols=i; | |
1237 if (i == 0) return 0; | |
1238 | |
1239 colortbl = xnew_array_and_zero (struct color_symbol, i); | |
1240 | |
1241 for (j=0; j<i; j++) | |
1242 { | |
1243 Lisp_Object cons = XCAR (results); | |
1244 colortbl[j].color = | |
1245 * COLOR_INSTANCE_GTK_COLOR (XCOLOR_INSTANCE (XCDR (cons))); | |
1246 | |
1247 colortbl[j].name = (char *) XSTRING_DATA (XCAR (cons)); | |
1248 free_cons (XCONS (cons)); | |
1249 cons = results; | |
1250 results = XCDR (results); | |
1251 free_cons (XCONS (cons)); | |
1252 } | |
1253 return colortbl; | |
1254 } | |
1255 | |
1256 static void | |
1257 gtk_xpm_instantiate (Lisp_Object image_instance, Lisp_Object instantiator, | |
1258 Lisp_Object pointer_fg, Lisp_Object pointer_bg, | |
1259 int dest_mask, Lisp_Object domain) | |
1260 { | |
1261 /* This function can GC */ | |
1262 char temp_file_name[1024]; | |
1263 struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance); | |
1264 Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii); | |
1265 Lisp_Object data = find_keyword_in_vector (instantiator, Q_data); | |
1266 GdkColormap *cmap; | |
1267 int depth; | |
1268 GdkVisual *visual; | |
1269 GdkPixmap *pixmap; | |
1270 GdkPixmap *mask = 0; | |
1271 GdkWindow *window = 0; | |
1272 int nsymbols = 0, i = 0; | |
1273 struct color_symbol *color_symbols = NULL; | |
1274 GdkColor *transparent_color = NULL; | |
1275 Lisp_Object color_symbol_alist = find_keyword_in_vector (instantiator, | |
1276 Q_color_symbols); | |
1277 enum image_instance_type type; | |
1278 int force_mono; | |
1279 unsigned int w, h; | |
1280 | |
1281 if (!DEVICE_GTK_P (XDEVICE (device))) | |
1282 signal_simple_error ("Not a Gtk device", device); | |
1283 | |
1284 if (dest_mask & IMAGE_COLOR_PIXMAP_MASK) | |
1285 type = IMAGE_COLOR_PIXMAP; | |
1286 else if (dest_mask & IMAGE_MONO_PIXMAP_MASK) | |
1287 type = IMAGE_MONO_PIXMAP; | |
1288 else if (dest_mask & IMAGE_POINTER_MASK) | |
1289 type = IMAGE_POINTER; | |
1290 else | |
1291 incompatible_image_types (instantiator, dest_mask, | |
1292 IMAGE_MONO_PIXMAP_MASK | IMAGE_COLOR_PIXMAP_MASK | |
1293 | IMAGE_POINTER_MASK); | |
1294 force_mono = (type != IMAGE_COLOR_PIXMAP); | |
1295 | |
1296 window = GET_GTK_WIDGET_WINDOW (DEVICE_GTK_APP_SHELL (XDEVICE (device))); | |
1297 cmap = DEVICE_GTK_COLORMAP (XDEVICE (device)); | |
1298 depth = DEVICE_GTK_DEPTH (XDEVICE (device)); | |
1299 visual = DEVICE_GTK_VISUAL (XDEVICE (device)); | |
1300 | |
1301 gtk_initialize_pixmap_image_instance (ii, 1, type); | |
1302 | |
1303 assert (!NILP (data)); | |
1304 | |
1305 /* Need to get the transparent color here */ | |
1306 color_symbols = extract_xpm_color_names (device, domain, color_symbol_alist, &nsymbols); | |
1307 for (i = 0; i < nsymbols; i++) | |
1308 { | |
1309 if (!strcasecmp ("BgColor", color_symbols[i].name) || | |
1310 !strcasecmp ("None", color_symbols[i].name)) | |
1311 { | |
1312 transparent_color = &color_symbols[i].color; | |
1313 } | |
1314 } | |
1315 | |
1316 write_lisp_string_to_temp_file (data, temp_file_name); | |
1317 pixmap = gdk_pixmap_create_from_xpm (window, &mask, transparent_color, temp_file_name); | |
1318 unlink (temp_file_name); | |
1319 | |
1320 if (color_symbols) xfree (color_symbols); | |
1321 | |
1322 if (!pixmap) | |
1323 { | |
1324 signal_image_error ("Error reading pixmap", data); | |
1325 } | |
1326 | |
1327 gdk_window_get_geometry (pixmap, NULL, NULL, &w, &h, &depth); | |
1328 | |
1329 IMAGE_INSTANCE_GTK_PIXMAP (ii) = pixmap; | |
1330 IMAGE_INSTANCE_GTK_MASK (ii) = mask; | |
1331 IMAGE_INSTANCE_GTK_COLORMAP (ii) = cmap; | |
1332 IMAGE_INSTANCE_GTK_PIXELS (ii) = 0; | |
1333 IMAGE_INSTANCE_GTK_NPIXELS (ii) = 0; | |
1334 IMAGE_INSTANCE_PIXMAP_WIDTH (ii) = w; | |
1335 IMAGE_INSTANCE_PIXMAP_HEIGHT (ii) = h; | |
1336 IMAGE_INSTANCE_PIXMAP_FILENAME (ii) = | |
1337 find_keyword_in_vector (instantiator, Q_file); | |
1338 | |
1339 switch (type) | |
1340 { | |
1341 case IMAGE_MONO_PIXMAP: | |
1342 break; | |
1343 | |
1344 case IMAGE_COLOR_PIXMAP: | |
1345 { | |
1346 IMAGE_INSTANCE_PIXMAP_DEPTH (ii) = depth; | |
1347 } | |
1348 break; | |
1349 | |
1350 case IMAGE_POINTER: | |
1351 { | |
1352 GdkColor fg, bg; | |
1353 unsigned int xhot, yhot; | |
1354 | |
1355 /* #### Gtk does not give us access to the hotspots of a pixmap */ | |
1356 xhot = yhot = 1; | |
1357 XSETINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii), xhot); | |
1358 XSETINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii), yhot); | |
1359 | |
1360 check_pointer_sizes (w, h, instantiator); | |
1361 | |
1362 /* If the loaded pixmap has colors allocated (meaning it came from an | |
1363 XPM file), then use those as the default colors for the cursor we | |
1364 create. Otherwise, default to pointer_fg and pointer_bg. | |
1365 */ | |
1366 if (depth > 1) | |
1367 { | |
1368 warn_when_safe (Qunimplemented, Qnotice, | |
1369 "GTK does not support XPM cursors...\n"); | |
1370 IMAGE_INSTANCE_GTK_CURSOR (ii) = gdk_cursor_new (GDK_COFFEE_MUG); | |
1371 } | |
1372 else | |
1373 { | |
1374 generate_cursor_fg_bg (device, &pointer_fg, &pointer_bg, | |
1375 &fg, &bg); | |
1376 IMAGE_INSTANCE_PIXMAP_FG (ii) = pointer_fg; | |
1377 IMAGE_INSTANCE_PIXMAP_BG (ii) = pointer_bg; | |
1378 IMAGE_INSTANCE_GTK_CURSOR (ii) = gdk_cursor_new_from_pixmap (pixmap, mask, &fg, &bg, xhot, yhot); | |
1379 } | |
1380 } | |
1381 | |
1382 break; | |
1383 | |
1384 default: | |
1385 abort (); | |
1386 } | |
1387 } | |
1388 #endif /* HAVE_XPM */ | |
1389 | |
1390 | |
1391 #ifdef HAVE_XFACE | |
1392 | |
1393 /********************************************************************** | |
1394 * X-Face * | |
1395 **********************************************************************/ | |
1396 #if defined(EXTERN) | |
1397 /* This is about to get redefined! */ | |
1398 #undef EXTERN | |
1399 #endif | |
1400 /* We have to define SYSV32 so that compface.h includes string.h | |
1401 instead of strings.h. */ | |
1402 #define SYSV32 | |
1403 #ifdef __cplusplus | |
1404 extern "C" { | |
1405 #endif | |
1406 #include <compface.h> | |
1407 #ifdef __cplusplus | |
1408 } | |
1409 #endif | |
1410 /* JMP_BUF cannot be used here because if it doesn't get defined | |
1411 to jmp_buf we end up with a conflicting type error with the | |
1412 definition in compface.h */ | |
1413 extern jmp_buf comp_env; | |
1414 #undef SYSV32 | |
1415 | |
1416 static void | |
1417 gtk_xface_instantiate (Lisp_Object image_instance, Lisp_Object instantiator, | |
1418 Lisp_Object pointer_fg, Lisp_Object pointer_bg, | |
1419 int dest_mask, Lisp_Object domain) | |
1420 { | |
1421 Lisp_Object data = find_keyword_in_vector (instantiator, Q_data); | |
1422 int i, stattis; | |
1423 char *p, *bits, *bp; | |
1424 CONST char * volatile emsg = 0; | |
1425 CONST char * volatile dstring; | |
1426 | |
1427 assert (!NILP (data)); | |
1428 | |
1429 LISP_STRING_TO_EXTERNAL (data, dstring, Qbinary); | |
1430 | |
1431 if ((p = strchr (dstring, ':'))) | |
1432 { | |
1433 dstring = p + 1; | |
1434 } | |
1435 | |
1436 /* Must use setjmp not SETJMP because we used jmp_buf above not JMP_BUF */ | |
1437 if (!(stattis = setjmp (comp_env))) | |
1438 { | |
1439 UnCompAll ((char *) dstring); | |
1440 UnGenFace (); | |
1441 } | |
1442 | |
1443 switch (stattis) | |
1444 { | |
1445 case -2: | |
1446 emsg = "uncompface: internal error"; | |
1447 break; | |
1448 case -1: | |
1449 emsg = "uncompface: insufficient or invalid data"; | |
1450 break; | |
1451 case 1: | |
1452 emsg = "uncompface: excess data ignored"; | |
1453 break; | |
1454 } | |
1455 | |
1456 if (emsg) | |
1457 signal_simple_error_2 (emsg, data, Qimage); | |
1458 | |
1459 bp = bits = (char *) alloca (PIXELS / 8); | |
1460 | |
1461 /* the compface library exports char F[], which uses a single byte per | |
1462 pixel to represent a 48x48 bitmap. Yuck. */ | |
1463 for (i = 0, p = F; i < (PIXELS / 8); ++i) | |
1464 { | |
1465 int n, b; | |
1466 /* reverse the bit order of each byte... */ | |
1467 for (b = n = 0; b < 8; ++b) | |
1468 { | |
1469 n |= ((*p++) << b); | |
1470 } | |
1471 *bp++ = (char) n; | |
1472 } | |
1473 | |
1474 xbm_instantiate_1 (image_instance, instantiator, pointer_fg, | |
1475 pointer_bg, dest_mask, 48, 48, bits); | |
1476 } | |
1477 | |
1478 #endif /* HAVE_XFACE */ | |
1479 | |
1480 /********************************************************************** | |
1481 * RESOURCES * | |
1482 **********************************************************************/ | |
1483 | |
1484 static void | |
1485 gtk_resource_validate (Lisp_Object instantiator) | |
1486 { | |
1487 if ((NILP (find_keyword_in_vector (instantiator, Q_file)) | |
1488 && | |
1489 NILP (find_keyword_in_vector (instantiator, Q_resource_id))) | |
1490 || | |
1491 NILP (find_keyword_in_vector (instantiator, Q_resource_type))) | |
1492 signal_simple_error ("Must supply :file, :resource-id and :resource-type", | |
1493 instantiator); | |
1494 } | |
1495 | |
1496 static Lisp_Object | |
1497 gtk_resource_normalize (Lisp_Object inst, Lisp_Object console_type, Lisp_Object dest_mask) | |
1498 { | |
1499 /* This function can call lisp */ | |
1500 Lisp_Object file = Qnil; | |
1501 struct gcpro gcpro1, gcpro2; | |
1502 Lisp_Object alist = Qnil; | |
1503 | |
1504 GCPRO2 (file, alist); | |
1505 | |
1506 file = potential_pixmap_file_instantiator (inst, Q_file, Q_data, | |
1507 console_type); | |
1508 | |
1509 if (CONSP (file)) /* failure locating filename */ | |
1510 signal_double_file_error ("Opening pixmap file", | |
1511 "no such file or directory", | |
1512 Fcar (file)); | |
1513 | |
1514 if (NILP (file)) /* no conversion necessary */ | |
1515 RETURN_UNGCPRO (inst); | |
1516 | |
1517 alist = tagged_vector_to_alist (inst); | |
1518 | |
1519 { | |
1520 alist = remassq_no_quit (Q_file, alist); | |
1521 alist = Fcons (Fcons (Q_file, file), alist); | |
1522 } | |
1523 | |
1524 { | |
1525 Lisp_Object result = alist_to_tagged_vector (Qgtk_resource, alist); | |
1526 free_alist (alist); | |
1527 RETURN_UNGCPRO (result); | |
1528 } | |
1529 } | |
1530 | |
1531 static int | |
1532 gtk_resource_possible_dest_types (void) | |
1533 { | |
1534 return IMAGE_POINTER_MASK | IMAGE_COLOR_PIXMAP_MASK; | |
1535 } | |
1536 | |
1537 extern guint symbol_to_enum (Lisp_Object, GtkType); | |
1538 | |
1539 static guint resource_name_to_resource (Lisp_Object name, int type) | |
1540 { | |
1541 if (type == IMAGE_POINTER) | |
1542 return (symbol_to_enum (name, GTK_TYPE_GDK_CURSOR_TYPE)); | |
1543 else | |
1544 return (0); | |
1545 } | |
1546 | |
1547 static int | |
1548 resource_symbol_to_type (Lisp_Object data) | |
1549 { | |
1550 if (EQ (data, Qcursor)) | |
1551 return IMAGE_POINTER; | |
1552 #if 0 | |
1553 else if (EQ (data, Qicon)) | |
1554 return IMAGE_ICON; | |
1555 else if (EQ (data, Qbitmap)) | |
1556 return IMAGE_BITMAP; | |
1557 #endif | |
1558 else | |
1559 return 0; | |
1560 } | |
1561 | |
1562 static void | |
1563 gtk_resource_instantiate (Lisp_Object image_instance, Lisp_Object instantiator, | |
1564 Lisp_Object pointer_fg, Lisp_Object pointer_bg, | |
1565 int dest_mask, Lisp_Object domain) | |
1566 { | |
1567 struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance); | |
1568 GdkCursor *c = NULL; | |
1569 unsigned int type = 0; | |
1570 Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii); | |
1571 Lisp_Object resource_type = find_keyword_in_vector (instantiator, Q_resource_type); | |
1572 Lisp_Object resource_id = find_keyword_in_vector (instantiator, Q_resource_id); | |
1573 | |
1574 if (!DEVICE_GTK_P (XDEVICE (device))) | |
1575 signal_simple_error ("Not a GTK device", device); | |
1576 | |
1577 type = resource_symbol_to_type (resource_type); | |
1578 | |
1579 // if (dest_mask & IMAGE_POINTER_MASK && type == IMAGE_POINTER_MASK) | |
1580 // iitype = IMAGE_POINTER; | |
1581 // else if (dest_mask & IMAGE_COLOR_PIXMAP_MASK) | |
1582 // iitype = IMAGE_COLOR_PIXMAP; | |
1583 // else | |
1584 // incompatible_image_types (instantiator, dest_mask, | |
1585 // IMAGE_COLOR_PIXMAP_MASK | IMAGE_POINTER_MASK); | |
1586 | |
1587 /* mess with the keyword info we were provided with */ | |
1588 gtk_initialize_pixmap_image_instance (ii, 1, type); | |
1589 c = gdk_cursor_new (resource_name_to_resource (resource_id, type)); | |
1590 IMAGE_INSTANCE_GTK_CURSOR (ii) = c; | |
1591 IMAGE_INSTANCE_PIXMAP_FILENAME (ii) = resource_id; | |
1592 IMAGE_INSTANCE_PIXMAP_WIDTH (ii) = 10; | |
1593 IMAGE_INSTANCE_PIXMAP_HEIGHT (ii) = 10; | |
1594 IMAGE_INSTANCE_PIXMAP_DEPTH (ii) = 1; | |
1595 } | |
1596 | |
1597 static void | |
1598 check_valid_resource_symbol (Lisp_Object data) | |
1599 { | |
1600 CHECK_SYMBOL (data); | |
1601 if (!resource_symbol_to_type (data)) | |
1602 signal_simple_error ("invalid resource type", data); | |
1603 } | |
1604 | |
1605 static void | |
1606 check_valid_resource_id (Lisp_Object data) | |
1607 { | |
1608 if (!resource_name_to_resource (data, IMAGE_POINTER) | |
1609 && | |
1610 !resource_name_to_resource (data, IMAGE_COLOR_PIXMAP) | |
1611 #if 0 | |
1612 && | |
1613 !resource_name_to_resource (data, IMAGE_BITMAP) | |
1614 #endif | |
1615 ) | |
1616 signal_simple_error ("invalid resource identifier", data); | |
1617 } | |
1618 | |
1619 #if 0 | |
1620 void | |
1621 check_valid_string_or_int (Lisp_Object data) | |
1622 { | |
1623 if (!INTP (data)) | |
1624 CHECK_STRING (data); | |
1625 else | |
1626 CHECK_INT (data); | |
1627 } | |
1628 #endif | |
1629 | |
1630 | |
1631 /********************************************************************** | |
1632 * Autodetect * | |
1633 **********************************************************************/ | |
1634 | |
1635 static void | |
1636 autodetect_validate (Lisp_Object instantiator) | |
1637 { | |
1638 data_must_be_present (instantiator); | |
1639 } | |
1640 | |
1641 static Lisp_Object | |
1642 autodetect_normalize (Lisp_Object instantiator, | |
1643 Lisp_Object console_type, | |
1644 Lisp_Object dest_mask) | |
1645 { | |
1646 Lisp_Object file = find_keyword_in_vector (instantiator, Q_data); | |
1647 Lisp_Object filename = Qnil; | |
1648 Lisp_Object data = Qnil; | |
1649 struct gcpro gcpro1, gcpro2, gcpro3; | |
1650 Lisp_Object alist = Qnil; | |
1651 | |
1652 GCPRO3 (filename, data, alist); | |
1653 | |
1654 if (NILP (file)) /* no conversion necessary */ | |
1655 RETURN_UNGCPRO (instantiator); | |
1656 | |
1657 alist = tagged_vector_to_alist (instantiator); | |
1658 | |
1659 filename = locate_pixmap_file (file); | |
1660 if (!NILP (filename)) | |
1661 { | |
1662 int xhot, yhot; | |
1663 /* #### Apparently some versions of XpmReadFileToData, which is | |
1664 called by pixmap_to_lisp_data, don't return an error value | |
1665 if the given file is not a valid XPM file. Instead, they | |
1666 just seg fault. It is definitely caused by passing a | |
1667 bitmap. To try and avoid this we check for bitmaps first. */ | |
1668 | |
1669 data = bitmap_to_lisp_data (filename, &xhot, &yhot, 1); | |
1670 | |
1671 if (!EQ (data, Qt)) | |
1672 { | |
1673 alist = remassq_no_quit (Q_data, alist); | |
1674 alist = Fcons (Fcons (Q_file, filename), | |
1675 Fcons (Fcons (Q_data, data), alist)); | |
1676 if (xhot != -1) | |
1677 alist = Fcons (Fcons (Q_hotspot_x, make_int (xhot)), | |
1678 alist); | |
1679 if (yhot != -1) | |
1680 alist = Fcons (Fcons (Q_hotspot_y, make_int (yhot)), | |
1681 alist); | |
1682 | |
1683 alist = xbm_mask_file_munging (alist, filename, Qnil, console_type); | |
1684 | |
1685 { | |
1686 Lisp_Object result = alist_to_tagged_vector (Qxbm, alist); | |
1687 free_alist (alist); | |
1688 RETURN_UNGCPRO (result); | |
1689 } | |
1690 } | |
1691 | |
1692 #ifdef HAVE_XPM | |
1693 data = pixmap_to_lisp_data (filename, 1); | |
1694 | |
1695 if (!EQ (data, Qt)) | |
1696 { | |
1697 alist = remassq_no_quit (Q_data, alist); | |
1698 alist = Fcons (Fcons (Q_file, filename), | |
1699 Fcons (Fcons (Q_data, data), alist)); | |
1700 alist = Fcons (Fcons (Q_color_symbols, | |
1701 evaluate_xpm_color_symbols ()), | |
1702 alist); | |
1703 { | |
1704 Lisp_Object result = alist_to_tagged_vector (Qxpm, alist); | |
1705 free_alist (alist); | |
1706 RETURN_UNGCPRO (result); | |
1707 } | |
1708 } | |
1709 #endif | |
1710 } | |
1711 | |
1712 /* If we couldn't convert it, just put it back as it is. | |
1713 We might try to further frob it later as a cursor-font | |
1714 specification. (We can't do that now because we don't know | |
1715 what dest-types it's going to be instantiated into.) */ | |
1716 { | |
1717 Lisp_Object result = alist_to_tagged_vector (Qautodetect, alist); | |
1718 free_alist (alist); | |
1719 RETURN_UNGCPRO (result); | |
1720 } | |
1721 } | |
1722 | |
1723 static int | |
1724 autodetect_possible_dest_types (void) | |
1725 { | |
1726 return | |
1727 IMAGE_MONO_PIXMAP_MASK | | |
1728 IMAGE_COLOR_PIXMAP_MASK | | |
1729 IMAGE_POINTER_MASK | | |
1730 IMAGE_TEXT_MASK; | |
1731 } | |
1732 | |
1733 static void | |
1734 autodetect_instantiate (Lisp_Object image_instance, | |
1735 Lisp_Object instantiator, | |
1736 Lisp_Object pointer_fg, | |
1737 Lisp_Object pointer_bg, | |
1738 int dest_mask, Lisp_Object domain) | |
1739 { | |
1740 Lisp_Object data = find_keyword_in_vector (instantiator, Q_data); | |
1741 struct gcpro gcpro1, gcpro2, gcpro3; | |
1742 Lisp_Object alist = Qnil; | |
1743 Lisp_Object result = Qnil; | |
1744 int is_cursor_font = 0; | |
1745 | |
1746 GCPRO3 (data, alist, result); | |
1747 | |
1748 alist = tagged_vector_to_alist (instantiator); | |
1749 if (dest_mask & IMAGE_POINTER_MASK) | |
1750 { | |
1751 CONST char *name_ext; | |
1752 | |
1753 TO_EXTERNAL_FORMAT (LISP_STRING, data, | |
1754 C_STRING_ALLOCA, name_ext, | |
1755 Qfile_name); | |
1756 | |
1757 if (cursor_name_to_index (name_ext) != -1) | |
1758 { | |
1759 result = alist_to_tagged_vector (Qcursor_font, alist); | |
1760 is_cursor_font = 1; | |
1761 } | |
1762 } | |
1763 | |
1764 if (!is_cursor_font) | |
1765 result = alist_to_tagged_vector (Qstring, alist); | |
1766 free_alist (alist); | |
1767 | |
1768 if (is_cursor_font) | |
1769 cursor_font_instantiate (image_instance, result, pointer_fg, | |
1770 pointer_bg, dest_mask, domain); | |
1771 else | |
1772 string_instantiate (image_instance, result, pointer_fg, | |
1773 pointer_bg, dest_mask, domain); | |
1774 | |
1775 UNGCPRO; | |
1776 } | |
1777 | |
1778 | |
1779 /********************************************************************** | |
1780 * Font * | |
1781 **********************************************************************/ | |
1782 | |
1783 static void | |
1784 font_validate (Lisp_Object instantiator) | |
1785 { | |
1786 data_must_be_present (instantiator); | |
1787 } | |
1788 | |
1789 static int | |
1790 font_possible_dest_types (void) | |
1791 { | |
1792 return IMAGE_POINTER_MASK; | |
1793 } | |
1794 | |
1795 static void | |
1796 font_instantiate (Lisp_Object image_instance, Lisp_Object instantiator, | |
1797 Lisp_Object pointer_fg, Lisp_Object pointer_bg, | |
1798 int dest_mask, Lisp_Object domain) | |
1799 { | |
1800 /* This function can GC */ | |
1801 Lisp_Object data = find_keyword_in_vector (instantiator, Q_data); | |
1802 struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance); | |
1803 Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii); | |
1804 GdkColor fg, bg; | |
1805 GdkFont *source, *mask; | |
1806 char source_name[MAXPATHLEN], mask_name[MAXPATHLEN], dummy; | |
1807 int source_char, mask_char; | |
1808 int count; | |
1809 Lisp_Object foreground, background; | |
1810 | |
1811 if (!DEVICE_GTK_P (XDEVICE (device))) | |
1812 signal_simple_error ("Not a Gtk device", device); | |
1813 | |
1814 if (!STRINGP (data) || | |
1815 strncmp ("FONT ", (char *) XSTRING_DATA (data), 5)) | |
1816 signal_simple_error ("Invalid font-glyph instantiator", | |
1817 instantiator); | |
1818 | |
1819 if (!(dest_mask & IMAGE_POINTER_MASK)) | |
1820 incompatible_image_types (instantiator, dest_mask, IMAGE_POINTER_MASK); | |
1821 | |
1822 foreground = find_keyword_in_vector (instantiator, Q_foreground); | |
1823 if (NILP (foreground)) | |
1824 foreground = pointer_fg; | |
1825 background = find_keyword_in_vector (instantiator, Q_background); | |
1826 if (NILP (background)) | |
1827 background = pointer_bg; | |
1828 | |
1829 generate_cursor_fg_bg (device, &foreground, &background, &fg, &bg); | |
1830 | |
1831 count = sscanf ((char *) XSTRING_DATA (data), | |
1832 "FONT %s %d %s %d %c", | |
1833 source_name, &source_char, | |
1834 mask_name, &mask_char, &dummy); | |
1835 /* Allow "%s %d %d" as well... */ | |
1836 if (count == 3 && (1 == sscanf (mask_name, "%d %c", &mask_char, &dummy))) | |
1837 count = 4, mask_name[0] = 0; | |
1838 | |
1839 if (count != 2 && count != 4) | |
1840 signal_simple_error ("invalid cursor specification", data); | |
1841 source = gdk_font_load (source_name); | |
1842 if (! source) | |
1843 signal_simple_error_2 ("couldn't load font", | |
1844 build_string (source_name), | |
1845 data); | |
1846 if (count == 2) | |
1847 mask = 0; | |
1848 else if (!mask_name[0]) | |
1849 mask = source; | |
1850 else | |
1851 { | |
1852 mask = gdk_font_load (mask_name); | |
1853 if (!mask) | |
1854 /* continuable */ | |
1855 Fsignal (Qerror, list3 (build_string ("couldn't load font"), | |
1856 build_string (mask_name), data)); | |
1857 } | |
1858 if (!mask) | |
1859 mask_char = 0; | |
1860 | |
1861 /* #### call XQueryTextExtents() and check_pointer_sizes() here. */ | |
1862 | |
1863 gtk_initialize_pixmap_image_instance (ii, 1, IMAGE_POINTER); | |
1864 | |
1865 IMAGE_INSTANCE_GTK_CURSOR (ii) = NULL; | |
1866 | |
1867 #if 0 | |
1868 /* #### BILL!!! There is no way to call this function from Gdk */ | |
1869 XCreateGlyphCursor (dpy, source, mask, source_char, mask_char, | |
1870 &fg, &bg); | |
1871 #endif | |
1872 XIMAGE_INSTANCE_PIXMAP_FG (image_instance) = foreground; | |
1873 XIMAGE_INSTANCE_PIXMAP_BG (image_instance) = background; | |
1874 | |
1875 gdk_font_unref (source); | |
1876 if (mask && mask != source) gdk_font_unref (mask); | |
1877 } | |
1878 | |
1879 | |
1880 /********************************************************************** | |
1881 * Cursor-Font * | |
1882 **********************************************************************/ | |
1883 | |
1884 static void | |
1885 cursor_font_validate (Lisp_Object instantiator) | |
1886 { | |
1887 data_must_be_present (instantiator); | |
1888 } | |
1889 | |
1890 static int | |
1891 cursor_font_possible_dest_types (void) | |
1892 { | |
1893 return IMAGE_POINTER_MASK; | |
1894 } | |
1895 | |
1896 static char *__downcase (const char *name) | |
1897 { | |
1898 char *converted = strdup(name); | |
1899 char *work = converted; | |
1900 | |
1901 while (*work) | |
1902 { | |
1903 *work = tolower(*work); | |
1904 work++; | |
1905 } | |
1906 return(converted); | |
1907 } | |
1908 | |
1909 /* This is basically the equivalent of XmuCursorNameToIndex */ | |
1910 static gint | |
1911 cursor_name_to_index (const char *name) | |
1912 { | |
1913 int i; | |
1914 static char *the_gdk_cursors[GDK_NUM_GLYPHS]; | |
1915 | |
1916 if (!the_gdk_cursors[GDK_BASED_ARROW_UP]) | |
1917 { | |
1918 /* Need to initialize the array */ | |
1919 /* Supposedly since this array is static it should be | |
1920 initialized to NULLs for us, but I'm very paranoid. */ | |
1921 for (i = 0; i < GDK_NUM_GLYPHS; i++) | |
1922 { | |
1923 the_gdk_cursors[i] = NULL; | |
1924 } | |
1925 | |
1926 #define FROB_CURSOR(x) the_gdk_cursors[GDK_##x] = __downcase(#x) | |
1927 FROB_CURSOR(ARROW); FROB_CURSOR(BASED_ARROW_DOWN); | |
1928 FROB_CURSOR(BASED_ARROW_UP); FROB_CURSOR(BOAT); | |
1929 FROB_CURSOR(BOGOSITY); FROB_CURSOR(BOTTOM_LEFT_CORNER); | |
1930 FROB_CURSOR(BOTTOM_RIGHT_CORNER); FROB_CURSOR(BOTTOM_SIDE); | |
1931 FROB_CURSOR(BOTTOM_TEE); FROB_CURSOR(BOX_SPIRAL); | |
1932 FROB_CURSOR(CENTER_PTR); FROB_CURSOR(CIRCLE); | |
1933 FROB_CURSOR(CLOCK); FROB_CURSOR(COFFEE_MUG); | |
1934 FROB_CURSOR(CROSS); FROB_CURSOR(CROSS_REVERSE); | |
1935 FROB_CURSOR(CROSSHAIR); FROB_CURSOR(DIAMOND_CROSS); | |
1936 FROB_CURSOR(DOT); FROB_CURSOR(DOTBOX); | |
1937 FROB_CURSOR(DOUBLE_ARROW); FROB_CURSOR(DRAFT_LARGE); | |
1938 FROB_CURSOR(DRAFT_SMALL); FROB_CURSOR(DRAPED_BOX); | |
1939 FROB_CURSOR(EXCHANGE); FROB_CURSOR(FLEUR); | |
1940 FROB_CURSOR(GOBBLER); FROB_CURSOR(GUMBY); | |
1941 FROB_CURSOR(HAND1); FROB_CURSOR(HAND2); | |
1942 FROB_CURSOR(HEART); FROB_CURSOR(ICON); | |
1943 FROB_CURSOR(IRON_CROSS); FROB_CURSOR(LEFT_PTR); | |
1944 FROB_CURSOR(LEFT_SIDE); FROB_CURSOR(LEFT_TEE); | |
1945 FROB_CURSOR(LEFTBUTTON); FROB_CURSOR(LL_ANGLE); | |
1946 FROB_CURSOR(LR_ANGLE); FROB_CURSOR(MAN); | |
1947 FROB_CURSOR(MIDDLEBUTTON); FROB_CURSOR(MOUSE); | |
1948 FROB_CURSOR(PENCIL); FROB_CURSOR(PIRATE); | |
1949 FROB_CURSOR(PLUS); FROB_CURSOR(QUESTION_ARROW); | |
1950 FROB_CURSOR(RIGHT_PTR); FROB_CURSOR(RIGHT_SIDE); | |
1951 FROB_CURSOR(RIGHT_TEE); FROB_CURSOR(RIGHTBUTTON); | |
1952 FROB_CURSOR(RTL_LOGO); FROB_CURSOR(SAILBOAT); | |
1953 FROB_CURSOR(SB_DOWN_ARROW); FROB_CURSOR(SB_H_DOUBLE_ARROW); | |
1954 FROB_CURSOR(SB_LEFT_ARROW); FROB_CURSOR(SB_RIGHT_ARROW); | |
1955 FROB_CURSOR(SB_UP_ARROW); FROB_CURSOR(SB_V_DOUBLE_ARROW); | |
1956 FROB_CURSOR(SHUTTLE); FROB_CURSOR(SIZING); | |
1957 FROB_CURSOR(SPIDER); FROB_CURSOR(SPRAYCAN); | |
1958 FROB_CURSOR(STAR); FROB_CURSOR(TARGET); | |
1959 FROB_CURSOR(TCROSS); FROB_CURSOR(TOP_LEFT_ARROW); | |
1960 FROB_CURSOR(TOP_LEFT_CORNER); FROB_CURSOR(TOP_RIGHT_CORNER); | |
1961 FROB_CURSOR(TOP_SIDE); FROB_CURSOR(TOP_TEE); | |
1962 FROB_CURSOR(TREK); FROB_CURSOR(UL_ANGLE); | |
1963 FROB_CURSOR(UMBRELLA); FROB_CURSOR(UR_ANGLE); | |
1964 FROB_CURSOR(WATCH); FROB_CURSOR(XTERM); | |
1965 FROB_CURSOR(X_CURSOR); | |
1966 #undef FROB_CURSOR | |
1967 } | |
1968 | |
1969 for (i = 0; i < GDK_NUM_GLYPHS; i++) | |
1970 { | |
1971 if (!the_gdk_cursors[i]) continue; | |
1972 if (!strcmp (the_gdk_cursors[i], name)) | |
1973 { | |
1974 return (i); | |
1975 } | |
1976 } | |
1977 return(-1); | |
1978 } | |
1979 | |
1980 static void | |
1981 cursor_font_instantiate (Lisp_Object image_instance, Lisp_Object instantiator, | |
1982 Lisp_Object pointer_fg, Lisp_Object pointer_bg, | |
1983 int dest_mask, Lisp_Object domain) | |
1984 { | |
1985 /* This function can GC */ | |
1986 Lisp_Object data = find_keyword_in_vector (instantiator, Q_data); | |
1987 struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance); | |
1988 Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii); | |
1989 int i; | |
1990 CONST char *name_ext; | |
1991 Lisp_Object foreground, background; | |
1992 | |
1993 if (!DEVICE_GTK_P (XDEVICE (device))) | |
1994 signal_simple_error ("Not a Gtk device", device); | |
1995 | |
1996 if (!(dest_mask & IMAGE_POINTER_MASK)) | |
1997 incompatible_image_types (instantiator, dest_mask, IMAGE_POINTER_MASK); | |
1998 | |
1999 TO_EXTERNAL_FORMAT (LISP_STRING, data, | |
2000 C_STRING_ALLOCA, name_ext, | |
2001 Qfile_name); | |
2002 | |
2003 if ((i = cursor_name_to_index (name_ext)) == -1) | |
2004 signal_simple_error ("Unrecognized cursor-font name", data); | |
2005 | |
2006 gtk_initialize_pixmap_image_instance (ii, 1, IMAGE_POINTER); | |
2007 IMAGE_INSTANCE_GTK_CURSOR (ii) = gdk_cursor_new (i); | |
2008 foreground = find_keyword_in_vector (instantiator, Q_foreground); | |
2009 if (NILP (foreground)) | |
2010 foreground = pointer_fg; | |
2011 background = find_keyword_in_vector (instantiator, Q_background); | |
2012 if (NILP (background)) | |
2013 background = pointer_bg; | |
2014 maybe_recolor_cursor (image_instance, foreground, background); | |
2015 } | |
2016 | |
2017 static int | |
2018 gtk_colorize_image_instance (Lisp_Object image_instance, | |
2019 Lisp_Object foreground, Lisp_Object background); | |
2020 | |
2021 | |
2022 /************************************************************************/ | |
2023 /* subwindow and widget support */ | |
2024 /************************************************************************/ | |
2025 | |
2026 /* unmap the image if it is a widget. This is used by redisplay via | |
2027 redisplay_unmap_subwindows */ | |
2028 static void | |
2029 gtk_unmap_subwindow (Lisp_Image_Instance *p) | |
2030 { | |
2031 if (IMAGE_INSTANCE_TYPE (p) == IMAGE_SUBWINDOW) | |
2032 { | |
2033 /* We don't support subwindows, but we do support widgets... */ | |
2034 abort (); | |
2035 } | |
2036 else /* must be a widget */ | |
2037 { | |
2038 /* Since we are being unmapped we want the enclosing frame to | |
2039 get focus. The losing with simple scrolling but is the safest | |
2040 thing to do. */ | |
2041 if (IMAGE_INSTANCE_GTK_CLIPWIDGET (p)) | |
2042 gtk_widget_unmap (IMAGE_INSTANCE_GTK_CLIPWIDGET (p)); | |
2043 } | |
2044 } | |
2045 | |
2046 /* map the subwindow. This is used by redisplay via | |
2047 redisplay_output_subwindow */ | |
2048 static void | |
2049 gtk_map_subwindow (Lisp_Image_Instance *p, int x, int y, | |
2050 struct display_glyph_area* dga) | |
2051 { | |
2052 assert (dga->width > 0 && dga->height > 0); | |
2053 | |
2054 if (IMAGE_INSTANCE_TYPE (p) == IMAGE_SUBWINDOW) | |
2055 { | |
2056 /* No subwindow support... */ | |
2057 abort (); | |
2058 } | |
2059 else /* must be a widget */ | |
2060 { | |
2061 struct frame *f = XFRAME (IMAGE_INSTANCE_FRAME (p)); | |
2062 GtkWidget *wid = IMAGE_INSTANCE_GTK_CLIPWIDGET (p); | |
2063 GtkAllocation a; | |
2064 | |
2065 if (!wid) return; | |
2066 | |
2067 a.x = x + IMAGE_INSTANCE_GTK_WIDGET_XOFFSET (p); | |
2068 a.y = y + IMAGE_INSTANCE_GTK_WIDGET_YOFFSET (p); | |
2069 a.width = dga->width; | |
2070 a.height = dga->height; | |
2071 | |
2072 if ((a.width != wid->allocation.width) || | |
2073 (a.height != wid->allocation.height)) | |
2074 { | |
2075 gtk_widget_size_allocate (IMAGE_INSTANCE_GTK_CLIPWIDGET (p), &a); | |
2076 } | |
2077 | |
2078 /* #### FIXME DAMMIT */ | |
2079 if ((wid->allocation.x != -dga->xoffset) || | |
2080 (wid->allocation.y != -dga->yoffset)) | |
2081 { | |
2082 guint32 old_flags = GTK_WIDGET_FLAGS (FRAME_GTK_TEXT_WIDGET (f)); | |
2083 | |
2084 /* Fucking GtkFixed widget queues a resize when you add a widget. | |
2085 ** But only if it is visible. | |
2086 ** losers. | |
2087 */ | |
2088 GTK_WIDGET_FLAGS(FRAME_GTK_TEXT_WIDGET (f)) &= ~GTK_VISIBLE; | |
2089 if (IMAGE_INSTANCE_GTK_ALREADY_PUT(p)) | |
2090 { | |
2091 gtk_fixed_move (GTK_FIXED (FRAME_GTK_TEXT_WIDGET (f)), | |
2092 wid, | |
2093 -dga->xoffset, -dga->yoffset); | |
2094 } | |
2095 else | |
2096 { | |
2097 IMAGE_INSTANCE_GTK_ALREADY_PUT(p) = TRUE; | |
2098 gtk_fixed_put (GTK_FIXED (FRAME_GTK_TEXT_WIDGET (f)), | |
2099 wid, | |
2100 -dga->xoffset, -dga->yoffset); | |
2101 } | |
2102 GTK_WIDGET_FLAGS(FRAME_GTK_TEXT_WIDGET (f)) = old_flags; | |
2103 } | |
2104 | |
2105 if (!IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP (p)) | |
2106 { | |
2107 gtk_widget_map (wid); | |
2108 } | |
2109 | |
2110 gtk_widget_draw (wid, NULL); | |
2111 } | |
2112 } | |
2113 | |
2114 /* when you click on a widget you may activate another widget this | |
2115 needs to be checked and all appropriate widgets updated */ | |
2116 static void | |
2117 gtk_redisplay_subwindow (Lisp_Image_Instance *p) | |
2118 { | |
2119 /* Update the subwindow size if necessary. */ | |
2120 if (IMAGE_INSTANCE_SIZE_CHANGED (p)) | |
2121 { | |
2122 #if 0 | |
2123 XResizeWindow (IMAGE_INSTANCE_X_SUBWINDOW_DISPLAY (p), | |
2124 IMAGE_INSTANCE_X_SUBWINDOW_ID (p), | |
2125 IMAGE_INSTANCE_WIDTH (p), | |
2126 IMAGE_INSTANCE_HEIGHT (p)); | |
2127 #endif | |
2128 } | |
2129 } | |
2130 | |
2131 /* Update all attributes that have changed. */ | |
2132 static void | |
2133 gtk_redisplay_widget (Lisp_Image_Instance *p) | |
2134 { | |
2135 /* This function can GC if IN_REDISPLAY is false. */ | |
2136 | |
2137 if (!IMAGE_INSTANCE_GTK_CLIPWIDGET (p)) | |
2138 return; | |
2139 | |
2140 #ifdef HAVE_WIDGETS | |
2141 /* First get the items if they have changed since this is a | |
2142 structural change. As such it will nuke all added values so we | |
2143 need to update most other things after the items have changed.*/ | |
2144 gtk_widget_show_all (IMAGE_INSTANCE_GTK_CLIPWIDGET (p)); | |
2145 if (IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (p)) | |
2146 { | |
2147 Lisp_Object image_instance; | |
2148 | |
2149 XSETIMAGE_INSTANCE (image_instance, p); | |
2150 | |
2151 /* Need to update GtkArgs that might have changed... */ | |
2152 /* #### FIXME!!! */ | |
2153 } | |
2154 else | |
2155 { | |
2156 /* #### FIXME!!! */ | |
2157 /* No items changed, so do nothing, right? */ | |
2158 } | |
2159 | |
2160 /* Possibly update the colors and font */ | |
2161 if (IMAGE_INSTANCE_WIDGET_FACE_CHANGED (p) | |
2162 || | |
2163 /* #### This is not sufficient because it will not cope with widgets | |
2164 that are not currently visible. Once redisplay has done the | |
2165 visible ones it will clear this flag so that when new ones | |
2166 become visible they will not be updated. */ | |
2167 XFRAME (IMAGE_INSTANCE_FRAME (p))->faces_changed | |
2168 || | |
2169 XFRAME (IMAGE_INSTANCE_FRAME (p))->frame_changed | |
2170 || | |
2171 IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (p)) | |
2172 { | |
2173 /* #### Write this function BILL! */ | |
2174 update_widget_face (NULL, p, IMAGE_INSTANCE_FRAME (p)); | |
2175 } | |
2176 | |
2177 /* Possibly update the text. */ | |
2178 if (IMAGE_INSTANCE_TEXT_CHANGED (p)) | |
2179 { | |
2180 char* str; | |
2181 Lisp_Object val = IMAGE_INSTANCE_WIDGET_TEXT (p); | |
2182 LISP_STRING_TO_EXTERNAL (val, str, Qnative); | |
2183 | |
2184 /* #### Need to special case each type of GtkWidget here! */ | |
2185 } | |
2186 | |
2187 /* Possibly update the size. */ | |
2188 if (IMAGE_INSTANCE_SIZE_CHANGED (p) | |
2189 || | |
2190 IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (p) | |
2191 || | |
2192 IMAGE_INSTANCE_TEXT_CHANGED (p)) | |
2193 { | |
2194 assert (IMAGE_INSTANCE_GTK_WIDGET_ID (p) && | |
2195 IMAGE_INSTANCE_GTK_CLIPWIDGET (p)) ; | |
2196 | |
2197 /* #### Resize the widget! */ | |
2198 /* gtk_widget_size_allocate () */ | |
2199 } | |
2200 | |
2201 /* Adjust offsets within the frame. */ | |
2202 if (XFRAME (IMAGE_INSTANCE_FRAME (p))->size_changed) | |
2203 { | |
2204 /* I don't think we need to do anything for Gtk here... */ | |
2205 } | |
2206 | |
2207 /* now modify the widget */ | |
2208 #endif | |
2209 } | |
2210 | |
2211 /* instantiate and gtk type subwindow */ | |
2212 static void | |
2213 gtk_subwindow_instantiate (Lisp_Object image_instance, Lisp_Object instantiator, | |
2214 Lisp_Object pointer_fg, Lisp_Object pointer_bg, | |
2215 int dest_mask, Lisp_Object domain) | |
2216 { | |
2217 /* This function can GC */ | |
2218 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance); | |
2219 Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii); | |
2220 Lisp_Object frame = DOMAIN_FRAME (domain); | |
2221 | |
2222 if (!DEVICE_GTK_P (XDEVICE (device))) | |
2223 signal_simple_error ("Not a GTK device", device); | |
2224 | |
2225 IMAGE_INSTANCE_TYPE (ii) = IMAGE_SUBWINDOW; | |
2226 | |
2227 ii->data = xnew_and_zero (struct gtk_subwindow_data); | |
2228 | |
2229 /* Create a window for clipping */ | |
2230 IMAGE_INSTANCE_GTK_CLIPWINDOW (ii) = NULL; | |
2231 | |
2232 /* Now put the subwindow inside the clip window. */ | |
2233 IMAGE_INSTANCE_SUBWINDOW_ID (ii) = (void *) NULL; | |
2234 } | |
2235 | |
2236 #ifdef HAVE_WIDGETS | |
2237 | |
2238 /************************************************************************/ | |
2239 /* widgets */ | |
2240 /************************************************************************/ | |
2241 static void | |
2242 update_widget_face (GtkWidget *w, Lisp_Image_Instance *ii, | |
2243 Lisp_Object domain) | |
2244 { | |
2245 if (0) | |
2246 { | |
2247 GtkStyle *style = gtk_widget_get_style (w); | |
2248 Lisp_Object pixel = Qnil; | |
2249 GdkColor *fcolor, *bcolor; | |
2250 | |
2251 style = gtk_style_copy (style); | |
2252 | |
2253 /* Update the foreground. */ | |
2254 pixel = FACE_FOREGROUND (IMAGE_INSTANCE_WIDGET_FACE (ii), domain); | |
2255 fcolor = COLOR_INSTANCE_GTK_COLOR (XCOLOR_INSTANCE (pixel)); | |
2256 | |
2257 /* Update the background. */ | |
2258 pixel = FACE_BACKGROUND (IMAGE_INSTANCE_WIDGET_FACE (ii), domain); | |
2259 bcolor = COLOR_INSTANCE_GTK_COLOR (XCOLOR_INSTANCE (pixel)); | |
2260 | |
2261 /* Update the font */ | |
2262 /* #### FIXME!!! Need to copy the widgets style, dick with it, and | |
2263 ** set the widgets style to the new style... | |
2264 */ | |
2265 gtk_widget_set_style (w, style); | |
2266 | |
2267 /* #### Megahack - but its just getting too complicated to do this | |
2268 in the right place. */ | |
2269 #if 0 | |
2270 if (EQ (IMAGE_INSTANCE_WIDGET_TYPE (ii), Qtab_control)) | |
2271 update_tab_widget_face (wv, ii, domain); | |
2272 #endif | |
2273 } | |
2274 } | |
2275 | |
2276 #if 0 | |
2277 static void | |
2278 update_tab_widget_face (GtkWidget *w, Lisp_Image_Instance *ii, | |
2279 Lisp_Object domain) | |
2280 { | |
2281 if (wv->contents) | |
2282 { | |
2283 widget_value* val = wv->contents, *cur; | |
2284 | |
2285 /* Give each child label the correct foreground color. */ | |
2286 Lisp_Object pixel = FACE_FOREGROUND | |
2287 (IMAGE_INSTANCE_WIDGET_FACE (ii), | |
2288 domain); | |
2289 XColor fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (pixel)); | |
2290 lw_add_widget_value_arg (val, XtNtabForeground, fcolor.pixel); | |
2291 wv->change = VISIBLE_CHANGE; | |
2292 val->change = VISIBLE_CHANGE; | |
2293 | |
2294 for (cur = val->next; cur; cur = cur->next) | |
2295 { | |
2296 cur->change = VISIBLE_CHANGE; | |
2297 if (cur->value) | |
2298 { | |
2299 lw_copy_widget_value_args (val, cur); | |
2300 } | |
2301 } | |
2302 } | |
2303 } | |
2304 #endif | |
2305 | |
2306 static Lisp_Object | |
2307 gtk_widget_instantiate_1 (Lisp_Object image_instance, Lisp_Object instantiator, | |
2308 Lisp_Object pointer_fg, Lisp_Object pointer_bg, | |
2309 Lisp_Object domain) | |
2310 { | |
2311 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance); | |
2312 Lisp_Object widget = Qnil; | |
2313 char *nm = NULL; | |
2314 GtkWidget *w = NULL; | |
2315 struct gcpro gcpro1; | |
2316 | |
2317 IMAGE_INSTANCE_TYPE (ii) = IMAGE_WIDGET; | |
2318 | |
2319 if (!NILP (IMAGE_INSTANCE_WIDGET_TEXT (ii))) | |
2320 { | |
2321 LISP_STRING_TO_EXTERNAL (IMAGE_INSTANCE_WIDGET_TEXT (ii), nm, Qnative); | |
2322 } | |
2323 | |
2324 ii->data = xnew_and_zero (struct gtk_subwindow_data); | |
2325 | |
2326 /* Create a clipping widget */ | |
2327 IMAGE_INSTANCE_GTK_CLIPWIDGET (ii) = NULL; | |
2328 IMAGE_INSTANCE_GTK_ALREADY_PUT(ii) = FALSE; | |
2329 | |
2330 /* Create the actual widget */ | |
2331 GCPRO1 (widget); | |
2332 widget = call5 (Qgtk_widget_instantiate_internal, | |
2333 image_instance, instantiator, | |
2334 pointer_fg, pointer_bg, | |
2335 domain); | |
2336 | |
2337 if (!NILP (widget)) | |
2338 { | |
2339 CHECK_GTK_OBJECT (widget); | |
2340 w = GTK_WIDGET (XGTK_OBJECT (widget)->object); | |
2341 } | |
2342 else | |
2343 { | |
2344 stderr_out ("Lisp-level creation of widget failed... falling back\n"); | |
2345 w = gtk_label_new ("Widget Creation Failed..."); | |
2346 } | |
2347 | |
2348 UNGCPRO; | |
2349 | |
2350 IMAGE_INSTANCE_SUBWINDOW_ID (ii) = (void *) w; | |
2351 | |
2352 /* #### HACK!!!! We should make this do the right thing if we | |
2353 ** really need a clip widget! | |
2354 */ | |
2355 IMAGE_INSTANCE_GTK_CLIPWIDGET (ii) = w; | |
2356 | |
2357 return (Qt); | |
2358 } | |
2359 | |
2360 static void | |
2361 gtk_widget_instantiate (Lisp_Object image_instance, Lisp_Object instantiator, | |
2362 Lisp_Object pointer_fg, Lisp_Object pointer_bg, | |
2363 int dest_mask, Lisp_Object domain) | |
2364 { | |
2365 call_with_suspended_errors ((lisp_fn_t) gtk_widget_instantiate_1, | |
2366 Qnil, Qimage, | |
2367 ERROR_ME_WARN, 5, | |
2368 image_instance, instantiator, | |
2369 pointer_fg, | |
2370 pointer_bg, | |
2371 domain); | |
2372 } | |
2373 | |
2374 /* get properties of a control */ | |
2375 static Lisp_Object | |
2376 gtk_widget_property (Lisp_Object image_instance, Lisp_Object prop) | |
2377 { | |
2378 /* Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance); */ | |
2379 | |
2380 /* get the text from a control */ | |
2381 if (EQ (prop, Q_text)) | |
2382 { | |
2383 return Qnil; | |
2384 } | |
2385 return Qunbound; | |
2386 } | |
2387 | |
2388 #define FAKE_GTK_WIDGET_INSTANTIATOR(x) \ | |
2389 static void \ | |
2390 gtk_##x##_instantiate (Lisp_Object image_instance, \ | |
2391 Lisp_Object instantiator, \ | |
2392 Lisp_Object pointer_fg, \ | |
2393 Lisp_Object pointer_bg, \ | |
2394 int dest_mask, Lisp_Object domain) \ | |
2395 { \ | |
2396 gtk_widget_instantiate (image_instance, instantiator, pointer_fg, \ | |
2397 pointer_bg, dest_mask, domain); \ | |
2398 } | |
2399 | |
2400 FAKE_GTK_WIDGET_INSTANTIATOR(native_layout); | |
2401 FAKE_GTK_WIDGET_INSTANTIATOR(button); | |
2402 FAKE_GTK_WIDGET_INSTANTIATOR(progress_gauge); | |
2403 FAKE_GTK_WIDGET_INSTANTIATOR(edit_field); | |
2404 FAKE_GTK_WIDGET_INSTANTIATOR(combo_box); | |
2405 FAKE_GTK_WIDGET_INSTANTIATOR(tab_control); | |
2406 FAKE_GTK_WIDGET_INSTANTIATOR(label); | |
2407 | |
2408 /* Update a button's clicked state. */ | |
2409 static void | |
2410 gtk_button_redisplay (Lisp_Object image_instance) | |
2411 { | |
2412 /* This function can GC if IN_REDISPLAY is false. */ | |
2413 Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance); | |
2414 GtkWidget *w = IMAGE_INSTANCE_GTK_CLIPWIDGET (p); | |
2415 | |
2416 if (GTK_WIDGET_TYPE (w) == gtk_button_get_type ()) | |
2417 { | |
2418 } | |
2419 else if (GTK_WIDGET_TYPE (w) == gtk_check_button_get_type ()) | |
2420 { | |
2421 } | |
2422 else if (GTK_WIDGET_TYPE (w) == gtk_radio_button_get_type ()) | |
2423 { | |
2424 } | |
2425 else | |
2426 { | |
2427 /* Unknown button type... */ | |
2428 abort(); | |
2429 } | |
2430 } | |
2431 | |
2432 /* get properties of a button */ | |
2433 static Lisp_Object | |
2434 gtk_button_property (Lisp_Object image_instance, Lisp_Object prop) | |
2435 { | |
2436 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance); | |
2437 | |
2438 /* check the state of a button */ | |
2439 if (EQ (prop, Q_selected)) | |
2440 { | |
2441 if (GTK_WIDGET_HAS_FOCUS (IMAGE_INSTANCE_SUBWINDOW_ID (ii))) | |
2442 return Qt; | |
2443 else | |
2444 return Qnil; | |
2445 } | |
2446 return Qunbound; | |
2447 } | |
2448 | |
2449 /* set the properties of a progress gauge */ | |
2450 static void | |
2451 gtk_progress_gauge_redisplay (Lisp_Object image_instance) | |
2452 { | |
2453 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance); | |
2454 | |
2455 if (IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (ii)) | |
2456 { | |
2457 gfloat f; | |
2458 Lisp_Object val; | |
2459 | |
2460 val = XGUI_ITEM (IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii))->value; | |
2461 f = XFLOATINT (val); | |
2462 | |
2463 gtk_progress_set_value (GTK_PROGRESS (IMAGE_INSTANCE_SUBWINDOW_ID (ii)), | |
2464 f); | |
2465 } | |
2466 } | |
2467 | |
2468 /* Set the properties of a tab control */ | |
2469 static void | |
2470 gtk_tab_control_redisplay (Lisp_Object image_instance) | |
2471 { | |
2472 /* #### Convert this to GTK baby! */ | |
2473 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance); | |
2474 | |
2475 if (IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (ii) || | |
2476 IMAGE_INSTANCE_WIDGET_ACTION_OCCURRED (ii)) | |
2477 { | |
2478 /* If only the order has changed then simply select the first | |
2479 one of the pending set. This stops horrendous rebuilding - | |
2480 and hence flicker - of the tabs each time you click on | |
2481 one. */ | |
2482 if (tab_control_order_only_changed (image_instance)) | |
2483 { | |
2484 Lisp_Object rest, selected = | |
2485 gui_item_list_find_selected | |
2486 (NILP (IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii)) ? | |
2487 XCDR (IMAGE_INSTANCE_WIDGET_ITEMS (ii)) : | |
2488 XCDR (IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii))); | |
2489 | |
2490 LIST_LOOP (rest, XCDR (IMAGE_INSTANCE_WIDGET_ITEMS (ii))) | |
2491 { | |
2492 if (gui_item_equal_sans_selected (XCAR (rest), selected, 0)) | |
2493 { | |
2494 Lisp_Object old_selected =gui_item_list_find_selected | |
2495 (XCDR (IMAGE_INSTANCE_WIDGET_ITEMS (ii))); | |
2496 | |
2497 /* Need to focus on the widget... */ | |
2498 stderr_out ("Hey, change the tab-focus you boob...\n"); | |
2499 | |
2500 /* Pick up the new selected item. */ | |
2501 XGUI_ITEM (old_selected)->selected = | |
2502 XGUI_ITEM (XCAR (rest))->selected; | |
2503 XGUI_ITEM (XCAR (rest))->selected = | |
2504 XGUI_ITEM (selected)->selected; | |
2505 /* We're not actually changing the items anymore. */ | |
2506 IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (ii) = 0; | |
2507 IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii) = Qnil; | |
2508 break; | |
2509 } | |
2510 } | |
2511 } | |
2512 else | |
2513 { | |
2514 /* More than just the order has changed... let's get busy! */ | |
2515 GtkNotebook *nb = GTK_NOTEBOOK (IMAGE_INSTANCE_GTK_CLIPWIDGET (ii)); | |
2516 guint num_pages = g_list_length (nb->children); | |
2517 Lisp_Object rest; | |
2518 | |
2519 if (num_pages >= 0) | |
2520 { | |
2521 int i; | |
2522 for (i = num_pages; i >= 0; --i) | |
2523 { | |
2524 gtk_notebook_remove_page (nb, i); | |
2525 } | |
2526 } | |
2527 | |
2528 LIST_LOOP (rest, XCDR (IMAGE_INSTANCE_WIDGET_ITEMS (ii))) | |
2529 { | |
2530 Lisp_Gui_Item *pgui = XGUI_ITEM (XCAR (rest)); | |
2531 char *c_name = NULL; | |
2532 | |
2533 if (!STRINGP (pgui->name)) | |
2534 pgui->name = Feval (pgui->name); | |
2535 | |
2536 CHECK_STRING (pgui->name); | |
2537 | |
2538 TO_EXTERNAL_FORMAT (LISP_STRING, pgui->name, | |
2539 C_STRING_ALLOCA, c_name, | |
2540 Qctext); | |
2541 | |
2542 gtk_notebook_append_page (nb, | |
2543 gtk_vbox_new (FALSE, 3), | |
2544 gtk_label_new (c_name)); | |
2545 } | |
2546 | |
2547 /* Show all the new widgets we just added... */ | |
2548 gtk_widget_show_all (GTK_WIDGET (nb)); | |
2549 } | |
2550 } | |
2551 | |
2552 /* Possibly update the face. */ | |
2553 #if 0 | |
2554 if (IMAGE_INSTANCE_WIDGET_FACE_CHANGED (ii) | |
2555 || | |
2556 XFRAME (IMAGE_INSTANCE_FRAME (ii))->faces_changed | |
2557 || | |
2558 IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (ii)) | |
2559 { | |
2560 update_tab_widget_face (wv, ii, | |
2561 IMAGE_INSTANCE_FRAME (ii)); | |
2562 } | |
2563 #endif | |
2564 } | |
2565 #endif /* HAVE_WIDGETS */ | |
2566 | |
2567 | |
2568 /************************************************************************/ | |
2569 /* initialization */ | |
2570 /************************************************************************/ | |
2571 void | |
2572 syms_of_glyphs_gtk (void) | |
2573 { | |
2574 defkeyword (&Q_resource_id, ":resource-id"); | |
2575 defkeyword (&Q_resource_type, ":resource-type"); | |
2576 #ifdef HAVE_WIDGETS | |
2577 defsymbol (&Qgtk_widget_instantiate_internal, "gtk-widget-instantiate-internal"); | |
2578 defsymbol (&Qgtk_widget_property_internal, "gtk-widget-property-internal"); | |
2579 defsymbol (&Qgtk_widget_redisplay_internal, "gtk-widget-redisplay-internal"); | |
2580 defsymbol (&Qgtk_widget_set_style, "gtk-widget-set-style"); | |
2581 #endif | |
2582 } | |
2583 | |
2584 void | |
2585 console_type_create_glyphs_gtk (void) | |
2586 { | |
2587 /* image methods */ | |
2588 CONSOLE_HAS_METHOD (gtk, print_image_instance); | |
2589 CONSOLE_HAS_METHOD (gtk, finalize_image_instance); | |
2590 CONSOLE_HAS_METHOD (gtk, image_instance_equal); | |
2591 CONSOLE_HAS_METHOD (gtk, image_instance_hash); | |
2592 CONSOLE_HAS_METHOD (gtk, colorize_image_instance); | |
2593 CONSOLE_HAS_METHOD (gtk, init_image_instance_from_eimage); | |
2594 CONSOLE_HAS_METHOD (gtk, locate_pixmap_file); | |
2595 CONSOLE_HAS_METHOD (gtk, unmap_subwindow); | |
2596 CONSOLE_HAS_METHOD (gtk, map_subwindow); | |
2597 CONSOLE_HAS_METHOD (gtk, redisplay_widget); | |
2598 CONSOLE_HAS_METHOD (gtk, redisplay_subwindow); | |
2599 } | |
2600 | |
2601 void | |
2602 image_instantiator_format_create_glyphs_gtk (void) | |
2603 { | |
2604 IIFORMAT_VALID_CONSOLE (gtk, nothing); | |
2605 IIFORMAT_VALID_CONSOLE (gtk, string); | |
2606 #ifdef HAVE_WIDGETS | |
2607 IIFORMAT_VALID_CONSOLE (gtk, layout); | |
2608 #endif | |
2609 IIFORMAT_VALID_CONSOLE (gtk, formatted_string); | |
2610 IIFORMAT_VALID_CONSOLE (gtk, inherit); | |
2611 #ifdef HAVE_XPM | |
2612 INITIALIZE_DEVICE_IIFORMAT (gtk, xpm); | |
2613 IIFORMAT_HAS_DEVMETHOD (gtk, xpm, instantiate); | |
2614 #endif | |
2615 #ifdef HAVE_JPEG | |
2616 IIFORMAT_VALID_CONSOLE (gtk, jpeg); | |
2617 #endif | |
2618 #ifdef HAVE_TIFF | |
2619 IIFORMAT_VALID_CONSOLE (gtk, tiff); | |
2620 #endif | |
2621 #ifdef HAVE_PNG | |
2622 IIFORMAT_VALID_CONSOLE (gtk, png); | |
2623 #endif | |
2624 #ifdef HAVE_GIF | |
2625 IIFORMAT_VALID_CONSOLE (gtk, gif); | |
2626 #endif | |
2627 | |
2628 INITIALIZE_DEVICE_IIFORMAT (gtk, subwindow); | |
2629 IIFORMAT_HAS_DEVMETHOD (gtk, subwindow, instantiate); | |
2630 | |
2631 #ifdef HAVE_WIDGETS | |
2632 /* layout widget */ | |
2633 INITIALIZE_DEVICE_IIFORMAT (gtk, native_layout); | |
2634 IIFORMAT_HAS_DEVMETHOD (gtk, native_layout, instantiate); | |
2635 | |
2636 /* button widget */ | |
2637 INITIALIZE_DEVICE_IIFORMAT (gtk, button); | |
2638 IIFORMAT_HAS_DEVMETHOD (gtk, button, property); | |
2639 IIFORMAT_HAS_DEVMETHOD (gtk, button, instantiate); | |
2640 IIFORMAT_HAS_DEVMETHOD (gtk, button, redisplay); | |
2641 /* general widget methods. */ | |
2642 INITIALIZE_DEVICE_IIFORMAT (gtk, widget); | |
2643 IIFORMAT_HAS_DEVMETHOD (gtk, widget, property); | |
2644 | |
2645 /* progress gauge */ | |
2646 INITIALIZE_DEVICE_IIFORMAT (gtk, progress_gauge); | |
2647 IIFORMAT_HAS_DEVMETHOD (gtk, progress_gauge, redisplay); | |
2648 IIFORMAT_HAS_DEVMETHOD (gtk, progress_gauge, instantiate); | |
2649 /* text field */ | |
2650 INITIALIZE_DEVICE_IIFORMAT (gtk, edit_field); | |
2651 IIFORMAT_HAS_DEVMETHOD (gtk, edit_field, instantiate); | |
2652 INITIALIZE_DEVICE_IIFORMAT (gtk, combo_box); | |
2653 IIFORMAT_HAS_DEVMETHOD (gtk, combo_box, instantiate); | |
2654 IIFORMAT_HAS_SHARED_DEVMETHOD (gtk, combo_box, redisplay, tab_control); | |
2655 /* tab control widget */ | |
2656 INITIALIZE_DEVICE_IIFORMAT (gtk, tab_control); | |
2657 IIFORMAT_HAS_DEVMETHOD (gtk, tab_control, instantiate); | |
2658 IIFORMAT_HAS_DEVMETHOD (gtk, tab_control, redisplay); | |
2659 /* label */ | |
2660 INITIALIZE_DEVICE_IIFORMAT (gtk, label); | |
2661 IIFORMAT_HAS_DEVMETHOD (gtk, label, instantiate); | |
2662 #endif | |
2663 | |
2664 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (cursor_font, "cursor-font"); | |
2665 IIFORMAT_VALID_CONSOLE (gtk, cursor_font); | |
2666 | |
2667 IIFORMAT_HAS_METHOD (cursor_font, validate); | |
2668 IIFORMAT_HAS_METHOD (cursor_font, possible_dest_types); | |
2669 IIFORMAT_HAS_METHOD (cursor_font, instantiate); | |
2670 | |
2671 IIFORMAT_VALID_KEYWORD (cursor_font, Q_data, check_valid_string); | |
2672 IIFORMAT_VALID_KEYWORD (cursor_font, Q_foreground, check_valid_string); | |
2673 IIFORMAT_VALID_KEYWORD (cursor_font, Q_background, check_valid_string); | |
2674 | |
2675 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (font, "font"); | |
2676 IIFORMAT_VALID_CONSOLE (gtk, font); | |
2677 | |
2678 IIFORMAT_HAS_METHOD (font, validate); | |
2679 IIFORMAT_HAS_METHOD (font, possible_dest_types); | |
2680 IIFORMAT_HAS_METHOD (font, instantiate); | |
2681 | |
2682 IIFORMAT_VALID_KEYWORD (font, Q_data, check_valid_string); | |
2683 IIFORMAT_VALID_KEYWORD (font, Q_foreground, check_valid_string); | |
2684 IIFORMAT_VALID_KEYWORD (font, Q_background, check_valid_string); | |
2685 | |
2686 #ifdef HAVE_XPM | |
2687 INITIALIZE_DEVICE_IIFORMAT (gtk, xpm); | |
2688 IIFORMAT_HAS_DEVMETHOD (gtk, xpm, instantiate); | |
2689 #endif | |
2690 | |
2691 #ifdef HAVE_XFACE | |
2692 INITIALIZE_DEVICE_IIFORMAT (gtk, xface); | |
2693 IIFORMAT_HAS_DEVMETHOD (gtk, xface, instantiate); | |
2694 #endif | |
2695 | |
2696 INITIALIZE_DEVICE_IIFORMAT (gtk, xbm); | |
2697 IIFORMAT_HAS_DEVMETHOD (gtk, xbm, instantiate); | |
2698 IIFORMAT_VALID_CONSOLE (gtk, xbm); | |
2699 | |
2700 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (gtk_resource, "gtk-resource"); | |
2701 IIFORMAT_VALID_CONSOLE (gtk, gtk_resource); | |
2702 | |
2703 IIFORMAT_HAS_METHOD (gtk_resource, validate); | |
2704 IIFORMAT_HAS_METHOD (gtk_resource, normalize); | |
2705 IIFORMAT_HAS_METHOD (gtk_resource, possible_dest_types); | |
2706 IIFORMAT_HAS_METHOD (gtk_resource, instantiate); | |
2707 | |
2708 IIFORMAT_VALID_KEYWORD (gtk_resource, Q_resource_type, check_valid_resource_symbol); | |
2709 IIFORMAT_VALID_KEYWORD (gtk_resource, Q_resource_id, check_valid_resource_id); | |
2710 IIFORMAT_VALID_KEYWORD (gtk_resource, Q_file, check_valid_string); | |
2711 | |
2712 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (autodetect, "autodetect"); | |
2713 IIFORMAT_VALID_CONSOLE (gtk, autodetect); | |
2714 | |
2715 IIFORMAT_HAS_METHOD (autodetect, validate); | |
2716 IIFORMAT_HAS_METHOD (autodetect, normalize); | |
2717 IIFORMAT_HAS_METHOD (autodetect, possible_dest_types); | |
2718 IIFORMAT_HAS_METHOD (autodetect, instantiate); | |
2719 | |
2720 IIFORMAT_VALID_KEYWORD (autodetect, Q_data, check_valid_string); | |
2721 } | |
2722 | |
2723 void | |
2724 vars_of_glyphs_gtk (void) | |
2725 { | |
2726 #ifdef HAVE_XFACE | |
2727 Fprovide (Qxface); | |
2728 #endif | |
2729 | |
2730 DEFVAR_LISP ("gtk-bitmap-file-path", &Vgtk_bitmap_file_path /* | |
2731 A list of the directories in which X bitmap files may be found. | |
2732 If nil, this is initialized from the "*bitmapFilePath" resource. | |
2733 This is used by the `make-image-instance' function (however, note that if | |
2734 the environment variable XBMLANGPATH is set, it is consulted first). | |
2735 */ ); | |
2736 Vgtk_bitmap_file_path = Qnil; | |
2737 } | |
2738 | |
2739 void | |
2740 complex_vars_of_glyphs_gtk (void) | |
2741 { | |
2742 #define BUILD_GLYPH_INST(variable, name) \ | |
2743 Fadd_spec_to_specifier \ | |
2744 (GLYPH_IMAGE (XGLYPH (variable)), \ | |
2745 vector3 (Qxbm, Q_data, \ | |
2746 list3 (make_int (name##_width), \ | |
2747 make_int (name##_height), \ | |
2748 make_ext_string (name##_bits, \ | |
2749 sizeof (name##_bits), \ | |
2750 Qbinary))), \ | |
2751 Qglobal, Qgtk, Qnil) | |
2752 | |
2753 BUILD_GLYPH_INST (Vtruncation_glyph, truncator); | |
2754 BUILD_GLYPH_INST (Vcontinuation_glyph, continuer); | |
2755 BUILD_GLYPH_INST (Vxemacs_logo, xemacs); | |
2756 BUILD_GLYPH_INST (Vhscroll_glyph, hscroll); | |
2757 | |
2758 #undef BUILD_GLYPH_INST | |
2759 } | |
2760 | |
2761 | |
2762 /* Ripped off from glyphs-msw.c */ | |
2763 /* | |
2764 * The data returned by the following routine is always in left-most byte | |
2765 * first and left-most bit first. If it doesn't return BitmapSuccess then | |
2766 * its arguments won't have been touched. This routine should look as much | |
2767 * like the Xlib routine XReadBitmapfile as possible. | |
2768 */ | |
2769 #define MAX_SIZE 1024 | |
2770 | |
2771 /* shared data for the image read/parse logic */ | |
2772 static short hexTable[256]; /* conversion value */ | |
2773 static int initialized = FALSE; /* easier to fill in at run time */ | |
2774 | |
2775 /* | |
2776 * Table index for the hex values. Initialized once, first time. | |
2777 * Used for translation value or delimiter significance lookup. | |
2778 */ | |
2779 static void initHexTable() | |
2780 { | |
2781 /* | |
2782 * We build the table at run time for several reasons: | |
2783 * | |
2784 * 1. portable to non-ASCII machines. | |
2785 * 2. still reentrant since we set the init flag after setting table. | |
2786 * 3. easier to extend. | |
2787 * 4. less prone to bugs. | |
2788 */ | |
2789 hexTable['0'] = 0; hexTable['1'] = 1; | |
2790 hexTable['2'] = 2; hexTable['3'] = 3; | |
2791 hexTable['4'] = 4; hexTable['5'] = 5; | |
2792 hexTable['6'] = 6; hexTable['7'] = 7; | |
2793 hexTable['8'] = 8; hexTable['9'] = 9; | |
2794 hexTable['A'] = 10; hexTable['B'] = 11; | |
2795 hexTable['C'] = 12; hexTable['D'] = 13; | |
2796 hexTable['E'] = 14; hexTable['F'] = 15; | |
2797 hexTable['a'] = 10; hexTable['b'] = 11; | |
2798 hexTable['c'] = 12; hexTable['d'] = 13; | |
2799 hexTable['e'] = 14; hexTable['f'] = 15; | |
2800 | |
2801 /* delimiters of significance are flagged w/ negative value */ | |
2802 hexTable[' '] = -1; hexTable[','] = -1; | |
2803 hexTable['}'] = -1; hexTable['\n'] = -1; | |
2804 hexTable['\t'] = -1; | |
2805 | |
2806 initialized = TRUE; | |
2807 } | |
2808 | |
2809 /* | |
2810 * read next hex value in the input stream, return -1 if EOF | |
2811 */ | |
2812 static int NextInt ( FILE *fstream ) | |
2813 { | |
2814 int ch; | |
2815 int value = 0; | |
2816 int gotone = 0; | |
2817 int done = 0; | |
2818 | |
2819 /* loop, accumulate hex value until find delimiter */ | |
2820 /* skip any initial delimiters found in read stream */ | |
2821 | |
2822 while (!done) { | |
2823 ch = getc(fstream); | |
2824 if (ch == EOF) { | |
2825 value = -1; | |
2826 done++; | |
2827 } else { | |
2828 /* trim high bits, check type and accumulate */ | |
2829 ch &= 0xff; | |
2830 if (isascii(ch) && isxdigit(ch)) { | |
2831 value = (value << 4) + hexTable[ch]; | |
2832 gotone++; | |
2833 } else if ((hexTable[ch]) < 0 && gotone) | |
2834 done++; | |
2835 } | |
2836 } | |
2837 return value; | |
2838 } | |
2839 | |
2840 int read_bitmap_data (fstream, width, height, datap, x_hot, y_hot) | |
2841 FILE *fstream; /* handle on file */ | |
2842 unsigned int *width, *height; /* RETURNED */ | |
2843 unsigned char **datap; /* RETURNED */ | |
2844 int *x_hot, *y_hot; /* RETURNED */ | |
2845 { | |
2846 unsigned char *data = NULL; /* working variable */ | |
2847 char line[MAX_SIZE]; /* input line from file */ | |
2848 int size; /* number of bytes of data */ | |
2849 char name_and_type[MAX_SIZE]; /* an input line */ | |
2850 char *type; /* for parsing */ | |
2851 int value; /* from an input line */ | |
2852 int version10p; /* boolean, old format */ | |
2853 int padding; /* to handle alignment */ | |
2854 int bytes_per_line; /* per scanline of data */ | |
2855 unsigned int ww = 0; /* width */ | |
2856 unsigned int hh = 0; /* height */ | |
2857 int hx = -1; /* x hotspot */ | |
2858 int hy = -1; /* y hotspot */ | |
2859 | |
2860 #define Xmalloc(size) malloc(size) | |
2861 | |
2862 /* first time initialization */ | |
2863 if (initialized == FALSE) initHexTable(); | |
2864 | |
2865 /* error cleanup and return macro */ | |
2866 #define RETURN(code) { if (data) free (data); return code; } | |
2867 | |
2868 while (fgets(line, MAX_SIZE, fstream)) { | |
2869 if (strlen(line) == MAX_SIZE-1) { | |
2870 RETURN (BitmapFileInvalid); | |
2871 } | |
2872 if (sscanf(line,"#define %s %d",name_and_type,&value) == 2) { | |
2873 if (!(type = strrchr(name_and_type, '_'))) | |
2874 type = name_and_type; | |
2875 else | |
2876 type++; | |
2877 | |
2878 if (!strcmp("width", type)) | |
2879 ww = (unsigned int) value; | |
2880 if (!strcmp("height", type)) | |
2881 hh = (unsigned int) value; | |
2882 if (!strcmp("hot", type)) { | |
2883 if (type-- == name_and_type || type-- == name_and_type) | |
2884 continue; | |
2885 if (!strcmp("x_hot", type)) | |
2886 hx = value; | |
2887 if (!strcmp("y_hot", type)) | |
2888 hy = value; | |
2889 } | |
2890 continue; | |
2891 } | |
2892 | |
2893 if (sscanf(line, "static short %s = {", name_and_type) == 1) | |
2894 version10p = 1; | |
2895 else if (sscanf(line,"static unsigned char %s = {",name_and_type) == 1) | |
2896 version10p = 0; | |
2897 else if (sscanf(line, "static char %s = {", name_and_type) == 1) | |
2898 version10p = 0; | |
2899 else | |
2900 continue; | |
2901 | |
2902 if (!(type = strrchr(name_and_type, '_'))) | |
2903 type = name_and_type; | |
2904 else | |
2905 type++; | |
2906 | |
2907 if (strcmp("bits[]", type)) | |
2908 continue; | |
2909 | |
2910 if (!ww || !hh) | |
2911 RETURN (BitmapFileInvalid); | |
2912 | |
2913 if ((ww % 16) && ((ww % 16) < 9) && version10p) | |
2914 padding = 1; | |
2915 else | |
2916 padding = 0; | |
2917 | |
2918 bytes_per_line = (ww+7)/8 + padding; | |
2919 | |
2920 size = bytes_per_line * hh; | |
2921 data = (unsigned char *) Xmalloc ((unsigned int) size); | |
2922 if (!data) | |
2923 RETURN (BitmapNoMemory); | |
2924 | |
2925 if (version10p) { | |
2926 unsigned char *ptr; | |
2927 int bytes; | |
2928 | |
2929 for (bytes=0, ptr=data; bytes<size; (bytes += 2)) { | |
2930 if ((value = NextInt(fstream)) < 0) | |
2931 RETURN (BitmapFileInvalid); | |
2932 *(ptr++) = value; | |
2933 if (!padding || ((bytes+2) % bytes_per_line)) | |
2934 *(ptr++) = value >> 8; | |
2935 } | |
2936 } else { | |
2937 unsigned char *ptr; | |
2938 int bytes; | |
2939 | |
2940 for (bytes=0, ptr=data; bytes<size; bytes++, ptr++) { | |
2941 if ((value = NextInt(fstream)) < 0) | |
2942 RETURN (BitmapFileInvalid); | |
2943 *ptr=value; | |
2944 } | |
2945 } | |
2946 break; | |
2947 } /* end while */ | |
2948 | |
2949 if (data == NULL) { | |
2950 RETURN (BitmapFileInvalid); | |
2951 } | |
2952 | |
2953 *datap = data; | |
2954 data = NULL; | |
2955 *width = ww; | |
2956 *height = hh; | |
2957 if (x_hot) *x_hot = hx; | |
2958 if (y_hot) *y_hot = hy; | |
2959 | |
2960 RETURN (BitmapSuccess); | |
2961 } | |
2962 | |
2963 | |
2964 int read_bitmap_data_from_file (CONST char *filename, unsigned int *width, | |
2965 unsigned int *height, unsigned char **datap, | |
2966 int *x_hot, int *y_hot) | |
2967 { | |
2968 FILE *fstream; | |
2969 int rval; | |
2970 | |
2971 if ((fstream = fopen (filename, "r")) == NULL) { | |
2972 return BitmapOpenFailed; | |
2973 } | |
2974 rval = read_bitmap_data (fstream, width, height, datap, x_hot, y_hot); | |
2975 fclose (fstream); | |
2976 return rval; | |
2977 } | |
2978 | |
2979 /* X specific crap */ | |
2980 #include <gdk/gdkx.h> | |
2981 /* #### Should remove all this X specific stuff when GTK/GDK matures a | |
2982 bit more and provides an abstraction for it. */ | |
2983 static int | |
2984 gtk_colorize_image_instance (Lisp_Object image_instance, | |
2985 Lisp_Object foreground, Lisp_Object background) | |
2986 { | |
2987 struct Lisp_Image_Instance *p; | |
2988 | |
2989 p = XIMAGE_INSTANCE (image_instance); | |
2990 | |
2991 switch (IMAGE_INSTANCE_TYPE (p)) | |
2992 { | |
2993 case IMAGE_MONO_PIXMAP: | |
2994 IMAGE_INSTANCE_TYPE (p) = IMAGE_COLOR_PIXMAP; | |
2995 /* Make sure there aren't two pointers to the same mask, causing | |
2996 it to get freed twice. */ | |
2997 IMAGE_INSTANCE_GTK_MASK (p) = 0; | |
2998 break; | |
2999 | |
3000 default: | |
3001 return 0; | |
3002 } | |
3003 | |
3004 { | |
3005 GdkWindow *draw = GET_GTK_WIDGET_WINDOW (DEVICE_GTK_APP_SHELL (XDEVICE (IMAGE_INSTANCE_DEVICE (p)))); | |
3006 GdkPixmap *new_pxmp = gdk_pixmap_new (draw, | |
3007 IMAGE_INSTANCE_PIXMAP_WIDTH (p), | |
3008 IMAGE_INSTANCE_PIXMAP_HEIGHT (p), | |
3009 DEVICE_GTK_DEPTH (XDEVICE (IMAGE_INSTANCE_DEVICE (p)))); | |
3010 GdkGCValues gcv; | |
3011 GdkGC *gc; | |
3012 | |
3013 gcv.foreground = * COLOR_INSTANCE_GTK_COLOR (XCOLOR_INSTANCE (foreground)); | |
3014 gcv.background = * COLOR_INSTANCE_GTK_COLOR (XCOLOR_INSTANCE (background)); | |
3015 gc = gdk_gc_new_with_values (new_pxmp, &gcv, GDK_GC_BACKGROUND | GDK_GC_FOREGROUND); | |
3016 | |
3017 XCopyPlane (GDK_WINDOW_XDISPLAY (draw), | |
3018 GDK_WINDOW_XWINDOW (IMAGE_INSTANCE_GTK_PIXMAP (p)), | |
3019 GDK_WINDOW_XWINDOW (new_pxmp), | |
3020 GDK_GC_XGC (gc), 0, 0, | |
3021 IMAGE_INSTANCE_PIXMAP_WIDTH (p), | |
3022 IMAGE_INSTANCE_PIXMAP_HEIGHT (p), | |
3023 0, 0, 1); | |
3024 | |
3025 gdk_gc_destroy (gc); | |
3026 IMAGE_INSTANCE_GTK_PIXMAP (p) = new_pxmp; | |
3027 IMAGE_INSTANCE_PIXMAP_DEPTH (p) = DEVICE_GTK_DEPTH (XDEVICE (IMAGE_INSTANCE_DEVICE (p))); | |
3028 IMAGE_INSTANCE_PIXMAP_FG (p) = foreground; | |
3029 IMAGE_INSTANCE_PIXMAP_BG (p) = background; | |
3030 return 1; | |
3031 } | |
3032 } | |
3033 |