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
8 This file is part of SXEmacs
10 SXEmacs is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
15 SXEmacs is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>. */
24 /* Synched up with: Not in FSF. */
26 /* Original author: Jamie Zawinski for 19.8
27 font-truename stuff added by Jamie Zawinski for 19.10
28 subwindow support added by Chuck Thompson
29 additional XPM support added by Chuck Thompson
30 initial X-Face support added by Stig
31 rewritten/restructured by Ben Wing for 19.12/19.13
32 GIF/JPEG support added by Ben Wing for 19.14
33 PNG support added by Bill Perry for 19.14
34 Improved GIF/JPEG support added by Bill Perry for 19.14
35 Cleanup/simplification of error handling by Ben Wing for 19.14
36 Pointer/icon overhaul, more restructuring by Ben Wing for 19.14
37 GIF support changed to external GIFlib 3.1 by Jareth Hein for 21.0
38 Many changes for color work and optimizations by Jareth Hein for 21.0
39 Switch of GIF/JPEG/PNG to new EImage intermediate code by Jareth Hein for 21.0
40 TIFF code by Jareth Hein for 21.0
41 GIF/JPEG/PNG/TIFF code moved to new glyph-eimage.c for 21.0
42 Gtk version by William Perry for 21.1
45 Support the GrayScale, StaticColor and StaticGray visual classes.
46 Convert images.el to C and stick it in here?
52 #include "console-gtk.h"
53 #include "ui/glyphs.h"
54 #include "glyphs-gtk.h"
55 #include "objects-gtk.h"
60 #include "ui/window.h"
62 #include "ui/insdel.h"
66 #include "events/events.h"
68 #include "ui/imgproc.h"
74 #if defined (HAVE_XPM)
79 #include "mule/file-coding.h"
82 extern void enqueue_gtk_dispatch_event(Lisp_Object event);
84 /* Widget callback hash table callback slot. */
85 #define WIDGET_GLYPH_SLOT 0
88 # define FOUR_BYTE_TYPE unsigned int
89 #elif SXE_LONGBITS == 32
90 # define FOUR_BYTE_TYPE unsigned long
91 #elif SXE_SHORTBITS == 32
92 # define FOUR_BYTE_TYPE unsigned short
94 #error What kind of strange-ass system are we running on?
97 DECLARE_IMAGE_INSTANTIATOR_FORMAT(nothing);
98 DECLARE_IMAGE_INSTANTIATOR_FORMAT(string);
99 DECLARE_IMAGE_INSTANTIATOR_FORMAT(formatted_string);
100 DECLARE_IMAGE_INSTANTIATOR_FORMAT(inherit);
102 DECLARE_IMAGE_INSTANTIATOR_FORMAT(jpeg);
105 DECLARE_IMAGE_INSTANTIATOR_FORMAT(tiff);
108 DECLARE_IMAGE_INSTANTIATOR_FORMAT(png);
111 DECLARE_IMAGE_INSTANTIATOR_FORMAT(gif);
115 DECLARE_IMAGE_INSTANTIATOR_FORMAT(rawrgb);
116 DECLARE_IMAGE_INSTANTIATOR_FORMAT(rawrgba);
120 DEFINE_DEVICE_IIFORMAT(gtk, xface);
125 DEFINE_DEVICE_IIFORMAT(gtk, xpm);
128 DEFINE_DEVICE_IIFORMAT(gtk, xbm);
129 DEFINE_DEVICE_IIFORMAT(gtk, subwindow);
131 DEFINE_IMAGE_INSTANTIATOR_FORMAT(cursor_font);
132 Lisp_Object Qcursor_font;
134 DEFINE_IMAGE_INSTANTIATOR_FORMAT(font);
136 DEFINE_IMAGE_INSTANTIATOR_FORMAT(autodetect);
139 DECLARE_IMAGE_INSTANTIATOR_FORMAT(layout);
140 DEFINE_DEVICE_IIFORMAT(gtk, widget);
141 DEFINE_DEVICE_IIFORMAT(gtk, native_layout);
142 DEFINE_DEVICE_IIFORMAT(gtk, button);
143 DEFINE_DEVICE_IIFORMAT(gtk, progress_gauge);
144 DEFINE_DEVICE_IIFORMAT(gtk, edit_field);
145 DEFINE_DEVICE_IIFORMAT(gtk, combo_box);
146 DEFINE_DEVICE_IIFORMAT(gtk, tab_control);
147 DEFINE_DEVICE_IIFORMAT(gtk, label);
150 static void update_widget_face(GtkWidget * w, Lisp_Image_Instance * ii,
152 static void cursor_font_instantiate(Lisp_Object image_instance,
153 Lisp_Object instantiator,
154 Lisp_Object pointer_fg,
155 Lisp_Object pointer_bg,
156 int dest_mask, Lisp_Object domain);
158 static gint cursor_name_to_index(const char *name);
160 #ifndef BitmapSuccess
161 #define BitmapSuccess 0
162 #define BitmapOpenFailed 1
163 #define BitmapFileInvalid 2
164 #define BitmapNoMemory 3
167 #include "ui/bitmaps.h"
169 DEFINE_IMAGE_INSTANTIATOR_FORMAT(gtk_resource);
170 Lisp_Object Q_resource_type, Q_resource_id;
171 Lisp_Object Qgtk_resource;
173 Lisp_Object Qgtk_widget_instantiate_internal, Qgtk_widget_property_internal;
174 Lisp_Object Qgtk_widget_redisplay_internal, Qgtk_widget_set_style;
179 /************************************************************************/
180 /* image instance methods */
181 /************************************************************************/
183 /************************************************************************/
184 /* convert from a series of RGB triples to an XImage formated for the */
186 /************************************************************************/
187 static GdkImage *convert_EImage_to_GDKImage(Lisp_Object device, int width,
188 int height, unsigned char *pic,
189 unsigned long **pixtbl,
195 int depth, byte_cnt, i, j;
197 unsigned char *data, *ip, *dp = NULL;
198 quant_table *qtable = NULL;
204 cmap = DEVICE_GTK_COLORMAP(XDEVICE(device));
205 vis = DEVICE_GTK_VISUAL(XDEVICE(device));
206 depth = DEVICE_GTK_DEPTH(XDEVICE(device));
208 if (vis->type == GDK_VISUAL_GRAYSCALE
209 || vis->type == GDK_VISUAL_STATIC_COLOR
210 || vis->type == GDK_VISUAL_STATIC_GRAY) {
211 /* #### Implement me!!! */
215 if (vis->type == GDK_VISUAL_PSEUDO_COLOR) {
216 /* Quantize the image and get a histogram while we're at it.
217 Do this first to save memory */
218 qtable = build_EImage_quantable(pic, width, height, 256);
223 /* The first parameter (GdkWindow *) is allowed to be NULL if we
224 ** specify the depth */
225 outimg = gdk_image_new(GDK_IMAGE_FASTEST, vis, width, height);
230 byte_cnt = outimg->bpp;
232 data = (unsigned char *)outimg->mem;
235 gdk_image_destroy(outimg);
239 if (vis->type == GDK_VISUAL_PSEUDO_COLOR) {
240 unsigned long pixarray[256];
242 /* use our quantize table to allocate the colors */
244 *pixtbl = xnew_array(unsigned long, pixcount);
247 /* ### should implement a sort by popularity to assure proper allocation */
249 for (i = 0; i < qtable->num_active_colors; i++) {
253 color.red = qtable->rm[i] ? qtable->rm[i] << 8 : 0;
254 color.green = qtable->gm[i] ? qtable->gm[i] << 8 : 0;
255 color.blue = qtable->bm[i] ? qtable->bm[i] << 8 : 0;
256 res = allocate_nearest_color(cmap, vis, &color);
257 if (res > 0 && res < 3) {
258 DO_REALLOC_ATOMIC(*pixtbl, pixcount, n + 1,
260 (*pixtbl)[n] = color.pixel;
263 pixarray[i] = color.pixel;
267 for (i = 0; i < height; i++) {
268 dp = data + (i * outimg->bpl);
269 for (j = 0; j < width; j++) {
274 pixarray[QUANT_GET_COLOR
275 (qtable, rd, gr, bl)];
277 if (outimg->byte_order == GDK_MSB_FIRST)
278 for (q = 4 - byte_cnt; q < 4; q++)
281 for (q = 3; q >= 4 - byte_cnt; q--)
284 if (outimg->byte_order == GDK_MSB_FIRST)
285 for (q = byte_cnt - 1; q >= 0; q--)
288 for (q = 0; q < byte_cnt; q++)
295 unsigned long rshift, gshift, bshift, rbits, gbits, bbits, junk;
296 junk = vis->red_mask;
298 while ((junk & 0x1) == 0) {
307 junk = vis->green_mask;
309 while ((junk & 0x1) == 0) {
318 junk = vis->blue_mask;
320 while ((junk & 0x1) == 0) {
330 for (i = 0; i < height; i++) {
331 dp = data + (i * outimg->bpl);
332 for (j = 0; j < width; j++) {
334 rd = *ip++ << (rbits - 8);
336 rd = *ip++ >> (8 - rbits);
338 gr = *ip++ << (gbits - 8);
340 gr = *ip++ >> (8 - gbits);
342 bl = *ip++ << (bbits - 8);
344 bl = *ip++ >> (8 - bbits);
347 (rd << rshift) | (gr << gshift) | (bl <<
350 if (outimg->byte_order == GDK_MSB_FIRST)
351 for (q = 4 - byte_cnt; q < 4; q++)
354 for (q = 3; q >= 4 - byte_cnt; q--)
357 if (outimg->byte_order == GDK_MSB_FIRST)
358 for (q = byte_cnt - 1; q >= 0; q--)
361 for (q = 0; q < byte_cnt; q++)
371 gtk_print_image_instance(struct Lisp_Image_Instance *p,
372 Lisp_Object printcharfun, int escapeflag)
376 switch (IMAGE_INSTANCE_TYPE(p)) {
377 case IMAGE_MONO_PIXMAP:
378 case IMAGE_COLOR_PIXMAP:
380 write_fmt_str(printcharfun, " (0x%lx",
381 (unsigned long)IMAGE_INSTANCE_GTK_PIXMAP(p));
382 if (IMAGE_INSTANCE_GTK_MASK(p)) {
383 write_fmt_str(printcharfun, "/0x%lx",
384 (unsigned long)IMAGE_INSTANCE_GTK_MASK(p));
386 write_c_string(")", printcharfun);
389 case IMAGE_SUBWINDOW:
390 /* #### implement me */
397 static void gtk_finalize_image_instance(struct Lisp_Image_Instance *p)
402 if (DEVICE_LIVE_P(XDEVICE(p->device))) {
405 if (IMAGE_INSTANCE_TYPE(p) == IMAGE_WIDGET) {
406 if (IMAGE_INSTANCE_SUBWINDOW_ID(p)) {
407 gtk_widget_destroy(IMAGE_INSTANCE_SUBWINDOW_ID
410 /* We can release the callbacks again. */
412 /* ungcpro_popup_callbacks (...); */
414 /* IMAGE_INSTANCE_GTK_WIDGET_ID (p) = 0; */
415 IMAGE_INSTANCE_GTK_CLIPWIDGET(p) = 0;
419 else if (IMAGE_INSTANCE_TYPE(p) == IMAGE_SUBWINDOW) {
423 if (IMAGE_INSTANCE_PIXMAP_TIMEOUT(p))
424 disable_glyph_animated_timeout
425 (IMAGE_INSTANCE_PIXMAP_TIMEOUT(p));
427 if (IMAGE_INSTANCE_GTK_MASK(p) &&
428 IMAGE_INSTANCE_GTK_MASK(p) !=
429 IMAGE_INSTANCE_GTK_PIXMAP(p))
430 gdk_pixmap_unref(IMAGE_INSTANCE_GTK_MASK(p));
431 IMAGE_INSTANCE_PIXMAP_MASK(p) = 0;
433 if (IMAGE_INSTANCE_GTK_PIXMAP_SLICES(p)) {
435 i < IMAGE_INSTANCE_PIXMAP_MAXSLICE(p); i++)
436 if (IMAGE_INSTANCE_GTK_PIXMAP_SLICE
439 (IMAGE_INSTANCE_GTK_PIXMAP_SLICE
441 IMAGE_INSTANCE_GTK_PIXMAP_SLICE
444 xfree(IMAGE_INSTANCE_GTK_PIXMAP_SLICES(p));
445 IMAGE_INSTANCE_GTK_PIXMAP_SLICES(p) = 0;
448 if (IMAGE_INSTANCE_GTK_CURSOR(p)) {
449 gdk_cursor_destroy(IMAGE_INSTANCE_GTK_CURSOR
451 IMAGE_INSTANCE_GTK_CURSOR(p) = 0;
457 if (IMAGE_INSTANCE_GTK_NPIXELS(p) != 0) {
459 IMAGE_INSTANCE_GTK_COLORMAP(p),
460 IMAGE_INSTANCE_GTK_PIXELS(p),
461 IMAGE_INSTANCE_GTK_NPIXELS(p), 0);
462 IMAGE_INSTANCE_GTK_NPIXELS(p) = 0;
467 if (IMAGE_INSTANCE_TYPE(p) != IMAGE_WIDGET
468 && IMAGE_INSTANCE_TYPE(p) != IMAGE_SUBWINDOW
469 && IMAGE_INSTANCE_GTK_PIXELS(p)) {
470 xfree(IMAGE_INSTANCE_GTK_PIXELS(p));
471 IMAGE_INSTANCE_GTK_PIXELS(p) = 0;
479 gtk_image_instance_equal(struct Lisp_Image_Instance *p1,
480 struct Lisp_Image_Instance *p2, int depth)
482 switch (IMAGE_INSTANCE_TYPE(p1)) {
483 case IMAGE_MONO_PIXMAP:
484 case IMAGE_COLOR_PIXMAP:
486 if (IMAGE_INSTANCE_GTK_COLORMAP(p1) !=
487 IMAGE_INSTANCE_GTK_COLORMAP(p2)
488 || IMAGE_INSTANCE_GTK_NPIXELS(p1) !=
489 IMAGE_INSTANCE_GTK_NPIXELS(p2))
492 case IMAGE_SUBWINDOW:
493 /* #### implement me */
504 gtk_image_instance_hash(struct Lisp_Image_Instance *p, int depth)
506 switch (IMAGE_INSTANCE_TYPE(p)) {
507 case IMAGE_MONO_PIXMAP:
508 case IMAGE_COLOR_PIXMAP:
510 return IMAGE_INSTANCE_GTK_NPIXELS(p);
512 case IMAGE_SUBWINDOW:
513 /* #### implement me */
521 /* Set all the slots in an image instance structure to reasonable
522 default values. This is used somewhere within an instantiate
523 method. It is assumed that the device slot within the image
524 instance is already set -- this is the case when instantiate
525 methods are called. */
528 gtk_initialize_pixmap_image_instance(struct Lisp_Image_Instance *ii,
529 int slices, enum image_instance_type type)
531 ii->data = xnew_and_zero(struct gtk_image_instance_data);
532 IMAGE_INSTANCE_PIXMAP_MAXSLICE(ii) = slices;
533 IMAGE_INSTANCE_GTK_PIXMAP_SLICES(ii) =
534 xnew_array_and_zero(GdkPixmap *, slices);
535 IMAGE_INSTANCE_TYPE(ii) = type;
536 IMAGE_INSTANCE_PIXMAP_FILENAME(ii) = Qnil;
537 IMAGE_INSTANCE_PIXMAP_MASK_FILENAME(ii) = Qnil;
538 IMAGE_INSTANCE_PIXMAP_HOTSPOT_X(ii) = Qnil;
539 IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(ii) = Qnil;
540 IMAGE_INSTANCE_PIXMAP_FG(ii) = Qnil;
541 IMAGE_INSTANCE_PIXMAP_BG(ii) = Qnil;
544 /************************************************************************/
545 /* pixmap file functions */
546 /************************************************************************/
548 /* Where bitmaps are; initialized from resource database */
549 Lisp_Object Vgtk_bitmap_file_path;
552 #define BITMAPDIR "/usr/include/X11/bitmaps"
555 /* Given a pixmap filename, look through all of the "standard" places
556 where the file might be located. Return a full pathname if found;
557 otherwise, return Qnil. */
559 static Lisp_Object gtk_locate_pixmap_file(Lisp_Object name)
561 /* This function can GC if IN_REDISPLAY is false */
563 /* Check non-absolute pathnames with a directory component relative to
564 the search path; that's the way Xt does it. */
565 /* #### Unix-specific */
566 if (XSTRING_BYTE(name, 0) == '/' ||
567 (XSTRING_BYTE(name, 0) == '.' &&
568 (XSTRING_BYTE(name, 1) == '/' ||
569 (XSTRING_BYTE(name, 1) == '.' &&
570 (XSTRING_BYTE(name, 2) == '/'))))) {
571 if (!NILP(Ffile_readable_p(name)))
577 if (NILP(Vdefault_gtk_device))
578 /* This may occur during intialization. */
581 if (NILP(Vgtk_bitmap_file_path)) {
582 Vgtk_bitmap_file_path = nconc2(Vgtk_bitmap_file_path,
583 (decode_path(BITMAPDIR)));
588 if (locate_file(Vgtk_bitmap_file_path, name, Qnil, &found, R_OK)
590 Lisp_Object temp = list1(Vdata_directory);
594 locate_file(temp, name, Qnil, &found, R_OK);
602 static Lisp_Object locate_pixmap_file(Lisp_Object name)
604 return gtk_locate_pixmap_file(name);
607 /************************************************************************/
608 /* cursor functions */
609 /************************************************************************/
611 /* Check that this server supports cursors of size WIDTH * HEIGHT. If
612 not, signal an error. INSTANTIATOR is only used in the error
616 check_pointer_sizes(unsigned int width, unsigned int height,
617 Lisp_Object instantiator)
619 /* #### BILL!!! There is no way to call XQueryBestCursor from Gdk! */
621 unsigned int best_width, best_height;
622 if (!XQueryBestCursor(DisplayOfScreen(xs), RootWindowOfScreen(xs),
623 width, height, &best_width, &best_height))
624 /* this means that an X error of some sort occurred (we trap
625 these so they're not fatal). */
626 signal_simple_error("XQueryBestCursor() failed?", instantiator);
628 if (width > best_width || height > best_height)
629 error_with_frob(instantiator,
630 "pointer too large (%dx%d): "
631 "server requires %dx%d or smaller",
632 width, height, best_width, best_height);
637 generate_cursor_fg_bg(Lisp_Object device, Lisp_Object * foreground,
638 Lisp_Object * background, GdkColor * xfg, GdkColor * xbg)
640 if (!NILP(*foreground) && !COLOR_INSTANCEP(*foreground))
642 Fmake_color_instance(*foreground, device,
643 encode_error_behavior_flag(ERROR_ME));
644 if (COLOR_INSTANCEP(*foreground))
645 *xfg = *COLOR_INSTANCE_GTK_COLOR(XCOLOR_INSTANCE(*foreground));
648 xfg->red = xfg->green = xfg->blue = 0;
651 if (!NILP(*background) && !COLOR_INSTANCEP(*background))
653 Fmake_color_instance(*background, device,
654 encode_error_behavior_flag(ERROR_ME));
655 if (COLOR_INSTANCEP(*background))
656 *xbg = *COLOR_INSTANCE_GTK_COLOR(XCOLOR_INSTANCE(*background));
659 xbg->red = xbg->green = xbg->blue = ~0;
664 maybe_recolor_cursor(Lisp_Object image_instance, Lisp_Object foreground,
665 Lisp_Object background)
669 Lisp_Object device = XIMAGE_INSTANCE_DEVICE(image_instance);
672 generate_cursor_fg_bg(device, &foreground, &background, &xfg, &xbg);
673 if (!NILP(foreground) || !NILP(background)) {
674 XRecolorCursor(DEVICE_X_DISPLAY(XDEVICE(device)),
675 XIMAGE_INSTANCE_GTK_CURSOR(image_instance),
677 XIMAGE_INSTANCE_PIXMAP_FG(image_instance) = foreground;
678 XIMAGE_INSTANCE_PIXMAP_BG(image_instance) = background;
681 /* stderr_out ("Don't know how to recolor cursors in Gtk!\n"); */
685 /************************************************************************/
686 /* color pixmap functions */
687 /************************************************************************/
689 /* Initialize an image instance from an XImage.
691 DEST_MASK specifies the mask of allowed image types.
693 PIXELS and NPIXELS specify an array of pixels that are used in
694 the image. These need to be kept around for the duration of the
695 image. When the image instance is freed, XFreeColors() will
696 automatically be called on all the pixels specified here; thus,
697 you should have allocated the pixels yourself using XAllocColor()
698 or the like. The array passed in is used directly without
699 being copied, so it should be heap data created with xmalloc().
700 It will be freed using xfree() when the image instance is
703 If this fails, signal an error. INSTANTIATOR is only used
704 in the error message.
706 #### This should be able to handle conversion into `pointer'.
707 Use the same code as for `xpm'. */
710 init_image_instance_from_gdk_image(struct Lisp_Image_Instance *ii,
711 GdkImage * gdk_image,
714 unsigned long *pixels,
716 int slices, Lisp_Object instantiator)
718 Lisp_Object device = IMAGE_INSTANCE_DEVICE(ii);
723 if (!DEVICE_GTK_P(XDEVICE(device)))
724 signal_simple_error("Not a Gtk device", device);
726 d = GET_GTK_WIDGET_WINDOW(DEVICE_GTK_APP_SHELL(XDEVICE(device)));
728 if (!(dest_mask & IMAGE_COLOR_PIXMAP_MASK))
729 incompatible_image_types(instantiator, dest_mask,
730 IMAGE_COLOR_PIXMAP_MASK);
733 gdk_pixmap_new(d, gdk_image->width, gdk_image->height,
736 signal_simple_error("Unable to create pixmap", instantiator);
738 gc = gdk_gc_new(pixmap);
740 gdk_pixmap_unref(pixmap);
741 signal_simple_error("Unable to create GC", instantiator);
744 gdk_draw_image(GDK_DRAWABLE(pixmap), gc, gdk_image,
745 0, 0, 0, 0, gdk_image->width, gdk_image->height);
749 gtk_initialize_pixmap_image_instance(ii, slices, IMAGE_COLOR_PIXMAP);
751 IMAGE_INSTANCE_PIXMAP_FILENAME(ii) =
752 find_keyword_in_vector(instantiator, Q_file);
754 IMAGE_INSTANCE_GTK_PIXMAP(ii) = pixmap;
755 IMAGE_INSTANCE_GTK_MASK(ii) = 0;
756 IMAGE_INSTANCE_PIXMAP_WIDTH(ii) = gdk_image->width;
757 IMAGE_INSTANCE_PIXMAP_HEIGHT(ii) = gdk_image->height;
758 IMAGE_INSTANCE_PIXMAP_DEPTH(ii) = gdk_image->depth;
759 IMAGE_INSTANCE_GTK_COLORMAP(ii) = cmap;
760 IMAGE_INSTANCE_GTK_PIXELS(ii) = pixels;
761 IMAGE_INSTANCE_GTK_NPIXELS(ii) = npixels;
765 void init_image_instance_from_gdk_pixmap(struct Lisp_Image_Instance *ii,
766 struct device *device,
767 GdkPixmap * gdk_pixmap,
769 Lisp_Object instantiator)
772 gint width, height, depth;
774 if (!DEVICE_GTK_P(device))
777 IMAGE_INSTANCE_DEVICE(ii) = device;
778 IMAGE_INSTANCE_TYPE(ii) = IMAGE_COLOR_PIXMAP;
780 d = GET_GTK_WIDGET_WINDOW(DEVICE_GTK_APP_SHELL(device));
782 if (!(dest_mask & IMAGE_COLOR_PIXMAP_MASK))
783 incompatible_image_types(instantiator, dest_mask,
784 IMAGE_COLOR_PIXMAP_MASK);
786 gtk_initialize_pixmap_image_instance(ii, IMAGE_COLOR_PIXMAP);
788 gdk_window_get_geometry(gdk_pixmap, NULL, NULL, &width, &height,
791 IMAGE_INSTANCE_PIXMAP_FILENAME(ii) = Qnil;
792 IMAGE_INSTANCE_GTK_PIXMAP(ii) = gdk_pixmap;
793 IMAGE_INSTANCE_GTK_MASK(ii) = 0;
794 IMAGE_INSTANCE_PIXMAP_WIDTH(ii) = width;
795 IMAGE_INSTANCE_PIXMAP_HEIGHT(ii) = height;
796 IMAGE_INSTANCE_PIXMAP_DEPTH(ii) = depth;
797 IMAGE_INSTANCE_GTK_COLORMAP(ii) = gdk_window_get_colormap(gdk_pixmap);
798 IMAGE_INSTANCE_GTK_PIXELS(ii) = 0;
799 IMAGE_INSTANCE_GTK_NPIXELS(ii) = 0;
804 image_instance_add_gdk_image(Lisp_Image_Instance * ii,
805 GdkImage * gdk_image,
806 int slice, Lisp_Object instantiator)
808 Lisp_Object device = IMAGE_INSTANCE_DEVICE(ii);
813 d = GET_GTK_WIDGET_WINDOW(DEVICE_GTK_APP_SHELL(XDEVICE(device)));
816 gdk_pixmap_new(d, gdk_image->width, gdk_image->height,
820 signal_simple_error("Unable to create pixmap", instantiator);
822 gc = gdk_gc_new(pixmap);
825 gdk_pixmap_unref(pixmap);
826 signal_simple_error("Unable to create GC", instantiator);
829 gdk_draw_image(GDK_DRAWABLE(pixmap), gc, gdk_image, 0, 0, 0, 0,
830 gdk_image->width, gdk_image->height);
834 IMAGE_INSTANCE_GTK_PIXMAP_SLICE(ii, slice) = pixmap;
838 gtk_init_image_instance_from_eimage(struct Lisp_Image_Instance *ii,
839 int width, int height,
841 unsigned char *eimage,
843 Lisp_Object instantiator,
846 Lisp_Object device = IMAGE_INSTANCE_DEVICE(ii);
847 GdkColormap *cmap = DEVICE_GTK_COLORMAP(XDEVICE(device));
848 unsigned long *pixtbl = NULL;
853 for (slice = 0; slice < slices; slice++) {
855 convert_EImage_to_GDKImage(device, width, height, eimage,
861 ("EImage to GdkImage conversion failed",
866 /* Now create the pixmap and set up the image instance */
867 init_image_instance_from_gdk_image(ii, gdk_image,
873 image_instance_add_gdk_image(ii, gdk_image, slice,
877 gdk_image_destroy(gdk_image);
883 /* Given inline data for a mono pixmap, create and return the
884 corresponding X object. */
886 static GdkPixmap *pixmap_from_xbm_inline(Lisp_Object device, int width,
888 /* Note that data is in ext-format! */
889 CONST Extbyte * bits)
891 return (gdk_bitmap_create_from_data
892 (GET_GTK_WIDGET_WINDOW(DEVICE_GTK_APP_SHELL(XDEVICE(device))),
893 (char *)bits, width, height));
896 /* Given inline data for a mono pixmap, initialize the given
897 image instance accordingly. */
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! */
904 Lisp_Object instantiator,
905 Lisp_Object pointer_fg,
906 Lisp_Object pointer_bg,
908 GdkPixmap * mask, Lisp_Object mask_filename)
910 Lisp_Object device = IMAGE_INSTANCE_DEVICE(ii);
911 Lisp_Object foreground =
912 find_keyword_in_vector(instantiator, Q_foreground);
913 Lisp_Object background =
914 find_keyword_in_vector(instantiator, Q_background);
917 enum image_instance_type type;
919 GET_GTK_WIDGET_WINDOW(DEVICE_GTK_APP_SHELL(XDEVICE(device)));
920 GdkColormap *cmap = DEVICE_GTK_COLORMAP(XDEVICE(device));
924 gdk_color_black(cmap, &black);
925 gdk_color_white(cmap, &white);
927 if (!DEVICE_GTK_P(XDEVICE(device)))
928 signal_simple_error("Not a Gtk device", device);
930 if ((dest_mask & IMAGE_MONO_PIXMAP_MASK) &&
931 (dest_mask & IMAGE_COLOR_PIXMAP_MASK)) {
932 if (!NILP(foreground) || !NILP(background))
933 type = IMAGE_COLOR_PIXMAP;
935 type = IMAGE_MONO_PIXMAP;
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;
943 incompatible_image_types(instantiator, dest_mask,
944 IMAGE_MONO_PIXMAP_MASK |
945 IMAGE_COLOR_PIXMAP_MASK |
948 gtk_initialize_pixmap_image_instance(ii, 1, type);
949 IMAGE_INSTANCE_PIXMAP_WIDTH(ii) = width;
950 IMAGE_INSTANCE_PIXMAP_HEIGHT(ii) = height;
951 IMAGE_INSTANCE_PIXMAP_FILENAME(ii) =
952 find_keyword_in_vector(instantiator, Q_file);
955 case IMAGE_MONO_PIXMAP:
957 IMAGE_INSTANCE_GTK_PIXMAP(ii) =
958 pixmap_from_xbm_inline(device, width, height,
963 case IMAGE_COLOR_PIXMAP:
965 gint d = DEVICE_GTK_DEPTH(XDEVICE(device));
967 if (!NILP(foreground) && !COLOR_INSTANCEP(foreground))
969 Fmake_color_instance(foreground, device,
970 encode_error_behavior_flag
973 if (COLOR_INSTANCEP(foreground))
974 fg = *COLOR_INSTANCE_GTK_COLOR(XCOLOR_INSTANCE
977 if (!NILP(background) && !COLOR_INSTANCEP(background))
979 Fmake_color_instance(background, device,
980 encode_error_behavior_flag
983 if (COLOR_INSTANCEP(background))
984 bg = *COLOR_INSTANCE_GTK_COLOR(XCOLOR_INSTANCE
987 /* We used to duplicate the pixels using XAllocColor(), to protect
988 against their getting freed. Just as easy to just store the
989 color instances here and GC-protect them, so this doesn't
991 IMAGE_INSTANCE_PIXMAP_FG(ii) = foreground;
992 IMAGE_INSTANCE_PIXMAP_BG(ii) = background;
993 IMAGE_INSTANCE_GTK_PIXMAP(ii) =
994 gdk_pixmap_create_from_data(draw, (char *)bits,
995 width, height, d, &fg,
997 IMAGE_INSTANCE_PIXMAP_DEPTH(ii) = d;
1003 GdkColor fg_color, bg_color;
1006 check_pointer_sizes(width, height, instantiator);
1009 gdk_pixmap_create_from_data(draw, (char *)bits,
1013 if (NILP(foreground))
1014 foreground = pointer_fg;
1015 if (NILP(background))
1016 background = pointer_bg;
1017 generate_cursor_fg_bg(device, &foreground, &background,
1018 &fg_color, &bg_color);
1020 IMAGE_INSTANCE_PIXMAP_FG(ii) = foreground;
1021 IMAGE_INSTANCE_PIXMAP_BG(ii) = background;
1022 IMAGE_INSTANCE_PIXMAP_HOTSPOT_X(ii) =
1023 find_keyword_in_vector(instantiator, Q_hotspot_x);
1024 IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(ii) =
1025 find_keyword_in_vector(instantiator, Q_hotspot_y);
1026 IMAGE_INSTANCE_GTK_CURSOR(ii) =
1027 gdk_cursor_new_from_pixmap(source, mask, &fg_color,
1030 (IMAGE_INSTANCE_PIXMAP_HOTSPOT_X
1033 (IMAGE_INSTANCE_PIXMAP_HOTSPOT_X
1036 (IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y
1039 (IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y
1050 xbm_instantiate_1(Lisp_Object image_instance, Lisp_Object instantiator,
1051 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1052 int dest_mask, int width, int height,
1053 /* Note that data is in ext-format! */
1056 Lisp_Object mask_data =
1057 find_keyword_in_vector(instantiator, Q_mask_data);
1058 Lisp_Object mask_file =
1059 find_keyword_in_vector(instantiator, Q_mask_file);
1060 struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
1061 GdkPixmap *mask = 0;
1062 CONST char *gcc_may_you_rot_in_hell;
1064 if (!NILP(mask_data)) {
1065 TO_EXTERNAL_FORMAT(LISP_STRING, XCAR(XCDR(XCDR(mask_data))),
1066 C_STRING_ALLOCA, gcc_may_you_rot_in_hell,
1069 pixmap_from_xbm_inline(IMAGE_INSTANCE_DEVICE(ii),
1070 XINT(XCAR(mask_data)),
1071 XINT(XCAR(XCDR(mask_data))),
1072 (CONST unsigned char *)
1073 gcc_may_you_rot_in_hell);
1076 init_image_instance_from_xbm_inline(ii, width, height, bits,
1077 instantiator, pointer_fg,
1078 pointer_bg, dest_mask, mask,
1082 /* Instantiate method for XBM's. */
1085 gtk_xbm_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
1086 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1087 int dest_mask, Lisp_Object domain)
1089 Lisp_Object data = find_keyword_in_vector(instantiator, Q_data);
1090 CONST char *gcc_go_home;
1092 assert(!NILP(data));
1094 TO_EXTERNAL_FORMAT(LISP_STRING, XCAR(XCDR(XCDR(data))),
1095 C_STRING_ALLOCA, gcc_go_home, Qbinary);
1097 xbm_instantiate_1(image_instance, instantiator, pointer_fg,
1098 pointer_bg, dest_mask, XINT(XCAR(data)),
1099 XINT(XCAR(XCDR(data))), gcc_go_home);
1103 /**********************************************************************
1105 **********************************************************************/
1107 /* strcasecmp() is not sufficiently portable or standard,
1108 and it's easier just to write our own. */
1109 static int ascii_strcasecmp(const char *s1, const char *s2)
1114 if (c1 >= 'A' && c1 <= 'Z')
1116 if (c2 >= 'A' && c2 <= 'Z')
1125 struct color_symbol {
1130 static struct color_symbol *extract_xpm_color_names(Lisp_Object device,
1136 /* This function can GC */
1138 Lisp_Object results = Qnil;
1140 struct color_symbol *colortbl;
1141 struct gcpro gcpro1, gcpro2;
1143 GCPRO2(results, device);
1145 /* We built up results to be (("name" . #<color>) ...) so that if an
1146 error happens we don't lose any malloc()ed data, or more importantly,
1147 leave any pixels allocated in the server. */
1149 LIST_LOOP(rest, color_symbol_alist) {
1150 Lisp_Object cons = XCAR(rest);
1151 Lisp_Object name = XCAR(cons);
1152 Lisp_Object value = XCDR(cons);
1157 Fmake_color_instance
1159 encode_error_behavior_flag(ERROR_ME_NOT));
1161 assert(COLOR_SPECIFIERP(value));
1162 value = Fspecifier_instance(value, domain, Qnil, Qnil);
1166 results = noseeum_cons(noseeum_cons(name, value), results);
1169 UNGCPRO; /* no more evaluation */
1175 colortbl = xnew_array_and_zero(struct color_symbol, i);
1177 for (j = 0; j < i; j++) {
1178 Lisp_Object cons = XCAR(results);
1180 *COLOR_INSTANCE_GTK_COLOR(XCOLOR_INSTANCE(XCDR(cons)));
1182 colortbl[j].name = (char *)XSTRING_DATA(XCAR(cons));
1183 free_cons(XCONS(cons));
1185 results = XCDR(results);
1186 free_cons(XCONS(cons));
1192 gtk_xpm_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
1193 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1194 int dest_mask, Lisp_Object domain)
1196 /* This function can GC */
1197 char temp_file_name[1024];
1198 struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
1199 Lisp_Object device = IMAGE_INSTANCE_DEVICE(ii);
1200 Lisp_Object data = find_keyword_in_vector(instantiator, Q_data);
1205 GdkPixmap *mask = 0;
1206 GdkWindow *window = 0;
1207 int nsymbols = 0, i = 0;
1208 struct color_symbol *color_symbols = NULL;
1209 Lisp_Object color_symbol_alist = find_keyword_in_vector(instantiator,
1211 enum image_instance_type type;
1214 const unsigned char *volatile dstring;
1216 if (!DEVICE_GTK_P(XDEVICE(device)))
1217 signal_simple_error("Not a Gtk device", device);
1219 if (dest_mask & IMAGE_COLOR_PIXMAP_MASK)
1220 type = IMAGE_COLOR_PIXMAP;
1221 else if (dest_mask & IMAGE_MONO_PIXMAP_MASK)
1222 type = IMAGE_MONO_PIXMAP;
1223 else if (dest_mask & IMAGE_POINTER_MASK)
1224 type = IMAGE_POINTER;
1226 incompatible_image_types(instantiator, dest_mask,
1227 IMAGE_MONO_PIXMAP_MASK |
1228 IMAGE_COLOR_PIXMAP_MASK |
1229 IMAGE_POINTER_MASK);
1230 force_mono = (type != IMAGE_COLOR_PIXMAP);
1232 window = GET_GTK_WIDGET_WINDOW(DEVICE_GTK_APP_SHELL(XDEVICE(device)));
1233 cmap = DEVICE_GTK_COLORMAP(XDEVICE(device));
1234 depth = DEVICE_GTK_DEPTH(XDEVICE(device));
1235 visual = DEVICE_GTK_VISUAL(XDEVICE(device));
1237 gtk_initialize_pixmap_image_instance(ii, 1, type);
1239 assert(!NILP(data));
1241 /* Extract all the entries from xpm-color-symbols */
1243 extract_xpm_color_names(device, domain, color_symbol_alist,
1246 assert(!NILP(data));
1248 LISP_STRING_TO_EXTERNAL(data, dstring, Qbinary);
1251 * GTK only uses the 'c' color entry of an XPM and doesn't use the symbolic
1252 * color names at all. This is unfortunate because the way to change the
1253 * colors from lisp is by adding the symbolic names, and the new colors, to
1254 * the variable xpm-color-symbols.
1256 * To get around this decode the XPM, add a 'c' entry of the desired color
1257 * for each matching symbolic color, recode the XPM and pass it to GTK. The
1258 * decode and recode stages aren't too bad because this also performs the
1259 * external to internal format translation, which avoids contortions like
1260 * writing the XPM back to disk in order to get it processed.
1268 XpmCreateXpmImageFromBuffer((char *)dstring, &image, &info);
1270 for (i = 0; i < nsymbols; i++) {
1273 for (j = 0; j < image.ncolors; j++) {
1274 if (image.colorTable[j].symbolic != NULL &&
1275 !ascii_strcasecmp(color_symbols[i].name,
1276 image.colorTable[j].
1278 int maxLen = 16, sz;
1279 image.colorTable[j].c_color =
1282 sz = snprintf(image.colorTable[j].c_color,
1283 maxLen, "#%.4x%.4x%.4x",
1284 color_symbols[i].color.red,
1285 color_symbols[i].color.green,
1286 color_symbols[i].color.blue);
1287 assert( sz >= 0 && sz < maxLen);
1292 XpmCreateDataFromXpmImage(&data, &image, &info);
1294 pixmap = gdk_pixmap_create_from_xpm_d(window, &mask, NULL,
1299 xfree(color_symbols);
1302 signal_image_error("Error reading pixmap", data);
1305 gdk_window_get_geometry(pixmap, NULL, NULL, &w, &h, &depth);
1307 IMAGE_INSTANCE_GTK_PIXMAP(ii) = pixmap;
1308 IMAGE_INSTANCE_PIXMAP_MASK(ii) = (void *)mask;
1309 IMAGE_INSTANCE_GTK_COLORMAP(ii) = cmap;
1310 IMAGE_INSTANCE_GTK_PIXELS(ii) = 0;
1311 IMAGE_INSTANCE_GTK_NPIXELS(ii) = 0;
1312 IMAGE_INSTANCE_PIXMAP_WIDTH(ii) = w;
1313 IMAGE_INSTANCE_PIXMAP_HEIGHT(ii) = h;
1314 IMAGE_INSTANCE_PIXMAP_FILENAME(ii) =
1315 find_keyword_in_vector(instantiator, Q_file);
1318 case IMAGE_MONO_PIXMAP:
1321 case IMAGE_COLOR_PIXMAP:
1323 IMAGE_INSTANCE_PIXMAP_DEPTH(ii) = depth;
1330 unsigned int xhot, yhot;
1332 /* #### Gtk does not give us access to the hotspots of a pixmap */
1334 XSETINT(IMAGE_INSTANCE_PIXMAP_HOTSPOT_X(ii), xhot);
1335 XSETINT(IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(ii), yhot);
1337 check_pointer_sizes(w, h, instantiator);
1339 /* If the loaded pixmap has colors allocated (meaning it came from an
1340 XPM file), then use those as the default colors for the cursor we
1341 create. Otherwise, default to pointer_fg and pointer_bg.
1344 warn_when_safe(Qunimplemented, Qnotice,
1345 "GTK does not support XPM cursors...\n");
1346 IMAGE_INSTANCE_GTK_CURSOR(ii) =
1347 gdk_cursor_new(GDK_COFFEE_MUG);
1349 generate_cursor_fg_bg(device, &pointer_fg,
1350 &pointer_bg, &fg, &bg);
1351 IMAGE_INSTANCE_PIXMAP_FG(ii) = pointer_fg;
1352 IMAGE_INSTANCE_PIXMAP_BG(ii) = pointer_bg;
1353 IMAGE_INSTANCE_GTK_CURSOR(ii) =
1354 gdk_cursor_new_from_pixmap(pixmap, mask,
1366 #endif /* HAVE_XPM */
1370 /**********************************************************************
1372 **********************************************************************/
1374 /* This is about to get redefined! */
1377 /* We have to define SYSV32 so that compface.h includes string.h
1378 instead of strings.h. */
1383 #include <compface.h>
1387 /* JMP_BUF cannot be used here because if it doesn't get defined
1388 to jmp_buf we end up with a conflicting type error with the
1389 definition in compface.h */ extern jmp_buf comp_env;
1393 gtk_xface_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
1394 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1395 int dest_mask, Lisp_Object domain)
1397 Lisp_Object data = find_keyword_in_vector(instantiator, Q_data);
1399 char *p, *bits, *bp;
1400 CONST char *volatile emsg = 0;
1401 CONST char *volatile dstring;
1403 assert(!NILP(data));
1405 LISP_STRING_TO_EXTERNAL(data, dstring, Qbinary);
1407 if ((p = strchr(dstring, ':'))) {
1411 /* Must use setjmp not SETJMP because we used jmp_buf above not JMP_BUF */
1412 if (!(stattis = setjmp(comp_env))) {
1413 UnCompAll((char *)dstring);
1419 emsg = "uncompface: internal error";
1422 emsg = "uncompface: insufficient or invalid data";
1425 emsg = "uncompface: excess data ignored";
1430 signal_simple_error_2(emsg, data, Qimage);
1432 bp = bits = (char *)alloca(PIXELS / 8);
1434 /* the compface library exports char F[], which uses a single byte per
1435 pixel to represent a 48x48 bitmap. Yuck. */
1436 for (i = 0, p = F; i < (PIXELS / 8); ++i) {
1438 /* reverse the bit order of each byte... */
1439 for (b = n = 0; b < 8; ++b) {
1445 xbm_instantiate_1(image_instance, instantiator, pointer_fg,
1446 pointer_bg, dest_mask, 48, 48, bits);
1449 #endif /* HAVE_XFACE */
1451 /**********************************************************************
1453 **********************************************************************/
1455 static void gtk_resource_validate(Lisp_Object instantiator)
1457 if ((NILP(find_keyword_in_vector(instantiator, Q_file))
1458 && NILP(find_keyword_in_vector(instantiator, Q_resource_id)))
1459 || NILP(find_keyword_in_vector(instantiator, Q_resource_type)))
1461 ("Must supply :file, :resource-id and :resource-type",
1466 gtk_resource_normalize(Lisp_Object inst, Lisp_Object console_type,
1467 Lisp_Object dest_mask)
1469 /* This function can call lisp */
1470 Lisp_Object file = Qnil;
1471 struct gcpro gcpro1, gcpro2;
1472 Lisp_Object alist = Qnil;
1474 GCPRO2(file, alist);
1476 file = potential_pixmap_file_instantiator(inst, Q_file, Q_data,
1479 if (CONSP(file)) /* failure locating filename */
1480 signal_double_file_error("Opening pixmap file",
1481 "no such file or directory",
1484 if (NILP(file)) /* no conversion necessary */
1485 RETURN_UNGCPRO(inst);
1487 alist = tagged_vector_to_alist(inst);
1490 alist = remassq_no_quit(Q_file, alist);
1491 alist = Fcons(Fcons(Q_file, file), alist);
1495 Lisp_Object result =
1496 alist_to_tagged_vector(Qgtk_resource, alist);
1498 RETURN_UNGCPRO(result);
1502 static int gtk_resource_possible_dest_types(void)
1504 return IMAGE_POINTER_MASK | IMAGE_COLOR_PIXMAP_MASK;
1507 extern guint symbol_to_enum(Lisp_Object, GtkType);
1509 static guint resource_name_to_resource(Lisp_Object name, int type)
1511 if (type == IMAGE_POINTER)
1512 return (symbol_to_enum(name, GTK_TYPE_GDK_CURSOR_TYPE));
1517 static int resource_symbol_to_type(Lisp_Object data)
1519 if (EQ(data, Qcursor))
1520 return IMAGE_POINTER;
1522 else if (EQ(data, Qicon))
1524 else if (EQ(data, Qbitmap))
1525 return IMAGE_BITMAP;
1532 gtk_resource_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
1533 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1534 int dest_mask, Lisp_Object domain)
1536 struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
1537 GdkCursor *c = NULL;
1538 unsigned int type = 0;
1539 Lisp_Object device = IMAGE_INSTANCE_DEVICE(ii);
1540 Lisp_Object resource_type =
1541 find_keyword_in_vector(instantiator, Q_resource_type);
1542 Lisp_Object resource_id =
1543 find_keyword_in_vector(instantiator, Q_resource_id);
1545 if (!DEVICE_GTK_P(XDEVICE(device)))
1546 signal_simple_error("Not a GTK device", device);
1548 type = resource_symbol_to_type(resource_type);
1551 if (dest_mask & IMAGE_POINTER_MASK && type == IMAGE_POINTER_MASK)
1552 iitype = IMAGE_POINTER;
1553 else if (dest_mask & IMAGE_COLOR_PIXMAP_MASK)
1554 iitype = IMAGE_COLOR_PIXMAP;
1556 incompatible_image_types(instantiator, dest_mask,
1557 IMAGE_COLOR_PIXMAP_MASK |
1558 IMAGE_POINTER_MASK);
1561 /* mess with the keyword info we were provided with */
1562 gtk_initialize_pixmap_image_instance(ii, 1, type);
1563 c = gdk_cursor_new(resource_name_to_resource(resource_id, type));
1564 IMAGE_INSTANCE_GTK_CURSOR(ii) = c;
1565 IMAGE_INSTANCE_PIXMAP_FILENAME(ii) = resource_id;
1566 IMAGE_INSTANCE_PIXMAP_WIDTH(ii) = 10;
1567 IMAGE_INSTANCE_PIXMAP_HEIGHT(ii) = 10;
1568 IMAGE_INSTANCE_PIXMAP_DEPTH(ii) = 1;
1571 static void check_valid_resource_symbol(Lisp_Object data)
1574 if (!resource_symbol_to_type(data))
1575 signal_simple_error("invalid resource type", data);
1578 static void check_valid_resource_id(Lisp_Object data)
1580 if (!resource_name_to_resource(data, IMAGE_POINTER)
1581 && !resource_name_to_resource(data, IMAGE_COLOR_PIXMAP)
1583 && !resource_name_to_resource(data, IMAGE_BITMAP)
1586 signal_simple_error("invalid resource identifier", data);
1590 void check_valid_string_or_int(Lisp_Object data)
1599 /**********************************************************************
1601 **********************************************************************/
1603 static void autodetect_validate(Lisp_Object instantiator)
1605 data_must_be_present(instantiator);
1609 autodetect_normalize(Lisp_Object instantiator,
1610 Lisp_Object console_type, Lisp_Object dest_mask)
1612 Lisp_Object file = find_keyword_in_vector(instantiator, Q_data);
1613 Lisp_Object filename = Qnil;
1614 Lisp_Object data = Qnil;
1615 struct gcpro gcpro1, gcpro2, gcpro3;
1616 Lisp_Object alist = Qnil;
1618 GCPRO3(filename, data, alist);
1620 if (NILP(file)) /* no conversion necessary */
1621 RETURN_UNGCPRO(instantiator);
1623 alist = tagged_vector_to_alist(instantiator);
1625 filename = locate_pixmap_file(file);
1626 if (!NILP(filename)) {
1628 /* #### Apparently some versions of XpmReadFileToData, which is
1629 called by pixmap_to_lisp_data, don't return an error value
1630 if the given file is not a valid XPM file. Instead, they
1631 just seg fault. It is definitely caused by passing a
1632 bitmap. To try and avoid this we check for bitmaps first. */
1634 data = bitmap_to_lisp_data(filename, &xhot, &yhot, 1);
1636 if (!EQ(data, Qt)) {
1637 alist = remassq_no_quit(Q_data, alist);
1638 alist = Fcons(Fcons(Q_file, filename),
1639 Fcons(Fcons(Q_data, data), alist));
1642 Fcons(Fcons(Q_hotspot_x, make_int(xhot)),
1646 Fcons(Fcons(Q_hotspot_y, make_int(yhot)),
1650 xbm_mask_file_munging(alist, filename, Qnil,
1654 Lisp_Object result =
1655 alist_to_tagged_vector(Qxbm, alist);
1657 RETURN_UNGCPRO(result);
1661 data = pixmap_to_lisp_data(filename, 1);
1663 if (!EQ(data, Qt)) {
1664 alist = remassq_no_quit(Q_data, alist);
1665 alist = Fcons(Fcons(Q_file, filename),
1666 Fcons(Fcons(Q_data, data), alist));
1667 alist = Fcons(Fcons(Q_color_symbols,
1668 evaluate_xpm_color_symbols()),
1671 Lisp_Object result =
1672 alist_to_tagged_vector(Qxpm, alist);
1674 RETURN_UNGCPRO(result);
1680 /* If we couldn't convert it, just put it back as it is.
1681 We might try to further frob it later as a cursor-font
1682 specification. (We can't do that now because we don't know
1683 what dest-types it's going to be instantiated into.) */
1685 Lisp_Object result = alist_to_tagged_vector(Qautodetect, alist);
1687 RETURN_UNGCPRO(result);
1691 static int autodetect_possible_dest_types(void)
1694 IMAGE_MONO_PIXMAP_MASK |
1695 IMAGE_COLOR_PIXMAP_MASK | IMAGE_POINTER_MASK | IMAGE_TEXT_MASK;
1699 autodetect_instantiate(Lisp_Object image_instance,
1700 Lisp_Object instantiator,
1701 Lisp_Object pointer_fg,
1702 Lisp_Object pointer_bg,
1703 int dest_mask, Lisp_Object domain)
1705 Lisp_Object data = find_keyword_in_vector(instantiator, Q_data);
1706 struct gcpro gcpro1, gcpro2, gcpro3;
1707 Lisp_Object alist = Qnil;
1708 Lisp_Object result = Qnil;
1709 int is_cursor_font = 0;
1711 GCPRO3(data, alist, result);
1713 alist = tagged_vector_to_alist(instantiator);
1714 if (dest_mask & IMAGE_POINTER_MASK) {
1715 CONST char *name_ext;
1717 TO_EXTERNAL_FORMAT(LISP_STRING, data,
1718 C_STRING_ALLOCA, name_ext, Qfile_name);
1720 if (cursor_name_to_index(name_ext) != -1) {
1721 result = alist_to_tagged_vector(Qcursor_font, alist);
1726 if (!is_cursor_font)
1727 result = alist_to_tagged_vector(Qstring, alist);
1731 cursor_font_instantiate(image_instance, result, pointer_fg,
1732 pointer_bg, dest_mask, domain);
1734 string_instantiate(image_instance, result, pointer_fg,
1735 pointer_bg, dest_mask, domain);
1740 /**********************************************************************
1742 **********************************************************************/
1744 static void font_validate(Lisp_Object instantiator)
1746 data_must_be_present(instantiator);
1749 static int font_possible_dest_types(void)
1751 return IMAGE_POINTER_MASK;
1755 font_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
1756 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1757 int dest_mask, Lisp_Object domain)
1759 /* This function can GC */
1760 Lisp_Object data = find_keyword_in_vector(instantiator, Q_data);
1761 struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
1762 Lisp_Object device = IMAGE_INSTANCE_DEVICE(ii);
1764 GdkFont *source, *mask;
1765 char source_name[MAXPATHLEN], mask_name[MAXPATHLEN], dummy;
1766 int source_char, mask_char;
1768 Lisp_Object foreground, background;
1770 if (!DEVICE_GTK_P(XDEVICE(device)))
1771 signal_simple_error("Not a Gtk device", device);
1773 if (!STRINGP(data) || strncmp("FONT ", (char *)XSTRING_DATA(data), 5))
1774 signal_simple_error("Invalid font-glyph instantiator",
1777 if (!(dest_mask & IMAGE_POINTER_MASK))
1778 incompatible_image_types(instantiator, dest_mask,
1779 IMAGE_POINTER_MASK);
1781 foreground = find_keyword_in_vector(instantiator, Q_foreground);
1782 if (NILP(foreground))
1783 foreground = pointer_fg;
1784 background = find_keyword_in_vector(instantiator, Q_background);
1785 if (NILP(background))
1786 background = pointer_bg;
1788 generate_cursor_fg_bg(device, &foreground, &background, &fg, &bg);
1790 count = sscanf((char *)XSTRING_DATA(data),
1791 "FONT %s %d %s %d %c",
1792 source_name, &source_char,
1793 mask_name, &mask_char, &dummy);
1794 /* Allow "%s %d %d" as well... */
1795 if (count == 3 && (1 == sscanf(mask_name, "%d %c", &mask_char, &dummy)))
1796 count = 4, mask_name[0] = 0;
1798 if (count != 2 && count != 4)
1799 signal_simple_error("invalid cursor specification", data);
1800 source = gdk_font_load(source_name);
1802 signal_simple_error_2("couldn't load font",
1803 build_string(source_name), data);
1806 else if (!mask_name[0])
1809 mask = gdk_font_load(mask_name);
1813 list3(build_string("couldn't load font"),
1814 build_string(mask_name), data));
1819 /* #### call XQueryTextExtents() and check_pointer_sizes() here. */
1821 gtk_initialize_pixmap_image_instance(ii, 1, IMAGE_POINTER);
1823 IMAGE_INSTANCE_GTK_CURSOR(ii) = NULL;
1826 /* #### BILL!!! There is no way to call this function from Gdk */
1827 XCreateGlyphCursor(dpy, source, mask, source_char, mask_char, &fg, &bg);
1829 XIMAGE_INSTANCE_PIXMAP_FG(image_instance) = foreground;
1830 XIMAGE_INSTANCE_PIXMAP_BG(image_instance) = background;
1832 gdk_font_unref(source);
1833 if (mask && mask != source)
1834 gdk_font_unref(mask);
1837 /**********************************************************************
1839 **********************************************************************/
1841 static void cursor_font_validate(Lisp_Object instantiator)
1843 data_must_be_present(instantiator);
1846 static int cursor_font_possible_dest_types(void)
1848 return IMAGE_POINTER_MASK;
1851 static char *__downcase(const char *name)
1853 char *converted = strdup(name);
1854 char *work = converted;
1857 *work = tolower(*work);
1863 /* This is basically the equivalent of XmuCursorNameToIndex */
1864 static gint cursor_name_to_index(const char *name)
1867 static char *the_gdk_cursors[GDK_NUM_GLYPHS];
1869 if (!the_gdk_cursors[GDK_BASED_ARROW_UP]) {
1870 /* Need to initialize the array */
1871 /* Supposedly since this array is static it should be
1872 initialized to NULLs for us, but I'm very paranoid. */
1873 for (i = 0; i < GDK_NUM_GLYPHS; i++) {
1874 the_gdk_cursors[i] = NULL;
1877 #define FROB_CURSOR(x) the_gdk_cursors[GDK_##x] = __downcase(#x)
1879 FROB_CURSOR(BASED_ARROW_DOWN);
1880 FROB_CURSOR(BASED_ARROW_UP);
1882 FROB_CURSOR(BOGOSITY);
1883 FROB_CURSOR(BOTTOM_LEFT_CORNER);
1884 FROB_CURSOR(BOTTOM_RIGHT_CORNER);
1885 FROB_CURSOR(BOTTOM_SIDE);
1886 FROB_CURSOR(BOTTOM_TEE);
1887 FROB_CURSOR(BOX_SPIRAL);
1888 FROB_CURSOR(CENTER_PTR);
1889 FROB_CURSOR(CIRCLE);
1891 FROB_CURSOR(COFFEE_MUG);
1893 FROB_CURSOR(CROSS_REVERSE);
1894 FROB_CURSOR(CROSSHAIR);
1895 FROB_CURSOR(DIAMOND_CROSS);
1897 FROB_CURSOR(DOTBOX);
1898 FROB_CURSOR(DOUBLE_ARROW);
1899 FROB_CURSOR(DRAFT_LARGE);
1900 FROB_CURSOR(DRAFT_SMALL);
1901 FROB_CURSOR(DRAPED_BOX);
1902 FROB_CURSOR(EXCHANGE);
1904 FROB_CURSOR(GOBBLER);
1910 FROB_CURSOR(IRON_CROSS);
1911 FROB_CURSOR(LEFT_PTR);
1912 FROB_CURSOR(LEFT_SIDE);
1913 FROB_CURSOR(LEFT_TEE);
1914 FROB_CURSOR(LEFTBUTTON);
1915 FROB_CURSOR(LL_ANGLE);
1916 FROB_CURSOR(LR_ANGLE);
1918 FROB_CURSOR(MIDDLEBUTTON);
1920 FROB_CURSOR(PENCIL);
1921 FROB_CURSOR(PIRATE);
1923 FROB_CURSOR(QUESTION_ARROW);
1924 FROB_CURSOR(RIGHT_PTR);
1925 FROB_CURSOR(RIGHT_SIDE);
1926 FROB_CURSOR(RIGHT_TEE);
1927 FROB_CURSOR(RIGHTBUTTON);
1928 FROB_CURSOR(RTL_LOGO);
1929 FROB_CURSOR(SAILBOAT);
1930 FROB_CURSOR(SB_DOWN_ARROW);
1931 FROB_CURSOR(SB_H_DOUBLE_ARROW);
1932 FROB_CURSOR(SB_LEFT_ARROW);
1933 FROB_CURSOR(SB_RIGHT_ARROW);
1934 FROB_CURSOR(SB_UP_ARROW);
1935 FROB_CURSOR(SB_V_DOUBLE_ARROW);
1936 FROB_CURSOR(SHUTTLE);
1937 FROB_CURSOR(SIZING);
1938 FROB_CURSOR(SPIDER);
1939 FROB_CURSOR(SPRAYCAN);
1941 FROB_CURSOR(TARGET);
1942 FROB_CURSOR(TCROSS);
1943 FROB_CURSOR(TOP_LEFT_ARROW);
1944 FROB_CURSOR(TOP_LEFT_CORNER);
1945 FROB_CURSOR(TOP_RIGHT_CORNER);
1946 FROB_CURSOR(TOP_SIDE);
1947 FROB_CURSOR(TOP_TEE);
1949 FROB_CURSOR(UL_ANGLE);
1950 FROB_CURSOR(UMBRELLA);
1951 FROB_CURSOR(UR_ANGLE);
1954 FROB_CURSOR(X_CURSOR);
1958 for (i = 0; i < GDK_NUM_GLYPHS; i++) {
1959 if (!the_gdk_cursors[i])
1961 if (!strcmp(the_gdk_cursors[i], name)) {
1969 cursor_font_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
1970 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1971 int dest_mask, Lisp_Object domain)
1973 /* This function can GC */
1974 Lisp_Object data = find_keyword_in_vector(instantiator, Q_data);
1975 struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
1976 Lisp_Object device = IMAGE_INSTANCE_DEVICE(ii);
1978 CONST char *name_ext;
1979 Lisp_Object foreground, background;
1981 if (!DEVICE_GTK_P(XDEVICE(device)))
1982 signal_simple_error("Not a Gtk device", device);
1984 if (!(dest_mask & IMAGE_POINTER_MASK))
1985 incompatible_image_types(instantiator, dest_mask,
1986 IMAGE_POINTER_MASK);
1988 TO_EXTERNAL_FORMAT(LISP_STRING, data,
1989 C_STRING_ALLOCA, name_ext, Qfile_name);
1991 if ((i = cursor_name_to_index(name_ext)) == -1)
1992 signal_simple_error("Unrecognized cursor-font name", data);
1994 gtk_initialize_pixmap_image_instance(ii, 1, IMAGE_POINTER);
1995 IMAGE_INSTANCE_GTK_CURSOR(ii) = gdk_cursor_new(i);
1996 foreground = find_keyword_in_vector(instantiator, Q_foreground);
1997 if (NILP(foreground))
1998 foreground = pointer_fg;
1999 background = find_keyword_in_vector(instantiator, Q_background);
2000 if (NILP(background))
2001 background = pointer_bg;
2002 maybe_recolor_cursor(image_instance, foreground, background);
2006 gtk_colorize_image_instance(Lisp_Object image_instance,
2007 Lisp_Object foreground, Lisp_Object background);
2009 /************************************************************************/
2010 /* subwindow and widget support */
2011 /************************************************************************/
2013 /* unmap the image if it is a widget. This is used by redisplay via
2014 redisplay_unmap_subwindows */
2015 static void gtk_unmap_subwindow(Lisp_Image_Instance * p)
2017 if (IMAGE_INSTANCE_TYPE(p) == IMAGE_SUBWINDOW) {
2018 /* We don't support subwindows, but we do support widgets... */
2020 } else { /* must be a widget */
2022 /* Since we are being unmapped we want the enclosing frame to
2023 get focus. The losing with simple scrolling but is the safest
2025 if (IMAGE_INSTANCE_GTK_CLIPWIDGET(p))
2026 gtk_widget_unmap(IMAGE_INSTANCE_GTK_CLIPWIDGET(p));
2030 /* map the subwindow. This is used by redisplay via
2031 redisplay_output_subwindow */
2033 gtk_map_subwindow(Lisp_Image_Instance * p, int x, int y,
2034 struct display_glyph_area *dga)
2036 assert(dga->width > 0 && dga->height > 0);
2038 if (IMAGE_INSTANCE_TYPE(p) == IMAGE_SUBWINDOW) {
2039 /* No subwindow support... */
2041 } else { /* must be a widget */
2043 struct frame *f = XFRAME(IMAGE_INSTANCE_FRAME(p));
2044 GtkWidget *wid = IMAGE_INSTANCE_GTK_CLIPWIDGET(p);
2051 a.x = x + IMAGE_INSTANCE_GTK_WIDGET_XOFFSET(p);
2052 a.y = y + IMAGE_INSTANCE_GTK_WIDGET_YOFFSET(p);
2053 a.width = dga->width;
2054 a.height = dga->height;
2056 /* Is the widget cganging position? */
2057 moving = (a.x != wid->allocation.x) ||
2058 (a.y != wid->allocation.y);
2060 if ((a.width != wid->allocation.width) ||
2061 (a.height != wid->allocation.height) || moving) {
2062 gtk_widget_size_allocate(IMAGE_INSTANCE_GTK_CLIPWIDGET
2068 GTK_WIDGET_FLAGS(FRAME_GTK_TEXT_WIDGET(f));
2070 /* GtkFixed widget queues a resize when you add a widget.
2071 ** But only if it is visible.
2074 GTK_WIDGET_FLAGS(FRAME_GTK_TEXT_WIDGET(f)) &=
2077 if (IMAGE_INSTANCE_GTK_ALREADY_PUT(p)) {
2078 gtk_fixed_move(GTK_FIXED
2079 (FRAME_GTK_TEXT_WIDGET(f)), wid,
2082 IMAGE_INSTANCE_GTK_ALREADY_PUT(p) = TRUE;
2083 gtk_fixed_put(GTK_FIXED
2084 (FRAME_GTK_TEXT_WIDGET(f)), wid,
2088 GTK_WIDGET_FLAGS(FRAME_GTK_TEXT_WIDGET(f)) = old_flags;
2090 if (IMAGE_INSTANCE_GTK_ALREADY_PUT(p)) {
2093 /* Must make sure we have put the image at least once! */
2094 IMAGE_INSTANCE_GTK_ALREADY_PUT(p) = TRUE;
2095 gtk_fixed_put(GTK_FIXED
2096 (FRAME_GTK_TEXT_WIDGET(f)), wid,
2101 if (!IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP(p)) {
2102 gtk_widget_map(wid);
2105 gtk_widget_draw(wid, NULL);
2109 /* when you click on a widget you may activate another widget this
2110 needs to be checked and all appropriate widgets updated */
2111 static void gtk_redisplay_subwindow(Lisp_Image_Instance * p)
2113 /* Update the subwindow size if necessary. */
2114 if (IMAGE_INSTANCE_SIZE_CHANGED(p)) {
2116 XResizeWindow(IMAGE_INSTANCE_X_SUBWINDOW_DISPLAY(p),
2117 IMAGE_INSTANCE_X_SUBWINDOW_ID(p),
2118 IMAGE_INSTANCE_WIDTH(p),
2119 IMAGE_INSTANCE_HEIGHT(p));
2124 /* Update all attributes that have changed. */
2125 static void gtk_redisplay_widget(Lisp_Image_Instance * p)
2127 /* This function can GC if IN_REDISPLAY is false. */
2129 if (!IMAGE_INSTANCE_GTK_CLIPWIDGET(p))
2133 /* First get the items if they have changed since this is a
2134 structural change. As such it will nuke all added values so we
2135 need to update most other things after the items have changed. */
2136 gtk_widget_show_all(IMAGE_INSTANCE_GTK_CLIPWIDGET(p));
2137 if (IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED(p)) {
2138 Lisp_Object image_instance;
2140 XSETIMAGE_INSTANCE(image_instance, p);
2142 /* Need to update GtkArgs that might have changed... */
2146 /* No items changed, so do nothing, right? */
2149 /* Possibly update the colors and font */
2150 if (IMAGE_INSTANCE_WIDGET_FACE_CHANGED(p)
2152 /* #### This is not sufficient because it will not cope with widgets
2153 that are not currently visible. Once redisplay has done the
2154 visible ones it will clear this flag so that when new ones
2155 become visible they will not be updated. */
2156 XFRAME(IMAGE_INSTANCE_FRAME(p))->faces_changed
2158 XFRAME(IMAGE_INSTANCE_FRAME(p))->frame_changed
2159 || IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED(p)) {
2160 /* #### Write this function BILL! */
2161 update_widget_face(NULL, p, IMAGE_INSTANCE_FRAME(p));
2164 /* Possibly update the text. */
2165 if (IMAGE_INSTANCE_TEXT_CHANGED(p)) {
2167 Lisp_Object val = IMAGE_INSTANCE_WIDGET_TEXT(p);
2168 LISP_STRING_TO_EXTERNAL(val, str, Qnative);
2170 /* #### Need to special case each type of GtkWidget here! */
2173 /* Possibly update the size. */
2174 if (IMAGE_INSTANCE_SIZE_CHANGED(p)
2175 || IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED(p)
2176 || IMAGE_INSTANCE_TEXT_CHANGED(p)) {
2178 GtkAllocation a = IMAGE_INSTANCE_GTK_CLIPWIDGET(p)->allocation;
2180 assert(IMAGE_INSTANCE_GTK_WIDGET_ID(p) &&
2181 IMAGE_INSTANCE_GTK_CLIPWIDGET(p));
2183 a.width = r.width = IMAGE_INSTANCE_WIDTH(p);
2184 a.height = r.height = IMAGE_INSTANCE_HEIGHT(p);
2186 /* Force the widget's preferred and actual size to what we say it shall
2188 gtk_widget_size_request(IMAGE_INSTANCE_GTK_CLIPWIDGET(p), &r);
2189 gtk_widget_size_allocate(IMAGE_INSTANCE_GTK_CLIPWIDGET(p), &a);
2192 /* Adjust offsets within the frame. */
2193 if (XFRAME(IMAGE_INSTANCE_FRAME(p))->size_changed) {
2194 /* I don't think we need to do anything for Gtk here... */
2197 /* now modify the widget */
2201 /* instantiate and gtk type subwindow */
2203 gtk_subwindow_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
2204 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2205 int dest_mask, Lisp_Object domain)
2207 /* This function can GC */
2208 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2209 Lisp_Object device = IMAGE_INSTANCE_DEVICE(ii);
2210 Lisp_Object frame = DOMAIN_FRAME(domain);
2212 if (!DEVICE_GTK_P(XDEVICE(device)))
2213 signal_simple_error("Not a GTK device", device);
2215 IMAGE_INSTANCE_TYPE(ii) = IMAGE_SUBWINDOW;
2217 ii->data = xnew_and_zero(struct gtk_subwindow_data);
2219 /* Create a window for clipping */
2220 IMAGE_INSTANCE_GTK_CLIPWINDOW(ii) = NULL;
2222 /* Now put the subwindow inside the clip window. */
2223 IMAGE_INSTANCE_SUBWINDOW_ID(ii) = (void *)NULL;
2228 /************************************************************************/
2230 /************************************************************************/
2232 update_widget_face(GtkWidget * w, Lisp_Image_Instance * ii, Lisp_Object domain)
2235 GtkStyle *style = gtk_widget_get_style(w);
2236 Lisp_Object pixel = Qnil;
2237 GdkColor *fcolor, *bcolor;
2239 style = gtk_style_copy(style);
2241 /* Update the foreground. */
2242 pixel = FACE_FOREGROUND(IMAGE_INSTANCE_WIDGET_FACE(ii), domain);
2243 fcolor = COLOR_INSTANCE_GTK_COLOR(XCOLOR_INSTANCE(pixel));
2245 /* Update the background. */
2246 pixel = FACE_BACKGROUND(IMAGE_INSTANCE_WIDGET_FACE(ii), domain);
2247 bcolor = COLOR_INSTANCE_GTK_COLOR(XCOLOR_INSTANCE(pixel));
2249 /* Update the font */
2250 /* #### FIXME!!! Need to copy the widgets style, dick with it, and
2251 ** set the widgets style to the new style...
2253 gtk_widget_set_style(w, style);
2255 /* #### Megahack - but its just getting too complicated to do this
2256 in the right place. */
2258 if (EQ(IMAGE_INSTANCE_WIDGET_TYPE(ii), Qtab_control))
2259 update_tab_widget_face(wv, ii, domain);
2266 update_tab_widget_face(GtkWidget * w, Lisp_Image_Instance * ii,
2270 widget_value *val = wv->contents, *cur;
2272 /* Give each child label the correct foreground color. */
2273 Lisp_Object pixel = FACE_FOREGROUND
2274 (IMAGE_INSTANCE_WIDGET_FACE(ii),
2276 XColor fcolor = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(pixel));
2277 lw_add_widget_value_arg(val, XtNtabForeground, fcolor.pixel);
2278 wv->change = VISIBLE_CHANGE;
2279 val->change = VISIBLE_CHANGE;
2281 for (cur = val->next; cur; cur = cur->next) {
2282 cur->change = VISIBLE_CHANGE;
2284 lw_copy_widget_value_args(val, cur);
2292 gtk_widget_instantiate_1(Lisp_Object image_instance, Lisp_Object instantiator,
2293 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2296 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2297 Lisp_Object widget = Qnil;
2299 GtkWidget *w = NULL;
2300 struct gcpro gcpro1;
2302 IMAGE_INSTANCE_TYPE(ii) = IMAGE_WIDGET;
2304 if (!NILP(IMAGE_INSTANCE_WIDGET_TEXT(ii))) {
2305 LISP_STRING_TO_EXTERNAL(IMAGE_INSTANCE_WIDGET_TEXT(ii), nm,
2309 ii->data = xnew_and_zero(struct gtk_subwindow_data);
2311 /* Create a clipping widget */
2312 IMAGE_INSTANCE_GTK_CLIPWIDGET(ii) = NULL;
2313 IMAGE_INSTANCE_GTK_ALREADY_PUT(ii) = FALSE;
2315 /* Create the actual widget */
2317 widget = call5(Qgtk_widget_instantiate_internal,
2318 image_instance, instantiator,
2319 pointer_fg, pointer_bg, domain);
2321 if (!NILP(widget)) {
2322 CHECK_GTK_OBJECT(widget);
2323 w = GTK_WIDGET(XGTK_OBJECT(widget)->object);
2326 ("Lisp-level creation of widget failed... falling back\n");
2327 w = gtk_label_new("Widget Creation Failed...");
2332 IMAGE_INSTANCE_SUBWINDOW_ID(ii) = (void *)w;
2334 /* #### HACK!!!! We should make this do the right thing if we
2335 ** really need a clip widget!
2337 IMAGE_INSTANCE_GTK_CLIPWIDGET(ii) = w;
2339 /* The current theme may produce a widget of a different size that what we
2340 expect so force reconsideration of the widget's size. */
2341 IMAGE_INSTANCE_LAYOUT_CHANGED(ii) = 1;
2347 gtk_widget_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
2348 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2349 int dest_mask, Lisp_Object domain)
2351 call_with_suspended_errors((lisp_fn_t) gtk_widget_instantiate_1,
2354 image_instance, instantiator,
2355 pointer_fg, pointer_bg, domain);
2358 /* get properties of a control */
2360 gtk_widget_property(Lisp_Object image_instance, Lisp_Object prop)
2362 /* Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance); */
2364 /* get the text from a control */
2365 if (EQ(prop, Q_text)) {
2371 #define FAKE_GTK_WIDGET_INSTANTIATOR(x) \
2373 gtk_##x##_instantiate (Lisp_Object image_instance, \
2374 Lisp_Object instantiator, \
2375 Lisp_Object pointer_fg, \
2376 Lisp_Object pointer_bg, \
2377 int dest_mask, Lisp_Object domain) \
2379 gtk_widget_instantiate (image_instance, instantiator, pointer_fg, \
2380 pointer_bg, dest_mask, domain); \
2383 FAKE_GTK_WIDGET_INSTANTIATOR(native_layout);
2384 FAKE_GTK_WIDGET_INSTANTIATOR(button);
2385 FAKE_GTK_WIDGET_INSTANTIATOR(progress_gauge);
2386 FAKE_GTK_WIDGET_INSTANTIATOR(edit_field);
2387 FAKE_GTK_WIDGET_INSTANTIATOR(combo_box);
2388 FAKE_GTK_WIDGET_INSTANTIATOR(label);
2389 /* Note: tab_control has a custom instantiator (see below) */
2392 Ask the widget to return it's preferred size. This device method must
2393 defined for all widgets that also have format specific version of
2394 query_geometry defined in glyphs-widget.c. This is because those format
2395 specific versions return sizes that are appropriate for the X widgets. For
2396 GTK, the size of a widget can change at runtime due to the user changing
2399 This method can be called before the widget is instantiated. This is
2400 because instantiate_image_instantiator() is tying to be helpful to other
2401 toolkits and supply sane geometry values to them. This is not appropriate
2402 for GTK and can be ignored.
2404 This method can be used by all widgets.
2407 gtk_widget_query_geometry(Lisp_Object image_instance,
2408 int *width, int *height,
2409 enum image_instance_geometry disp, Lisp_Object domain)
2411 Lisp_Image_Instance *p = XIMAGE_INSTANCE(image_instance);
2413 if (p->data != NULL) {
2414 GtkWidget *w = IMAGE_INSTANCE_GTK_CLIPWIDGET(p);
2417 gtk_widget_size_request(w, &r);
2423 /* Button functions. */
2425 /* Update a button's clicked state. */
2426 static void gtk_button_redisplay(Lisp_Object image_instance)
2428 /* This function can GC if IN_REDISPLAY is false. */
2429 Lisp_Image_Instance *p = XIMAGE_INSTANCE(image_instance);
2430 GtkWidget *w = IMAGE_INSTANCE_GTK_CLIPWIDGET(p);
2432 if (GTK_WIDGET_TYPE(w) == gtk_button_get_type()) {
2433 } else if (GTK_WIDGET_TYPE(w) == gtk_check_button_get_type()) {
2434 } else if (GTK_WIDGET_TYPE(w) == gtk_radio_button_get_type()) {
2436 /* Unknown button type... */
2441 /* get properties of a button */
2443 gtk_button_property(Lisp_Object image_instance, Lisp_Object prop)
2445 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2447 /* check the state of a button */
2448 if (EQ(prop, Q_selected)) {
2449 if (GTK_WIDGET_HAS_FOCUS(IMAGE_INSTANCE_SUBWINDOW_ID(ii)))
2457 /* Progress gauge functions. */
2459 /* set the properties of a progress gauge */
2460 static void gtk_progress_gauge_redisplay(Lisp_Object image_instance)
2462 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2464 if (IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED(ii)) {
2468 val = XGUI_ITEM(IMAGE_INSTANCE_WIDGET_PENDING_ITEMS(ii))->value;
2471 gtk_progress_set_value(GTK_PROGRESS
2472 (IMAGE_INSTANCE_SUBWINDOW_ID(ii)), f);
2476 /* Tab Control functions. */
2479 Register a widget's callbacks with the frame's hashtable. The hashtable is
2480 weak so deregistration is handled automatically. Tab controls have per-tab
2481 callback list functions and the GTK callback architecture is not
2482 sufficiently flexible to deal with this. Instead, the functions are
2483 registered here and the id is passed through the callback loop.
2486 gtk_register_gui_item(Lisp_Object image_instance, Lisp_Object gui,
2489 struct frame *f = XFRAME(DOMAIN_FRAME(domain));
2490 int id = gui_item_id_hash(FRAME_GTK_WIDGET_CALLBACK_HASH_TABLE(f),
2491 gui, WIDGET_GLYPH_SLOT);
2493 Fputhash(make_int(id), image_instance,
2494 FRAME_GTK_WIDGET_INSTANCE_HASH_TABLE(f));
2495 Fputhash(make_int(id), XGUI_ITEM(gui)->callback,
2496 FRAME_GTK_WIDGET_CALLBACK_HASH_TABLE(f));
2497 Fputhash(make_int(id), XGUI_ITEM(gui)->callback_ex,
2498 FRAME_GTK_WIDGET_CALLBACK_EX_HASH_TABLE(f));
2503 Append the given item as a tab to the notebook. Callbacks, etc are all
2507 gtk_add_tab_item(Lisp_Object image_instance,
2508 GtkNotebook * nb, Lisp_Object item, Lisp_Object domain, int i)
2512 char *c_name = NULL;
2515 if (GUI_ITEMP(item)) {
2516 Lisp_Gui_Item *pgui = XGUI_ITEM(item);
2518 if (!STRINGP(pgui->name))
2519 pgui->name = Feval(pgui->name);
2521 CHECK_STRING(pgui->name);
2523 hash_id = gtk_register_gui_item(image_instance, item, domain);
2530 TO_EXTERNAL_FORMAT(LISP_STRING, name, C_STRING_ALLOCA, c_name, Qctext);
2532 /* Dummy widget that the notbook wants to display when a tab is selected. */
2533 box = gtk_vbox_new(FALSE, 3);
2536 Store the per-tab callback data id in the tab. The callback functions
2537 themselves could have been stored in the widget but this avoids having to
2538 worry about the garbage collector running between here and the callback
2541 gtk_object_set_data(GTK_OBJECT(box), GTK_DATA_TAB_HASHCODE_IDENTIFIER,
2542 (gpointer) hash_id);
2544 gtk_notebook_append_page(nb, box, gtk_label_new(c_name));
2547 /* Signal handler for the switch-page signal. */
2548 static void gtk_tab_control_callback(GtkNotebook * notebook,
2549 GtkNotebookPage * page,
2550 gint page_num, gpointer user_data)
2553 This callback is called for every selection, not just user selection.
2554 We're only interested in user selection, which occurs outside of
2559 Lisp_Object image_instance, callback, callback_ex;
2560 Lisp_Object frame, event;
2561 int update_subwindows_p = 0;
2562 struct frame *f = gtk_widget_to_frame(GTK_WIDGET(notebook));
2567 frame = wrap_frame(f);
2569 id = (int)gtk_object_get_data(GTK_OBJECT(page->child),
2570 GTK_DATA_TAB_HASHCODE_IDENTIFIER);
2571 image_instance = Fgethash(make_int(id),
2572 FRAME_GTK_WIDGET_INSTANCE_HASH_TABLE
2575 Fgethash(make_int(id),
2576 FRAME_GTK_WIDGET_CALLBACK_HASH_TABLE(f), Qnil);
2578 Fgethash(make_int(id),
2579 FRAME_GTK_WIDGET_CALLBACK_EX_HASH_TABLE(f), Qnil);
2580 update_subwindows_p = 1;
2582 /* It is possible for a widget action to cause it to get out of
2583 sync with its instantiator. Thus it is necessary to signal
2584 this possibility. */
2585 if (IMAGE_INSTANCEP(image_instance))
2586 XIMAGE_INSTANCE_WIDGET_ACTION_OCCURRED(image_instance) =
2589 if (!NILP(callback_ex) && !UNBOUNDP(callback_ex)) {
2590 event = Fmake_event(Qnil, Qnil);
2592 XEVENT(event)->event_type = misc_user_event;
2593 XEVENT(event)->channel = frame;
2594 XEVENT(event)->event.eval.function = Qeval;
2595 XEVENT(event)->event.eval.object =
2596 list4(Qfuncall, callback_ex, image_instance, event);
2597 } else if (NILP(callback) || UNBOUNDP(callback))
2600 Lisp_Object fn, arg;
2602 event = Fmake_event(Qnil, Qnil);
2604 get_gui_callback(callback, &fn, &arg);
2605 XEVENT(event)->event_type = misc_user_event;
2606 XEVENT(event)->channel = frame;
2607 XEVENT(event)->event.eval.function = fn;
2608 XEVENT(event)->event.eval.object = arg;
2612 enqueue_gtk_dispatch_event(event);
2614 /* The result of this evaluation could cause other instances to change so
2615 enqueue an update callback to check this. */
2616 if (update_subwindows_p && !NILP(event))
2617 enqueue_magic_eval_event(update_widget_instances,
2622 /* Create a tab_control widget. The special handling of the individual tabs
2623 means that the normal instantiation code cannot be used. */
2625 gtk_tab_control_instantiate(Lisp_Object image_instance,
2626 Lisp_Object instantiator,
2627 Lisp_Object pointer_fg,
2628 Lisp_Object pointer_bg,
2629 int dest_mask, Lisp_Object domain)
2632 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2637 /* The normal instantiation is still needed. */
2638 gtk_widget_instantiate(image_instance, instantiator, pointer_fg,
2639 pointer_bg, dest_mask, domain);
2641 nb = GTK_NOTEBOOK(IMAGE_INSTANCE_GTK_CLIPWIDGET(ii));
2643 /* Add items to the tab, find the current selection */
2644 LIST_LOOP(rest, XCDR(IMAGE_INSTANCE_WIDGET_ITEMS(ii))) {
2645 gtk_add_tab_item(image_instance, nb, XCAR(rest), domain, i);
2647 if (gui_item_selected_p(XCAR(rest)))
2653 gtk_notebook_set_page(nb, selected);
2655 /* Call per-tab lisp callback when a tab is pressed. */
2656 gtk_signal_connect(GTK_OBJECT(nb), "switch-page",
2657 GTK_SIGNAL_FUNC(gtk_tab_control_callback), NULL);
2660 /* Set the properties of a tab control */
2661 static void gtk_tab_control_redisplay(Lisp_Object image_instance)
2663 /* #### Convert this to GTK baby! */
2664 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2666 if (IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED(ii) ||
2667 IMAGE_INSTANCE_WIDGET_ACTION_OCCURRED(ii)) {
2668 /* If only the order has changed then simply select the first
2669 one of the pending set. This stops horrendous rebuilding -
2670 and hence flicker - of the tabs each time you click on
2672 if (tab_control_order_only_changed(image_instance)) {
2674 Lisp_Object rest, selected =
2675 gui_item_list_find_selected
2676 (NILP(IMAGE_INSTANCE_WIDGET_PENDING_ITEMS(ii)) ?
2677 XCDR(IMAGE_INSTANCE_WIDGET_ITEMS(ii)) :
2678 XCDR(IMAGE_INSTANCE_WIDGET_PENDING_ITEMS(ii)));
2680 LIST_LOOP(rest, XCDR(IMAGE_INSTANCE_WIDGET_ITEMS(ii))) {
2681 if (gui_item_equal_sans_selected
2682 (XCAR(rest), selected, 0)) {
2683 Lisp_Object old_selected =
2684 gui_item_list_find_selected(XCDR
2685 (IMAGE_INSTANCE_WIDGET_ITEMS
2688 /* Pick up the new selected item. */
2689 XGUI_ITEM(old_selected)->selected =
2690 XGUI_ITEM(XCAR(rest))->selected;
2691 XGUI_ITEM(XCAR(rest))->selected =
2692 XGUI_ITEM(selected)->selected;
2693 /* We're not actually changing the items anymore. */
2694 IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED(ii)
2696 IMAGE_INSTANCE_WIDGET_PENDING_ITEMS(ii)
2699 gtk_notebook_set_page(GTK_NOTEBOOK
2700 (IMAGE_INSTANCE_GTK_CLIPWIDGET
2709 /* More than just the order has changed... let's get busy! */
2711 GTK_NOTEBOOK(IMAGE_INSTANCE_GTK_CLIPWIDGET(ii));
2712 guint num_pages = g_list_length(nb->children);
2716 /* Why is there no API to remove everything from a notebook? */
2717 if (num_pages >= 0) {
2718 for (i = num_pages; i >= 0; --i) {
2719 gtk_notebook_remove_page(nb, i);
2726 XCDR(IMAGE_INSTANCE_WIDGET_PENDING_ITEMS(ii)))
2728 gtk_add_tab_item(image_instance, nb, XCAR(rest),
2729 IMAGE_INSTANCE_FRAME(ii), i);
2732 /* Show all the new widgets we just added... */
2733 gtk_widget_show_all(GTK_WIDGET(nb));
2737 /* Possibly update the face. */
2739 if (IMAGE_INSTANCE_WIDGET_FACE_CHANGED(ii)
2741 XFRAME(IMAGE_INSTANCE_FRAME(ii))->faces_changed
2742 || IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED(ii)) {
2743 update_tab_widget_face(wv, ii, IMAGE_INSTANCE_FRAME(ii));
2747 #endif /* HAVE_WIDGETS */
2749 /************************************************************************/
2750 /* initialization */
2751 /************************************************************************/
2752 void syms_of_glyphs_gtk(void)
2754 defkeyword(&Q_resource_id, ":resource-id");
2755 defkeyword(&Q_resource_type, ":resource-type");
2757 defsymbol(&Qgtk_widget_instantiate_internal,
2758 "gtk-widget-instantiate-internal");
2759 defsymbol(&Qgtk_widget_property_internal,
2760 "gtk-widget-property-internal");
2761 defsymbol(&Qgtk_widget_redisplay_internal,
2762 "gtk-widget-redisplay-internal");
2763 defsymbol(&Qgtk_widget_set_style, "gtk-widget-set-style");
2767 void console_type_create_glyphs_gtk(void)
2770 CONSOLE_HAS_METHOD(gtk, print_image_instance);
2771 CONSOLE_HAS_METHOD(gtk, finalize_image_instance);
2772 CONSOLE_HAS_METHOD(gtk, image_instance_equal);
2773 CONSOLE_HAS_METHOD(gtk, image_instance_hash);
2774 CONSOLE_HAS_METHOD(gtk, colorize_image_instance);
2775 CONSOLE_HAS_METHOD(gtk, init_image_instance_from_eimage);
2776 CONSOLE_HAS_METHOD(gtk, locate_pixmap_file);
2777 CONSOLE_HAS_METHOD(gtk, unmap_subwindow);
2778 CONSOLE_HAS_METHOD(gtk, map_subwindow);
2779 CONSOLE_HAS_METHOD(gtk, redisplay_widget);
2780 CONSOLE_HAS_METHOD(gtk, redisplay_subwindow);
2783 void image_instantiator_format_create_glyphs_gtk(void)
2785 IIFORMAT_VALID_CONSOLE(gtk, nothing);
2786 IIFORMAT_VALID_CONSOLE(gtk, string);
2788 IIFORMAT_VALID_CONSOLE(gtk, layout);
2790 IIFORMAT_VALID_CONSOLE(gtk, formatted_string);
2791 IIFORMAT_VALID_CONSOLE(gtk, inherit);
2793 INITIALIZE_DEVICE_IIFORMAT(gtk, xpm);
2794 IIFORMAT_HAS_DEVMETHOD(gtk, xpm, instantiate);
2797 IIFORMAT_VALID_CONSOLE(gtk, jpeg);
2800 IIFORMAT_VALID_CONSOLE(gtk, tiff);
2803 IIFORMAT_VALID_CONSOLE(gtk, png);
2806 IIFORMAT_VALID_CONSOLE(gtk, gif);
2809 IIFORMAT_VALID_CONSOLE(gtk, rawrgb);
2810 IIFORMAT_VALID_CONSOLE(gtk, rawrgba);
2813 INITIALIZE_DEVICE_IIFORMAT(gtk, subwindow);
2814 IIFORMAT_HAS_DEVMETHOD(gtk, subwindow, instantiate);
2818 INITIALIZE_DEVICE_IIFORMAT(gtk, native_layout);
2819 IIFORMAT_HAS_DEVMETHOD(gtk, native_layout, instantiate);
2822 INITIALIZE_DEVICE_IIFORMAT(gtk, button);
2823 IIFORMAT_HAS_DEVMETHOD(gtk, button, property);
2824 IIFORMAT_HAS_DEVMETHOD(gtk, button, instantiate);
2825 IIFORMAT_HAS_DEVMETHOD(gtk, button, redisplay);
2826 IIFORMAT_HAS_SHARED_DEVMETHOD(gtk, button, query_geometry, widget);
2827 /* general widget methods. */
2828 INITIALIZE_DEVICE_IIFORMAT(gtk, widget);
2829 IIFORMAT_HAS_DEVMETHOD(gtk, widget, property);
2830 IIFORMAT_HAS_DEVMETHOD(gtk, widget, query_geometry);
2832 /* progress gauge */
2833 INITIALIZE_DEVICE_IIFORMAT(gtk, progress_gauge);
2834 IIFORMAT_HAS_DEVMETHOD(gtk, progress_gauge, redisplay);
2835 IIFORMAT_HAS_DEVMETHOD(gtk, progress_gauge, instantiate);
2836 IIFORMAT_HAS_SHARED_DEVMETHOD(gtk, progress_gauge, query_geometry,
2839 INITIALIZE_DEVICE_IIFORMAT(gtk, edit_field);
2840 IIFORMAT_HAS_DEVMETHOD(gtk, edit_field, instantiate);
2841 INITIALIZE_DEVICE_IIFORMAT(gtk, combo_box);
2842 IIFORMAT_HAS_DEVMETHOD(gtk, combo_box, instantiate);
2843 IIFORMAT_HAS_SHARED_DEVMETHOD(gtk, combo_box, redisplay, tab_control);
2844 /* tab control widget */
2845 INITIALIZE_DEVICE_IIFORMAT(gtk, tab_control);
2846 IIFORMAT_HAS_DEVMETHOD(gtk, tab_control, instantiate);
2847 IIFORMAT_HAS_DEVMETHOD(gtk, tab_control, redisplay);
2848 IIFORMAT_HAS_SHARED_DEVMETHOD(gtk, tab_control, query_geometry, widget);
2850 INITIALIZE_DEVICE_IIFORMAT(gtk, label);
2851 IIFORMAT_HAS_DEVMETHOD(gtk, label, instantiate);
2854 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(cursor_font, "cursor-font");
2855 IIFORMAT_VALID_CONSOLE(gtk, cursor_font);
2857 IIFORMAT_HAS_METHOD(cursor_font, validate);
2858 IIFORMAT_HAS_METHOD(cursor_font, possible_dest_types);
2859 IIFORMAT_HAS_METHOD(cursor_font, instantiate);
2861 IIFORMAT_VALID_KEYWORD(cursor_font, Q_data, check_valid_string);
2862 IIFORMAT_VALID_KEYWORD(cursor_font, Q_foreground, check_valid_string);
2863 IIFORMAT_VALID_KEYWORD(cursor_font, Q_background, check_valid_string);
2865 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(font, "font");
2866 IIFORMAT_VALID_CONSOLE(gtk, font);
2868 IIFORMAT_HAS_METHOD(font, validate);
2869 IIFORMAT_HAS_METHOD(font, possible_dest_types);
2870 IIFORMAT_HAS_METHOD(font, instantiate);
2872 IIFORMAT_VALID_KEYWORD(font, Q_data, check_valid_string);
2873 IIFORMAT_VALID_KEYWORD(font, Q_foreground, check_valid_string);
2874 IIFORMAT_VALID_KEYWORD(font, Q_background, check_valid_string);
2877 INITIALIZE_DEVICE_IIFORMAT(gtk, xpm);
2878 IIFORMAT_HAS_DEVMETHOD(gtk, xpm, instantiate);
2882 INITIALIZE_DEVICE_IIFORMAT(gtk, xface);
2883 IIFORMAT_HAS_DEVMETHOD(gtk, xface, instantiate);
2886 INITIALIZE_DEVICE_IIFORMAT(gtk, xbm);
2887 IIFORMAT_HAS_DEVMETHOD(gtk, xbm, instantiate);
2888 IIFORMAT_VALID_CONSOLE(gtk, xbm);
2890 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(gtk_resource, "gtk-resource");
2891 IIFORMAT_VALID_CONSOLE(gtk, gtk_resource);
2893 IIFORMAT_HAS_METHOD(gtk_resource, validate);
2894 IIFORMAT_HAS_METHOD(gtk_resource, normalize);
2895 IIFORMAT_HAS_METHOD(gtk_resource, possible_dest_types);
2896 IIFORMAT_HAS_METHOD(gtk_resource, instantiate);
2898 IIFORMAT_VALID_KEYWORD(gtk_resource, Q_resource_type,
2899 check_valid_resource_symbol);
2900 IIFORMAT_VALID_KEYWORD(gtk_resource, Q_resource_id,
2901 check_valid_resource_id);
2902 IIFORMAT_VALID_KEYWORD(gtk_resource, Q_file, check_valid_string);
2904 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(autodetect, "autodetect");
2905 IIFORMAT_VALID_CONSOLE(gtk, autodetect);
2907 IIFORMAT_HAS_METHOD(autodetect, validate);
2908 IIFORMAT_HAS_METHOD(autodetect, normalize);
2909 IIFORMAT_HAS_METHOD(autodetect, possible_dest_types);
2910 IIFORMAT_HAS_METHOD(autodetect, instantiate);
2912 IIFORMAT_VALID_KEYWORD(autodetect, Q_data, check_valid_string);
2915 void vars_of_glyphs_gtk(void)
2921 DEFVAR_LISP("gtk-bitmap-file-path", &Vgtk_bitmap_file_path /*
2922 A list of the directories in which X bitmap files may be found.
2923 If nil, this is initialized from the "*bitmapFilePath" resource.
2924 This is used by the `make-image-instance' function (however, note that if
2925 the environment variable XBMLANGPATH is set, it is consulted first).
2927 Vgtk_bitmap_file_path = Qnil;
2930 void complex_vars_of_glyphs_gtk(void)
2932 #define BUILD_GLYPH_INST(variable, name) \
2933 Fadd_spec_to_specifier \
2934 (GLYPH_IMAGE (XGLYPH (variable)), \
2935 vector3 (Qxbm, Q_data, \
2936 list3 (make_int (name##_width), \
2937 make_int (name##_height), \
2938 make_ext_string (name##_bits, \
2939 sizeof (name##_bits), \
2941 Qglobal, Qgtk, Qnil)
2943 BUILD_GLYPH_INST(Vtruncation_glyph, truncator);
2944 BUILD_GLYPH_INST(Vcontinuation_glyph, continuer);
2945 BUILD_GLYPH_INST(Vsxemacs_logo, sxemacs);
2946 BUILD_GLYPH_INST(Vhscroll_glyph, hscroll);
2948 #undef BUILD_GLYPH_INST
2951 /* Ripped off from glyphs-msw.c */
2953 * The data returned by the following routine is always in left-most byte
2954 * first and left-most bit first. If it doesn't return BitmapSuccess then
2955 * its arguments won't have been touched. This routine should look as much
2956 * like the Xlib routine XReadBitmapfile as possible.
2958 #define MAX_SIZE 1024
2960 /* shared data for the image read/parse logic */
2961 static short hexTable[256]; /* conversion value */
2962 static int gtk_glyphs_initialized = FALSE; /* easier to fill in at run time */
2965 * Table index for the hex values. Initialized once, first time.
2966 * Used for translation value or delimiter significance lookup.
2968 static void initHexTable()
2971 * We build the table at run time for several reasons:
2973 * 1. portable to non-ASCII machines.
2974 * 2. still reentrant since we set the init flag after setting table.
2975 * 3. easier to extend.
2976 * 4. less prone to bugs.
3001 /* delimiters of significance are flagged w/ negative value */
3005 hexTable['\n'] = -1;
3006 hexTable['\t'] = -1;
3008 gtk_glyphs_initialized = TRUE;
3012 * read next hex value in the input stream, return -1 if EOF
3014 static int NextInt(FILE * fstream)
3021 /* loop, accumulate hex value until find delimiter */
3022 /* skip any initial delimiters found in read stream */
3030 /* trim high bits, check type and accumulate */
3032 if (isascii(ch) && isxdigit(ch)) {
3033 value = (value << 4) + hexTable[ch];
3035 } else if ((hexTable[ch]) < 0 && gotone)
3042 int read_bitmap_data(fstream, width, height, datap, x_hot, y_hot)
3043 FILE *fstream; /* handle on file */
3044 unsigned int *width, *height; /* RETURNED */
3045 unsigned char **datap; /* RETURNED */
3046 int *x_hot, *y_hot; /* RETURNED */
3048 unsigned char *data = NULL; /* working variable */
3049 char line[MAX_SIZE]; /* input line from file */
3050 int size; /* number of bytes of data */
3051 char name_and_type[MAX_SIZE]; /* an input line */
3052 char *type; /* for parsing */
3053 int value; /* from an input line */
3054 int version10p; /* boolean, old format */
3055 int padding; /* to handle alignment */
3056 int bytes_per_line; /* per scanline of data */
3057 unsigned int ww = 0; /* width */
3058 unsigned int hh = 0; /* height */
3059 int hx = -1; /* x hotspot */
3060 int hy = -1; /* y hotspot */
3062 #define Xmalloc(size) malloc(size)
3064 /* first time initialization */
3065 if (gtk_glyphs_initialized == FALSE)
3068 /* error cleanup and return macro */
3069 #define RETURN(code) { if (data) free (data); return code; }
3071 while (fgets(line, MAX_SIZE, fstream)) {
3072 if (strlen(line) == MAX_SIZE - 1) {
3073 RETURN(BitmapFileInvalid);
3075 if (sscanf(line, "#define %s %d", name_and_type, &value) == 2) {
3076 if (!(type = strrchr(name_and_type, '_')))
3077 type = name_and_type;
3081 if (!strcmp("width", type))
3082 ww = (unsigned int)value;
3083 if (!strcmp("height", type))
3084 hh = (unsigned int)value;
3085 if (!strcmp("hot", type)) {
3086 if (type-- == name_and_type
3087 || type-- == name_and_type)
3089 if (!strcmp("x_hot", type))
3091 if (!strcmp("y_hot", type))
3097 if (sscanf(line, "static short %s = {", name_and_type) == 1)
3100 (line, "static unsigned char %s = {",
3101 name_and_type) == 1)
3103 else if (sscanf(line, "static char %s = {", name_and_type) == 1)
3108 if (!(type = strrchr(name_and_type, '_')))
3109 type = name_and_type;
3113 if (strcmp("bits[]", type))
3117 RETURN(BitmapFileInvalid);
3119 if ((ww % 16) && ((ww % 16) < 9) && version10p)
3124 bytes_per_line = (ww + 7) / 8 + padding;
3126 size = bytes_per_line * hh;
3127 data = (unsigned char *)Xmalloc((unsigned int)size);
3129 RETURN(BitmapNoMemory);
3135 for (bytes = 0, ptr = data; bytes < size; (bytes += 2)) {
3136 if ((value = NextInt(fstream)) < 0)
3137 RETURN(BitmapFileInvalid);
3139 if (!padding || ((bytes + 2) % bytes_per_line))
3140 *(ptr++) = value >> 8;
3146 for (bytes = 0, ptr = data; bytes < size;
3148 if ((value = NextInt(fstream)) < 0)
3149 RETURN(BitmapFileInvalid);
3157 RETURN(BitmapFileInvalid);
3169 RETURN(BitmapSuccess);
3172 int read_bitmap_data_from_file(CONST char *filename, unsigned int *width,
3173 unsigned int *height, unsigned char **datap,
3174 int *x_hot, int *y_hot)
3179 if ((fstream = fopen(filename, "r")) == NULL) {
3180 return BitmapOpenFailed;
3182 rval = read_bitmap_data(fstream, width, height, datap, x_hot, y_hot);
3187 /* X specific crap */
3188 #include <gdk/gdkx.h>
3189 /* #### Should remove all this X specific stuff when GTK/GDK matures a
3190 bit more and provides an abstraction for it. */
3192 gtk_colorize_image_instance(Lisp_Object image_instance,
3193 Lisp_Object foreground, Lisp_Object background)
3195 struct Lisp_Image_Instance *p;
3197 p = XIMAGE_INSTANCE(image_instance);
3199 switch (IMAGE_INSTANCE_TYPE(p)) {
3200 case IMAGE_MONO_PIXMAP:
3201 IMAGE_INSTANCE_TYPE(p) = IMAGE_COLOR_PIXMAP;
3202 /* Make sure there aren't two pointers to the same mask, causing
3203 it to get freed twice. */
3204 IMAGE_INSTANCE_GTK_MASK(p) = 0;
3213 GET_GTK_WIDGET_WINDOW(DEVICE_GTK_APP_SHELL
3214 (XDEVICE(IMAGE_INSTANCE_DEVICE(p))));
3215 GdkPixmap *new_pxmp = gdk_pixmap_new(draw,
3216 IMAGE_INSTANCE_PIXMAP_WIDTH
3218 IMAGE_INSTANCE_PIXMAP_HEIGHT
3220 DEVICE_GTK_DEPTH(XDEVICE
3221 (IMAGE_INSTANCE_DEVICE
3227 *COLOR_INSTANCE_GTK_COLOR(XCOLOR_INSTANCE(foreground));
3229 *COLOR_INSTANCE_GTK_COLOR(XCOLOR_INSTANCE(background));
3230 gc = gdk_gc_new_with_values(new_pxmp, &gcv,
3234 XCopyPlane(GDK_WINDOW_XDISPLAY(draw),
3235 GDK_WINDOW_XWINDOW(IMAGE_INSTANCE_GTK_PIXMAP(p)),
3236 GDK_WINDOW_XWINDOW(new_pxmp),
3237 GDK_GC_XGC(gc), 0, 0,
3238 IMAGE_INSTANCE_PIXMAP_WIDTH(p),
3239 IMAGE_INSTANCE_PIXMAP_HEIGHT(p), 0, 0, 1);
3242 IMAGE_INSTANCE_GTK_PIXMAP(p) = new_pxmp;
3243 IMAGE_INSTANCE_PIXMAP_DEPTH(p) =
3244 DEVICE_GTK_DEPTH(XDEVICE(IMAGE_INSTANCE_DEVICE(p)));
3245 IMAGE_INSTANCE_PIXMAP_FG(p) = foreground;
3246 IMAGE_INSTANCE_PIXMAP_BG(p) = background;