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 Copyright (C) 1999, 2000, 2002 Andy Piper
9 This file is part of SXEmacs
11 SXEmacs is free software: you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
16 SXEmacs is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>. */
25 /* Synched up with: Not in FSF. */
27 /* 7-8-00 This file is more or less Mule-ized in my Mule workspace. */
29 /* Original author: Jamie Zawinski for 19.8
30 font-truename stuff added by Jamie Zawinski for 19.10
31 subwindow support added by Chuck Thompson
32 additional XPM support added by Chuck Thompson
33 initial X-Face support added by Stig
34 rewritten/restructured by Ben Wing for 19.12/19.13
35 GIF/JPEG support added by Ben Wing for 19.14
36 PNG support added by Bill Perry for 19.14
37 Improved GIF/JPEG support added by Bill Perry for 19.14
38 Cleanup/simplification of error handling by Ben Wing for 19.14
39 Pointer/icon overhaul, more restructuring by Ben Wing for 19.14
40 GIF support changed to external GIFlib 3.1 by Jareth Hein for 21.0
41 Many changes for color work and optimizations by Jareth Hein for 21.0
42 Switch of GIF/JPEG/PNG to new EImage intermediate code by Jareth Hein for 21.0
43 TIFF code by Jareth Hein for 21.0
44 GIF/JPEG/PNG/TIFF code moved to new glyph-eimage.c by Andy Piper for 21.0
45 Subwindow and Widget support by Andy Piper for 21.2
48 Support the GrayScale, StaticColor and StaticGray visual classes.
49 Convert images.el to C and stick it in here?
55 #include "console-x.h"
57 #include "objects-x.h"
64 #include "ui/window.h"
66 #include "ui/insdel.h"
71 #include "ui/imgproc.h"
78 #include "mule/file-coding.h"
81 #ifdef LWLIB_WIDGETS_MOTIF
84 #include <X11/IntrinsicP.h>
86 /* what's this? what's wrong with uint32_t? */
89 # define FOUR_BYTE_TYPE unsigned int
90 #elif SXE_LONGBITS == 32
91 # define FOUR_BYTE_TYPE unsigned long
92 #elif SXE_SHORTBITS == 32
93 # define FOUR_BYTE_TYPE unsigned short
95 #error What kind of strange-ass system are we running on?
99 #define LISP_DEVICE_TO_X_SCREEN(dev) XDefaultScreenOfDisplay (DEVICE_X_DISPLAY (XDEVICE (dev)))
101 DECLARE_IMAGE_INSTANTIATOR_FORMAT(nothing);
102 DECLARE_IMAGE_INSTANTIATOR_FORMAT(string);
103 DECLARE_IMAGE_INSTANTIATOR_FORMAT(formatted_string);
104 DECLARE_IMAGE_INSTANTIATOR_FORMAT(inherit);
106 DECLARE_IMAGE_INSTANTIATOR_FORMAT(jpeg);
109 DECLARE_IMAGE_INSTANTIATOR_FORMAT(tiff);
111 #if defined WITH_PNG && defined HAVE_PNG
112 DECLARE_IMAGE_INSTANTIATOR_FORMAT(png);
115 DECLARE_IMAGE_INSTANTIATOR_FORMAT(gif);
118 DEFINE_DEVICE_IIFORMAT(x, xpm);
120 DEFINE_DEVICE_IIFORMAT(x, xbm);
121 DEFINE_DEVICE_IIFORMAT(x, subwindow);
123 DEFINE_DEVICE_IIFORMAT(x, xface);
126 DECLARE_IMAGE_INSTANTIATOR_FORMAT(rawrgb);
127 DECLARE_IMAGE_INSTANTIATOR_FORMAT(rawrgba);
130 DEFINE_IMAGE_INSTANTIATOR_FORMAT(cursor_font);
131 Lisp_Object Qcursor_font;
133 DEFINE_IMAGE_INSTANTIATOR_FORMAT(font);
135 DEFINE_IMAGE_INSTANTIATOR_FORMAT(autodetect);
138 DECLARE_IMAGE_INSTANTIATOR_FORMAT(layout);
139 DEFINE_DEVICE_IIFORMAT(x, widget);
140 DEFINE_DEVICE_IIFORMAT(x, native_layout);
141 DEFINE_DEVICE_IIFORMAT(x, button);
142 DEFINE_DEVICE_IIFORMAT(x, progress_gauge);
143 DEFINE_DEVICE_IIFORMAT(x, edit_field);
144 #if defined (LWLIB_WIDGETS_MOTIF) && XmVERSION > 1
145 DEFINE_DEVICE_IIFORMAT(x, combo_box);
147 DEFINE_DEVICE_IIFORMAT(x, tab_control);
148 DEFINE_DEVICE_IIFORMAT(x, label);
151 static void cursor_font_instantiate(Lisp_Object image_instance,
152 Lisp_Object instantiator,
153 Lisp_Object pointer_fg,
154 Lisp_Object pointer_bg,
155 int dest_mask, Lisp_Object domain);
159 update_widget_face(widget_value * wv,
160 Lisp_Image_Instance * ii, Lisp_Object domain);
162 update_tab_widget_face(widget_value * wv,
163 Lisp_Image_Instance * ii, Lisp_Object domain);
165 void emacs_Xt_handle_widget_losing_focus(struct frame *f, Widget losing_widget);
166 void enqueue_focus_event(Widget wants_it, Lisp_Object frame, int in_p);
168 #include "ui/bitmaps.h"
170 /************************************************************************/
171 /* image instance methods */
172 /************************************************************************/
174 /************************************************************************/
175 /* convert from a series of RGB triples to an XImage formated for the */
177 /************************************************************************/
178 static XImage *convert_EImage_to_XImage(Lisp_Object device, int width,
179 int height, unsigned char *pic,
180 unsigned long **pixtbl, int *npixels)
186 int depth, bitmap_pad, bits_per_pixel, byte_cnt, i, j;
188 unsigned char *data, *ip, *dp;
189 quant_table *qtable = 0;
192 /* kicked in favour of C99's uint32_t */
199 dpy = DEVICE_X_DISPLAY(XDEVICE(device));
200 cmap = DEVICE_X_COLORMAP(XDEVICE(device));
201 vis = DEVICE_X_VISUAL(XDEVICE(device));
202 depth = DEVICE_X_DEPTH(XDEVICE(device));
204 if (vis->class == GrayScale || vis->class == StaticColor ||
205 vis->class == StaticGray) {
206 /* #### Implement me!!! */
210 if (vis->class == PseudoColor) {
211 /* Quantize the image and get a histogram while we're at it.
212 Do this first to save memory */
213 qtable = build_EImage_quantable(pic, width, height, 256);
218 bitmap_pad = ((depth > 16) ? 32 : (depth > 8) ? 16 : 8);
220 outimg = XCreateImage(dpy, vis,
221 depth, ZPixmap, 0, 0, width, height,
226 bits_per_pixel = outimg->bits_per_pixel;
227 byte_cnt = bits_per_pixel >> 3;
229 data = xmalloc_atomic(outimg->bytes_per_line * height);
231 XDestroyImage(outimg);
234 outimg->data = (char *)data;
236 if (vis->class == PseudoColor) {
237 unsigned long pixarray[256];
240 /* use our quantize table to allocate the colors */
242 *pixtbl = xnew_atomic_array(unsigned long, pixcount);
245 /* #### should implement a sort by popularity to
246 * assure proper allocation */
248 for (i = 0; i < qtable->num_active_colors; i++) {
252 color.red = qtable->rm[i] ? qtable->rm[i] << 8 : 0;
253 color.green = qtable->gm[i] ? qtable->gm[i] << 8 : 0;
254 color.blue = qtable->bm[i] ? qtable->bm[i] << 8 : 0;
255 color.flags = DoRed | DoGreen | DoBlue;
256 res = allocate_nearest_color(dpy, 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->bytes_per_line);
269 for (j = 0; j < width; j++) {
274 pixarray[QUANT_GET_COLOR
275 (qtable, rd, gr, bl)];
276 #ifdef WORDS_BIGENDIAN
277 if (outimg->byte_order == MSBFirst)
278 for (q = 4 - byte_cnt; q < 4; q++)
281 for (q = 3; q >= 4 - byte_cnt; q--)
284 if (outimg->byte_order == MSBFirst)
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->bytes_per_line);
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 <<
349 #ifdef WORDS_BIGENDIAN
350 if (outimg->byte_order == MSBFirst)
351 for (q = 4 - byte_cnt; q < 4; q++)
354 for (q = 3; q >= 4 - byte_cnt; q--)
357 if (outimg->byte_order == MSBFirst)
358 for (q = byte_cnt - 1; q >= 0; q--)
361 for (q = 0; q < byte_cnt; q++)
371 x_print_image_instance(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 sprintf(buf, " (0x%lx",
381 (unsigned long)IMAGE_INSTANCE_X_PIXMAP(p));
382 write_c_string(buf, printcharfun);
383 if (IMAGE_INSTANCE_X_MASK(p)) {
384 sprintf(buf, "/0x%lx",
385 (unsigned long)IMAGE_INSTANCE_X_MASK(p));
386 write_c_string(buf, printcharfun);
388 write_c_string(")", printcharfun);
394 case IMAGE_SUBWINDOW:
402 extern int debug_widget_instances;
405 static void x_finalize_image_instance(Lisp_Image_Instance * p)
410 if (DEVICE_LIVE_P(XDEVICE(IMAGE_INSTANCE_DEVICE(p)))) {
411 Display *dpy = DEVICE_X_DISPLAY
412 (XDEVICE(IMAGE_INSTANCE_DEVICE(p)));
415 else if (IMAGE_INSTANCE_TYPE(p) == IMAGE_WIDGET) {
416 if (IMAGE_INSTANCE_SUBWINDOW_ID(p)) {
418 debug_widget_instances--;
419 stderr_out("widget destroyed, %d left\n",
420 debug_widget_instances);
422 lw_destroy_widget(IMAGE_INSTANCE_X_WIDGET_ID
424 lw_destroy_widget(IMAGE_INSTANCE_X_CLIPWIDGET
427 /* We can release the callbacks again. */
428 ungcpro_popup_callbacks
429 (IMAGE_INSTANCE_X_WIDGET_LWID(p));
431 IMAGE_INSTANCE_X_WIDGET_ID(p) = 0;
432 IMAGE_INSTANCE_X_CLIPWIDGET(p) = 0;
436 else if (IMAGE_INSTANCE_TYPE(p) == IMAGE_SUBWINDOW) {
437 if (IMAGE_INSTANCE_SUBWINDOW_ID(p))
439 IMAGE_INSTANCE_X_SUBWINDOW_ID
441 IMAGE_INSTANCE_SUBWINDOW_ID(p) = 0;
444 if (IMAGE_INSTANCE_PIXMAP_TIMEOUT(p))
445 disable_glyph_animated_timeout
446 (IMAGE_INSTANCE_PIXMAP_TIMEOUT(p));
448 if (IMAGE_INSTANCE_X_MASK(p) &&
449 IMAGE_INSTANCE_X_MASK(p) !=
450 IMAGE_INSTANCE_X_PIXMAP(p))
451 XFreePixmap(dpy, IMAGE_INSTANCE_X_MASK(p));
452 IMAGE_INSTANCE_PIXMAP_MASK(p) = 0;
454 if (IMAGE_INSTANCE_X_PIXMAP_SLICES(p)) {
456 i < IMAGE_INSTANCE_PIXMAP_MAXSLICE(p); i++)
457 if (IMAGE_INSTANCE_X_PIXMAP_SLICE(p, i)) {
459 IMAGE_INSTANCE_X_PIXMAP_SLICE
461 IMAGE_INSTANCE_X_PIXMAP_SLICE(p,
465 xfree(IMAGE_INSTANCE_X_PIXMAP_SLICES(p));
466 IMAGE_INSTANCE_X_PIXMAP_SLICES(p) = 0;
469 if (IMAGE_INSTANCE_X_CURSOR(p)) {
470 XFreeCursor(dpy, IMAGE_INSTANCE_X_CURSOR(p));
471 IMAGE_INSTANCE_X_CURSOR(p) = 0;
474 if (IMAGE_INSTANCE_X_NPIXELS(p) != 0) {
476 IMAGE_INSTANCE_X_COLORMAP(p),
477 IMAGE_INSTANCE_X_PIXELS(p),
478 IMAGE_INSTANCE_X_NPIXELS(p), 0);
479 IMAGE_INSTANCE_X_NPIXELS(p) = 0;
483 /* You can sometimes have pixels without a live device. I forget
484 why, but that's why we free them here if we have a pixmap type
485 image instance. It probably means that we might also get a memory
486 leak with widgets. */
487 if (IMAGE_INSTANCE_TYPE(p) != IMAGE_WIDGET
488 && IMAGE_INSTANCE_TYPE(p) != IMAGE_SUBWINDOW
489 && IMAGE_INSTANCE_X_PIXELS(p)) {
490 xfree(IMAGE_INSTANCE_X_PIXELS(p));
491 IMAGE_INSTANCE_X_PIXELS(p) = 0;
499 x_image_instance_equal(Lisp_Image_Instance * p1,
500 Lisp_Image_Instance * p2, int depth)
502 switch (IMAGE_INSTANCE_TYPE(p1)) {
503 case IMAGE_MONO_PIXMAP:
504 case IMAGE_COLOR_PIXMAP:
506 if (IMAGE_INSTANCE_X_COLORMAP(p1) !=
507 IMAGE_INSTANCE_X_COLORMAP(p2)
508 || IMAGE_INSTANCE_X_NPIXELS(p1) !=
509 IMAGE_INSTANCE_X_NPIXELS(p2))
516 case IMAGE_SUBWINDOW:
525 static unsigned long x_image_instance_hash(Lisp_Image_Instance * p, int depth)
527 switch (IMAGE_INSTANCE_TYPE(p)) {
528 case IMAGE_MONO_PIXMAP:
529 case IMAGE_COLOR_PIXMAP:
531 return IMAGE_INSTANCE_X_NPIXELS(p);
536 case IMAGE_SUBWINDOW:
543 /* Set all the slots in an image instance structure to reasonable
544 default values. This is used somewhere within an instantiate
545 method. It is assumed that the device slot within the image
546 instance is already set -- this is the case when instantiate
547 methods are called. */
550 x_initialize_pixmap_image_instance(Lisp_Image_Instance * ii,
551 int slices, enum image_instance_type type)
553 ii->data = xnew_and_zero(struct x_image_instance_data);
554 IMAGE_INSTANCE_PIXMAP_MAXSLICE(ii) = slices;
555 IMAGE_INSTANCE_X_PIXMAP_SLICES(ii) =
556 xnew_array_and_zero(Pixmap, slices);
557 IMAGE_INSTANCE_TYPE(ii) = type;
558 IMAGE_INSTANCE_PIXMAP_FILENAME(ii) = Qnil;
559 IMAGE_INSTANCE_PIXMAP_MASK_FILENAME(ii) = Qnil;
560 IMAGE_INSTANCE_PIXMAP_HOTSPOT_X(ii) = Qnil;
561 IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(ii) = Qnil;
562 IMAGE_INSTANCE_PIXMAP_FG(ii) = Qnil;
563 IMAGE_INSTANCE_PIXMAP_BG(ii) = Qnil;
566 /************************************************************************/
567 /* pixmap file functions */
568 /************************************************************************/
570 /* Where bitmaps are; initialized from resource database */
571 Lisp_Object Vx_bitmap_file_path;
574 #define BITMAPDIR "/usr/include/X11/bitmaps"
577 #define USE_XBMLANGPATH
579 /* Given a pixmap filename, look through all of the "standard" places
580 where the file might be located. Return a full pathname if found;
581 otherwise, return Qnil. */
583 static Lisp_Object x_locate_pixmap_file(Lisp_Object name)
585 /* This function can GC if IN_REDISPLAY is false */
588 /* Check non-absolute pathnames with a directory component relative to
589 the search path; that's the way Xt does it. */
590 /* #### Unix-specific */
591 if (XSTRING_BYTE(name, 0) == '/' ||
592 (XSTRING_BYTE(name, 0) == '.' &&
593 (XSTRING_BYTE(name, 1) == '/' ||
594 (XSTRING_BYTE(name, 1) == '.' &&
595 (XSTRING_BYTE(name, 2) == '/'))))) {
596 if (!NILP(Ffile_readable_p(name)))
597 return Fexpand_file_name(name, Qnil);
602 if (NILP(Vdefault_x_device))
603 /* This may occur during initialization. */
606 /* We only check the bitmapFilePath resource on the original X device. */
607 display = DEVICE_X_DISPLAY(XDEVICE(Vdefault_x_device));
609 #ifdef USE_XBMLANGPATH
611 char *path = egetenv("XBMLANGPATH");
612 SubstitutionRec subs[1];
614 subs[0].substitution = (char *)XSTRING_DATA(name);
615 /* #### Motif uses a big hairy default if $XBMLANGPATH isn't set.
616 We don't. If you want it used, set it. */
618 (path = XtResolvePathname(display, "bitmaps", 0, 0, path,
619 subs, XtNumber(subs), 0))) {
620 name = build_string(path);
627 if (NILP(Vx_bitmap_file_path)) {
630 if (XrmGetResource(XtDatabase(display),
631 "bitmapFilePath", "BitmapFilePath", &type,
633 && !strcmp(type, "String"))
634 Vx_bitmap_file_path =
635 decode_env_path(0, (char *)value.addr);
636 Vx_bitmap_file_path =
637 nconc2(Vx_bitmap_file_path, (decode_path(BITMAPDIR)));
642 if (locate_file(Vx_bitmap_file_path, name, Qnil, &found, R_OK) <
644 Lisp_Object temp = list1(Vdata_directory);
648 locate_file(temp, name, Qnil, &found, R_OK);
656 static Lisp_Object locate_pixmap_file(Lisp_Object name)
658 return x_locate_pixmap_file(name);
663 write_lisp_string_to_temp_file(Lisp_Object string, char *filename_out)
665 Lisp_Object instream, outstream;
666 Lstream *istr, *ostr;
667 char tempbuf[1024]; /* some random amount */
670 static Extbyte_dynarr *conversion_out_dynarr;
671 Bytecount bstart, bend;
672 struct gcpro gcpro1, gcpro2;
674 Lisp_Object conv_out_stream;
679 /* This function can GC */
680 if (!conversion_out_dynarr)
681 conversion_out_dynarr = Dynarr_new(Extbyte);
683 Dynarr_reset(conversion_out_dynarr);
685 /* Create the temporary file ... */
686 sprintf(filename_out, "/tmp/emacs%d.XXXXXX", (int)getpid());
687 mktemp(filename_out);
688 tmpfil = fopen(filename_out, "w");
691 int old_errno = errno;
693 unlink(filename_out);
696 report_file_error("Creating temp file",
697 list1(build_string(filename_out)));
700 CHECK_STRING(string);
701 get_string_range_byte(string, Qnil, Qnil, &bstart, &bend,
702 GB_HISTORICAL_STRING_BEHAVIOR);
703 instream = make_lisp_string_input_stream(string, bstart, bend);
704 istr = XLSTREAM(instream);
705 /* setup the out stream */
707 make_dynarr_output_stream((unsigned_char_dynarr *)
708 conversion_out_dynarr);
709 ostr = XLSTREAM(outstream);
711 /* setup the conversion stream */
713 make_encoding_output_stream(ostr, Fget_coding_system(Qbinary));
714 costr = XLSTREAM(conv_out_stream);
715 GCPRO3(instream, outstream, conv_out_stream);
717 GCPRO2(instream, outstream);
720 /* Get the data while doing the conversion */
722 Lstream_data_count size_in_bytes =
723 Lstream_read(istr, tempbuf, sizeof(tempbuf));
726 /* It does seem the flushes are necessary... */
728 Lstream_write(costr, tempbuf, size_in_bytes);
729 Lstream_flush(costr);
731 Lstream_write(ostr, tempbuf, size_in_bytes);
735 ((unsigned char *)Dynarr_atp(conversion_out_dynarr, 0),
736 Dynarr_length(conversion_out_dynarr), 1, tmpfil) != 1) {
740 /* reset the dynarr */
741 Lstream_rewind(ostr);
744 if (fclose(tmpfil) != 0)
748 Lstream_close(costr);
753 Lstream_delete(istr);
754 Lstream_delete(ostr);
756 Lstream_delete(costr);
760 report_file_error("Writing temp file",
761 list1(build_string(filename_out)));
765 /************************************************************************/
766 /* cursor functions */
767 /************************************************************************/
769 /* Check that this server supports cursors of size WIDTH * HEIGHT. If
770 not, signal an error. INSTANTIATOR is only used in the error
774 check_pointer_sizes(Screen * xs, unsigned int width, unsigned int height,
775 Lisp_Object instantiator)
777 unsigned int best_width, best_height;
778 if (!XQueryBestCursor(DisplayOfScreen(xs), RootWindowOfScreen(xs),
779 width, height, &best_width, &best_height))
780 /* this means that an X error of some sort occurred (we trap
781 these so they're not fatal). */
782 signal_simple_error("XQueryBestCursor() failed?", instantiator);
784 if (width > best_width || height > best_height)
785 error_with_frob(instantiator,
786 "pointer too large (%dx%d): "
787 "server requires %dx%d or smaller",
788 width, height, best_width, best_height);
792 generate_cursor_fg_bg(Lisp_Object device, Lisp_Object * foreground,
793 Lisp_Object * background, XColor * xfg, XColor * xbg)
795 if (!NILP(*foreground) && !COLOR_INSTANCEP(*foreground))
797 Fmake_color_instance(*foreground, device,
798 encode_error_behavior_flag(ERROR_ME));
799 if (COLOR_INSTANCEP(*foreground))
800 *xfg = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(*foreground));
803 xfg->red = xfg->green = xfg->blue = 0;
806 if (!NILP(*background) && !COLOR_INSTANCEP(*background))
808 Fmake_color_instance(*background, device,
809 encode_error_behavior_flag(ERROR_ME));
810 if (COLOR_INSTANCEP(*background))
811 *xbg = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(*background));
814 xbg->red = xbg->green = xbg->blue = USHRT_MAX;
819 maybe_recolor_cursor(Lisp_Object image_instance, Lisp_Object foreground,
820 Lisp_Object background)
822 Lisp_Object device = XIMAGE_INSTANCE_DEVICE(image_instance);
825 generate_cursor_fg_bg(device, &foreground, &background, &xfg, &xbg);
826 if (!NILP(foreground) || !NILP(background)) {
827 XRecolorCursor(DEVICE_X_DISPLAY(XDEVICE(device)),
828 XIMAGE_INSTANCE_X_CURSOR(image_instance),
830 XIMAGE_INSTANCE_PIXMAP_FG(image_instance) = foreground;
831 XIMAGE_INSTANCE_PIXMAP_BG(image_instance) = background;
835 /************************************************************************/
836 /* color pixmap functions */
837 /************************************************************************/
839 /* Initialize an image instance from an XImage.
841 DEST_MASK specifies the mask of allowed image types.
843 PIXELS and NPIXELS specify an array of pixels that are used in
844 the image. These need to be kept around for the duration of the
845 image. When the image instance is freed, XFreeColors() will
846 automatically be called on all the pixels specified here; thus,
847 you should have allocated the pixels yourself using XAllocColor()
848 or the like. The array passed in is used directly without
849 being copied, so it should be heap data created with xmalloc().
850 It will be freed using xfree() when the image instance is
853 If this fails, signal an error. INSTANTIATOR is only used
854 in the error message.
856 #### This should be able to handle conversion into `pointer'.
857 Use the same code as for `xpm'. */
860 init_image_instance_from_x_image(Lisp_Image_Instance * ii,
864 unsigned long *pixels,
866 int slices, Lisp_Object instantiator)
868 Lisp_Object device = IMAGE_INSTANCE_DEVICE(ii);
874 if (!DEVICE_X_P(XDEVICE(device)))
875 signal_simple_error("Not an X device", device);
877 dpy = DEVICE_X_DISPLAY(XDEVICE(device));
878 d = XtWindow(DEVICE_XT_APP_SHELL(XDEVICE(device)));
880 if (!(dest_mask & IMAGE_COLOR_PIXMAP_MASK))
881 incompatible_image_types(instantiator, dest_mask,
882 IMAGE_COLOR_PIXMAP_MASK);
884 pixmap = XCreatePixmap(dpy, d, ximage->width,
885 ximage->height, ximage->depth);
887 signal_simple_error("Unable to create pixmap", instantiator);
889 gc = XCreateGC(dpy, pixmap, 0, NULL);
891 XFreePixmap(dpy, pixmap);
892 signal_simple_error("Unable to create GC", instantiator);
895 XPutImage(dpy, pixmap, gc, ximage, 0, 0, 0, 0,
896 ximage->width, ximage->height);
900 x_initialize_pixmap_image_instance(ii, slices, IMAGE_COLOR_PIXMAP);
902 IMAGE_INSTANCE_PIXMAP_FILENAME(ii) =
903 find_keyword_in_vector(instantiator, Q_file);
905 /* Fixup a set of pixmaps. */
906 IMAGE_INSTANCE_X_PIXMAP(ii) = pixmap;
908 IMAGE_INSTANCE_PIXMAP_MASK(ii) = 0;
909 IMAGE_INSTANCE_PIXMAP_WIDTH(ii) = ximage->width;
910 IMAGE_INSTANCE_PIXMAP_HEIGHT(ii) = ximage->height;
911 IMAGE_INSTANCE_PIXMAP_DEPTH(ii) = ximage->depth;
912 IMAGE_INSTANCE_X_COLORMAP(ii) = cmap;
913 IMAGE_INSTANCE_X_PIXELS(ii) = pixels;
914 IMAGE_INSTANCE_X_NPIXELS(ii) = npixels;
918 image_instance_add_x_image(Lisp_Image_Instance * ii,
919 XImage * ximage, int slice, Lisp_Object instantiator)
921 Lisp_Object device = IMAGE_INSTANCE_DEVICE(ii);
927 dpy = DEVICE_X_DISPLAY(XDEVICE(device));
928 d = XtWindow(DEVICE_XT_APP_SHELL(XDEVICE(device)));
930 pixmap = XCreatePixmap(dpy, d, ximage->width,
931 ximage->height, ximage->depth);
933 signal_simple_error("Unable to create pixmap", instantiator);
935 gc = XCreateGC(dpy, pixmap, 0, NULL);
937 XFreePixmap(dpy, pixmap);
938 signal_simple_error("Unable to create GC", instantiator);
941 XPutImage(dpy, pixmap, gc, ximage, 0, 0, 0, 0,
942 ximage->width, ximage->height);
946 IMAGE_INSTANCE_X_PIXMAP_SLICE(ii, slice) = pixmap;
950 x_init_image_instance_from_eimage(Lisp_Image_Instance * ii,
951 int width, int height,
953 unsigned char *eimage,
955 Lisp_Object instantiator, Lisp_Object domain)
957 Lisp_Object device = IMAGE_INSTANCE_DEVICE(ii);
958 Colormap cmap = DEVICE_X_COLORMAP(XDEVICE(device));
959 unsigned long *pixtbl = NULL;
962 XImage *volatile ximage;
964 for (slice = 0; slice < slices; slice++) {
965 ximage = convert_EImage_to_XImage(device, width, height,
967 (width * height * 3 * slice),
972 signal_image_error("EImage to XImage conversion failed",
976 /* Now create the pixmap and set up the image instance */
978 init_image_instance_from_x_image(ii, ximage, dest_mask,
979 cmap, pixtbl, npixels,
980 slices, instantiator);
982 image_instance_add_x_image(ii, ximage, slice,
990 XDestroyImage(ximage);
996 int read_bitmap_data_from_file(const char *filename, unsigned int *width,
997 unsigned int *height, unsigned char **datap,
998 int *x_hot, int *y_hot)
1000 return XmuReadBitmapDataFromFile(filename, width, height,
1001 datap, x_hot, y_hot);
1004 /* Given inline data for a mono pixmap, create and return the
1005 corresponding X object. */
1008 pixmap_from_xbm_inline(Lisp_Object device, int width, int height,
1009 /* Note that data is in ext-format! */
1012 return XCreatePixmapFromBitmapData
1013 (DEVICE_X_DISPLAY(XDEVICE(device)),
1014 XtWindow(DEVICE_XT_APP_SHELL(XDEVICE(device))),
1015 bits, width, height, 1, 0, 1);
1018 /* Given inline data for a mono pixmap, initialize the given
1019 image instance accordingly. */
1022 init_image_instance_from_xbm_inline(Lisp_Image_Instance * ii,
1023 int width, int height,
1024 /* Note that data is in ext-format! */
1026 Lisp_Object instantiator,
1027 Lisp_Object pointer_fg,
1028 Lisp_Object pointer_bg,
1030 Pixmap mask, Lisp_Object mask_filename)
1032 Lisp_Object device = IMAGE_INSTANCE_DEVICE(ii);
1033 Lisp_Object foreground =
1034 find_keyword_in_vector(instantiator, Q_foreground);
1035 Lisp_Object background =
1036 find_keyword_in_vector(instantiator, Q_background);
1040 enum image_instance_type type;
1042 if (!DEVICE_X_P(XDEVICE(device)))
1043 signal_simple_error("Not an X device", device);
1045 dpy = DEVICE_X_DISPLAY(XDEVICE(device));
1046 draw = XtWindow(DEVICE_XT_APP_SHELL(XDEVICE(device)));
1047 scr = DefaultScreenOfDisplay(dpy);
1049 if ((dest_mask & IMAGE_MONO_PIXMAP_MASK) &&
1050 (dest_mask & IMAGE_COLOR_PIXMAP_MASK)) {
1051 if (!NILP(foreground) || !NILP(background))
1052 type = IMAGE_COLOR_PIXMAP;
1054 type = IMAGE_MONO_PIXMAP;
1055 } else if (dest_mask & IMAGE_MONO_PIXMAP_MASK)
1056 type = IMAGE_MONO_PIXMAP;
1057 else if (dest_mask & IMAGE_COLOR_PIXMAP_MASK)
1058 type = IMAGE_COLOR_PIXMAP;
1059 else if (dest_mask & IMAGE_POINTER_MASK)
1060 type = IMAGE_POINTER;
1062 incompatible_image_types(instantiator, dest_mask,
1063 IMAGE_MONO_PIXMAP_MASK |
1064 IMAGE_COLOR_PIXMAP_MASK |
1065 IMAGE_POINTER_MASK);
1067 x_initialize_pixmap_image_instance(ii, 1, type);
1068 IMAGE_INSTANCE_PIXMAP_WIDTH(ii) = width;
1069 IMAGE_INSTANCE_PIXMAP_HEIGHT(ii) = height;
1070 IMAGE_INSTANCE_PIXMAP_FILENAME(ii) =
1071 find_keyword_in_vector(instantiator, Q_file);
1074 case IMAGE_MONO_PIXMAP: {
1075 IMAGE_INSTANCE_X_PIXMAP(ii) =
1076 pixmap_from_xbm_inline(device, width, height,
1081 case IMAGE_COLOR_PIXMAP: {
1082 Dimension d = DEVICE_X_DEPTH(XDEVICE(device));
1083 unsigned long fg = BlackPixelOfScreen(scr);
1084 unsigned long bg = WhitePixelOfScreen(scr);
1086 if (!NILP(foreground) && !COLOR_INSTANCEP(foreground))
1088 Fmake_color_instance(foreground, device,
1089 encode_error_behavior_flag
1092 if (COLOR_INSTANCEP(foreground))
1093 fg = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE
1094 (foreground)).pixel;
1096 if (!NILP(background) && !COLOR_INSTANCEP(background))
1098 Fmake_color_instance(background, device,
1099 encode_error_behavior_flag
1102 if (COLOR_INSTANCEP(background))
1103 bg = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE
1104 (background)).pixel;
1106 /* We used to duplicate the pixels using XAllocColor(), to protect
1107 against their getting freed. Just as easy to just store the
1108 color instances here and GC-protect them, so this doesn't
1110 IMAGE_INSTANCE_PIXMAP_FG(ii) = foreground;
1111 IMAGE_INSTANCE_PIXMAP_BG(ii) = background;
1112 IMAGE_INSTANCE_X_PIXMAP(ii) =
1113 XCreatePixmapFromBitmapData(dpy, draw,
1114 (char *)bits, width,
1116 IMAGE_INSTANCE_PIXMAP_DEPTH(ii) = d;
1120 case IMAGE_POINTER: {
1121 XColor fg_color, bg_color;
1124 check_pointer_sizes(scr, width, height, instantiator);
1127 XCreatePixmapFromBitmapData(dpy, draw,
1128 (char *)bits, width,
1131 if (NILP(foreground))
1132 foreground = pointer_fg;
1133 if (NILP(background))
1134 background = pointer_bg;
1135 generate_cursor_fg_bg(device, &foreground, &background,
1136 &fg_color, &bg_color);
1138 IMAGE_INSTANCE_PIXMAP_FG(ii) = foreground;
1139 IMAGE_INSTANCE_PIXMAP_BG(ii) = background;
1140 IMAGE_INSTANCE_PIXMAP_HOTSPOT_X(ii) =
1141 find_keyword_in_vector(instantiator, Q_hotspot_x);
1142 IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(ii) =
1143 find_keyword_in_vector(instantiator, Q_hotspot_y);
1144 IMAGE_INSTANCE_X_CURSOR(ii) =
1146 (dpy, source, mask, &fg_color, &bg_color,
1147 !NILP(IMAGE_INSTANCE_PIXMAP_HOTSPOT_X(ii)) ?
1148 XINT(IMAGE_INSTANCE_PIXMAP_HOTSPOT_X(ii)) : 0,
1149 !NILP(IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(ii)) ?
1150 XINT(IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(ii)) : 0);
1157 case IMAGE_SUBWINDOW:
1165 xbm_instantiate_1(Lisp_Object image_instance, Lisp_Object instantiator,
1166 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1167 int dest_mask, int width, int height,
1168 /* Note that data is in ext-format! */
1171 Lisp_Object mask_data =
1172 find_keyword_in_vector(instantiator, Q_mask_data);
1173 Lisp_Object mask_file =
1174 find_keyword_in_vector(instantiator, Q_mask_file);
1175 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
1178 if (!NILP(mask_data)) {
1181 LISP_STRING_TO_EXTERNAL(XCAR(XCDR(XCDR(mask_data))), ext_data,
1183 mask = pixmap_from_xbm_inline(
1184 IMAGE_INSTANCE_DEVICE(ii),
1185 XINT(XCAR(mask_data)),
1186 XINT(XCAR(XCDR(mask_data))),
1190 init_image_instance_from_xbm_inline(ii, width, height, bits,
1191 instantiator, pointer_fg,
1192 pointer_bg, dest_mask, mask,
1196 /* Instantiate method for XBM's. */
1199 x_xbm_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
1200 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1201 int dest_mask, Lisp_Object domain)
1203 Lisp_Object data = find_keyword_in_vector(instantiator, Q_data);
1206 assert(!NILP(data));
1208 LISP_STRING_TO_EXTERNAL(XCAR(XCDR(XCDR(data))), ext_data, Qbinary);
1210 xbm_instantiate_1(image_instance, instantiator, pointer_fg,
1211 pointer_bg, dest_mask, XINT(XCAR(data)),
1212 XINT(XCAR(XCDR(data))), ext_data);
1217 /**********************************************************************
1219 **********************************************************************/
1220 /* xpm 3.2g and better has XpmCreatePixmapFromBuffer()...
1221 There was no version number in xpm.h before 3.3, but this should do.
1223 #if (XpmVersion >= 3) || defined(XpmExactColors)
1224 # define XPM_DOES_BUFFERS
1227 #ifndef XPM_DOES_BUFFERS
1228 Your version of XPM is too old.You cannot compile with it.
1229 Upgrade to version 3.2 g or better or compile with-- with - xpm = no.
1230 #endif /* !XPM_DOES_BUFFERS */
1231 static XpmColorSymbol *
1232 extract_xpm_color_names(XpmAttributes * xpmattrs, Lisp_Object device,
1234 Lisp_Object color_symbol_alist) {
1235 /* This function can GC */
1236 Display * dpy = DEVICE_X_DISPLAY(XDEVICE(device));
1237 Colormap cmap = DEVICE_X_COLORMAP(XDEVICE(device));
1240 Lisp_Object results = Qnil;
1242 XpmColorSymbol *symbols;
1243 struct gcpro gcpro1, gcpro2;
1245 GCPRO2(results, device);
1247 /* We built up results to be (("name" . #<color>) ...) so that if an
1248 error happens we don't lose any malloc()ed data, or more importantly,
1249 leave any pixels allocated in the server. */
1251 LIST_LOOP(rest, color_symbol_alist) {
1252 Lisp_Object cons = XCAR(rest);
1253 Lisp_Object name = XCAR(cons);
1254 Lisp_Object value = XCDR(cons);
1259 Fmake_color_instance
1261 encode_error_behavior_flag(ERROR_ME_NOT));
1263 assert(COLOR_SPECIFIERP(value));
1264 value = Fspecifier_instance(value, domain, Qnil, Qnil);
1268 results = noseeum_cons(noseeum_cons(name, value), results);
1271 UNGCPRO; /* no more evaluation */
1276 symbols = xnew_atomic_array(XpmColorSymbol, i);
1277 xpmattrs->valuemask |= XpmColorSymbols;
1278 xpmattrs->colorsymbols = symbols;
1279 xpmattrs->numsymbols = i;
1282 Lisp_Object cons = XCAR(results);
1283 color = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(XCDR(cons)));
1284 /* Duplicate the pixel value so that we still have
1285 * a lock on it if the pixel we were passed is later freed. */
1286 if (!XAllocColor(dpy, cmap, &color)) {
1287 /* it must be allocable since we're
1288 * just duplicating it */
1292 symbols[i].name = (char *)XSTRING_DATA(XCAR(cons));
1293 symbols[i].pixel = color.pixel;
1294 symbols[i].value = 0;
1295 free_cons(XCONS(cons));
1297 results = XCDR(results);
1298 free_cons(XCONS(cons));
1303 static void xpm_free(XpmAttributes * xpmattrs)
1305 /* Could conceivably lose if XpmXXX returned an error without first
1306 initializing this structure, if we didn't know that initializing it
1307 to all zeros was ok (and also that it's ok to call XpmFreeAttributes()
1308 multiple times, since it zeros slots as it frees them...) */
1309 XpmFreeAttributes(xpmattrs);
1313 x_xpm_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
1314 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1315 int dest_mask, Lisp_Object domain)
1317 /* This function can GC */
1318 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
1319 Lisp_Object device = IMAGE_INSTANCE_DEVICE(ii);
1320 Lisp_Object data = find_keyword_in_vector(instantiator, Q_data);
1328 XpmAttributes xpmattrs;
1330 XpmColorSymbol *color_symbols;
1331 Lisp_Object color_symbol_alist = find_keyword_in_vector(instantiator,
1333 enum image_instance_type type;
1337 if (!DEVICE_X_P(XDEVICE(device)))
1338 signal_simple_error("Not an X device", device);
1340 dpy = DEVICE_X_DISPLAY(XDEVICE(device));
1341 xs = DefaultScreenOfDisplay(dpy);
1343 if (dest_mask & IMAGE_COLOR_PIXMAP_MASK)
1344 type = IMAGE_COLOR_PIXMAP;
1345 else if (dest_mask & IMAGE_MONO_PIXMAP_MASK)
1346 type = IMAGE_MONO_PIXMAP;
1347 else if (dest_mask & IMAGE_POINTER_MASK)
1348 type = IMAGE_POINTER;
1350 incompatible_image_types(instantiator, dest_mask,
1351 IMAGE_MONO_PIXMAP_MASK |
1352 IMAGE_COLOR_PIXMAP_MASK |
1353 IMAGE_POINTER_MASK);
1354 force_mono = (type != IMAGE_COLOR_PIXMAP);
1357 /* Although I haven't found it documented yet, it appears that pointers are
1358 always colored via the default window colormap... Sigh. */
1359 if (type == IMAGE_POINTER) {
1360 cmap = DefaultColormap(dpy, DefaultScreen(dpy));
1361 depth = DefaultDepthOfScreen(xs);
1362 visual = DefaultVisualOfScreen(xs);
1364 cmap = DEVICE_X_COLORMAP(XDEVICE(device));
1365 depth = DEVICE_X_DEPTH(XDEVICE(device));
1366 visual = DEVICE_X_VISUAL(XDEVICE(device));
1369 cmap = DEVICE_X_COLORMAP(XDEVICE(device));
1370 depth = DEVICE_X_DEPTH(XDEVICE(device));
1371 visual = DEVICE_X_VISUAL(XDEVICE(device));
1374 x_initialize_pixmap_image_instance(ii, 1, type);
1376 assert(!NILP(data));
1380 xzero(xpmattrs); /* want XpmInitAttributes() */
1381 xpmattrs.valuemask = XpmReturnPixels;
1383 /* Without this, we get a 1-bit version of the color image, which
1384 isn't quite right. With this, we get the mono image, which might
1385 be very different looking. */
1386 xpmattrs.valuemask |= XpmColorKey;
1387 xpmattrs.color_key = XPM_MONO;
1389 xpmattrs.valuemask |= XpmDepth;
1391 xpmattrs.closeness = 65535;
1392 xpmattrs.valuemask |= XpmCloseness;
1393 xpmattrs.depth = depth;
1394 xpmattrs.valuemask |= XpmDepth;
1395 xpmattrs.visual = visual;
1396 xpmattrs.valuemask |= XpmVisual;
1397 xpmattrs.colormap = cmap;
1398 xpmattrs.valuemask |= XpmColormap;
1401 color_symbols = extract_xpm_color_names(&xpmattrs, device, domain,
1402 color_symbol_alist);
1404 result = XpmCreatePixmapFromBuffer(dpy,
1405 XtWindow(DEVICE_XT_APP_SHELL
1407 (char *)XSTRING_DATA(data), &pixmap,
1410 if (color_symbols) {
1411 xfree(color_symbols);
1412 xpmattrs.colorsymbols = 0; /* in case XpmFreeAttr is too smart... */
1413 xpmattrs.numsymbols = 0;
1419 case XpmFileInvalid:
1421 xpm_free(&xpmattrs);
1422 signal_image_error("invalid XPM data", data);
1424 case XpmColorFailed:
1427 xpm_free(&xpmattrs);
1429 /* second time; blow out. */
1430 signal_double_file_error("Reading pixmap data",
1431 "color allocation failed",
1434 if (!(dest_mask & IMAGE_MONO_PIXMAP_MASK)) {
1435 /* second time; blow out. */
1436 signal_double_file_error
1437 ("Reading pixmap data",
1438 "color allocation failed", data);
1441 IMAGE_INSTANCE_TYPE(ii) = IMAGE_MONO_PIXMAP;
1447 xpm_free(&xpmattrs);
1448 signal_double_file_error("Parsing pixmap data",
1449 "out of memory", data);
1453 xpm_free(&xpmattrs);
1454 signal_double_file_error_2("Parsing pixmap data",
1455 "unknown error code",
1456 make_int(result), data);
1461 h = xpmattrs.height;
1464 int npixels = xpmattrs.npixels;
1468 pixels = xnew_atomic_array(Pixel, npixels);
1469 memcpy(pixels, xpmattrs.pixels,
1470 npixels * sizeof(Pixel));
1475 IMAGE_INSTANCE_X_PIXMAP(ii) = pixmap;
1476 IMAGE_INSTANCE_PIXMAP_MASK(ii) = (void *)mask;
1477 IMAGE_INSTANCE_X_COLORMAP(ii) = cmap;
1478 IMAGE_INSTANCE_X_PIXELS(ii) = pixels;
1479 IMAGE_INSTANCE_X_NPIXELS(ii) = npixels;
1480 IMAGE_INSTANCE_PIXMAP_WIDTH(ii) = w;
1481 IMAGE_INSTANCE_PIXMAP_HEIGHT(ii) = h;
1482 IMAGE_INSTANCE_PIXMAP_FILENAME(ii) =
1483 find_keyword_in_vector(instantiator, Q_file);
1487 case IMAGE_MONO_PIXMAP:
1490 case IMAGE_COLOR_PIXMAP: {
1491 IMAGE_INSTANCE_PIXMAP_DEPTH(ii) = depth;
1495 case IMAGE_POINTER: {
1496 int npixels = xpmattrs.npixels;
1497 Pixel *pixels = xpmattrs.pixels;
1500 int xhot = 0, yhot = 0;
1502 if (xpmattrs.valuemask & XpmHotspot) {
1503 xhot = xpmattrs.x_hotspot;
1504 XSETINT(IMAGE_INSTANCE_PIXMAP_HOTSPOT_X(ii),
1505 xpmattrs.x_hotspot);
1507 if (xpmattrs.valuemask & XpmHotspot) {
1508 yhot = xpmattrs.y_hotspot;
1509 XSETINT(IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(ii),
1510 xpmattrs.y_hotspot);
1512 check_pointer_sizes(xs, w, h, instantiator);
1514 /* If the loaded pixmap has colors allocated (meaning it came
1515 from an XPM file), then use those as the default colors for
1516 the cursor we create. Otherwise, default to pointer_fg and
1520 /* With an XBM file, it's obvious which bit is
1521 foreground and which is background, or rather, it's
1522 implicit: in an XBM file, a 1 bit is foreground, and
1523 a 0 bit is background.
1525 XCreatePixmapCursor() assumes this property of the
1526 pixmap it is called with as well; the `foreground'
1527 color argument is used for the 1 bits.
1529 With an XPM file, it's tricker, since the elements of
1530 the pixmap don't represent FG and BG, but are actual
1531 pixel values. So we need to figure out which of
1532 those pixels is the foreground color and which is the
1533 background. We do it by comparing RGB and assuming
1534 that the darker color is the foreground. This works
1535 with the result of xbmtopbm|ppmtoxpm, at least.
1537 It might be nice if there was some way to tag the
1538 colors in the XPM file with whether they are the
1539 foreground - perhaps with logical color names
1542 Once we have decided which color is the foreground,
1543 we need to ensure that that color corresponds to a
1544 `1' bit in the Pixmap. The XPM library wrote into
1545 the (1-bit) pixmap with XPutPixel, which will ignore
1546 all but the least significant bit.
1548 This means that a 1 bit in the image corresponds to
1549 `fg' only if `fg.pixel' is odd.
1551 (This also means that the image will be all the same
1552 color if both `fg' and `bg' are odd or even, but we
1553 can safely assume that that won't happen if the XPM
1554 file is sensible I think.)
1556 The desired result is that the image use `1' to
1557 represent the foreground color, and `0' to represent
1558 the background color. So, we may need to invert the
1559 image to accomplish this; we invert if fg is
1560 odd. (Remember that WhitePixel and BlackPixel are not
1561 necessarily 1 and 0 respectively, though I think it
1562 might be safe to assume that one of them is always 1
1563 and the other is always 0. We also pretty much need
1564 to assume that one is even and the other is odd.)
1567 fg.pixel = pixels[0]; /* pick a pixel at random. */
1568 bg.pixel = fg.pixel;
1569 for (i = 1; i < npixels; i++) {
1570 /* Look for an "other" pixel value. */
1571 bg.pixel = pixels[i];
1572 if (fg.pixel != bg.pixel)
1576 /* If (fg.pixel == bg.pixel) then probably something has
1577 gone wrong, but I don't think signalling an error
1578 would be appropriate. */
1580 XQueryColor(dpy, cmap, &fg);
1581 XQueryColor(dpy, cmap, &bg);
1583 /* If the foreground is lighter than the background,
1584 swap them. (This occurs semi-randomly, depending on
1585 the ordering of the color list in the XPM file.)
1588 unsigned short fg_total =
1589 ((fg.red / 3) + (fg.green / 3)
1591 unsigned short bg_total =
1592 ((bg.red / 3) + (bg.green / 3)
1594 if (fg_total > bg_total) {
1602 /* If the fg pixel corresponds to a `0' in the bitmap,
1603 invert it. (This occurs (only?) on servers with
1606 if ((fg.pixel & 1) == 0) {
1609 gcv.function = GXxor;
1611 gc = XCreateGC(dpy, pixmap,
1613 GCForeground), &gcv);
1614 XFillRectangle(dpy, pixmap, gc, 0, 0, w,
1619 generate_cursor_fg_bg(device, &pointer_fg,
1620 &pointer_bg, &fg, &bg);
1621 IMAGE_INSTANCE_PIXMAP_FG(ii) = pointer_fg;
1622 IMAGE_INSTANCE_PIXMAP_BG(ii) = pointer_bg;
1625 IMAGE_INSTANCE_X_CURSOR(ii) =
1627 (dpy, pixmap, mask, &fg, &bg, xhot, yhot);
1635 case IMAGE_SUBWINDOW:
1641 xpm_free(&xpmattrs); /* after we've read pixels and hotspot */
1644 #endif /* HAVE_XPM */
1648 /**********************************************************************
1650 **********************************************************************/
1652 /* This is about to get redefined! */
1655 /* We have to define SYSV32 so that compface.h includes string.h
1656 instead of strings.h. */
1661 #include <compface.h>
1665 /* JMP_BUF cannot be used here because if it doesn't get defined
1666 to jmp_buf we end up with a conflicting type error with the
1667 definition in compface.h */ extern jmp_buf comp_env;
1671 x_xface_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
1672 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1673 int dest_mask, Lisp_Object domain)
1675 Lisp_Object data = find_keyword_in_vector(instantiator, Q_data);
1679 const char *volatile emsg = 0;
1680 char *volatile dstring;
1682 assert(!NILP(data));
1684 LISP_STRING_TO_EXTERNAL(data, dstring, Qbinary);
1686 if ((p = strchr(dstring, ':'))) {
1690 /* Must use setjmp not SETJMP because we used jmp_buf above not
1692 if (!(stattis = setjmp(comp_env))) {
1699 emsg = "uncompface: internal error";
1702 emsg = "uncompface: insufficient or invalid data";
1705 emsg = "uncompface: excess data ignored";
1712 signal_simple_error_2(emsg, data, Qimage);
1714 bp = bits = (char *)alloca(PIXELS / 8);
1716 /* the compface library exports char F[], which uses a single byte per
1717 pixel to represent a 48x48 bitmap. Yuck. */
1718 for (i = 0, p = F; i < (PIXELS / 8); ++i) {
1720 /* reverse the bit order of each byte... */
1721 for (b = n = 0; b < 8; ++b) {
1727 xbm_instantiate_1(image_instance, instantiator, pointer_fg,
1728 pointer_bg, dest_mask, 48, 48, bits);
1731 #endif /* HAVE_XFACE */
1733 /**********************************************************************
1735 **********************************************************************/
1737 static void autodetect_validate(Lisp_Object instantiator)
1739 data_must_be_present(instantiator);
1743 autodetect_normalize(Lisp_Object instantiator,
1744 Lisp_Object console_type, Lisp_Object dest_mask)
1746 Lisp_Object file = find_keyword_in_vector(instantiator, Q_data);
1747 Lisp_Object filename = Qnil;
1748 Lisp_Object data = Qnil;
1749 struct gcpro gcpro1, gcpro2, gcpro3;
1750 Lisp_Object alist = Qnil;
1752 GCPRO3(filename, data, alist);
1754 if (NILP(file)) /* no conversion necessary */
1755 RETURN_UNGCPRO(instantiator);
1757 alist = tagged_vector_to_alist(instantiator);
1759 filename = locate_pixmap_file(file);
1760 if (!NILP(filename)) {
1762 /* #### Apparently some versions of XpmReadFileToData, which is
1763 called by pixmap_to_lisp_data, don't return an error value if
1764 the given file is not a valid XPM file. Instead, they just
1765 seg fault. It is definitely caused by passing a bitmap. To
1766 try and avoid this we check for bitmaps first. */
1768 data = bitmap_to_lisp_data(filename, &xhot, &yhot, 1);
1770 if (!EQ(data, Qt)) {
1771 alist = remassq_no_quit(Q_data, alist);
1772 alist = Fcons(Fcons(Q_file, filename),
1773 Fcons(Fcons(Q_data, data), alist));
1775 alist = Fcons(Fcons(Q_hotspot_x, make_int(xhot)),
1779 alist = Fcons(Fcons(Q_hotspot_y,
1783 alist = xbm_mask_file_munging(alist, filename, Qnil,
1787 Lisp_Object result =
1788 alist_to_tagged_vector(Qxbm, alist);
1790 RETURN_UNGCPRO(result);
1794 data = pixmap_to_lisp_data(filename, 1);
1796 if (!EQ(data, Qt)) {
1797 alist = remassq_no_quit(Q_data, alist);
1798 alist = Fcons(Fcons(Q_file, filename),
1799 Fcons(Fcons(Q_data, data), alist));
1800 alist = Fcons(Fcons(Q_color_symbols,
1801 evaluate_xpm_color_symbols()),
1804 Lisp_Object result =
1805 alist_to_tagged_vector(Qxpm, alist);
1807 RETURN_UNGCPRO(result);
1813 /* If we couldn't convert it, just put it back as it is.
1814 We might try to further frob it later as a cursor-font
1815 specification. (We can't do that now because we don't know
1816 what dest-types it's going to be instantiated into.) */
1818 Lisp_Object result = alist_to_tagged_vector(Qautodetect, alist);
1820 RETURN_UNGCPRO(result);
1824 static int autodetect_possible_dest_types(void)
1827 IMAGE_MONO_PIXMAP_MASK |
1828 IMAGE_COLOR_PIXMAP_MASK | IMAGE_POINTER_MASK | IMAGE_TEXT_MASK;
1832 autodetect_instantiate(Lisp_Object image_instance,
1833 Lisp_Object instantiator,
1834 Lisp_Object pointer_fg,
1835 Lisp_Object pointer_bg,
1836 int dest_mask, Lisp_Object domain)
1838 Lisp_Object data = find_keyword_in_vector(instantiator, Q_data);
1839 struct gcpro gcpro1, gcpro2, gcpro3;
1840 Lisp_Object alist = Qnil;
1841 Lisp_Object result = Qnil;
1842 int is_cursor_font = 0;
1844 GCPRO3(data, alist, result);
1846 alist = tagged_vector_to_alist(instantiator);
1847 if (dest_mask & IMAGE_POINTER_MASK) {
1848 const char *name_ext;
1849 LISP_STRING_TO_EXTERNAL(data, name_ext, Qfile_name);
1850 if (XmuCursorNameToIndex(name_ext) != -1) {
1851 result = alist_to_tagged_vector(Qcursor_font, alist);
1856 if (!is_cursor_font)
1857 result = alist_to_tagged_vector(Qstring, alist);
1861 cursor_font_instantiate(image_instance, result, pointer_fg,
1862 pointer_bg, dest_mask, domain);
1864 string_instantiate(image_instance, result, pointer_fg,
1865 pointer_bg, dest_mask, domain);
1870 /**********************************************************************
1872 **********************************************************************/
1874 static void font_validate(Lisp_Object instantiator)
1876 data_must_be_present(instantiator);
1879 /* XmuCvtStringToCursor is bogus in the following ways:
1881 - When it can't convert the given string to a real cursor, it will
1882 sometimes return a "success" value, after triggering a BadPixmap
1883 error. It then gives you a cursor that will itself generate BadCursor
1884 errors. So we install this error handler to catch/notice the X error
1885 and take that as meaning "couldn't convert."
1887 - When you tell it to find a cursor file that doesn't exist, it prints
1888 an error message on stderr. You can't make it not do that.
1890 - Also, using Xmu means we can't properly hack Lisp_Image_Instance
1891 objects, or XPM files, or $XBMLANGPATH.
1894 /* Duplicate the behavior of XmuCvtStringToCursor() to bypass its bogusness. */
1896 static int XLoadFont_got_error;
1898 static int XLoadFont_error_handler(Display * dpy, XErrorEvent * xerror)
1900 XLoadFont_got_error = 1;
1904 static Font safe_XLoadFont(Display * dpy, char *name)
1907 int (*old_handler) (Display *, XErrorEvent *);
1908 XLoadFont_got_error = 0;
1910 old_handler = XSetErrorHandler(XLoadFont_error_handler);
1911 font = XLoadFont(dpy, name);
1913 XSetErrorHandler(old_handler);
1914 if (XLoadFont_got_error)
1919 static int font_possible_dest_types(void)
1921 return IMAGE_POINTER_MASK;
1925 font_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
1926 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1927 int dest_mask, Lisp_Object domain)
1929 /* This function can GC */
1930 Lisp_Object data = find_keyword_in_vector(instantiator, Q_data);
1931 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
1932 Lisp_Object device = IMAGE_INSTANCE_DEVICE(ii);
1936 char source_name[MAXPATHLEN], mask_name[MAXPATHLEN], dummy;
1937 int source_char, mask_char;
1939 Lisp_Object foreground, background;
1941 if (!DEVICE_X_P(XDEVICE(device)))
1942 signal_simple_error("Not an X device", device);
1944 dpy = DEVICE_X_DISPLAY(XDEVICE(device));
1946 if (!STRINGP(data) || strncmp("FONT ", (char *)XSTRING_DATA(data), 5))
1947 signal_simple_error("Invalid font-glyph instantiator",
1950 if (!(dest_mask & IMAGE_POINTER_MASK))
1951 incompatible_image_types(instantiator, dest_mask,
1952 IMAGE_POINTER_MASK);
1954 foreground = find_keyword_in_vector(instantiator, Q_foreground);
1955 if (NILP(foreground))
1956 foreground = pointer_fg;
1957 background = find_keyword_in_vector(instantiator, Q_background);
1958 if (NILP(background))
1959 background = pointer_bg;
1961 generate_cursor_fg_bg(device, &foreground, &background, &fg, &bg);
1963 count = sscanf((char *)XSTRING_DATA(data),
1964 "FONT %s %d %s %d %c",
1965 source_name, &source_char,
1966 mask_name, &mask_char, &dummy);
1967 /* Allow "%s %d %d" as well... */
1968 if (count == 3 && (1 == sscanf(mask_name, "%d %c", &mask_char, &dummy)))
1969 count = 4, mask_name[0] = 0;
1971 if (count != 2 && count != 4)
1972 signal_simple_error("invalid cursor specification", data);
1973 source = safe_XLoadFont(dpy, source_name);
1975 signal_simple_error_2("couldn't load font",
1976 build_string(source_name), data);
1979 else if (!mask_name[0])
1982 mask = safe_XLoadFont(dpy, mask_name);
1986 list3(build_string("couldn't load font"),
1987 build_string(mask_name), data));
1992 /* #### call XQueryTextExtents() and check_pointer_sizes() here. */
1994 x_initialize_pixmap_image_instance(ii, 1, IMAGE_POINTER);
1995 IMAGE_INSTANCE_X_CURSOR(ii) =
1996 XCreateGlyphCursor(dpy, source, mask, source_char, mask_char,
1998 XIMAGE_INSTANCE_PIXMAP_FG(image_instance) = foreground;
1999 XIMAGE_INSTANCE_PIXMAP_BG(image_instance) = background;
2000 XUnloadFont(dpy, source);
2001 if (mask && mask != source)
2002 XUnloadFont(dpy, mask);
2005 /**********************************************************************
2007 **********************************************************************/
2009 static void cursor_font_validate(Lisp_Object instantiator)
2011 data_must_be_present(instantiator);
2014 static int cursor_font_possible_dest_types(void)
2016 return IMAGE_POINTER_MASK;
2020 cursor_font_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
2021 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2022 int dest_mask, Lisp_Object domain)
2024 /* This function can GC */
2025 Lisp_Object data = find_keyword_in_vector(instantiator, Q_data);
2026 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2027 Lisp_Object device = IMAGE_INSTANCE_DEVICE(ii);
2030 const char *name_ext;
2031 Lisp_Object foreground, background;
2033 if (!DEVICE_X_P(XDEVICE(device)))
2034 signal_simple_error("Not an X device", device);
2036 dpy = DEVICE_X_DISPLAY(XDEVICE(device));
2038 if (!(dest_mask & IMAGE_POINTER_MASK))
2039 incompatible_image_types(instantiator, dest_mask,
2040 IMAGE_POINTER_MASK);
2042 LISP_STRING_TO_EXTERNAL(data, name_ext, Qfile_name);
2043 if ((i = XmuCursorNameToIndex(name_ext)) == -1)
2044 signal_simple_error("Unrecognized cursor-font name", data);
2046 x_initialize_pixmap_image_instance(ii, 1, IMAGE_POINTER);
2047 IMAGE_INSTANCE_X_CURSOR(ii) = XCreateFontCursor(dpy, i);
2048 foreground = find_keyword_in_vector(instantiator, Q_foreground);
2049 if (NILP(foreground))
2050 foreground = pointer_fg;
2051 background = find_keyword_in_vector(instantiator, Q_background);
2052 if (NILP(background))
2053 background = pointer_bg;
2054 maybe_recolor_cursor(image_instance, foreground, background);
2058 x_colorize_image_instance(Lisp_Object image_instance,
2059 Lisp_Object foreground, Lisp_Object background)
2061 Lisp_Image_Instance *p;
2063 p = XIMAGE_INSTANCE(image_instance);
2065 switch (IMAGE_INSTANCE_TYPE(p)) {
2066 case IMAGE_MONO_PIXMAP:
2067 IMAGE_INSTANCE_TYPE(p) = IMAGE_COLOR_PIXMAP;
2068 /* Make sure there aren't two pointers to the same mask, causing
2069 it to get freed twice. */
2070 IMAGE_INSTANCE_PIXMAP_MASK(p) = 0;
2076 case IMAGE_SUBWINDOW:
2078 case IMAGE_COLOR_PIXMAP:
2086 DEVICE_X_DISPLAY(XDEVICE(IMAGE_INSTANCE_DEVICE(p)));
2088 XtWindow(DEVICE_XT_APP_SHELL
2089 (XDEVICE(IMAGE_INSTANCE_DEVICE(p))));
2090 Dimension d = DEVICE_X_DEPTH(XDEVICE(IMAGE_INSTANCE_DEVICE(p)));
2091 Pixmap new = XCreatePixmap(dpy, draw,
2092 IMAGE_INSTANCE_PIXMAP_WIDTH(p),
2093 IMAGE_INSTANCE_PIXMAP_HEIGHT(p), d);
2097 color = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(foreground));
2098 gcv.foreground = color.pixel;
2099 color = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(background));
2100 gcv.background = color.pixel;
2101 gc = XCreateGC(dpy, new, GCBackground | GCForeground, &gcv);
2102 XCopyPlane(dpy, IMAGE_INSTANCE_X_PIXMAP(p), new, gc, 0, 0,
2103 IMAGE_INSTANCE_PIXMAP_WIDTH(p),
2104 IMAGE_INSTANCE_PIXMAP_HEIGHT(p), 0, 0, 1);
2106 IMAGE_INSTANCE_X_PIXMAP(p) = new;
2107 IMAGE_INSTANCE_PIXMAP_DEPTH(p) = d;
2108 IMAGE_INSTANCE_PIXMAP_FG(p) = foreground;
2109 IMAGE_INSTANCE_PIXMAP_BG(p) = background;
2114 /************************************************************************/
2115 /* subwindow and widget support */
2116 /************************************************************************/
2118 /* unmap the image if it is a widget. This is used by redisplay via
2119 redisplay_unmap_subwindows */
2120 static void x_unmap_subwindow(Lisp_Image_Instance * p)
2122 if (IMAGE_INSTANCE_TYPE(p) == IMAGE_SUBWINDOW) {
2124 (IMAGE_INSTANCE_X_SUBWINDOW_DISPLAY(p),
2125 IMAGE_INSTANCE_X_CLIPWINDOW(p));
2126 } else { /* must be a widget */
2128 /* Since we are being unmapped we want the enclosing frame to
2129 get focus. The losing with simple scrolling but is the safest
2131 emacs_Xt_handle_widget_losing_focus
2132 (XFRAME(IMAGE_INSTANCE_FRAME(p)),
2133 IMAGE_INSTANCE_X_WIDGET_ID(p));
2134 XtUnmapWidget(IMAGE_INSTANCE_X_CLIPWIDGET(p));
2138 /* map the subwindow. This is used by redisplay via
2139 redisplay_output_subwindow */
2141 x_map_subwindow(Lisp_Image_Instance * p, int x, int y,
2142 struct display_glyph_area *dga)
2144 assert(dga->width > 0 && dga->height > 0);
2145 if (IMAGE_INSTANCE_TYPE(p) == IMAGE_SUBWINDOW) {
2146 Window subwindow = IMAGE_INSTANCE_X_SUBWINDOW_ID(p);
2147 XMoveResizeWindow(IMAGE_INSTANCE_X_SUBWINDOW_DISPLAY(p),
2148 IMAGE_INSTANCE_X_CLIPWINDOW(p),
2149 x, y, dga->width, dga->height);
2150 XMoveWindow(IMAGE_INSTANCE_X_SUBWINDOW_DISPLAY(p),
2151 subwindow, -dga->xoffset, -dga->yoffset);
2152 if (!IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP(p))
2153 XMapWindow(IMAGE_INSTANCE_X_SUBWINDOW_DISPLAY(p),
2154 IMAGE_INSTANCE_X_CLIPWINDOW(p));
2155 } else { /* must be a widget */
2157 XtConfigureWidget(IMAGE_INSTANCE_X_CLIPWIDGET(p),
2158 x + IMAGE_INSTANCE_X_WIDGET_XOFFSET(p),
2159 y + IMAGE_INSTANCE_X_WIDGET_YOFFSET(p),
2160 dga->width, dga->height, 0);
2161 XtMoveWidget(IMAGE_INSTANCE_X_WIDGET_ID(p),
2162 -dga->xoffset, -dga->yoffset);
2163 if (!IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP(p))
2164 XtMapWidget(IMAGE_INSTANCE_X_CLIPWIDGET(p));
2165 if (IMAGE_INSTANCE_WANTS_INITIAL_FOCUS(p)) {
2166 /* #### FIXME to pop-up the find dialog we map the text-field
2167 seven times! This doesn't show on a fast linux, though. */
2168 enqueue_focus_event(IMAGE_INSTANCE_X_WIDGET_ID(p),
2169 IMAGE_INSTANCE_FRAME(p), 1);
2174 /* when you click on a widget you may activate another widget this
2175 needs to be checked and all appropriate widgets updated */
2176 static void x_redisplay_subwindow(Lisp_Image_Instance * p)
2178 /* Update the subwindow size if necessary. */
2179 if (IMAGE_INSTANCE_SIZE_CHANGED(p)) {
2180 XResizeWindow(IMAGE_INSTANCE_X_SUBWINDOW_DISPLAY(p),
2181 IMAGE_INSTANCE_X_SUBWINDOW_ID(p),
2182 IMAGE_INSTANCE_WIDTH(p),
2183 IMAGE_INSTANCE_HEIGHT(p));
2187 /* Update all attributes that have changed. Lwlib actually does most
2189 static void x_redisplay_widget(Lisp_Image_Instance * p)
2191 /* This function can GC if IN_REDISPLAY is false. */
2193 widget_value *wv = 0;
2195 /* First get the items if they have changed since this is a
2196 structural change. As such it will nuke all added values so we
2197 need to update most other things after the items have changed. */
2198 if (IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED(p)) {
2199 Lisp_Object image_instance;
2201 XSETIMAGE_INSTANCE(image_instance, p);
2202 wv = gui_items_to_widget_values
2203 (image_instance, IMAGE_INSTANCE_WIDGET_PENDING_ITEMS(p),
2204 /* #### this is not right; we need to keep track of which widgets
2205 want accelerators and which don't */ 0);
2206 wv->change = STRUCTURAL_CHANGE;
2208 /* Assume the lotus position, breath deeply and chant to
2209 yourself lwlibsux, lwlibsux ... lw_get_all_values returns a
2210 reference to the real values rather than a copy thus any
2211 changes we make to the values we get back will look like they
2212 have already been applied. If we rebuild the widget tree then
2213 we may lose properties. */
2214 wv = copy_widget_value_tree(lw_get_all_values
2215 (IMAGE_INSTANCE_X_WIDGET_LWID(p)),
2219 /* Possibly update the colors and font */
2220 if (IMAGE_INSTANCE_WIDGET_FACE_CHANGED(p)
2222 /* #### This is not sufficient because it will not cope with widgets
2223 that are not currently visible. Once redisplay has done the
2224 visible ones it will clear this flag so that when new ones
2225 become visible they will not be updated. */
2226 XFRAME(IMAGE_INSTANCE_FRAME(p))->faces_changed
2228 XFRAME(IMAGE_INSTANCE_FRAME(p))->frame_changed
2229 || IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED(p)) {
2230 update_widget_face(wv, p, IMAGE_INSTANCE_FRAME(p));
2233 /* Possibly update the text. */
2234 if (IMAGE_INSTANCE_TEXT_CHANGED(p)) {
2236 Lisp_Object val = IMAGE_INSTANCE_WIDGET_TEXT(p);
2237 LISP_STRING_TO_EXTERNAL(val, str, Qnative);
2241 /* Possibly update the size. */
2242 if (IMAGE_INSTANCE_SIZE_CHANGED(p)
2243 || IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED(p)
2244 || IMAGE_INSTANCE_TEXT_CHANGED(p)) {
2245 assert(IMAGE_INSTANCE_X_WIDGET_ID(p) &&
2246 IMAGE_INSTANCE_X_CLIPWIDGET(p));
2248 if (IMAGE_INSTANCE_X_WIDGET_ID(p)->core.being_destroyed
2249 || !XtIsManaged(IMAGE_INSTANCE_X_WIDGET_ID(p))) {
2251 XSETIMAGE_INSTANCE(sw, p);
2252 signal_simple_error("SXEmacs bug: subwindow is deleted",
2256 lw_add_widget_value_arg(wv, XtNwidth,
2257 IMAGE_INSTANCE_WIDTH(p));
2258 lw_add_widget_value_arg(wv, XtNheight,
2259 IMAGE_INSTANCE_HEIGHT(p));
2262 /* Adjust offsets within the frame. */
2263 if (XFRAME(IMAGE_INSTANCE_FRAME(p))->size_changed) {
2265 XtSetArg(al[0], XtNx, &IMAGE_INSTANCE_X_WIDGET_XOFFSET(p));
2266 XtSetArg(al[1], XtNy, &IMAGE_INSTANCE_X_WIDGET_YOFFSET(p));
2267 XtGetValues(FRAME_X_TEXT_WIDGET
2268 (XFRAME(IMAGE_INSTANCE_FRAME(p))), al, 2);
2271 /* now modify the widget */
2272 lw_modify_all_widgets(IMAGE_INSTANCE_X_WIDGET_LWID(p), wv, True);
2273 free_widget_value_tree(wv);
2277 /* instantiate and x type subwindow */
2279 x_subwindow_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
2280 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2281 int dest_mask, Lisp_Object domain)
2283 /* This function can GC */
2284 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2285 Lisp_Object device = IMAGE_INSTANCE_DEVICE(ii);
2286 Lisp_Object frame = DOMAIN_FRAME(domain);
2287 struct frame *f = XFRAME(frame);
2291 XSetWindowAttributes xswa;
2293 unsigned int w = IMAGE_INSTANCE_WIDTH(ii),
2294 h = IMAGE_INSTANCE_HEIGHT(ii);
2296 if (!DEVICE_X_P(XDEVICE(device)))
2297 signal_simple_error("Not an X device", device);
2299 dpy = DEVICE_X_DISPLAY(XDEVICE(device));
2300 xs = DefaultScreenOfDisplay(dpy);
2302 IMAGE_INSTANCE_TYPE(ii) = IMAGE_SUBWINDOW;
2304 pw = XtWindow(FRAME_X_TEXT_WIDGET(f));
2306 ii->data = xnew_and_zero(struct x_subwindow_data);
2308 IMAGE_INSTANCE_X_SUBWINDOW_PARENT(ii) = pw;
2309 IMAGE_INSTANCE_X_SUBWINDOW_DISPLAY(ii) = DisplayOfScreen(xs);
2311 xswa.backing_store = Always;
2312 valueMask |= CWBackingStore;
2313 xswa.colormap = DefaultColormapOfScreen(xs);
2314 valueMask |= CWColormap;
2316 /* Create a window for clipping */
2317 IMAGE_INSTANCE_X_CLIPWINDOW(ii) =
2318 XCreateWindow(dpy, pw, 0, 0, w, h, 0, CopyFromParent,
2319 InputOutput, CopyFromParent, valueMask, &xswa);
2321 /* Now put the subwindow inside the clip window. */
2322 win = XCreateWindow(dpy, IMAGE_INSTANCE_X_CLIPWINDOW(ii),
2323 0, 0, w, h, 0, CopyFromParent,
2324 InputOutput, CopyFromParent, valueMask, &xswa);
2326 IMAGE_INSTANCE_SUBWINDOW_ID(ii) = (void *)win;
2329 /* Account for some of the limitations with widget images. */
2330 static int x_widget_border_width(void)
2332 return DEFAULT_WIDGET_BORDER_WIDTH * 2;
2336 x_subwindow_query_geometry(Lisp_Object image_instance,
2337 int *width, int *height)
2339 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2341 unsigned int dx, dy, dbdw, dd, dw = 20, dh = 20;
2343 XGetGeometry(IMAGE_INSTANCE_X_SUBWINDOW_DISPLAY(ii),
2344 (Window)IMAGE_INSTANCE_SUBWINDOW_ID(ii),
2345 &droot, &dx, &dy, &dw, &dh, &dbdw, &dd);
2353 /* #### Should this function exist? If there's any doubt I'm not implementing it --andyp */
2354 DEFUN("change-subwindow-property", Fchange_subwindow_property, 3, 3, 0, /*
2355 For the given SUBWINDOW, set PROPERTY to DATA, which is a string.
2356 Subwindows are not currently implemented.
2358 (subwindow, property, data))
2364 CHECK_SUBWINDOW(subwindow);
2365 CHECK_STRING(property);
2368 sw = XSUBWINDOW(subwindow);
2369 dpy = DisplayOfScreen(LISP_DEVICE_TO_X_SCREEN
2370 (FRAME_DEVICE(XFRAME(sw->frame))));
2372 property_atom = XInternAtom(dpy, (char *)XSTRING_DATA(property), False);
2373 XChangeProperty(dpy, sw->subwindow, property_atom, XA_STRING, 8,
2375 XSTRING_DATA(data), XSTRING_LENGTH(data));
2383 /************************************************************************/
2385 /************************************************************************/
2388 update_widget_face(widget_value * wv, Lisp_Image_Instance * ii,
2391 #ifdef LWLIB_WIDGETS_MOTIF
2392 XmFontList fontList;
2394 /* Update the foreground. */
2395 Lisp_Object pixel = FACE_FOREGROUND(IMAGE_INSTANCE_WIDGET_FACE(ii),
2397 XColor fcolor = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(pixel)), bcolor;
2398 lw_add_widget_value_arg(wv, XtNforeground, fcolor.pixel);
2400 /* Update the background. */
2401 pixel = FACE_BACKGROUND(IMAGE_INSTANCE_WIDGET_FACE(ii), domain);
2402 bcolor = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(pixel));
2403 lw_add_widget_value_arg(wv, XtNbackground, bcolor.pixel);
2405 #ifdef LWLIB_WIDGETS_MOTIF
2406 fontList = XmFontListCreate
2407 (FONT_INSTANCE_X_FONT
2408 (XFONT_INSTANCE(query_string_font
2409 (IMAGE_INSTANCE_WIDGET_TEXT(ii),
2410 IMAGE_INSTANCE_WIDGET_FACE(ii),
2411 domain))), XmSTRING_DEFAULT_CHARSET);
2412 lw_add_widget_value_arg(wv, XmNfontList, (XtArgVal) fontList);
2415 Lisp_Object tmp = query_string_font(
2416 IMAGE_INSTANCE_WIDGET_TEXT(ii),
2417 IMAGE_INSTANCE_WIDGET_FACE(ii), domain);
2418 lw_add_widget_value_arg(
2420 (XtArgVal)FONT_INSTANCE_X_FONT(XFONT_INSTANCE(tmp)));
2422 wv->change = VISIBLE_CHANGE;
2423 /* #### Megahack - but its just getting too complicated to do this
2424 in the right place. */
2425 if (EQ(IMAGE_INSTANCE_WIDGET_TYPE(ii), Qtab_control)) {
2426 update_tab_widget_face(wv, ii, domain);
2432 update_tab_widget_face(widget_value * wv, Lisp_Image_Instance * ii,
2436 widget_value *val = wv->contents, *cur;
2438 /* Give each child label the correct foreground color. */
2439 Lisp_Object pixel = FACE_FOREGROUND
2440 (IMAGE_INSTANCE_WIDGET_FACE(ii),
2442 XColor fcolor = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(pixel));
2443 lw_add_widget_value_arg(val, XtNtabForeground, fcolor.pixel);
2444 wv->change = VISIBLE_CHANGE;
2445 val->change = VISIBLE_CHANGE;
2447 for (cur = val->next; cur; cur = cur->next) {
2448 cur->change = VISIBLE_CHANGE;
2450 lw_copy_widget_value_args(val, cur);
2457 x_widget_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
2458 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2459 int dest_mask, Lisp_Object domain,
2460 const char *type, widget_value * wv)
2462 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2463 Lisp_Object device = IMAGE_INSTANCE_DEVICE(ii), pixel;
2464 struct device *d = XDEVICE(device);
2465 Lisp_Object frame = DOMAIN_FRAME(domain);
2466 struct frame *f = XFRAME(frame);
2471 int id = new_lwlib_id();
2472 widget_value *clip_wv;
2473 XColor fcolor, bcolor;
2476 signal_simple_error("Not an X device", device);
2478 /* have to set the type this late in case there is no device
2479 instantiation for a widget. But we can go ahead and do it without
2480 checking because there is always a generic instantiator. */
2481 IMAGE_INSTANCE_TYPE(ii) = IMAGE_WIDGET;
2483 if (!NILP(IMAGE_INSTANCE_WIDGET_TEXT(ii)))
2484 LISP_STRING_TO_EXTERNAL(IMAGE_INSTANCE_WIDGET_TEXT(ii), nm,
2487 ii->data = xnew_and_zero(struct x_subwindow_data);
2489 /* Create a clip window to contain the subwidget. Incredibly the
2490 SXEmacs manager seems to be the most appropriate widget for
2491 this. Nothing else is simple enough and yet does what is
2493 clip_wv = xmalloc_widget_value();
2495 lw_add_widget_value_arg(clip_wv, XtNresize, False);
2496 lw_add_widget_value_arg(clip_wv, XtNwidth,
2497 IMAGE_INSTANCE_WIDTH(ii));
2498 lw_add_widget_value_arg(clip_wv, XtNheight,
2499 IMAGE_INSTANCE_HEIGHT(ii));
2500 clip_wv->enabled = True;
2502 clip_wv->name = xstrdup("clip-window");
2503 clip_wv->value = xstrdup("clip-window");
2505 IMAGE_INSTANCE_X_CLIPWIDGET(ii)
2506 = lw_create_widget("clip-window", "clip-window", new_lwlib_id(),
2507 clip_wv, FRAME_X_CONTAINER_WIDGET(f),
2510 free_widget_value_tree(clip_wv);
2512 /* create a sensible name. */
2513 if (wv->name == 0 || strcmp(wv->name, "") == 0)
2514 wv->name = xstrdup(type);
2516 /* copy any args we were given */
2518 lw_add_value_args_to_args(wv, al, &ac);
2520 /* Fixup the colors. We have to do this *before* the widget gets
2521 created so that Motif will fix up the shadow colors
2522 correctly. Once the widget is created Motif won't do this
2524 pixel = FACE_FOREGROUND
2525 (IMAGE_INSTANCE_WIDGET_FACE(ii), IMAGE_INSTANCE_FRAME(ii));
2526 fcolor = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(pixel));
2528 pixel = FACE_BACKGROUND
2529 (IMAGE_INSTANCE_WIDGET_FACE(ii), IMAGE_INSTANCE_FRAME(ii));
2530 bcolor = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(pixel));
2532 lw_add_widget_value_arg(wv, XtNbackground, bcolor.pixel);
2533 lw_add_widget_value_arg(wv, XtNforeground, fcolor.pixel);
2534 /* we cannot allow widgets to resize themselves */
2535 lw_add_widget_value_arg(wv, XtNresize, False);
2536 lw_add_widget_value_arg(wv, XtNwidth, IMAGE_INSTANCE_WIDTH(ii));
2537 lw_add_widget_value_arg(wv, XtNheight, IMAGE_INSTANCE_HEIGHT(ii));
2538 /* update the font. */
2539 update_widget_face(wv, ii, domain);
2542 lw_create_widget(type, wv->name, id, wv,
2543 IMAGE_INSTANCE_X_CLIPWIDGET(ii), False, 0,
2544 popup_selection_callback, 0);
2546 IMAGE_INSTANCE_SUBWINDOW_ID(ii) = (void *)wid;
2547 IMAGE_INSTANCE_X_WIDGET_LWID(ii) = id;
2548 /* because the EmacsManager is the widgets parent we have to
2549 offset the redisplay of the widget by the amount the text
2550 widget is inside the manager. */
2552 XtSetArg(al[ac], XtNx, &IMAGE_INSTANCE_X_WIDGET_XOFFSET(ii));
2554 XtSetArg(al[ac], XtNy, &IMAGE_INSTANCE_X_WIDGET_YOFFSET(ii));
2556 XtGetValues(FRAME_X_TEXT_WIDGET(f), al, ac);
2558 XtSetMappedWhenManaged(wid, TRUE);
2560 free_widget_value_tree(wv);
2561 /* A kludgy but simple way to make sure the callback for a widget
2562 doesn't get deleted. */
2563 gcpro_popup_callbacks(id);
2566 /* get properties of a control */
2568 x_widget_property(Lisp_Object image_instance, Lisp_Object prop)
2570 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2571 /* get the text from a control */
2572 if (EQ(prop, Q_text)) {
2574 lw_get_all_values(IMAGE_INSTANCE_X_WIDGET_LWID(ii));
2575 return build_ext_string(wv->value, Qnative);
2580 /* Instantiate a layout control for putting other widgets in. */
2582 x_native_layout_instantiate(Lisp_Object image_instance,
2583 Lisp_Object instantiator, Lisp_Object pointer_fg,
2584 Lisp_Object pointer_bg, int dest_mask,
2587 x_widget_instantiate(image_instance, instantiator, pointer_fg,
2588 pointer_bg, dest_mask, domain, "layout", 0);
2591 /* Instantiate a button widget. Unfortunately instantiated widgets are
2592 particular to a frame since they need to have a parent. It's not
2593 like images where you just select the image into the context you
2594 want to display it in and BitBlt it. So images instances can have a
2595 many-to-one relationship with things you see, whereas widgets can
2596 only be one-to-one (i.e. per frame) */
2598 x_button_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
2599 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2600 int dest_mask, Lisp_Object domain)
2602 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2603 Lisp_Object gui = IMAGE_INSTANCE_WIDGET_ITEM(ii);
2604 Lisp_Object glyph = find_keyword_in_vector(instantiator, Q_image);
2605 widget_value *wv = gui_items_to_widget_values(image_instance, gui, 1);
2608 if (!IMAGE_INSTANCEP(glyph))
2610 glyph_image_instance(glyph, domain, ERROR_ME, 1);
2613 x_widget_instantiate(image_instance, instantiator, pointer_fg,
2614 pointer_bg, dest_mask, domain, "button", wv);
2616 /* add the image if one was given */
2617 if (!NILP(glyph) && IMAGE_INSTANCEP(glyph)
2618 && IMAGE_INSTANCE_PIXMAP_TYPE_P(XIMAGE_INSTANCE(glyph))) {
2621 #ifdef LWLIB_WIDGETS_MOTIF
2622 XtSetArg(al[ac], XmNlabelType, XmPIXMAP);
2624 XtSetArg(al[ac], XmNlabelPixmap,
2625 XIMAGE_INSTANCE_X_PIXMAP(glyph));
2628 XtSetArg(al[ac], XtNpixmap, XIMAGE_INSTANCE_X_PIXMAP(glyph));
2631 XtSetValues(IMAGE_INSTANCE_X_WIDGET_ID(ii), al, ac);
2635 /* Update a button's clicked state.
2637 #### This is overkill, but it works. Right now this causes all
2638 button instances to flash for some reason buried deep in lwlib. In
2639 theory this should be the Right Thing to do since lwlib should only
2640 merge in changed values - and if nothing has changed then nothing
2641 should get done. This may be because of the args stuff,
2642 i.e. although the arg contents may be the same the args look
2643 different and so are re-applied to the widget. */
2644 static void x_button_redisplay(Lisp_Object image_instance)
2646 /* This function can GC if IN_REDISPLAY is false. */
2647 Lisp_Image_Instance *p = XIMAGE_INSTANCE(image_instance);
2648 widget_value *wv = gui_items_to_widget_values(image_instance,
2649 IMAGE_INSTANCE_WIDGET_ITEMS
2652 /* now modify the widget */
2653 lw_modify_all_widgets(IMAGE_INSTANCE_X_WIDGET_LWID(p), wv, True);
2654 free_widget_value_tree(wv);
2657 /* get properties of a button */
2659 x_button_property(Lisp_Object image_instance, Lisp_Object prop)
2661 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2662 /* check the state of a button */
2663 if (EQ(prop, Q_selected)) {
2665 lw_get_all_values(IMAGE_INSTANCE_X_WIDGET_LWID(ii));
2675 /* instantiate a progress gauge */
2677 x_progress_gauge_instantiate(Lisp_Object image_instance,
2678 Lisp_Object instantiator, Lisp_Object pointer_fg,
2679 Lisp_Object pointer_bg, int dest_mask,
2682 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2683 Lisp_Object gui = IMAGE_INSTANCE_WIDGET_ITEM(ii);
2684 widget_value *wv = gui_items_to_widget_values(image_instance, gui, 0);
2686 x_widget_instantiate(image_instance, instantiator, pointer_fg,
2687 pointer_bg, dest_mask, domain, "progress", wv);
2690 /* set the properties of a progress gauge */
2691 static void x_progress_gauge_redisplay(Lisp_Object image_instance)
2693 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2695 if (IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED(ii)) {
2698 #ifdef ERROR_CHECK_GLYPHS
2699 assert(GUI_ITEMP(IMAGE_INSTANCE_WIDGET_PENDING_ITEMS(ii)));
2701 val = XGUI_ITEM(IMAGE_INSTANCE_WIDGET_PENDING_ITEMS(ii))->value;
2702 XtSetArg(al[0], XtNvalue, XINT(val));
2703 XtSetValues(IMAGE_INSTANCE_X_WIDGET_ID(ii), al, 1);
2707 /* instantiate an edit control */
2709 x_edit_field_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
2710 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2711 int dest_mask, Lisp_Object domain)
2713 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2714 Lisp_Object gui = IMAGE_INSTANCE_WIDGET_ITEM(ii);
2715 widget_value *wv = gui_items_to_widget_values(image_instance, gui, 0);
2717 x_widget_instantiate(image_instance, instantiator, pointer_fg,
2718 pointer_bg, dest_mask, domain, "text-field", wv);
2721 #if defined (LWLIB_WIDGETS_MOTIF) && XmVERSION > 1
2722 /* instantiate a combo control */
2724 x_combo_box_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
2725 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2726 int dest_mask, Lisp_Object domain)
2728 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2729 widget_value *wv = 0;
2730 /* This is not done generically because of sizing problems under
2731 mswindows. REVISE ME: We don't support windows, so? */
2732 widget_instantiate(image_instance, instantiator, pointer_fg,
2733 pointer_bg, dest_mask, domain);
2735 wv = gui_items_to_widget_values(image_instance,
2736 IMAGE_INSTANCE_WIDGET_ITEMS(ii), 0);
2738 x_widget_instantiate(image_instance, instantiator, pointer_fg,
2739 pointer_bg, dest_mask, domain, "combo-box", wv);
2744 x_tab_control_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
2745 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2746 int dest_mask, Lisp_Object domain)
2748 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2749 widget_value *wv = gui_items_to_widget_values(image_instance,
2750 IMAGE_INSTANCE_WIDGET_ITEMS
2752 update_tab_widget_face(wv, ii, IMAGE_INSTANCE_FRAME(ii));
2753 x_widget_instantiate(image_instance, instantiator, pointer_fg,
2754 pointer_bg, dest_mask, domain, "tab-control", wv);
2757 /* Set the properties of a tab control */
2758 static void x_tab_control_redisplay(Lisp_Object image_instance)
2760 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2762 if (IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED(ii)
2763 || IMAGE_INSTANCE_WIDGET_ACTION_OCCURRED(ii)) {
2764 /* If only the order has changed then simply select the first
2765 one of the pending set. This stops horrendous rebuilding -
2766 and hence flicker - of the tabs each time you click on
2768 if (tab_control_order_only_changed(image_instance)) {
2769 Lisp_Object rest, selected =
2770 gui_item_list_find_selected
2771 (NILP(IMAGE_INSTANCE_WIDGET_PENDING_ITEMS(ii)) ?
2772 XCDR(IMAGE_INSTANCE_WIDGET_ITEMS(ii)) :
2773 XCDR(IMAGE_INSTANCE_WIDGET_PENDING_ITEMS(ii)));
2775 LIST_LOOP(rest, XCDR(IMAGE_INSTANCE_WIDGET_ITEMS(ii))) {
2776 if (gui_item_equal_sans_selected
2777 (XCAR(rest), selected, 0)) {
2778 /* There may be an encapsulated way of doing this,
2779 but I couldn't find it. */
2780 Lisp_Object old_selected =
2781 gui_item_list_find_selected(XCDR
2782 (IMAGE_INSTANCE_WIDGET_ITEMS
2786 unsigned int num_children, i;
2789 LISP_STRING_TO_EXTERNAL(XGUI_ITEM
2793 /* The name may contain a `.' which confuses
2794 XtNameToWidget, so we do it ourselves. */
2797 (IMAGE_INSTANCE_X_WIDGET_ID(ii),
2799 for (i = 0; i < num_children; i++) {
2801 (XtName(children[i]),
2810 (IMAGE_INSTANCE_X_WIDGET_ID
2815 /* Pick up the new selected item. */
2816 XGUI_ITEM(old_selected)->selected =
2817 XGUI_ITEM(XCAR(rest))->selected;
2818 XGUI_ITEM(XCAR(rest))->selected =
2819 XGUI_ITEM(selected)->selected;
2820 /* We're not actually changing the items anymore. */
2821 IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED(ii)
2823 IMAGE_INSTANCE_WIDGET_PENDING_ITEMS(ii)
2830 /* Possibly update the face. */
2831 if (IMAGE_INSTANCE_WIDGET_FACE_CHANGED(ii)
2833 XFRAME(IMAGE_INSTANCE_FRAME(ii))->faces_changed
2834 || IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED(ii)) {
2835 /* See previous comments on the brokeness of lwlib.
2837 #### There's actually not much point in doing this here
2838 since, colors will have been set appropriately by
2839 x_redisplay_widget. */
2840 widget_value *wv = copy_widget_value_tree
2841 (lw_get_all_values(IMAGE_INSTANCE_X_WIDGET_LWID(ii)),
2844 update_tab_widget_face(wv, ii, IMAGE_INSTANCE_FRAME(ii));
2846 lw_modify_all_widgets(IMAGE_INSTANCE_X_WIDGET_LWID(ii), wv,
2848 free_widget_value_tree(wv);
2852 /* instantiate a static control possible for putting other things in */
2854 x_label_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
2855 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2856 int dest_mask, Lisp_Object domain)
2858 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2859 Lisp_Object gui = IMAGE_INSTANCE_WIDGET_ITEM(ii);
2860 widget_value *wv = gui_items_to_widget_values(image_instance, gui, 0);
2862 x_widget_instantiate(image_instance, instantiator, pointer_fg,
2863 pointer_bg, dest_mask, domain, "button", wv);
2865 #endif /* HAVE_WIDGETS */
2867 /************************************************************************/
2868 /* initialization */
2869 /************************************************************************/
2871 void syms_of_glyphs_x(void)
2874 DEFSUBR(Fchange_subwindow_property);
2878 void console_type_create_glyphs_x(void)
2882 CONSOLE_HAS_METHOD(x, print_image_instance);
2883 CONSOLE_HAS_METHOD(x, finalize_image_instance);
2884 CONSOLE_HAS_METHOD(x, image_instance_equal);
2885 CONSOLE_HAS_METHOD(x, image_instance_hash);
2886 CONSOLE_HAS_METHOD(x, colorize_image_instance);
2887 CONSOLE_HAS_METHOD(x, init_image_instance_from_eimage);
2888 CONSOLE_HAS_METHOD(x, locate_pixmap_file);
2889 CONSOLE_HAS_METHOD(x, unmap_subwindow);
2890 CONSOLE_HAS_METHOD(x, map_subwindow);
2891 CONSOLE_HAS_METHOD(x, redisplay_widget);
2892 CONSOLE_HAS_METHOD(x, redisplay_subwindow);
2893 CONSOLE_HAS_METHOD(x, widget_border_width);
2896 void image_instantiator_format_create_glyphs_x(void)
2898 IIFORMAT_VALID_CONSOLE(x, nothing);
2899 IIFORMAT_VALID_CONSOLE(x, string);
2901 IIFORMAT_VALID_CONSOLE(x, layout);
2903 IIFORMAT_VALID_CONSOLE(x, formatted_string);
2904 IIFORMAT_VALID_CONSOLE(x, inherit);
2906 INITIALIZE_DEVICE_IIFORMAT(x, xpm);
2907 IIFORMAT_HAS_DEVMETHOD(x, xpm, instantiate);
2910 IIFORMAT_VALID_CONSOLE(x, jpeg);
2913 IIFORMAT_VALID_CONSOLE(x, tiff);
2915 #if defined WITH_PNG && defined HAVE_PNG
2916 IIFORMAT_VALID_CONSOLE(x, png);
2919 IIFORMAT_VALID_CONSOLE(x, gif);
2922 IIFORMAT_VALID_CONSOLE(x, rawrgb);
2923 IIFORMAT_VALID_CONSOLE(x, rawrgba);
2926 INITIALIZE_DEVICE_IIFORMAT(x, xbm);
2927 IIFORMAT_HAS_DEVMETHOD(x, xbm, instantiate);
2929 INITIALIZE_DEVICE_IIFORMAT(x, subwindow);
2930 IIFORMAT_HAS_DEVMETHOD(x, subwindow, instantiate);
2933 INITIALIZE_DEVICE_IIFORMAT(x, native_layout);
2934 IIFORMAT_HAS_DEVMETHOD(x, native_layout, instantiate);
2936 INITIALIZE_DEVICE_IIFORMAT(x, button);
2937 IIFORMAT_HAS_DEVMETHOD(x, button, property);
2938 IIFORMAT_HAS_DEVMETHOD(x, button, instantiate);
2939 IIFORMAT_HAS_DEVMETHOD(x, button, redisplay);
2940 /* general widget methods. */
2941 INITIALIZE_DEVICE_IIFORMAT(x, widget);
2942 IIFORMAT_HAS_DEVMETHOD(x, widget, property);
2943 /* progress gauge */
2944 INITIALIZE_DEVICE_IIFORMAT(x, progress_gauge);
2945 IIFORMAT_HAS_DEVMETHOD(x, progress_gauge, redisplay);
2946 IIFORMAT_HAS_DEVMETHOD(x, progress_gauge, instantiate);
2948 INITIALIZE_DEVICE_IIFORMAT(x, edit_field);
2949 IIFORMAT_HAS_DEVMETHOD(x, edit_field, instantiate);
2950 #if defined (LWLIB_WIDGETS_MOTIF) && XmVERSION > 1
2952 INITIALIZE_DEVICE_IIFORMAT(x, combo_box);
2953 IIFORMAT_HAS_DEVMETHOD(x, combo_box, instantiate);
2954 IIFORMAT_HAS_SHARED_DEVMETHOD(x, combo_box, redisplay, tab_control);
2956 /* tab control widget */
2957 INITIALIZE_DEVICE_IIFORMAT(x, tab_control);
2958 IIFORMAT_HAS_DEVMETHOD(x, tab_control, instantiate);
2959 IIFORMAT_HAS_DEVMETHOD(x, tab_control, redisplay);
2961 INITIALIZE_DEVICE_IIFORMAT(x, label);
2962 IIFORMAT_HAS_DEVMETHOD(x, label, instantiate);
2964 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(cursor_font, "cursor-font");
2965 IIFORMAT_VALID_CONSOLE(x, cursor_font);
2967 IIFORMAT_HAS_METHOD(cursor_font, validate);
2968 IIFORMAT_HAS_METHOD(cursor_font, possible_dest_types);
2969 IIFORMAT_HAS_METHOD(cursor_font, instantiate);
2971 IIFORMAT_VALID_KEYWORD(cursor_font, Q_data, check_valid_string);
2972 IIFORMAT_VALID_KEYWORD(cursor_font, Q_foreground, check_valid_string);
2973 IIFORMAT_VALID_KEYWORD(cursor_font, Q_background, check_valid_string);
2975 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(font, "font");
2977 IIFORMAT_HAS_METHOD(font, validate);
2978 IIFORMAT_HAS_METHOD(font, possible_dest_types);
2979 IIFORMAT_HAS_METHOD(font, instantiate);
2980 IIFORMAT_VALID_CONSOLE(x, font);
2982 IIFORMAT_VALID_KEYWORD(font, Q_data, check_valid_string);
2983 IIFORMAT_VALID_KEYWORD(font, Q_foreground, check_valid_string);
2984 IIFORMAT_VALID_KEYWORD(font, Q_background, check_valid_string);
2987 INITIALIZE_DEVICE_IIFORMAT(x, xface);
2988 IIFORMAT_HAS_DEVMETHOD(x, xface, instantiate);
2991 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(autodetect, "autodetect");
2993 IIFORMAT_HAS_METHOD(autodetect, validate);
2994 IIFORMAT_HAS_METHOD(autodetect, normalize);
2995 IIFORMAT_HAS_METHOD(autodetect, possible_dest_types);
2996 /* #### autodetect is flawed IMO:
2997 1. It makes the assumption that you can detect whether the user
2998 wanted a cursor or a string based on the data, since the data is a
2999 string you have to prioritise cursors. Instead we will force users
3000 to pick the appropriate image type, this is what we do under
3002 2. It doesn't fit with the new domain model - you cannot tell which
3003 domain it needs to be instantiated in until you've actually
3004 instantiated it, which mucks up caching.
3005 3. It only copes with cursors and strings which seems bogus. */
3006 IIFORMAT_HAS_SHARED_METHOD(autodetect, governing_domain, subwindow);
3007 IIFORMAT_HAS_METHOD(autodetect, instantiate);
3008 IIFORMAT_VALID_CONSOLE(x, autodetect);
3010 IIFORMAT_VALID_KEYWORD(autodetect, Q_data, check_valid_string);
3013 void vars_of_glyphs_x(void)
3015 DEFVAR_LISP("x-bitmap-file-path", &Vx_bitmap_file_path /*
3016 A list of the directories in which X bitmap files may be found.
3017 If nil, this is initialized from the "*bitmapFilePath" resource.
3018 This is used by the `make-image-instance' function (however, note that if
3019 the environment variable XBMLANGPATH is set, it is consulted first).
3021 Vx_bitmap_file_path = Qnil;
3024 void complex_vars_of_glyphs_x(void)
3026 #define BUILD_GLYPH_INST(variable, name) \
3027 Fadd_spec_to_specifier \
3028 (GLYPH_IMAGE (XGLYPH (variable)), \
3029 vector3 (Qxbm, Q_data, \
3030 list3 (make_int (name##_width), \
3031 make_int (name##_height), \
3032 make_ext_string ((Extbyte *) name##_bits, \
3033 sizeof (name##_bits), \
3037 BUILD_GLYPH_INST(Vtruncation_glyph, truncator);
3038 BUILD_GLYPH_INST(Vcontinuation_glyph, continuer);
3039 BUILD_GLYPH_INST(Vsxemacs_logo, sxemacs);
3040 BUILD_GLYPH_INST(Vhscroll_glyph, hscroll);
3042 #undef BUILD_GLYPH_INST