comparison src/objects-gtk.c @ 462:0784d089fdc9 r21-2-46

Import from CVS: tag r21-2-46
author cvs
date Mon, 13 Aug 2007 11:44:37 +0200
parents
children 183866b06e0b
comparison
equal deleted inserted replaced
461:120ed4009e51 462:0784d089fdc9
1 /* X-specific Lisp objects.
2 Copyright (C) 1993, 1994 Free Software Foundation, Inc.
3 Copyright (C) 1995 Board of Trustees, University of Illinois.
4 Copyright (C) 1995 Tinker Systems.
5 Copyright (C) 1995, 1996 Ben Wing.
6 Copyright (C) 1995 Sun Microsystems, Inc.
7
8 This file is part of XEmacs.
9
10 XEmacs is free software; you can redistribute it and/or modify it
11 under the terms of the GNU General Public License as published by the
12 Free Software Foundation; either version 2, or (at your option) any
13 later version.
14
15 XEmacs is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with XEmacs; see the file COPYING. If not, write to
22 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 Boston, MA 02111-1307, USA. */
24
25 /* Synched up with: Not in FSF. */
26
27 /* Authors: Jamie Zawinski, Chuck Thompson, Ben Wing */
28 /* Gtk version by William Perry */
29
30 #include <config.h>
31 #include "lisp.h"
32
33 #include "console-gtk.h"
34 #include "objects-gtk.h"
35
36 #include "buffer.h"
37 #include "device.h"
38 #include "insdel.h"
39
40 /* sigh */
41 #include <gdk/gdkx.h>
42
43
44 /************************************************************************/
45 /* color instances */
46 /************************************************************************/
47
48 /* Replacement for XAllocColor() that tries to return the nearest
49 available color if the colormap is full. Original was from FSFmacs,
50 but rewritten by Jareth Hein <jareth@camelot-soft.com> 97/11/25
51 Modified by Lee Kindness <lkindness@csl.co.uk> 31/08/99 to handle previous
52 total failure which was due to a read/write colorcell being the nearest
53 match - tries the next nearest...
54
55 Gdk takes care of all this behind the scenes, so we don't need to
56 worry about it.
57
58 Return value is 1 for normal success, 2 for nearest color success,
59 3 for Non-deallocable sucess. */
60 int
61 allocate_nearest_color (GdkColormap *colormap, GdkVisual *visual,
62 GdkColor *color_def)
63 {
64 int rc;
65
66 rc = gdk_colormap_alloc_color (colormap, color_def, FALSE, TRUE);
67
68 if (rc == TRUE)
69 return (1);
70
71 return (0);
72 }
73
74 int
75 gtk_parse_nearest_color (struct device *d, GdkColor *color, Bufbyte *name,
76 Bytecount len, Error_behavior errb)
77 {
78 GdkColormap *cmap;
79 GdkVisual *visual;
80 int result;
81
82 cmap = DEVICE_GTK_COLORMAP(d);
83 visual = DEVICE_GTK_VISUAL (d);
84
85 xzero (*color);
86 {
87 const Extbyte *extname;
88 Extcount extnamelen;
89
90 TO_EXTERNAL_FORMAT (DATA, (name, len), ALLOCA, (extname, extnamelen), Qbinary);
91
92 result = gdk_color_parse (extname, color);
93 }
94
95 if (result == FALSE)
96 {
97 maybe_signal_simple_error ("unrecognized color", make_string (name, len),
98 Qcolor, errb);
99 return 0;
100 }
101 result = allocate_nearest_color (cmap, visual, color);
102 if (!result)
103 {
104 maybe_signal_simple_error ("couldn't allocate color",
105 make_string (name, len), Qcolor, errb);
106 return 0;
107 }
108
109 return result;
110 }
111
112 static int
113 gtk_initialize_color_instance (struct Lisp_Color_Instance *c, Lisp_Object name,
114 Lisp_Object device, Error_behavior errb)
115 {
116 GdkColor color;
117 int result;
118
119 result = gtk_parse_nearest_color (XDEVICE (device), &color,
120 XSTRING_DATA (name),
121 XSTRING_LENGTH (name),
122 errb);
123
124 if (!result)
125 return 0;
126
127 /* Don't allocate the data until we're sure that we will succeed,
128 or the finalize method may get fucked. */
129 c->data = xnew (struct gtk_color_instance_data);
130 if (result == 3)
131 COLOR_INSTANCE_GTK_DEALLOC (c) = 0;
132 else
133 COLOR_INSTANCE_GTK_DEALLOC (c) = 1;
134 COLOR_INSTANCE_GTK_COLOR (c) = gdk_color_copy (&color);
135 return 1;
136 }
137
138 static void
139 gtk_print_color_instance (struct Lisp_Color_Instance *c,
140 Lisp_Object printcharfun,
141 int escapeflag)
142 {
143 char buf[100];
144 GdkColor *color = COLOR_INSTANCE_GTK_COLOR (c);
145 sprintf (buf, " %ld=(%X,%X,%X)",
146 color->pixel, color->red, color->green, color->blue);
147 write_c_string (buf, printcharfun);
148 }
149
150 static void
151 gtk_finalize_color_instance (struct Lisp_Color_Instance *c)
152 {
153 if (c->data)
154 {
155 if (DEVICE_LIVE_P (XDEVICE (c->device)))
156 {
157 if (COLOR_INSTANCE_GTK_DEALLOC (c))
158 {
159 gdk_colormap_free_colors (DEVICE_GTK_COLORMAP (XDEVICE (c->device)),
160 COLOR_INSTANCE_GTK_COLOR (c), 1);
161 }
162 gdk_color_free (COLOR_INSTANCE_GTK_COLOR (c));
163 }
164 xfree (c->data);
165 c->data = 0;
166 }
167 }
168
169 /* Color instances are equal if they resolve to the same color on the
170 screen (have the same RGB values). I imagine that
171 "same RGB values" == "same cell in the colormap." Arguably we should
172 be comparing their names or pixel values instead. */
173
174 static int
175 gtk_color_instance_equal (struct Lisp_Color_Instance *c1,
176 struct Lisp_Color_Instance *c2,
177 int depth)
178 {
179 return (gdk_color_equal (COLOR_INSTANCE_GTK_COLOR (c1),
180 COLOR_INSTANCE_GTK_COLOR (c2)));
181 }
182
183 static unsigned long
184 gtk_color_instance_hash (struct Lisp_Color_Instance *c, int depth)
185 {
186 return (gdk_color_hash (COLOR_INSTANCE_GTK_COLOR (c), NULL));
187 }
188
189 static Lisp_Object
190 gtk_color_instance_rgb_components (struct Lisp_Color_Instance *c)
191 {
192 GdkColor *color = COLOR_INSTANCE_GTK_COLOR (c);
193 return (list3 (make_int (color->red),
194 make_int (color->green),
195 make_int (color->blue)));
196 }
197
198 static int
199 gtk_valid_color_name_p (struct device *d, Lisp_Object color)
200 {
201 GdkColor c;
202 const char *extname;
203
204 TO_EXTERNAL_FORMAT (LISP_STRING, color, C_STRING_ALLOCA, extname, Qctext);
205
206 if (gdk_color_parse (extname, &c) != TRUE)
207 return(0);
208 return (1);
209 }
210
211
212 /************************************************************************/
213 /* font instances */
214 /************************************************************************/
215
216 static int
217 gtk_initialize_font_instance (struct Lisp_Font_Instance *f, Lisp_Object name,
218 Lisp_Object device, Error_behavior errb)
219 {
220 GdkFont *gf;
221 XFontStruct *xf;
222 const char *extname;
223
224 TO_EXTERNAL_FORMAT (LISP_STRING, f->name, C_STRING_ALLOCA, extname, Qctext);
225
226 gf = gdk_font_load (extname);
227
228 if (!gf)
229 {
230 maybe_signal_simple_error ("couldn't load font", f->name,
231 Qfont, errb);
232 return 0;
233 }
234
235 xf = GDK_FONT_XFONT (gf);
236
237 /* Don't allocate the data until we're sure that we will succeed,
238 or the finalize method may get fucked. */
239 f->data = xnew (struct gtk_font_instance_data);
240 FONT_INSTANCE_GTK_TRUENAME (f) = Qnil;
241 FONT_INSTANCE_GTK_FONT (f) = gf;
242 f->ascent = gf->ascent;
243 f->descent = gf->descent;
244 f->height = gf->ascent + gf->descent;
245
246 /* Now lets figure out the width of the font */
247 {
248 /* following change suggested by Ted Phelps <phelps@dstc.edu.au> */
249 unsigned int def_char = 'n'; /*xf->default_char;*/
250 unsigned int byte1, byte2;
251
252 once_more:
253 byte1 = def_char >> 8;
254 byte2 = def_char & 0xFF;
255
256 if (xf->per_char)
257 {
258 /* Old versions of the R5 font server have garbage (>63k) as
259 def_char. 'n' might not be a valid character. */
260 if (byte1 < xf->min_byte1 ||
261 byte1 > xf->max_byte1 ||
262 byte2 < xf->min_char_or_byte2 ||
263 byte2 > xf->max_char_or_byte2)
264 f->width = 0;
265 else
266 f->width = xf->per_char[(byte1 - xf->min_byte1) *
267 (xf->max_char_or_byte2 -
268 xf->min_char_or_byte2 + 1) +
269 (byte2 - xf->min_char_or_byte2)].width;
270 }
271 else
272 f->width = xf->max_bounds.width;
273
274 /* Some fonts have a default char whose width is 0. This is no good.
275 If that's the case, first try 'n' as the default char, and if n has
276 0 width too (unlikely) then just use the max width. */
277 if (f->width == 0)
278 {
279 if (def_char == xf->default_char)
280 f->width = xf->max_bounds.width;
281 else
282 {
283 def_char = xf->default_char;
284 goto once_more;
285 }
286 }
287 }
288
289 /* If all characters don't exist then there could potentially be
290 0-width characters lurking out there. Not setting this flag
291 trips an optimization that would make them appear to have width
292 to redisplay. This is bad. So we set it if not all characters
293 have the same width or if not all characters are defined.
294 */
295 /* #### This sucks. There is a measurable performance increase
296 when using proportional width fonts if this flag is not set.
297 Unfortunately so many of the fucking X fonts are not fully
298 defined that we could almost just get rid of this damn flag and
299 make it an assertion. */
300 f->proportional_p = (xf->min_bounds.width != xf->max_bounds.width ||
301 (/* x_handle_non_fully_specified_fonts */ 0 &&
302 !xf->all_chars_exist));
303 #if 0
304 f->width = gdk_char_width (gf, 'n');
305 f->proportional_p = (gdk_char_width (gf, '|') != gdk_char_width (gf, 'W')) ? 1 : 0;
306 #endif
307 return 1;
308 }
309
310 static void
311 gtk_mark_font_instance (struct Lisp_Font_Instance *f)
312 {
313 mark_object (FONT_INSTANCE_GTK_TRUENAME (f));
314 }
315
316 static void
317 gtk_print_font_instance (struct Lisp_Font_Instance *f,
318 Lisp_Object printcharfun,
319 int escapeflag)
320 {
321 char buf[200];
322 sprintf (buf, " 0x%lx", (unsigned long) gdk_font_id (FONT_INSTANCE_GTK_FONT (f)));
323 write_c_string (buf, printcharfun);
324 }
325
326 static void
327 gtk_finalize_font_instance (struct Lisp_Font_Instance *f)
328 {
329 if (f->data)
330 {
331 if (DEVICE_LIVE_P (XDEVICE (f->device)))
332 {
333 gdk_font_unref (FONT_INSTANCE_GTK_FONT (f));
334 }
335 xfree (f->data);
336 f->data = 0;
337 }
338 }
339
340 /* Forward declarations for X specific functions at the end of the file */
341 Lisp_Object __get_gtk_font_truename (GdkFont *gdk_font, int expandp);
342 static Lisp_Object __gtk_list_fonts_internal (const char *pattern);
343
344 static Lisp_Object
345 gtk_font_instance_truename (struct Lisp_Font_Instance *f, Error_behavior errb)
346 {
347 if (NILP (FONT_INSTANCE_GTK_TRUENAME (f)))
348 {
349 FONT_INSTANCE_GTK_TRUENAME (f) = __get_gtk_font_truename (FONT_INSTANCE_GTK_FONT (f), 1);
350
351 if (NILP (FONT_INSTANCE_GTK_TRUENAME (f)))
352 {
353 /* Ok, just this once, return the font name as the truename.
354 (This is only used by Fequal() right now.) */
355 return f->name;
356 }
357 }
358 return (FONT_INSTANCE_GTK_TRUENAME (f));
359 }
360
361 static Lisp_Object
362 gtk_font_instance_properties (struct Lisp_Font_Instance *f)
363 {
364 Lisp_Object result = Qnil;
365
366 /* #### BILL!!! */
367 /* There seems to be no way to get this information under Gtk */
368 return result;
369 }
370
371 static Lisp_Object
372 gtk_list_fonts (Lisp_Object pattern, Lisp_Object device)
373 {
374 const char *patternext;
375
376 TO_EXTERNAL_FORMAT (LISP_STRING, pattern, C_STRING_ALLOCA, patternext, Qbinary);
377
378 return (__gtk_list_fonts_internal (patternext));
379 }
380
381 #ifdef MULE
382
383 static int
384 gtk_font_spec_matches_charset (struct device *d, Lisp_Object charset,
385 const Bufbyte *nonreloc, Lisp_Object reloc,
386 Bytecount offset, Bytecount length)
387 {
388 if (UNBOUNDP (charset))
389 return 1;
390 /* Hack! Short font names don't have the registry in them,
391 so we just assume the user knows what they're doing in the
392 case of ASCII. For other charsets, you gotta give the
393 long form; sorry buster.
394 */
395 if (EQ (charset, Vcharset_ascii))
396 {
397 const Bufbyte *the_nonreloc = nonreloc;
398 int i;
399 Bytecount the_length = length;
400
401 if (!the_nonreloc)
402 the_nonreloc = XSTRING_DATA (reloc);
403 fixup_internal_substring (nonreloc, reloc, offset, &the_length);
404 the_nonreloc += offset;
405 if (!memchr (the_nonreloc, '*', the_length))
406 {
407 for (i = 0;; i++)
408 {
409 const Bufbyte *new_nonreloc = (const Bufbyte *)
410 memchr (the_nonreloc, '-', the_length);
411 if (!new_nonreloc)
412 break;
413 new_nonreloc++;
414 the_length -= new_nonreloc - the_nonreloc;
415 the_nonreloc = new_nonreloc;
416 }
417
418 /* If it has less than 5 dashes, it's a short font.
419 Of course, long fonts always have 14 dashes or so, but short
420 fonts never have more than 1 or 2 dashes, so this is some
421 sort of reasonable heuristic. */
422 if (i < 5)
423 return 1;
424 }
425 }
426
427 return (fast_string_match (XCHARSET_REGISTRY (charset),
428 nonreloc, reloc, offset, length, 1,
429 ERROR_ME, 0) >= 0);
430 }
431
432 /* find a font spec that matches font spec FONT and also matches
433 (the registry of) CHARSET. */
434 static Lisp_Object gtk_find_charset_font (Lisp_Object device, Lisp_Object font, Lisp_Object charset);
435
436 #endif /* MULE */
437
438
439 /************************************************************************/
440 /* initialization */
441 /************************************************************************/
442
443 void
444 syms_of_objects_gtk (void)
445 {
446 }
447
448 void
449 console_type_create_objects_gtk (void)
450 {
451 /* object methods */
452
453 CONSOLE_HAS_METHOD (gtk, initialize_color_instance);
454 CONSOLE_HAS_METHOD (gtk, print_color_instance);
455 CONSOLE_HAS_METHOD (gtk, finalize_color_instance);
456 CONSOLE_HAS_METHOD (gtk, color_instance_equal);
457 CONSOLE_HAS_METHOD (gtk, color_instance_hash);
458 CONSOLE_HAS_METHOD (gtk, color_instance_rgb_components);
459 CONSOLE_HAS_METHOD (gtk, valid_color_name_p);
460
461 CONSOLE_HAS_METHOD (gtk, initialize_font_instance);
462 CONSOLE_HAS_METHOD (gtk, mark_font_instance);
463 CONSOLE_HAS_METHOD (gtk, print_font_instance);
464 CONSOLE_HAS_METHOD (gtk, finalize_font_instance);
465 CONSOLE_HAS_METHOD (gtk, font_instance_truename);
466 CONSOLE_HAS_METHOD (gtk, font_instance_properties);
467 CONSOLE_HAS_METHOD (gtk, list_fonts);
468 #ifdef MULE
469 CONSOLE_HAS_METHOD (gtk, find_charset_font);
470 CONSOLE_HAS_METHOD (gtk, font_spec_matches_charset);
471 #endif
472 }
473
474 void
475 vars_of_objects_gtk (void)
476 {
477 }
478
479 /* #### BILL!!! Try to make this go away eventually */
480 /* X Specific stuff */
481 #include <X11/Xatom.h>
482
483 /* Unbounded, for sufficiently small values of infinity... */
484 #define MAX_FONT_COUNT 5000
485
486 #ifdef MULE
487 /* find a font spec that matches font spec FONT and also matches
488 (the registry of) CHARSET. */
489 static Lisp_Object
490 gtk_find_charset_font (Lisp_Object device, Lisp_Object font, Lisp_Object charset)
491 {
492 char **names;
493 int count = 0;
494 Lisp_Object result = Qnil;
495 const char *patternext;
496 int i;
497
498 TO_EXTERNAL_FORMAT (LISP_STRING, font, C_STRING_ALLOCA, patternext, Qbinary);
499
500 names = XListFonts (GDK_DISPLAY (),
501 patternext, MAX_FONT_COUNT, &count);
502 /* ### This code seems awfully bogus -- mrb */
503 for (i = 0; i < count; i ++)
504 {
505 const Bufbyte *intname;
506 Bytecount intlen;
507
508 TO_INTERNAL_FORMAT (C_STRING, names[i], ALLOCA, (intname, intlen),
509 Qctext);
510 if (gtk_font_spec_matches_charset (XDEVICE (device), charset,
511 intname, Qnil, 0, -1))
512 {
513 result = make_string ((char *) intname, intlen);
514 break;
515 }
516 }
517
518 if (names)
519 XFreeFontNames (names);
520
521 /* Check for a short font name. */
522 if (NILP (result)
523 && gtk_font_spec_matches_charset (XDEVICE (device), charset, 0,
524 font, 0, -1))
525 return font;
526
527 return result;
528 }
529 #endif /* MULE */
530
531 /* Unbounded, for sufficiently small values of infinity... */
532 #define MAX_FONT_COUNT 5000
533
534 static int
535 valid_font_name_p (Display *dpy, char *name)
536 {
537 /* Maybe this should be implemented by callign XLoadFont and trapping
538 the error. That would be a lot of work, and wasteful as hell, but
539 might be more correct.
540 */
541 int nnames = 0;
542 char **names = 0;
543 if (! name)
544 return 0;
545 names = XListFonts (dpy, name, 1, &nnames);
546 if (names)
547 XFreeFontNames (names);
548 return (nnames != 0);
549 }
550
551 Lisp_Object
552 __get_gtk_font_truename (GdkFont *gdk_font, int expandp)
553 {
554 Display *dpy = GDK_FONT_XDISPLAY (gdk_font);
555 GSList *names = ((GdkFontPrivate *) gdk_font)->names;
556 Lisp_Object font_name = Qnil;
557
558 while (names)
559 {
560 if (names->data)
561 {
562 if (valid_font_name_p (dpy, names->data))
563 {
564 if (!expandp)
565 {
566 /* They want the wildcarded version */
567 font_name = build_string (names->data);
568 }
569 else
570 {
571 /* Need to expand out */
572 int nnames = 0;
573 char **x_font_names = 0;
574
575 x_font_names = XListFonts (dpy, names->data, 1, &nnames);
576 if (x_font_names)
577 {
578 font_name = build_string (x_font_names[0]);
579 XFreeFontNames (x_font_names);
580 }
581 }
582 break;
583 }
584 }
585 names = names->next;
586 }
587 return (font_name);
588 }
589
590 static Lisp_Object __gtk_list_fonts_internal (const char *pattern)
591 {
592 char **names;
593 int count = 0;
594 Lisp_Object result = Qnil;
595
596 names = XListFonts (GDK_DISPLAY (), pattern, MAX_FONT_COUNT, &count);
597 while (count--)
598 result = Fcons (build_ext_string (names [count], Qbinary), result);
599 if (names)
600 XFreeFontNames (names);
601
602 return result;
603 }