Mercurial > hg > xemacs-beta
comparison src/redisplay-xlike-inc.c @ 4933:77e3b19bd245
merge
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Sun, 24 Jan 2010 22:06:20 -0600 |
parents | ea701c23ed84 |
children | e813cf16c015 |
comparison
equal
deleted
inserted
replaced
4883:f730384b8ddf | 4933:77e3b19bd245 |
---|---|
1 /* Common code between X and GTK. | |
2 Copyright (C) 1994, 1995 Board of Trustees, University of Illinois. | |
3 Copyright (C) 1994 Lucid, Inc. | |
4 Copyright (C) 1995 Sun Microsystems, Inc. | |
5 Copyright (C) 2002, 2003, 2005, 2009, 2010 Ben Wing. | |
6 | |
7 This file is part of XEmacs. | |
8 | |
9 XEmacs is free software; you can redistribute it and/or modify it | |
10 under the terms of the GNU General Public License as published by the | |
11 Free Software Foundation; either version 2, or (at your option) any | |
12 later version. | |
13 | |
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
17 for more details. | |
18 | |
19 You should have received a copy of the GNU General Public License | |
20 along with XEmacs; see the file COPYING. If not, write to | |
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
22 Boston, MA 02111-1307, USA. */ | |
23 | |
24 /* Synched up with: Not in FSF. */ | |
25 | |
26 /* Author: Chuck Thompson */ | |
27 /* Gtk flavor by William Perry */ | |
28 /* X and GTK code merged by Ben Wing, 1-10 */ | |
29 | |
30 /* Lots of work done by Ben Wing for Mule */ | |
31 | |
32 #include <config.h> | |
33 #include "lisp.h" | |
34 | |
35 #include "buffer.h" | |
36 #include "debug.h" | |
37 #include "device-impl.h" | |
38 #include "faces.h" | |
39 #include "file-coding.h" | |
40 #include "frame-impl.h" | |
41 #include "gutter.h" | |
42 #include "redisplay.h" | |
43 #include "sysdep.h" | |
44 #include "window.h" | |
45 | |
46 #ifdef MULE | |
47 #include "mule-ccl.h" | |
48 #endif | |
49 #include "charset.h" | |
50 | |
51 #ifdef THIS_IS_X | |
52 #include "console-x-impl.h" | |
53 #include "glyphs-x.h" | |
54 #include "objects-x-impl.h" | |
55 #include "xgccache.h" | |
56 #else /* THIS_IS_GTK */ | |
57 #include "console-gtk-impl.h" | |
58 #include "gccache-gtk.h" | |
59 #include "glyphs-gtk.h" | |
60 #include "objects-gtk-impl.h" | |
61 #endif /* THIS_IS_GTK */ | |
62 | |
63 #include "EmacsFrame.h" | |
64 #include "EmacsFrameP.h" | |
65 | |
66 #include "sysproc.h" /* for select() */ | |
67 | |
68 #ifdef THIS_IS_X | |
69 #include <X11/bitmaps/gray> | |
70 #endif /* THIS_IS_X */ | |
71 | |
72 #define EOL_CURSOR_WIDTH 5 | |
73 | |
74 /* About some of the types below: | |
75 | |
76 X has two ways of representing a color: (a) as an unsigned long | |
77 representing a color pixel value, i.e. the actual value stored in memory | |
78 or a file at a particular pixel location to indicate that the pixel | |
79 takes on a specific color; and (b) an XColor structure, which | |
80 encapsulates both the RGB components of a color and the associated color | |
81 pixel value. | |
82 | |
83 We call the former type XLIKE_PIXCOLOR and the latter XLIKE_COLOR. | |
84 GTK uses the same GdkColor structure for both, and normally passes in | |
85 a pointer. We provide routines to handle the two logical color types. */ | |
86 | |
87 #ifdef THIS_IS_X | |
88 | |
89 /***************************************************************************/ | |
90 /* Definitions implementing X flavor of XLIKE */ | |
91 /***************************************************************************/ | |
92 | |
93 #define XLIKE_NAME x | |
94 #define USED_IF_X(var) var | |
95 | |
96 /* types */ | |
97 #define XLIKE_DISPLAY Display * | |
98 #define XLIKE_WINDOW Window | |
99 #define XLIKE_GC GC | |
100 #define XLIKE_RECTANGLE XRectangle | |
101 #define XLIKE_GCVALUES XGCValues | |
102 #define XLIKE_COLOR XColor | |
103 #define XLIKE_PIXCOLOR unsigned long | |
104 | |
105 /* constants */ | |
106 #define XLIKE_NONE None | |
107 #define XLIKE_FALSE False | |
108 | |
109 #define XLIKE_GC_BACKGROUND GCBackground | |
110 #define XLIKE_GC_CLIP_MASK GCClipMask | |
111 #define XLIKE_GC_CLIP_X_ORIGIN GCClipXOrigin | |
112 #define XLIKE_GC_CLIP_Y_ORIGIN GCClipYOrigin | |
113 #define XLIKE_GC_EXPOSURES GCGraphicsExposures | |
114 #define XLIKE_GC_FILL GCFillStyle | |
115 #define XLIKE_GC_FONT GCFont | |
116 #define XLIKE_GC_FOREGROUND GCForeground | |
117 #define XLIKE_GC_FUNCTION GCFunction | |
118 #define XLIKE_GC_LINE_WIDTH GCLineWidth | |
119 #define XLIKE_GC_STIPPLE GCStipple | |
120 #define XLIKE_GC_TILE GCTile | |
121 | |
122 #define XLIKE_GX_COPY GXcopy | |
123 #define XLIKE_GX_XOR GXxor | |
124 | |
125 #define XLIKE_FILL_MEMBER fill_style | |
126 #define XLIKE_FILL_STIPPLED FillStippled | |
127 #define XLIKE_FILL_OPAQUE_STIPPLED FillOpaqueStippled | |
128 #define XLIKE_FILL_TILED FillTiled | |
129 #define XLIKE_FILL_SOLID FillSolid | |
130 | |
131 /* functions */ | |
132 #define GET_XLIKE_DISPLAY(d) DEVICE_X_DISPLAY (d) | |
133 #define GET_XLIKE_WINDOW(w) XtWindow (FRAME_X_TEXT_WIDGET (f)) | |
134 #define XLIKE_FILL_RECTANGLE(dpy, x_win, gc, x, y, width, height) \ | |
135 XFillRectangle (dpy, x_win, gc, x, y, width, height) | |
136 #define XLIKE_DRAW_RECTANGLE(dpy, x_win, gc, x, y, width, height) \ | |
137 XDrawRectangle (dpy, x_win, gc, x, y, width, height) | |
138 #define XLIKE_DRAW_LINE(dpy, x_win, gc, x1, y1, x2, y2) \ | |
139 XDrawLine (dpy, x_win, gc, x1, y1, x2, y2) | |
140 #define XLIKE_OUTPUT_XLIKE_PIXMAP x_output_x_pixmap | |
141 | |
142 #define XLIKE_DISPLAY_LINE_HEIGHT(dl) DISPLAY_LINE_HEIGHT (dl) | |
143 #define XLIKE_DISPLAY_LINE_YPOS(dl) DISPLAY_LINE_YPOS (dl) | |
144 #define XLIKE_DISPLAY_LINE_TOP_CLIP(dl) ((dl)->top_clip) | |
145 #define XLIKE_SET_CLIP_RECTANGLE(dpy, gc, xorig, yorig, prect) \ | |
146 /* #### why not Unsorted? */ \ | |
147 XSetClipRectangles (dpy, gc, xorig, yorig, prect, 1, YXBanded) | |
148 #define XLIKE_CLEAR_CLIP_MASK(dpy, gc) \ | |
149 do \ | |
150 { \ | |
151 XSetClipMask (dpy, gc, None); \ | |
152 XSetClipOrigin (dpy, gc, 0, 0); \ | |
153 } \ | |
154 while (0) | |
155 #define XLIKE_FLUSH(dpy) XSync (dpy, False) | |
156 #define XLIKE_CLEAR_AREA(dpy, win, x, y, width, height) \ | |
157 XClearArea (dpy, win, x, y, width, height, False) | |
158 | |
159 #define IMAGE_INSTANCE_XLIKE_MASK IMAGE_INSTANCE_X_MASK | |
160 #define XIMAGE_INSTANCE_XLIKE_PIXMAP XIMAGE_INSTANCE_X_PIXMAP | |
161 #define COLOR_INSTANCE_XLIKE_COLOR COLOR_INSTANCE_X_COLOR | |
162 #define FONT_INSTANCE_XLIKE_FONT FONT_INSTANCE_X_FONT | |
163 #define DEVICE_XLIKE_GC_CACHE DEVICE_X_GC_CACHE | |
164 #define DEVICE_XLIKE_GRAY_PIXMAP DEVICE_X_GRAY_PIXMAP | |
165 #define XLIKE_COLOR_TO_PIXCOLOR(ci) ((ci).pixel) | |
166 #define XLIKE_SET_PIXCOLOR_COPY(lval, rval) ((lval) = (rval)) | |
167 #define XLIKE_SET_PIXCOLOR_NUM(lval, rval) ((lval) = (rval)) | |
168 #define XLIKE_FONT_NUM(val) ((val)->fid) | |
169 | |
170 #define XLIKE_OUTPUT_XLIKE_PIXMAP x_output_x_pixmap | |
171 | |
172 /************ End X flavor of XLIKE **********/ | |
173 | |
174 | |
175 | |
176 | |
177 #else /* THIS_IS_GTK */ | |
178 | |
179 /***************************************************************************/ | |
180 /* Definitions implementing GTK flavor of XLIKE */ | |
181 /***************************************************************************/ | |
182 | |
183 #define XLIKE_NAME gtk | |
184 #define USED_IF_X(var) UNUSED (var) | |
185 | |
186 /*types */ | |
187 #define XLIKE_DISPLAY void * | |
188 #define XLIKE_WINDOW GdkWindow * | |
189 #define XLIKE_GC GdkGC * | |
190 #define XLIKE_RECTANGLE GdkRectangle | |
191 #define XLIKE_GCVALUES GdkGCValues | |
192 #define XLIKE_COLOR GdkColor * | |
193 #define XLIKE_PIXCOLOR GdkColor * | |
194 | |
195 /* constants */ | |
196 #define XLIKE_NONE 0 | |
197 #define XLIKE_FALSE FALSE | |
198 | |
199 #define XLIKE_GC_BACKGROUND GDK_GC_BACKGROUND | |
200 #define XLIKE_GC_CLIP_MASK GDK_GC_CLIP_MASK | |
201 #define XLIKE_GC_CLIP_X_ORIGIN GDK_GC_CLIP_X_ORIGIN | |
202 #define XLIKE_GC_CLIP_Y_ORIGIN GDK_GC_CLIP_Y_ORIGIN | |
203 #define XLIKE_GC_EXPOSURES GDK_GC_EXPOSURES | |
204 #define XLIKE_GC_FILL GDK_GC_FILL | |
205 #define XLIKE_GC_FONT GDK_GC_FONT | |
206 #define XLIKE_GC_FOREGROUND GDK_GC_FOREGROUND | |
207 #define XLIKE_GC_FUNCTION GDK_GC_FUNCTION | |
208 #define XLIKE_GC_LINE_WIDTH GDK_GC_LINE_WIDTH | |
209 #define XLIKE_GC_STIPPLE GDK_GC_STIPPLE | |
210 #define XLIKE_GC_TILE GDK_GC_TILE | |
211 | |
212 #define XLIKE_GX_COPY GDK_COPY | |
213 #define XLIKE_GX_XOR GDK_XOR | |
214 | |
215 #define XLIKE_FILL_MEMBER fill | |
216 #define XLIKE_FILL_STIPPLED GDK_STIPPLED | |
217 #define XLIKE_FILL_OPAQUE_STIPPLED GDK_OPAQUE_STIPPLED | |
218 #define XLIKE_FILL_TILED GDK_TILED | |
219 #define XLIKE_FILL_SOLID GDK_SOLID | |
220 | |
221 /* functions */ | |
222 | |
223 #define GET_XLIKE_DISPLAY(d) NULL | |
224 #define GET_XLIKE_WINDOW(w) GET_GTK_WIDGET_WINDOW (FRAME_GTK_TEXT_WIDGET (w)) | |
225 #define XLIKE_FILL_RECTANGLE(dpy, x_win, gc, x, y, width, height) \ | |
226 gdk_draw_rectangle (GDK_DRAWABLE (x_win), gc, TRUE, x, y, width, height) | |
227 #define XLIKE_DRAW_RECTANGLE(dpy, x_win, gc, x, y, width, height) \ | |
228 gdk_draw_rectangle (GDK_DRAWABLE (x_win), gc, FALSE, x, y, width, height) | |
229 #define XLIKE_DRAW_LINE(dpy, x_win, gc, x1, y1, x2, y2) \ | |
230 gdk_draw_line (GDK_DRAWABLE (x_win), gc, x1, y1, x2, y2) | |
231 #define XLIKE_OUTPUT_XLIKE_PIXMAP gtk_output_gdk_pixmap | |
232 | |
233 /* FIXME: This is totally bogus. It removes dl->top_clip from the | |
234 equations. If there is a bug involving this, fix it properly! | |
235 Or just ensure that top_clip is 0. */ | |
236 #define XLIKE_DISPLAY_LINE_HEIGHT(dl) \ | |
237 ((dl)->ascent + ((dl)->descent - (dl)->clip) | |
238 #define XLIKE_DISPLAY_LINE_YPOS(dl) ((dl)->ypos - (dl)->ascent) | |
239 #define XLIKE_DISPLAY_LINE_TOP_CLIP(dl) ((0) | |
240 #define XLIKE_SET_CLIP_RECTANGLE(dpy, gc, xorig, yorig, prect) \ | |
241 do \ | |
242 { \ | |
243 gdk_gc_set_clip_rectangle (gc, prect); \ | |
244 gdk_gc_set_clip_origin (gc, xorig, yorig); \ | |
245 } \ | |
246 while (0) | |
247 #define XLIKE_CLEAR_CLIP_MASK(dpy, gc) \ | |
248 do \ | |
249 { \ | |
250 gdk_gc_set_clip_rectangle (gc, NULL); \ | |
251 gdk_gc_set_clip_origin (gc, 0, 0); \ | |
252 } \ | |
253 while (0) | |
254 #define XLIKE_FLUSH(dpy) gdk_flush () | |
255 #define XLIKE_CLEAR_AREA(dpy, win, x, y, width, height) \ | |
256 gdk_window_clear_area (win, x, y, width, height) | |
257 | |
258 #define IMAGE_INSTANCE_XLIKE_MASK IMAGE_INSTANCE_GTK_MASK | |
259 #define XIMAGE_INSTANCE_XLIKE_PIXMAP XIMAGE_INSTANCE_GTK_PIXMAP | |
260 #define COLOR_INSTANCE_XLIKE_COLOR COLOR_INSTANCE_GTK_COLOR | |
261 #define FONT_INSTANCE_XLIKE_FONT FONT_INSTANCE_GTK_FONT | |
262 #define DEVICE_XLIKE_GRAY_PIXMAP DEVICE_GTK_GRAY_PIXMAP | |
263 #define DEVICE_XLIKE_GC_CACHE DEVICE_GTK_GC_CACHE | |
264 #define XLIKE_COLOR_TO_PIXCOLOR(ci) (ci) | |
265 #define XLIKE_SET_PIXCOLOR_COPY(lval, rval) ((lval) = *(rval)) | |
266 #define XLIKE_SET_PIXCOLOR_NUM(lval, rval) ((lval).pixel = (rval)) | |
267 #define XLIKE_FONT_NUM(val) (val) | |
268 | |
269 #define XLIKE_OUTPUT_XLIKE_PIXMAP gtk_output_gdk_pixmap | |
270 | |
271 static void gtk_output_pixmap (struct window *w, | |
272 Lisp_Object image_instance, | |
273 struct display_box *db, | |
274 struct display_glyph_area *dga, | |
275 face_index findex, | |
276 int cursor_start, | |
277 int cursor_width, | |
278 int cursor_height, | |
279 int bgpixmap); | |
280 static void gtk_clear_region (Lisp_Object locale, struct device* d, | |
281 struct frame* f, face_index findex, int x, int y, | |
282 int width, int height, Lisp_Object fcolor, | |
283 Lisp_Object bcolor, | |
284 Lisp_Object background_pixmap); | |
285 static void gtk_bevel_modeline (struct window *w, struct display_line *dl); | |
286 | |
287 #if 0 | |
288 static void __describe_gc (GdkGC *); | |
289 #endif | |
290 | |
291 /************ End GTK flavor of XLIKE **********/ | |
292 | |
293 #endif /* (not) THIS_IS_X */ | |
294 | |
295 | |
296 | |
297 /***************************************************************************/ | |
298 /* Common definitions */ | |
299 /***************************************************************************/ | |
300 | |
301 #define XCOLOR_INSTANCE_XLIKE_COLOR(x) \ | |
302 COLOR_INSTANCE_XLIKE_COLOR (XCOLOR_INSTANCE (x)) | |
303 | |
304 #define XLIKE_PASTE_1(a,b) a##_##b | |
305 #define XLIKE_PASTE(a,b) XLIKE_PASTE_1(a,b) | |
306 #define XLIKE_CONSOLE_HAS_METHOD_1(xlike, name) CONSOLE_HAS_METHOD (xlike, name) | |
307 #define XLIKE_CONSOLE_HAS_METHOD(name) \ | |
308 XLIKE_CONSOLE_HAS_METHOD_1 (XLIKE_NAME, name) | |
309 | |
310 /* Device methods */ | |
311 | |
312 #define XLIKE_text_width XLIKE_PASTE (XLIKE_NAME, text_width) | |
313 #define XLIKE_output_display_block XLIKE_PASTE (XLIKE_NAME, output_display_block) | |
314 #define XLIKE_divider_height XLIKE_PASTE (XLIKE_NAME, divider_height) | |
315 #define XLIKE_eol_cursor_width XLIKE_PASTE (XLIKE_NAME, eol_cursor_width) | |
316 #define XLIKE_output_vertical_divider XLIKE_PASTE (XLIKE_NAME, output_vertical_divider) | |
317 #define XLIKE_clear_region XLIKE_PASTE (XLIKE_NAME, clear_region) | |
318 #define XLIKE_clear_frame XLIKE_PASTE (XLIKE_NAME, clear_frame) | |
319 #define XLIKE_flash XLIKE_PASTE (XLIKE_NAME, flash) | |
320 #define XLIKE_ring_bell XLIKE_PASTE (XLIKE_NAME, ring_bell) | |
321 #define XLIKE_bevel_area XLIKE_PASTE (XLIKE_NAME, bevel_area) | |
322 #define XLIKE_output_string XLIKE_PASTE (XLIKE_NAME, output_string) | |
323 #define XLIKE_output_pixmap XLIKE_PASTE (XLIKE_NAME, output_pixmap) | |
324 #define XLIKE_window_output_begin XLIKE_PASTE (XLIKE_NAME, window_output_begin) | |
325 #define XLIKE_window_output_end XLIKE_PASTE (XLIKE_NAME, window_output_end) | |
326 | |
327 /* Miscellaneous split functions */ | |
328 | |
329 #define console_type_create_redisplay_XLIKE XLIKE_PASTE (console_type_create_redisplay, XLIKE_NAME) | |
330 #define XLIKE_get_gc XLIKE_PASTE (XLIKE_NAME, get_gc) | |
331 #define XLIKE_output_blank XLIKE_PASTE (XLIKE_NAME, output_blank) | |
332 #define XLIKE_text_width_single_run XLIKE_PASTE (XLIKE_NAME, text_width_single_run) | |
333 | |
334 static void XLIKE_output_blank (struct window *w, struct display_line *dl, | |
335 struct rune *rb, int start_pixpos, | |
336 int cursor_start, int cursor_width); | |
337 static void XLIKE_output_horizontal_line (struct window *w, | |
338 struct display_line *dl, | |
339 struct rune *rb); | |
340 | |
341 static void XLIKE_output_vertical_divider (struct window *w, int clear); | |
342 | |
343 static void XLIKE_output_eol_cursor (struct window *w, | |
344 struct display_line *dl, | |
345 int xpos, face_index findex); | |
346 static void XLIKE_clear_frame (struct frame *f); | |
347 static void XLIKE_clear_frame_windows (Lisp_Object window); | |
348 static void XLIKE_window_output_begin (struct window *w); | |
349 static void XLIKE_window_output_end (struct window *w); | |
350 static void XLIKE_bevel_area (struct window *w, face_index findex, | |
351 int x, int y, int width, int height, | |
352 int shadow_thickness, int edges, | |
353 enum edge_style style); | |
354 static void XLIKE_ring_bell (struct device *d, int volume, int pitch, | |
355 int duration); | |
356 | |
357 /****************************************************************************/ | |
358 /* */ | |
359 /* Separate textual runs */ | |
360 /* */ | |
361 /****************************************************************************/ | |
362 | |
363 | |
364 /* Note: We do not use the Xmb*() functions and XFontSets, nor the | |
365 Motif XFontLists and CompoundStrings. | |
366 Those functions are generally losing for a number of reasons. | |
367 Most important, they only support one locale (e.g. you could | |
368 display Japanese and ASCII text, but not mixed Japanese/Chinese | |
369 text). You could maybe call setlocale() frequently to try to deal | |
370 with this, but that would generally fail because an XFontSet is | |
371 tied to one locale and won't have the other character sets in it. | |
372 | |
373 fontconfig (the font database for Xft) has some specifier-like | |
374 properties, but it's not sufficient (witness the existence of | |
375 Pango). Pango might do the trick, but it's not a cross-platform | |
376 solution; it would need significant advantages to be worth the | |
377 effort. | |
378 */ | |
379 | |
380 struct textual_run | |
381 { | |
382 Lisp_Object charset; | |
383 unsigned char *ptr; | |
384 int len; | |
385 int dimension; | |
386 }; | |
387 | |
388 /* Separate out the text in STR (an array of Ichars, not a string | |
389 representation) of length LEN into a series of runs, stored in | |
390 RUN_STORAGE. RUN_STORAGE is guaranteed to hold enough space for all | |
391 runs that could be generated from this text. Each run points to the a | |
392 stretch of text given simply by the position codes TEXT_STORAGE into a | |
393 series of textual runs of a particular charset. Also convert the | |
394 characters as necessary into the format needed by XDrawImageString(), | |
395 XDrawImageString16(), et al. This means converting to one or two byte | |
396 format, possibly tweaking the high bits, and possibly running a CCL | |
397 program. You must pre-allocate the space used and pass it in. (This is | |
398 done so you can ALLOCA () the space.) (2 * len) bytes must be allocated | |
399 for TEXT_STORAGE and (len * sizeof (struct textual_run)) bytes of | |
400 RUN_STORAGE, where LEN is the length of the dynarr. | |
401 | |
402 bufchar might not be fixed width (in the case of UTF-8). | |
403 | |
404 Returns the number of runs actually used. */ | |
405 | |
406 /* Notes on Xft implementation | |
407 | |
408 - With Unicode, we're no longer going to have repertoires reified as | |
409 charsets. (Not that we ever really did, what with corporate variants, | |
410 and so on.) So we really should be querying the face for the desired | |
411 font, rather than the character for the charset, and that's what would | |
412 determine the separation into runs. | |
413 - The widechar versions of fontconfig (and therefore Xft) functions | |
414 seem to be just bigendian Unicode. So there's actually no need to use | |
415 the 8-bit versions in computing runs and runes, it would seem. | |
416 */ | |
417 | |
418 #if !defined(USE_XFT) && !defined(MULE) | |
419 static int | |
420 separate_textual_runs_nomule (unsigned char *text_storage, | |
421 struct textual_run *run_storage, | |
422 const Ichar *str, Charcount len, | |
423 struct face_cachel *UNUSED(cachel)) | |
424 { | |
425 if (!len) | |
426 return 0; | |
427 | |
428 run_storage[0].ptr = text_storage; | |
429 run_storage[0].len = len; | |
430 run_storage[0].dimension = 1; | |
431 run_storage[0].charset = Qnil; | |
432 | |
433 while (len--) | |
434 *text_storage++ = *str++; | |
435 return 1; | |
436 } | |
437 #endif | |
438 | |
439 #if defined(USE_XFT) && !defined(MULE) | |
440 /* | |
441 Note that in this configuration the "Croatian hack" of using an 8-bit, | |
442 non-Latin-1 font to get localized display without Mule simply isn't | |
443 available. That's by design -- Unicode does not aid or abet that kind | |
444 of punning. | |
445 This means that the cast to XftChar16 gives the correct "conversion" to | |
446 UCS-2. | |
447 #### Is there an alignment issue with text_storage? | |
448 */ | |
449 static int | |
450 separate_textual_runs_xft_nomule (unsigned char *text_storage, | |
451 struct textual_run *run_storage, | |
452 const Ichar *str, Charcount len, | |
453 struct face_cachel *UNUSED(cachel)) | |
454 { | |
455 int i; | |
456 if (!len) | |
457 return 0; | |
458 | |
459 run_storage[0].ptr = text_storage; | |
460 run_storage[0].len = len; | |
461 run_storage[0].dimension = 2; | |
462 run_storage[0].charset = Qnil; | |
463 | |
464 for (i = 0; i < len; i++) | |
465 { | |
466 *(XftChar16 *)text_storage = str[i]; | |
467 text_storage += sizeof(XftChar16); | |
468 } | |
469 return 1; | |
470 } | |
471 #endif | |
472 | |
473 #if defined(USE_XFT) && defined(MULE) | |
474 static int | |
475 separate_textual_runs_xft_mule (unsigned char *text_storage, | |
476 struct textual_run *run_storage, | |
477 const Ichar *str, Charcount len, | |
478 struct face_cachel *UNUSED(cachel)) | |
479 { | |
480 Lisp_Object prev_charset = Qunbound; | |
481 int runs_so_far = 0, i; | |
482 | |
483 run_storage[0].ptr = text_storage; | |
484 run_storage[0].len = len; | |
485 run_storage[0].dimension = 2; | |
486 run_storage[0].charset = Qnil; | |
487 | |
488 for (i = 0; i < len; i++) | |
489 { | |
490 Ichar ch = str[i]; | |
491 Lisp_Object charset = ichar_charset(ch); | |
492 int ucs = ichar_to_unicode(ch); | |
493 | |
494 /* If UCS is less than zero or greater than 0xFFFF, set ucs2 to | |
495 REPLACMENT CHARACTER. */ | |
496 /* That means we can't handle characters outside of the BMP for now */ | |
497 ucs = (ucs & ~0xFFFF) ? 0xFFFD : ucs; | |
498 | |
499 if (!EQ (charset, prev_charset)) | |
500 { | |
501 if (runs_so_far) | |
502 run_storage[runs_so_far-1].len = (text_storage - run_storage[runs_so_far-1].ptr) >> 1; | |
503 run_storage[runs_so_far].ptr = text_storage; | |
504 run_storage[runs_so_far].dimension = 2; | |
505 run_storage[runs_so_far].charset = charset; | |
506 prev_charset = charset; | |
507 runs_so_far++; | |
508 } | |
509 | |
510 *(XftChar16 *)text_storage = ucs; | |
511 text_storage += sizeof(XftChar16); | |
512 } | |
513 | |
514 if (runs_so_far) | |
515 run_storage[runs_so_far-1].len = (text_storage - run_storage[runs_so_far-1].ptr) >> 1; | |
516 return runs_so_far; | |
517 } | |
518 #endif | |
519 | |
520 #if !defined(USE_XFT) && defined(MULE) | |
521 /* | |
522 This is the most complex function of this group, due to the various | |
523 indexing schemes used by different fonts. For our purposes, they | |
524 fall into three classes. Some fonts are indexed compatibly with ISO | |
525 2022; those fonts just use the Mule internal representation directly | |
526 (typically the high bit must be reset; this is determined by the `graphic' | |
527 flag). Some fonts are indexed by Unicode, specifically by UCS-2. These | |
528 are all translated using `ichar_to_unicode'. Finally some fonts have | |
529 irregular indexes, and must be translated ad hoc. In XEmacs ad hoc | |
530 translations are accomplished with CCL programs. */ | |
531 static int | |
532 separate_textual_runs_mule (unsigned char *text_storage, | |
533 struct textual_run *run_storage, | |
534 const Ichar *str, Charcount len, | |
535 struct face_cachel *cachel) | |
536 { | |
537 Lisp_Object prev_charset = Qunbound; | |
538 int runs_so_far = 0, i; | |
539 Ibyte charset_leading_byte = LEADING_BYTE_ASCII; | |
540 int dimension = 1, graphic = 0, need_ccl_conversion = 0; | |
541 Lisp_Object ccl_prog; | |
542 struct ccl_program char_converter; | |
543 | |
544 int translate_to_ucs_2 = 0; | |
545 | |
546 for (i = 0; i < len; i++) | |
547 { | |
548 Ichar ch = str[i]; | |
549 Lisp_Object charset; | |
550 int byte1, byte2; /* BREAKUP_ICHAR dereferences the addresses | |
551 of its arguments as pointer to int. */ | |
552 BREAKUP_ICHAR (ch, charset, byte1, byte2); | |
553 | |
554 if (!EQ (charset, prev_charset)) | |
555 { | |
556 /* At this point, dimension' and `prev_charset' refer to just- | |
557 completed run. `runs_so_far' and `text_storage' refer to the | |
558 run about to start. */ | |
559 if (runs_so_far) | |
560 { | |
561 /* Update metadata for previous run. */ | |
562 run_storage[runs_so_far - 1].len = | |
563 text_storage - run_storage[runs_so_far - 1].ptr; | |
564 if (2 == dimension) run_storage[runs_so_far - 1].len >>= 1; | |
565 } | |
566 | |
567 /* Compute metadata for current run. | |
568 First, classify font. | |
569 If the font is indexed by UCS-2, set `translate_to_ucs_2'. | |
570 Else if the charset has a CCL program, set `need_ccl_conversion'. | |
571 Else if the font is indexed by an ISO 2022 "graphic register", | |
572 set `graphic'. | |
573 These flags are almost mutually exclusive, but we're sloppy | |
574 about resetting "shadowed" flags. So the flags must be checked | |
575 in the proper order in computing byte1 and byte2, below. */ | |
576 charset_leading_byte = XCHARSET_LEADING_BYTE(charset); | |
577 translate_to_ucs_2 = | |
578 bit_vector_bit (FACE_CACHEL_FONT_FINAL_STAGE (cachel), | |
579 charset_leading_byte - MIN_LEADING_BYTE); | |
580 if (translate_to_ucs_2) | |
581 { | |
582 dimension = 2; | |
583 } | |
584 else | |
585 { | |
586 dimension = XCHARSET_DIMENSION (charset); | |
587 | |
588 /* Check for CCL charset. | |
589 If setup_ccl_program fails, we'll get a garbaged display. | |
590 This should never happen, and even if it does, it should | |
591 be harmless (unless the X server has buggy handling of | |
592 characters undefined in the font). It may be marginally | |
593 more useful to users and debuggers than substituting a | |
594 fixed replacement character. */ | |
595 ccl_prog = XCHARSET_CCL_PROGRAM (charset); | |
596 if ((!NILP (ccl_prog)) | |
597 && (setup_ccl_program (&char_converter, ccl_prog) >= 0)) | |
598 { | |
599 need_ccl_conversion = 1; | |
600 } | |
601 else | |
602 { | |
603 /* The charset must have an ISO 2022-compatible font index. | |
604 There are 2 "registers" (what such fonts use as index). | |
605 GL (graphic == 0) has the high bit of each octet reset, | |
606 GR (graphic == 1) has it set. */ | |
607 graphic = XCHARSET_GRAPHIC (charset); | |
608 need_ccl_conversion = 0; | |
609 } | |
610 } | |
611 | |
612 /* Initialize metadata for current run. */ | |
613 run_storage[runs_so_far].ptr = text_storage; | |
614 run_storage[runs_so_far].charset = charset; | |
615 run_storage[runs_so_far].dimension = dimension; | |
616 | |
617 /* Update loop variables. */ | |
618 prev_charset = charset; | |
619 runs_so_far++; | |
620 } | |
621 | |
622 /* Must check flags in this order. See comment above. */ | |
623 if (translate_to_ucs_2) | |
624 { | |
625 int ucs = ichar_to_unicode(ch); | |
626 /* If UCS is less than zero or greater than 0xFFFF, set ucs2 to | |
627 REPLACMENT CHARACTER. */ | |
628 ucs = (ucs & ~0xFFFF) ? 0xFFFD : ucs; | |
629 | |
630 byte1 = ucs >> 8; | |
631 byte2 = ucs; | |
632 } | |
633 else if (need_ccl_conversion) | |
634 { | |
635 char_converter.reg[0] = charset_leading_byte; | |
636 char_converter.reg[1] = byte1; | |
637 char_converter.reg[2] = byte2; | |
638 ccl_driver (&char_converter, 0, 0, 0, 0, CCL_MODE_ENCODING); | |
639 byte1 = char_converter.reg[1]; | |
640 byte2 = char_converter.reg[2]; | |
641 } | |
642 else if (graphic == 0) | |
643 { | |
644 byte1 &= 0x7F; | |
645 byte2 &= 0x7F; | |
646 } | |
647 else | |
648 { | |
649 byte1 |= 0x80; | |
650 byte2 |= 0x80; | |
651 } | |
652 | |
653 *text_storage++ = (unsigned char)byte1; | |
654 | |
655 if (2 == dimension) *text_storage++ = (unsigned char)byte2; | |
656 } | |
657 | |
658 if (runs_so_far) | |
659 { | |
660 run_storage[runs_so_far - 1].len = | |
661 text_storage - run_storage[runs_so_far - 1].ptr; | |
662 /* Dimension retains the relevant value for the run before it. */ | |
663 if (2 == dimension) | |
664 run_storage[runs_so_far - 1].len >>= 1; | |
665 } | |
666 | |
667 return runs_so_far; | |
668 } | |
669 #endif | |
670 | |
671 static int | |
672 separate_textual_runs (unsigned char *text_storage, | |
673 struct textual_run *run_storage, | |
674 const Ichar *str, Charcount len, | |
675 struct face_cachel *cachel) | |
676 { | |
677 #if defined(USE_XFT) && defined(MULE) | |
678 return separate_textual_runs_xft_mule (text_storage, run_storage, | |
679 str, len, cachel); | |
680 #endif | |
681 #if defined(USE_XFT) && !defined(MULE) | |
682 return separate_textual_runs_xft_nomule (text_storage, run_storage, | |
683 str, len, cachel); | |
684 #endif | |
685 #if !defined(USE_XFT) && defined(MULE) | |
686 return separate_textual_runs_mule (text_storage, run_storage, | |
687 str, len, cachel); | |
688 #endif | |
689 #if !defined(USE_XFT) && !defined(MULE) | |
690 return separate_textual_runs_nomule (text_storage, run_storage, | |
691 str, len, cachel); | |
692 #endif | |
693 } | |
694 | |
695 /****************************************************************************/ | |
696 /* */ | |
697 /* Xlike output routines */ | |
698 /* */ | |
699 /****************************************************************************/ | |
700 | |
701 static int | |
702 XLIKE_text_width_single_run (struct frame * USED_IF_XFT (f), | |
703 struct face_cachel *cachel, | |
704 struct textual_run *run) | |
705 { | |
706 Lisp_Object font_inst = FACE_CACHEL_FONT (cachel, run->charset); | |
707 Lisp_Font_Instance *fi = XFONT_INSTANCE (font_inst); | |
708 | |
709 if (!fi->proportional_p) | |
710 return fi->width * run->len; | |
711 #ifdef USE_XFT | |
712 else if (FONT_INSTANCE_X_XFTFONT (fi)) | |
713 { | |
714 static XGlyphInfo glyphinfo; | |
715 struct device *d = XDEVICE (f->device); | |
716 Display *dpy = DEVICE_X_DISPLAY (d); | |
717 | |
718 if (run->dimension == 2) | |
719 { | |
720 XftTextExtents16 (dpy, | |
721 FONT_INSTANCE_X_XFTFONT (fi), | |
722 (XftChar16 *) run->ptr, run->len, &glyphinfo); | |
723 } | |
724 else | |
725 { | |
726 XftTextExtents8 (dpy, | |
727 FONT_INSTANCE_X_XFTFONT (fi), | |
728 run->ptr, run->len, &glyphinfo); | |
729 } | |
730 | |
731 return glyphinfo.xOff; | |
732 } | |
733 #endif | |
734 else if (FONT_INSTANCE_XLIKE_FONT (fi)) | |
735 { | |
736 if (run->dimension == 2) | |
737 { | |
738 #ifdef THIS_IS_X | |
739 return XTextWidth16 (FONT_INSTANCE_X_FONT (fi), | |
740 (XChar2b *) run->ptr, run->len); | |
741 #else /* THIS_IS_GTK */ | |
742 /* stderr_out ("Measuring wide characters\n"); */ | |
743 return gdk_text_width_wc (FONT_INSTANCE_GTK_FONT (fi), | |
744 (GdkWChar *) run->ptr, run->len); | |
745 #endif /* THIS_IS_GTK */ | |
746 } | |
747 else | |
748 { | |
749 #ifdef THIS_IS_X | |
750 return XTextWidth (FONT_INSTANCE_X_FONT (fi), | |
751 (char *) run->ptr, run->len); | |
752 #else /* THIS_IS_GTK */ | |
753 return gdk_text_width (FONT_INSTANCE_GTK_FONT (fi), | |
754 (char *) run->ptr, run->len); | |
755 #endif /* THIS_IS_GTK */ | |
756 } | |
757 } | |
758 else | |
759 abort(); | |
760 return 0; /* shut up GCC */ | |
761 } | |
762 | |
763 /* | |
764 XLIKE_text_width | |
765 | |
766 Given a string and a merged face, return the string's length in pixels | |
767 when displayed in the fonts associated with the face. | |
768 */ | |
769 | |
770 static int | |
771 XLIKE_text_width (struct window *w, struct face_cachel *cachel, | |
772 const Ichar *str, Charcount len) | |
773 { | |
774 /* !!#### Needs review */ | |
775 int width_so_far = 0; | |
776 unsigned char *text_storage = (unsigned char *) ALLOCA (2 * len); | |
777 struct textual_run *runs = alloca_array (struct textual_run, len); | |
778 struct frame *f = WINDOW_XFRAME (w); | |
779 int nruns; | |
780 int i; | |
781 | |
782 nruns = separate_textual_runs (text_storage, runs, str, len, | |
783 cachel); | |
784 | |
785 for (i = 0; i < nruns; i++) | |
786 width_so_far += XLIKE_text_width_single_run (f, cachel, runs + i); | |
787 | |
788 return width_so_far; | |
789 } | |
790 | |
791 /***************************************************************************** | |
792 XLIKE_divider_height | |
793 | |
794 Return the height of the horizontal divider. This is a function because | |
795 divider_height is a device method. | |
796 | |
797 #### If we add etched horizontal divider lines this will have to get | |
798 smarter. | |
799 ****************************************************************************/ | |
800 static int | |
801 XLIKE_divider_height (void) | |
802 { | |
803 #ifdef THIS_IS_X | |
804 return 1; | |
805 #else /* THIS_IS_GTK */ | |
806 return 2; | |
807 #endif /* THIS_IS_GTK */ | |
808 } | |
809 | |
810 /***************************************************************************** | |
811 XLIKE_eol_cursor_width | |
812 | |
813 Return the width of the end-of-line cursor. This is a function | |
814 because eol_cursor_width is a device method. | |
815 ****************************************************************************/ | |
816 static int | |
817 XLIKE_eol_cursor_width (void) | |
818 { | |
819 return EOL_CURSOR_WIDTH; | |
820 } | |
821 | |
822 /***************************************************************************** | |
823 XLIKE_output_display_block | |
824 | |
825 Given a display line, a block number for that start line, output all | |
826 runes between start and end in the specified display block. | |
827 ****************************************************************************/ | |
828 static void | |
829 XLIKE_output_display_block (struct window *w, struct display_line *dl, | |
830 int block, int start, int end, int start_pixpos, | |
831 int cursor_start, int cursor_width, | |
832 int cursor_height) | |
833 { | |
834 #ifndef USE_XFT | |
835 struct frame *f = XFRAME (w->frame); | |
836 #endif | |
837 Ichar_dynarr *buf; | |
838 Lisp_Object window; | |
839 | |
840 struct display_block *db = Dynarr_atp (dl->display_blocks, block); | |
841 rune_dynarr *rba = db->runes; | |
842 struct rune *rb; | |
843 | |
844 int elt = start; | |
845 face_index findex; | |
846 int xpos, width = 0; | |
847 Lisp_Object charset = Qunbound; /* Qnil is a valid charset when | |
848 MULE is not defined */ | |
849 | |
850 window = wrap_window (w); | |
851 rb = Dynarr_atp (rba, start); | |
852 | |
853 if (!rb) | |
854 /* Nothing to do so don't do anything. */ | |
855 return; | |
856 | |
857 findex = rb->findex; | |
858 xpos = rb->xpos; | |
859 if (rb->type == RUNE_CHAR) | |
860 charset = ichar_charset (rb->object.chr.ch); | |
861 | |
862 if (end < 0) | |
863 end = Dynarr_length (rba); | |
864 buf = Dynarr_new (Ichar); | |
865 | |
866 while (elt < end) | |
867 { | |
868 rb = Dynarr_atp (rba, elt); | |
869 | |
870 if (rb->findex == findex && rb->type == RUNE_CHAR | |
871 && rb->object.chr.ch != '\n' && rb->cursor_type != CURSOR_ON | |
872 && EQ (charset, ichar_charset (rb->object.chr.ch))) | |
873 { | |
874 Dynarr_add (buf, rb->object.chr.ch); | |
875 width += rb->width; | |
876 elt++; | |
877 } | |
878 else | |
879 { | |
880 if (Dynarr_length (buf)) | |
881 { | |
882 XLIKE_output_string (w, dl, buf, xpos, 0, start_pixpos, width, | |
883 findex, 0, cursor_start, cursor_width, | |
884 cursor_height); | |
885 xpos = rb->xpos; | |
886 width = 0; | |
887 } | |
888 Dynarr_reset (buf); | |
889 width = 0; | |
890 | |
891 if (rb->type == RUNE_CHAR) | |
892 { | |
893 findex = rb->findex; | |
894 xpos = rb->xpos; | |
895 charset = ichar_charset (rb->object.chr.ch); | |
896 | |
897 if (rb->cursor_type == CURSOR_ON) | |
898 { | |
899 if (rb->object.chr.ch == '\n') | |
900 { | |
901 XLIKE_output_eol_cursor (w, dl, xpos, findex); | |
902 } | |
903 else | |
904 { | |
905 Dynarr_add (buf, rb->object.chr.ch); | |
906 XLIKE_output_string (w, dl, buf, xpos, 0, start_pixpos, | |
907 rb->width, findex, 1, | |
908 cursor_start, cursor_width, | |
909 cursor_height); | |
910 Dynarr_reset (buf); | |
911 } | |
912 | |
913 xpos += rb->width; | |
914 elt++; | |
915 } | |
916 else if (rb->object.chr.ch == '\n') | |
917 { | |
918 /* Clear in case a cursor was formerly here. */ | |
919 redisplay_clear_region (window, findex, xpos, | |
920 XLIKE_DISPLAY_LINE_YPOS (dl), | |
921 rb->width, | |
922 XLIKE_DISPLAY_LINE_HEIGHT (dl)); | |
923 elt++; | |
924 } | |
925 } | |
926 else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE) | |
927 { | |
928 if (rb->type == RUNE_BLANK) | |
929 XLIKE_output_blank (w, dl, rb, start_pixpos, cursor_start, | |
930 cursor_width); | |
931 else | |
932 { | |
933 /* #### Our flagging of when we need to redraw the | |
934 modeline shadows sucks. Since RUNE_HLINE is only used | |
935 by the modeline at the moment it is a good bet | |
936 that if it gets redrawn then we should also | |
937 redraw the shadows. This won't be true forever. | |
938 We borrow the shadow_thickness_changed flag for | |
939 now. */ | |
940 w->shadow_thickness_changed = 1; | |
941 XLIKE_output_horizontal_line (w, dl, rb); | |
942 } | |
943 | |
944 elt++; | |
945 if (elt < end) | |
946 { | |
947 rb = Dynarr_atp (rba, elt); | |
948 | |
949 findex = rb->findex; | |
950 xpos = rb->xpos; | |
951 } | |
952 } | |
953 else if (rb->type == RUNE_DGLYPH) | |
954 { | |
955 Lisp_Object instance; | |
956 struct display_box dbox; | |
957 struct display_glyph_area dga; | |
958 | |
959 redisplay_calculate_display_boxes (dl, rb->xpos, rb->object.dglyph.xoffset, | |
960 rb->object.dglyph.yoffset, start_pixpos, | |
961 rb->width, &dbox, &dga); | |
962 | |
963 window = wrap_window (w); | |
964 instance = glyph_image_instance (rb->object.dglyph.glyph, | |
965 window, ERROR_ME_DEBUG_WARN, 1); | |
966 findex = rb->findex; | |
967 | |
968 if (IMAGE_INSTANCEP (instance)) | |
969 { | |
970 switch (XIMAGE_INSTANCE_TYPE (instance)) | |
971 { | |
972 case IMAGE_TEXT: | |
973 #ifdef THIS_IS_GTK | |
974 { | |
975 /* !!#### Examine for Mule-izing */ | |
976 /* #### This is way losing. See the comment in | |
977 add_glyph_rune(). */ | |
978 Lisp_Object string = | |
979 XIMAGE_INSTANCE_TEXT_STRING (instance); | |
980 convert_ibyte_string_into_ichar_dynarr | |
981 (XSTRING_DATA (string), XSTRING_LENGTH (string), | |
982 buf); | |
983 | |
984 gtk_output_string (w, dl, buf, xpos, | |
985 rb->object.dglyph.xoffset, | |
986 start_pixpos, -1, findex, | |
987 (rb->cursor_type == CURSOR_ON), | |
988 cursor_start, cursor_width, | |
989 cursor_height); | |
990 Dynarr_reset (buf); | |
991 } | |
992 break; | |
993 #else | |
994 ABORT (); | |
995 #endif /* THIS_IS_GTK */ | |
996 case IMAGE_MONO_PIXMAP: | |
997 case IMAGE_COLOR_PIXMAP: | |
998 redisplay_output_pixmap (w, instance, &dbox, &dga, | |
999 findex, cursor_start, | |
1000 cursor_width, | |
1001 cursor_height, 0); | |
1002 break; | |
1003 | |
1004 case IMAGE_WIDGET: | |
1005 if (EQ (XIMAGE_INSTANCE_WIDGET_TYPE (instance), | |
1006 Qlayout)) | |
1007 { | |
1008 redisplay_output_layout (window, instance, &dbox, | |
1009 &dga, findex, | |
1010 cursor_start, cursor_width, | |
1011 cursor_height); | |
1012 break; | |
1013 } | |
1014 | |
1015 case IMAGE_SUBWINDOW: | |
1016 redisplay_output_subwindow (w, instance, &dbox, &dga, | |
1017 findex, cursor_start, | |
1018 cursor_width, cursor_height); | |
1019 break; | |
1020 | |
1021 case IMAGE_NOTHING: | |
1022 /* nothing is as nothing does */ | |
1023 break; | |
1024 | |
1025 case IMAGE_POINTER: | |
1026 default: | |
1027 ABORT (); | |
1028 } | |
1029 IMAGE_INSTANCE_OPTIMIZE_OUTPUT | |
1030 (XIMAGE_INSTANCE (instance)) = 0; | |
1031 } | |
1032 | |
1033 xpos += rb->width; | |
1034 elt++; | |
1035 } | |
1036 else | |
1037 ABORT (); | |
1038 } | |
1039 } | |
1040 | |
1041 if (Dynarr_length (buf)) | |
1042 XLIKE_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex, | |
1043 0, cursor_start, cursor_width, cursor_height); | |
1044 | |
1045 if (dl->modeline | |
1046 && !EQ (Qzero, w->modeline_shadow_thickness) | |
1047 #ifndef USE_XFT | |
1048 /* This optimization doesn't work right with some Xft fonts, which | |
1049 leave antialiasing turds at the boundary. I don't know if this | |
1050 is an Xft bug or not, but I think it is. See x_output_string. */ | |
1051 && (f->clear | |
1052 || f->windows_structure_changed | |
1053 || w->shadow_thickness_changed) | |
1054 #endif | |
1055 ) | |
1056 bevel_modeline (w, dl); | |
1057 | |
1058 Dynarr_free (buf); | |
1059 } | |
1060 | |
1061 /***************************************************************************** | |
1062 XLIKE_get_gc | |
1063 | |
1064 Given a number of parameters return a GC with those properties. | |
1065 ****************************************************************************/ | |
1066 static XLIKE_GC | |
1067 XLIKE_get_gc (struct device *d, Lisp_Object font, Lisp_Object fg, | |
1068 Lisp_Object bg, Lisp_Object bg_pmap, Lisp_Object lwidth) | |
1069 { | |
1070 XLIKE_GCVALUES gcv; | |
1071 unsigned long mask; | |
1072 | |
1073 memset (&gcv, ~0, sizeof (gcv)); | |
1074 gcv.graphics_exposures = XLIKE_FALSE; | |
1075 /* Make absolutely sure that we don't pick up a clipping region in | |
1076 the GC returned by this function. */ | |
1077 gcv.clip_mask = XLIKE_NONE; | |
1078 gcv.clip_x_origin = 0; | |
1079 gcv.clip_y_origin = 0; | |
1080 gcv.XLIKE_FILL_MEMBER = XLIKE_FILL_SOLID; | |
1081 mask = XLIKE_GC_EXPOSURES | XLIKE_GC_CLIP_MASK | XLIKE_GC_CLIP_X_ORIGIN | XLIKE_GC_CLIP_Y_ORIGIN; | |
1082 mask |= XLIKE_GC_FILL; | |
1083 | |
1084 if (!NILP (font) | |
1085 #ifdef USE_XFT | |
1086 /* Only set the font if it's a core font */ | |
1087 /* the renderfont will be set elsewhere (not part of gc) */ | |
1088 && !FONT_INSTANCE_X_XFTFONT (XFONT_INSTANCE (font)) | |
1089 #endif | |
1090 ) | |
1091 { | |
1092 gcv.font = | |
1093 XLIKE_FONT_NUM (FONT_INSTANCE_XLIKE_FONT (XFONT_INSTANCE (font))); | |
1094 mask |= XLIKE_GC_FONT; | |
1095 } | |
1096 | |
1097 /* evil kludge! */ | |
1098 if (!NILP (fg) && !COLOR_INSTANCEP (fg) && !INTP (fg)) | |
1099 { | |
1100 /* #### I fixed one case where this was getting hit. It was a | |
1101 bad macro expansion (compiler bug). */ | |
1102 stderr_out ("Help! x_get_gc got a bogus fg value! fg = "); | |
1103 debug_print (fg); | |
1104 fg = Qnil; | |
1105 } | |
1106 | |
1107 if (!NILP (fg)) | |
1108 { | |
1109 if (COLOR_INSTANCEP (fg)) | |
1110 XLIKE_SET_PIXCOLOR_COPY | |
1111 (gcv.foreground, | |
1112 XLIKE_COLOR_TO_PIXCOLOR (XCOLOR_INSTANCE_XLIKE_COLOR (fg))); | |
1113 else | |
1114 XLIKE_SET_PIXCOLOR_NUM (gcv.foreground, XINT (fg)); | |
1115 mask |= XLIKE_GC_FOREGROUND; | |
1116 } | |
1117 | |
1118 if (!NILP (bg)) | |
1119 { | |
1120 if (COLOR_INSTANCEP (bg)) | |
1121 XLIKE_SET_PIXCOLOR_COPY | |
1122 (gcv.background, | |
1123 XLIKE_COLOR_TO_PIXCOLOR (XCOLOR_INSTANCE_XLIKE_COLOR (bg))); | |
1124 else | |
1125 XLIKE_SET_PIXCOLOR_NUM (gcv.background, XINT (bg)); | |
1126 mask |= XLIKE_GC_BACKGROUND; | |
1127 } | |
1128 | |
1129 /* This special case comes from a request to draw text with a face which has | |
1130 the dim property. We'll use a stippled foreground GC. */ | |
1131 if (EQ (bg_pmap, Qdim)) | |
1132 { | |
1133 assert (DEVICE_XLIKE_GRAY_PIXMAP (d) != XLIKE_NONE); | |
1134 | |
1135 gcv.XLIKE_FILL_MEMBER = XLIKE_FILL_STIPPLED; | |
1136 gcv.stipple = DEVICE_XLIKE_GRAY_PIXMAP (d); | |
1137 mask |= (XLIKE_GC_FILL | XLIKE_GC_STIPPLE); | |
1138 } | |
1139 else if (IMAGE_INSTANCEP (bg_pmap) | |
1140 && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap))) | |
1141 { | |
1142 if (XIMAGE_INSTANCE_PIXMAP_DEPTH (bg_pmap) == 0) | |
1143 { | |
1144 gcv.XLIKE_FILL_MEMBER = XLIKE_FILL_OPAQUE_STIPPLED; | |
1145 gcv.stipple = XIMAGE_INSTANCE_XLIKE_PIXMAP (bg_pmap); | |
1146 mask |= (XLIKE_GC_STIPPLE | XLIKE_GC_FILL); | |
1147 } | |
1148 else | |
1149 { | |
1150 gcv.XLIKE_FILL_MEMBER = XLIKE_FILL_TILED; | |
1151 gcv.tile = XIMAGE_INSTANCE_XLIKE_PIXMAP (bg_pmap); | |
1152 mask |= (XLIKE_GC_TILE | XLIKE_GC_FILL); | |
1153 } | |
1154 } | |
1155 | |
1156 if (!NILP (lwidth)) | |
1157 { | |
1158 gcv.line_width = XINT (lwidth); | |
1159 mask |= XLIKE_GC_LINE_WIDTH; | |
1160 } | |
1161 | |
1162 #if 0 | |
1163 debug_out ("\nx_get_gc: calling gc_cache_lookup\n"); | |
1164 #endif | |
1165 return gc_cache_lookup (DEVICE_XLIKE_GC_CACHE (d), &gcv, mask); | |
1166 } | |
1167 | |
1168 /***************************************************************************** | |
1169 XLIKE_output_string | |
1170 | |
1171 Given a string and a starting position, output that string in the | |
1172 given face. If cursor is true, draw a cursor around the string. | |
1173 Correctly handles multiple charsets in the string. | |
1174 | |
1175 The meaning of the parameters is something like this: | |
1176 | |
1177 W Window that the text is to be displayed in. | |
1178 DL Display line that this text is on. The values in the | |
1179 structure are used to determine the vertical position and | |
1180 clipping range of the text. | |
1181 BUF Dynamic array of Ichars specifying what is actually to be | |
1182 drawn. | |
1183 XPOS X position in pixels where the text should start being drawn. | |
1184 XOFFSET Number of pixels to be chopped off the left side of the | |
1185 text. The effect is as if the text were shifted to the | |
1186 left this many pixels and clipped at XPOS. | |
1187 CLIP_START Clip everything left of this X position. | |
1188 WIDTH Clip everything right of XPOS + WIDTH. | |
1189 FINDEX Index for the face cache element describing how to display | |
1190 the text. | |
1191 CURSOR #### I don't understand this. There's something | |
1192 strange and overcomplexified with this variable. | |
1193 Chuck, explain please? | |
1194 CURSOR_START Starting X position of cursor. | |
1195 CURSOR_WIDTH Width of cursor in pixels. | |
1196 CURSOR_HEIGHT Height of cursor in pixels. | |
1197 | |
1198 Starting Y position of cursor is the top of the text line. | |
1199 The cursor is drawn sometimes whether or not CURSOR is set. ??? | |
1200 ****************************************************************************/ | |
1201 #ifdef THIS_IS_GTK | |
1202 static | |
1203 void gdk_draw_text_image (GdkDrawable *drawable, | |
1204 GdkFont *font, | |
1205 GdkGC *gc, | |
1206 gint x, | |
1207 gint y, | |
1208 const gchar *text, | |
1209 gint text_length); | |
1210 | |
1211 #endif /* THIS_IS_GTK */ | |
1212 void | |
1213 XLIKE_output_string (struct window *w, struct display_line *dl, | |
1214 Ichar_dynarr *buf, int xpos, int xoffset, int clip_start, | |
1215 int width, face_index findex, int cursor, | |
1216 int cursor_start, int cursor_width, int cursor_height) | |
1217 { | |
1218 /* General variables */ | |
1219 struct frame *f = XFRAME (w->frame); | |
1220 struct device *d = XDEVICE (f->device); | |
1221 XLIKE_DISPLAY dpy = GET_XLIKE_DISPLAY (d); | |
1222 XLIKE_WINDOW x_win = GET_XLIKE_WINDOW (f); | |
1223 Lisp_Object window = wrap_window (w); | |
1224 | |
1225 int clip_end; | |
1226 | |
1227 /* Cursor-related variables */ | |
1228 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d)); | |
1229 int cursor_clip; | |
1230 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor, | |
1231 WINDOW_BUFFER (w)); | |
1232 struct face_cachel *cursor_cachel = 0; | |
1233 | |
1234 /* Text-related variables */ | |
1235 Lisp_Object bg_pmap; | |
1236 XLIKE_GC bgc, gc; | |
1237 int height = XLIKE_DISPLAY_LINE_HEIGHT (dl); | |
1238 int ypos = XLIKE_DISPLAY_LINE_YPOS (dl); | |
1239 int len = Dynarr_length (buf); | |
1240 unsigned char *text_storage = (unsigned char *) ALLOCA (2 * len); | |
1241 struct textual_run *runs = alloca_array (struct textual_run, len); | |
1242 int nruns; | |
1243 int i; | |
1244 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, findex); | |
1245 | |
1246 #ifdef THIS_IS_X | |
1247 int use_x_font = 1; /* #### bogus!! | |
1248 The logic of this function needs review! */ | |
1249 #endif | |
1250 #ifdef USE_XFT | |
1251 Colormap cmap = DEVICE_X_COLORMAP (d); | |
1252 Visual *visual = DEVICE_X_VISUAL (d); | |
1253 static XftColor fg, bg; | |
1254 XftDraw *xftDraw; | |
1255 | |
1256 /* Lazily initialize frame's xftDraw member. */ | |
1257 if (!FRAME_X_XFTDRAW (f)) { | |
1258 FRAME_X_XFTDRAW (f) = XftDrawCreate (dpy, x_win, visual, cmap); | |
1259 } | |
1260 xftDraw = FRAME_X_XFTDRAW (f); | |
1261 | |
1262 /* #### This will probably cause asserts when passed a Lisp integer for a | |
1263 color. See ca. line 759 this file. | |
1264 #### Maybe xft_convert_color should take an XColor, not a pixel. */ | |
1265 #define XFT_FROB_LISP_COLOR(color, dim) \ | |
1266 xft_convert_color (dpy, cmap, visual, \ | |
1267 COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (color)).pixel, \ | |
1268 (dim)) | |
1269 #endif /* USE_XFT */ | |
1270 | |
1271 if (width < 0) | |
1272 width = XLIKE_text_width (w, cachel, Dynarr_atp (buf, 0), | |
1273 Dynarr_length (buf)); | |
1274 | |
1275 /* Regularize the variables passed in. */ | |
1276 | |
1277 if (clip_start < xpos) | |
1278 clip_start = xpos; | |
1279 clip_end = xpos + width; | |
1280 if (clip_start >= clip_end) | |
1281 /* It's all clipped out. */ | |
1282 return; | |
1283 | |
1284 xpos -= xoffset; | |
1285 | |
1286 /* make sure the area we are about to display is subwindow free. */ | |
1287 redisplay_unmap_subwindows_maybe (f, clip_start, ypos, | |
1288 clip_end - clip_start, height); | |
1289 | |
1290 cursor_clip = (cursor_start >= clip_start && | |
1291 cursor_start < clip_end); | |
1292 | |
1293 /* This cursor code is really a mess. */ | |
1294 if (!NILP (w->text_cursor_visible_p) | |
1295 && (cursor | |
1296 || cursor_clip | |
1297 || (cursor_width | |
1298 && (cursor_start + cursor_width >= clip_start) | |
1299 && !NILP (bar_cursor_value)))) | |
1300 { | |
1301 /* These have to be in separate statements in order to avoid a | |
1302 compiler bug. */ | |
1303 face_index sucks = get_builtin_face_cache_index (w, Vtext_cursor_face); | |
1304 cursor_cachel = WINDOW_FACE_CACHEL (w, sucks); | |
1305 | |
1306 /* We have to reset this since any call to WINDOW_FACE_CACHEL | |
1307 may cause the cache to resize and any pointers to it to | |
1308 become invalid. */ | |
1309 cachel = WINDOW_FACE_CACHEL (w, findex); | |
1310 } | |
1311 | |
1312 #ifdef HAVE_XIM | |
1313 if (cursor && focus && (cursor_start == clip_start) && cursor_height) | |
1314 XIM_SetSpotLocation (f, xpos - 2, dl->ypos + dl->descent - 2); | |
1315 #endif /* HAVE_XIM */ | |
1316 | |
1317 bg_pmap = cachel->background_pixmap; | |
1318 if (!IMAGE_INSTANCEP (bg_pmap) | |
1319 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap))) | |
1320 bg_pmap = Qnil; | |
1321 | |
1322 if ((cursor && focus && NILP (bar_cursor_value) | |
1323 && !NILP (w->text_cursor_visible_p)) || NILP (bg_pmap)) | |
1324 bgc = 0; | |
1325 else | |
1326 bgc = XLIKE_get_gc (d, Qnil, cachel->foreground, cachel->background, | |
1327 bg_pmap, Qnil); | |
1328 | |
1329 if (bgc) | |
1330 { | |
1331 XLIKE_FILL_RECTANGLE (dpy, x_win, bgc, clip_start, | |
1332 ypos, clip_end - clip_start, | |
1333 height); | |
1334 } | |
1335 | |
1336 nruns = separate_textual_runs (text_storage, runs, Dynarr_atp (buf, 0), | |
1337 Dynarr_length (buf), cachel); | |
1338 | |
1339 for (i = 0; i < nruns; i++) | |
1340 { | |
1341 Lisp_Object font = FACE_CACHEL_FONT (cachel, runs[i].charset); | |
1342 Lisp_Font_Instance *fi = XFONT_INSTANCE (font); | |
1343 int this_width; | |
1344 int need_clipping; | |
1345 | |
1346 if (EQ (font, Vthe_null_font_instance)) | |
1347 continue; | |
1348 | |
1349 this_width = XLIKE_text_width_single_run (f, cachel, runs + i); | |
1350 need_clipping = (dl->clip || clip_start > xpos || | |
1351 clip_end < xpos + this_width); | |
1352 | |
1353 /* XDrawImageString only clears the area equal to the height of | |
1354 the given font. It is possible that a font is being displayed | |
1355 on a line taller than it is, so this would cause us to fail to | |
1356 clear some areas. */ | |
1357 if ((int) fi->height < (int) (height + dl->clip + | |
1358 XLIKE_DISPLAY_LINE_TOP_CLIP (dl))) | |
1359 { | |
1360 int clear_start = max (xpos, clip_start); | |
1361 int clear_end = min (xpos + this_width, clip_end); | |
1362 | |
1363 if (cursor) | |
1364 { | |
1365 int ypos1_line, ypos1_string, ypos2_line, ypos2_string; | |
1366 | |
1367 ypos1_string = dl->ypos - fi->ascent; | |
1368 ypos2_string = dl->ypos + fi->descent; | |
1369 ypos1_line = ypos; | |
1370 ypos2_line = ypos1_line + height; | |
1371 | |
1372 /* Make sure we don't clear below the real bottom of the | |
1373 line. */ | |
1374 if (ypos1_string > ypos2_line) | |
1375 ypos1_string = ypos2_line; | |
1376 if (ypos2_string > ypos2_line) | |
1377 ypos2_string = ypos2_line; | |
1378 | |
1379 if (ypos1_line < ypos1_string) | |
1380 { | |
1381 redisplay_clear_region (window, findex, clear_start, ypos1_line, | |
1382 clear_end - clear_start, | |
1383 ypos1_string - ypos1_line); | |
1384 } | |
1385 | |
1386 if (ypos2_line > ypos2_string) | |
1387 { | |
1388 redisplay_clear_region (window, findex, clear_start, ypos2_string, | |
1389 clear_end - clear_start, | |
1390 ypos2_line - ypos2_string); | |
1391 } | |
1392 } | |
1393 else | |
1394 { | |
1395 redisplay_clear_region (window, findex, clear_start, | |
1396 ypos, clear_end - clear_start, | |
1397 height); | |
1398 } | |
1399 } | |
1400 | |
1401 if (cursor && cursor_cachel && focus && NILP (bar_cursor_value)) | |
1402 { | |
1403 #ifdef USE_XFT | |
1404 fg = XFT_FROB_LISP_COLOR (cursor_cachel->foreground, 0); | |
1405 bg = XFT_FROB_LISP_COLOR (cursor_cachel->background, 0); | |
1406 #endif | |
1407 gc = XLIKE_get_gc (d, font, cursor_cachel->foreground, | |
1408 cursor_cachel->background, Qnil, Qnil); | |
1409 } | |
1410 else if (cachel->dim) | |
1411 { | |
1412 /* Ensure the gray bitmap exists */ | |
1413 if (DEVICE_XLIKE_GRAY_PIXMAP (d) == XLIKE_NONE) | |
1414 DEVICE_XLIKE_GRAY_PIXMAP (d) = | |
1415 #ifdef THIS_IS_X | |
1416 XCreateBitmapFromData (dpy, x_win, (char *)gray_bits, | |
1417 gray_width, gray_height) | |
1418 #else | |
1419 /* #### FIXME! Implement me! */ | |
1420 XLIKE_NONE | |
1421 #endif | |
1422 ; | |
1423 | |
1424 /* Request a GC with the gray stipple pixmap to draw dimmed text */ | |
1425 #ifdef USE_XFT | |
1426 fg = XFT_FROB_LISP_COLOR (cachel->foreground, 1); | |
1427 bg = XFT_FROB_LISP_COLOR (cachel->background, 0); | |
1428 #endif | |
1429 gc = XLIKE_get_gc (d, font, cachel->foreground, cachel->background, | |
1430 Qdim, Qnil); | |
1431 } | |
1432 else | |
1433 { | |
1434 #ifdef USE_XFT | |
1435 fg = XFT_FROB_LISP_COLOR (cachel->foreground, 0); | |
1436 bg = XFT_FROB_LISP_COLOR (cachel->background, 0); | |
1437 #endif | |
1438 gc = XLIKE_get_gc (d, font, cachel->foreground, cachel->background, | |
1439 Qnil, Qnil); | |
1440 } | |
1441 #ifdef USE_XFT | |
1442 { | |
1443 XftFont *rf = FONT_INSTANCE_X_XFTFONT (fi); | |
1444 | |
1445 if (rf) | |
1446 { | |
1447 use_x_font = 0; | |
1448 if (need_clipping) | |
1449 { | |
1450 Region clip_reg = XCreateRegion(); | |
1451 XRectangle clip_box = { clip_start, ypos, | |
1452 clip_end - clip_start, height }; | |
1453 | |
1454 XUnionRectWithRegion (&clip_box, clip_reg, clip_reg); | |
1455 XftDrawSetClip(xftDraw, clip_reg); | |
1456 XDestroyRegion(clip_reg); | |
1457 } | |
1458 | |
1459 if (!bgc) | |
1460 { | |
1461 /* #### Neither rect_height nor XftTextExtents as computed | |
1462 below handles the vertical space taken up by antialiasing, | |
1463 which for some fonts (eg, Bitstream Vera Sans Mono-16 on | |
1464 my Mac PowerBook G4) leaves behind orphaned dots on | |
1465 insertion or deletion earlier in the line, especially in | |
1466 the case of the underscore character. | |
1467 Interestingly, insertion or deletion of a single character | |
1468 immediately after a refresh does not leave any droppings, | |
1469 but any further insertions or deletions do. | |
1470 While adding a pixel to rect_height (mostly) takes care of | |
1471 this, it trashes aggressively laid-out elements like the | |
1472 modeline (overwriting part of the bevel). | |
1473 OK, unconditionally redraw the bevel, and increment | |
1474 rect_height by 1. See x_output_display_block. -- sjt */ | |
1475 struct textual_run *run = &runs[i]; | |
1476 int rect_width = x_text_width_single_run (f, cachel, run); | |
1477 #ifndef USE_XFTTEXTENTS_TO_AVOID_FONT_DROPPINGS | |
1478 int rect_height = FONT_INSTANCE_ASCENT(fi) | |
1479 + FONT_INSTANCE_DESCENT(fi) + 1; | |
1480 #else | |
1481 int rect_height = FONT_INSTANCE_ASCENT(fi) | |
1482 + FONT_INSTANCE_DESCENT(fi); | |
1483 XGlyphInfo gi; | |
1484 if (run->dimension == 2) { | |
1485 XftTextExtents16 (dpy, | |
1486 FONT_INSTANCE_X_XFTFONT(fi), | |
1487 (XftChar16 *) run->ptr, run->len, &gi); | |
1488 } else { | |
1489 XftTextExtents8 (dpy, | |
1490 FONT_INSTANCE_X_XFTFONT(fi), | |
1491 run->ptr, run->len, &gi); | |
1492 } | |
1493 rect_height = rect_height > gi.height | |
1494 ? rect_height : gi.height; | |
1495 #endif | |
1496 | |
1497 XftDrawRect (xftDraw, &bg, | |
1498 xpos, ypos, rect_width, rect_height); | |
1499 } | |
1500 | |
1501 if (runs[i].dimension == 1) | |
1502 XftDrawString8 (xftDraw, &fg, rf, xpos, dl->ypos, | |
1503 runs[i].ptr, runs[i].len); | |
1504 else | |
1505 XftDrawString16 (xftDraw, &fg, rf, xpos, dl->ypos, | |
1506 (XftChar16 *) runs[i].ptr, runs[i].len); | |
1507 } | |
1508 } | |
1509 #endif /* USE_XFT */ | |
1510 | |
1511 #ifdef THIS_IS_X | |
1512 if (use_x_font) | |
1513 #endif | |
1514 { | |
1515 if (need_clipping) | |
1516 { | |
1517 XLIKE_RECTANGLE clip_box; | |
1518 | |
1519 clip_box.x = 0; | |
1520 clip_box.y = 0; | |
1521 clip_box.width = clip_end - clip_start; | |
1522 clip_box.height = height; | |
1523 | |
1524 XLIKE_SET_CLIP_RECTANGLE (dpy, gc, clip_start, ypos, &clip_box); | |
1525 } | |
1526 | |
1527 #ifdef THIS_IS_X | |
1528 if (runs[i].dimension == 1) | |
1529 (bgc ? XDrawString : XDrawImageString) | |
1530 (dpy, x_win, gc, xpos, dl->ypos, | |
1531 (char *) runs[i].ptr, runs[i].len); | |
1532 else | |
1533 (bgc ? XDrawString16 : XDrawImageString16) | |
1534 (dpy, x_win, gc, xpos, dl->ypos, | |
1535 (XChar2b *) runs[i].ptr, runs[i].len); | |
1536 #else /* THIS_IS_GTK */ | |
1537 | |
1538 /* The X specific called different functions (XDraw*String | |
1539 vs. XDraw*String16), but apparently gdk_draw_text takes care | |
1540 of that for us. | |
1541 | |
1542 BUT, gdk_draw_text also does too much, by dividing the length | |
1543 by 2. So we fake them out my multiplying the length by the | |
1544 dimension of the text. This will do the right thing for | |
1545 single-dimension runs as well of course. | |
1546 */ | |
1547 (bgc ? gdk_draw_text : gdk_draw_text_image) | |
1548 (GDK_DRAWABLE (x_win), FONT_INSTANCE_GTK_FONT (fi), gc, xpos, | |
1549 dl->ypos, (char *) runs[i].ptr, runs[i].len * runs[i].dimension); | |
1550 #endif /* (not) THIS_IS_X */ | |
1551 } | |
1552 | |
1553 /* We draw underlines in the same color as the text. */ | |
1554 if (cachel->underline) | |
1555 { | |
1556 int upos, uthick; | |
1557 #ifdef THIS_IS_X | |
1558 unsigned long upos_ext, uthick_ext; | |
1559 XFontStruct *fs = | |
1560 use_x_font ? FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font)) : 0; | |
1561 /* #### the logic of the next two may be suboptimal: we may want | |
1562 to use the POSITION and/or THICKNESS information with Xft */ | |
1563 if (fs && XGetFontProperty (fs, XA_UNDERLINE_POSITION, &upos_ext)) | |
1564 upos = (int) upos_ext; | |
1565 else | |
1566 #else /* THIS_IS_GTK */ | |
1567 /* Cannot get at font properties in Gtk, so we resort to | |
1568 guessing */ | |
1569 #endif /* THIS_IS_GTK */ | |
1570 upos = dl->descent / 2; | |
1571 #ifdef THIS_IS_X | |
1572 if (fs && XGetFontProperty (fs, XA_UNDERLINE_THICKNESS, &uthick_ext)) | |
1573 uthick = (int) uthick_ext; | |
1574 else | |
1575 #endif /* THIS_IS_X */ | |
1576 uthick = 1; | |
1577 if (dl->ypos + upos < dl->ypos + dl->descent - dl->clip) | |
1578 { | |
1579 if (dl->ypos + upos + uthick > dl->ypos + dl->descent - dl->clip) | |
1580 uthick = dl->descent - dl->clip - upos; | |
1581 | |
1582 if (uthick == 1) | |
1583 { | |
1584 XLIKE_DRAW_LINE (dpy, x_win, gc, xpos, dl->ypos + upos, | |
1585 xpos + this_width, dl->ypos + upos); | |
1586 } | |
1587 else if (uthick > 1) | |
1588 { | |
1589 XLIKE_FILL_RECTANGLE (dpy, x_win, gc, xpos, | |
1590 dl->ypos + upos, this_width, uthick); | |
1591 } | |
1592 } | |
1593 } | |
1594 | |
1595 if (cachel->strikethru) | |
1596 { | |
1597 #ifdef THIS_IS_X | |
1598 int ascent, descent, upos, uthick; | |
1599 unsigned long ascent_ext, descent_ext, uthick_ext; | |
1600 XFontStruct *fs = FONT_INSTANCE_X_FONT (fi); | |
1601 #else /* THIS_IS_GTK */ | |
1602 gint ascent, descent, upos, uthick; | |
1603 GdkFont *gfont = FONT_INSTANCE_GTK_FONT (fi); | |
1604 #endif /* THIS_IS_GTK */ | |
1605 | |
1606 #ifdef THIS_IS_X | |
1607 if (!use_x_font) | |
1608 { | |
1609 ascent = dl->ascent; | |
1610 descent = dl->descent; | |
1611 uthick = 1; | |
1612 } | |
1613 else | |
1614 { | |
1615 if (!XGetFontProperty (fs, XA_STRIKEOUT_ASCENT, &ascent_ext)) | |
1616 ascent = fs->ascent; | |
1617 else | |
1618 ascent = (int) ascent_ext; | |
1619 if (!XGetFontProperty (fs, XA_STRIKEOUT_DESCENT, &descent_ext)) | |
1620 descent = fs->descent; | |
1621 else | |
1622 descent = (int) descent_ext; | |
1623 if (!XGetFontProperty (fs, XA_UNDERLINE_THICKNESS, &uthick_ext)) | |
1624 uthick = 1; | |
1625 else | |
1626 uthick = (int) uthick_ext; | |
1627 } | |
1628 #else /* THIS_IS_GTK */ | |
1629 /* Cannot get at font properties in Gtk, so we resort to | |
1630 guessing */ | |
1631 | |
1632 ascent = gfont->ascent; | |
1633 descent = gfont->descent; | |
1634 uthick = 1; | |
1635 #endif /* THIS_IS_GTK */ | |
1636 | |
1637 upos = ascent - ((ascent + descent) / 2) + 1; | |
1638 | |
1639 /* Generally, upos will be positive (above the baseline),so | |
1640 subtract */ | |
1641 if (dl->ypos - upos < dl->ypos + dl->descent - dl->clip) | |
1642 { | |
1643 if (dl->ypos - upos + uthick > dl->ypos + dl->descent - dl->clip) | |
1644 uthick = dl->descent - dl->clip + upos; | |
1645 | |
1646 if (uthick == 1) | |
1647 XLIKE_DRAW_LINE (dpy, x_win, gc, xpos, dl->ypos - upos, | |
1648 xpos + this_width, dl->ypos - upos); | |
1649 else if (uthick > 1) | |
1650 XLIKE_FILL_RECTANGLE (dpy, x_win, gc, xpos, dl->ypos + upos, | |
1651 this_width, uthick); | |
1652 } | |
1653 } | |
1654 | |
1655 /* Restore the GC */ | |
1656 if (need_clipping) | |
1657 { | |
1658 #ifdef USE_XFT | |
1659 if (!use_x_font) | |
1660 { | |
1661 XftDrawSetClip (xftDraw, 0); | |
1662 } | |
1663 else | |
1664 #endif | |
1665 XLIKE_CLEAR_CLIP_MASK (dpy, gc); | |
1666 } | |
1667 | |
1668 /* If we are actually superimposing the cursor then redraw with just | |
1669 the appropriate section highlighted. */ | |
1670 if (cursor_clip && !cursor && focus && cursor_cachel) | |
1671 { | |
1672 #ifdef USE_XFT | |
1673 if (!use_x_font) /* Xft */ | |
1674 { | |
1675 XftFont *rf = FONT_INSTANCE_X_XFTFONT (fi); | |
1676 | |
1677 { /* set up clipping */ | |
1678 Region clip_reg = XCreateRegion(); | |
1679 XRectangle clip_box = { cursor_start, ypos, | |
1680 cursor_width, height }; | |
1681 | |
1682 XUnionRectWithRegion (&clip_box, clip_reg, clip_reg); | |
1683 XftDrawSetClip(xftDraw, clip_reg); | |
1684 XDestroyRegion(clip_reg); | |
1685 } | |
1686 { /* draw background rectangle & draw text */ | |
1687 int rect_height = FONT_INSTANCE_ASCENT(fi) | |
1688 + FONT_INSTANCE_DESCENT(fi); | |
1689 int rect_width = x_text_width_single_run(f, cachel, &runs[i]); | |
1690 XftColor xft_color; | |
1691 | |
1692 xft_color = XFT_FROB_LISP_COLOR (cursor_cachel->background, 0); | |
1693 XftDrawRect (xftDraw, &xft_color, | |
1694 xpos, ypos, rect_width, rect_height); | |
1695 | |
1696 xft_color = XFT_FROB_LISP_COLOR (cursor_cachel->foreground, 0); | |
1697 if (runs[i].dimension == 1) | |
1698 XftDrawString8 (xftDraw, &xft_color, rf, xpos, dl->ypos, | |
1699 runs[i].ptr, runs[i].len); | |
1700 else | |
1701 XftDrawString16 (xftDraw, &xft_color, rf, xpos, dl->ypos, | |
1702 (XftChar16 *) runs[i].ptr, runs[i].len); | |
1703 } | |
1704 | |
1705 XftDrawSetClip(xftDraw, 0); | |
1706 } | |
1707 else /* core font, not Xft */ | |
1708 #endif /* USE_XFT */ | |
1709 { | |
1710 XLIKE_RECTANGLE clip_box; | |
1711 XLIKE_GC cgc; | |
1712 cgc = XLIKE_get_gc (d, font, cursor_cachel->foreground, | |
1713 cursor_cachel->background, Qnil, Qnil); | |
1714 | |
1715 clip_box.x = 0; | |
1716 clip_box.y = 0; | |
1717 clip_box.width = cursor_width; | |
1718 clip_box.height = height; | |
1719 | |
1720 XLIKE_SET_CLIP_RECTANGLE (dpy, cgc, cursor_start, ypos, | |
1721 &clip_box); | |
1722 #ifdef THIS_IS_X | |
1723 if (runs[i].dimension == 1) | |
1724 XDrawImageString (dpy, x_win, cgc, xpos, dl->ypos, | |
1725 (char *) runs[i].ptr, runs[i].len); | |
1726 else | |
1727 XDrawImageString16 (dpy, x_win, cgc, xpos, dl->ypos, | |
1728 (XChar2b *) runs[i].ptr, runs[i].len); | |
1729 #else | |
1730 /* The X specific called different functions (XDraw*String | |
1731 vs. XDraw*String16), but apparently gdk_draw_text takes care | |
1732 of that for us. | |
1733 | |
1734 BUT, gdk_draw_text also does too much, by dividing the | |
1735 length by 2. So we fake them out my multiplying the | |
1736 length by the dimension of the text. This will do the | |
1737 right thing for single-dimension runs as well of course. | |
1738 */ | |
1739 gdk_draw_text_image (GDK_DRAWABLE (x_win), | |
1740 FONT_INSTANCE_GTK_FONT (fi), cgc, xpos, | |
1741 dl->ypos, (char *) runs[i].ptr, | |
1742 runs[i].len * runs[i].dimension); | |
1743 #endif /* (not) THIS_IS_X */ | |
1744 | |
1745 XLIKE_CLEAR_CLIP_MASK (dpy, cgc); | |
1746 } | |
1747 } | |
1748 | |
1749 xpos += this_width; | |
1750 } | |
1751 | |
1752 /* Draw the non-focus box or bar-cursor as needed. */ | |
1753 /* Can't this logic be simplified? */ | |
1754 if (cursor_cachel | |
1755 && ((cursor && !focus && NILP (bar_cursor_value)) | |
1756 || (cursor_width | |
1757 && (cursor_start + cursor_width >= clip_start) | |
1758 && !NILP (bar_cursor_value)))) | |
1759 { | |
1760 int tmp_height, tmp_y; | |
1761 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2; | |
1762 int need_clipping = (cursor_start < clip_start | |
1763 || clip_end < cursor_start + cursor_width); | |
1764 | |
1765 /* #### This value is correct (as far as I know) because | |
1766 all of the times we need to draw this cursor, we will | |
1767 be called with exactly one character, so we know we | |
1768 can always use runs[0]. | |
1769 | |
1770 This is bogus as all hell, however. The cursor handling in | |
1771 this function is way bogus and desperately needs to be | |
1772 cleaned up. (In particular, the drawing of the cursor should | |
1773 really really be separated out of this function. This may be | |
1774 a bit tricky now because this function itself does way too | |
1775 much stuff, a lot of which needs to be moved into | |
1776 redisplay.c.) This is the only way to be able to easily add | |
1777 new cursor types or (e.g.) make the bar cursor be able to | |
1778 span two characters instead of overlaying just one. */ | |
1779 int bogusly_obtained_ascent_value = | |
1780 XFONT_INSTANCE (FACE_CACHEL_FONT (cachel, runs[0].charset))->ascent; | |
1781 | |
1782 if (!NILP (bar_cursor_value)) | |
1783 { | |
1784 gc = XLIKE_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, | |
1785 make_int (bar_width)); | |
1786 } | |
1787 else | |
1788 { | |
1789 gc = XLIKE_get_gc (d, Qnil, cursor_cachel->background, | |
1790 Qnil, Qnil, Qnil); | |
1791 } | |
1792 | |
1793 tmp_y = dl->ypos - bogusly_obtained_ascent_value; | |
1794 tmp_height = cursor_height; | |
1795 if (tmp_y + tmp_height > (int) (ypos + height)) | |
1796 { | |
1797 tmp_y = ypos + height - tmp_height; | |
1798 if (tmp_y < (int) ypos) | |
1799 tmp_y = ypos; | |
1800 tmp_height = ypos + height - tmp_y; | |
1801 } | |
1802 | |
1803 if (need_clipping) | |
1804 { | |
1805 XLIKE_RECTANGLE clip_box; | |
1806 clip_box.x = 0; | |
1807 clip_box.y = 0; | |
1808 clip_box.width = clip_end - clip_start; | |
1809 clip_box.height = tmp_height; | |
1810 XLIKE_SET_CLIP_RECTANGLE (dpy, gc, clip_start, tmp_y, &clip_box); | |
1811 } | |
1812 | |
1813 if (!focus && NILP (bar_cursor_value)) | |
1814 { | |
1815 XLIKE_DRAW_RECTANGLE (dpy, x_win, gc, cursor_start, tmp_y, | |
1816 cursor_width - 1, tmp_height - 1); | |
1817 } | |
1818 else if (focus && !NILP (bar_cursor_value)) | |
1819 { | |
1820 XLIKE_DRAW_LINE (dpy, x_win, gc, cursor_start + bar_width - 1, tmp_y, | |
1821 cursor_start + bar_width - 1, | |
1822 tmp_y + tmp_height - 1); | |
1823 } | |
1824 | |
1825 /* Restore the GC */ | |
1826 if (need_clipping) | |
1827 { | |
1828 XLIKE_CLEAR_CLIP_MASK (dpy, gc); | |
1829 } | |
1830 } | |
1831 | |
1832 #ifdef USE_XFT | |
1833 #undef XFT_FROB_LISP_COLOR | |
1834 #endif | |
1835 } | |
1836 | |
1837 #ifdef THIS_IS_GTK | |
1838 static void | |
1839 our_draw_bitmap (GdkDrawable *drawable, | |
1840 GdkGC *gc, | |
1841 GdkPixmap *src, | |
1842 gint xsrc, | |
1843 gint ysrc, | |
1844 gint xdest, | |
1845 gint ydest, | |
1846 gint width, | |
1847 gint height); | |
1848 #endif /* THIS_IS_GTK */ | |
1849 | |
1850 | |
1851 void | |
1852 XLIKE_OUTPUT_XLIKE_PIXMAP (struct frame *f, Lisp_Image_Instance *p, int x, | |
1853 int y, int xoffset, int yoffset, | |
1854 int width, int height, | |
1855 XLIKE_PIXCOLOR fg, XLIKE_PIXCOLOR bg, | |
1856 XLIKE_GC override_gc) | |
1857 { | |
1858 struct device *d = XDEVICE (f->device); | |
1859 XLIKE_DISPLAY dpy = GET_XLIKE_DISPLAY (d); | |
1860 XLIKE_WINDOW x_win = GET_XLIKE_WINDOW (f); | |
1861 XLIKE_GC gc; | |
1862 XLIKE_GCVALUES gcv; | |
1863 unsigned long pixmap_mask; | |
1864 | |
1865 if (!override_gc) | |
1866 { | |
1867 memset (&gcv, ~0, sizeof (gcv)); | |
1868 gcv.graphics_exposures = XLIKE_FALSE; | |
1869 XLIKE_SET_PIXCOLOR_COPY (gcv.foreground, fg); | |
1870 XLIKE_SET_PIXCOLOR_COPY (gcv.background, bg); | |
1871 pixmap_mask = XLIKE_GC_FOREGROUND | XLIKE_GC_BACKGROUND | XLIKE_GC_EXPOSURES; | |
1872 | |
1873 if (IMAGE_INSTANCE_XLIKE_MASK (p)) | |
1874 { | |
1875 gcv.function = XLIKE_GX_COPY; | |
1876 gcv.clip_mask = IMAGE_INSTANCE_XLIKE_MASK (p); | |
1877 gcv.clip_x_origin = x - xoffset; | |
1878 gcv.clip_y_origin = y - yoffset; | |
1879 pixmap_mask |= (XLIKE_GC_FUNCTION | XLIKE_GC_CLIP_MASK | | |
1880 XLIKE_GC_CLIP_X_ORIGIN | | |
1881 XLIKE_GC_CLIP_Y_ORIGIN); | |
1882 /* Can't set a clip rectangle below because we already have a mask. | |
1883 We could conceivably create a new clipmask by zeroing out | |
1884 everything outside the clip region. Is it worth it? | |
1885 Is it possible to get an equivalent effect by changing the | |
1886 args to XCopyArea below rather than messing with a clip box? | |
1887 - dkindred@cs.cmu.edu | |
1888 Yes. We don't clip at all now - andy@xemacs.org | |
1889 */ | |
1890 } | |
1891 | |
1892 gc = gc_cache_lookup (DEVICE_XLIKE_GC_CACHE (d), &gcv, pixmap_mask); | |
1893 } | |
1894 else | |
1895 { | |
1896 gc = override_gc; | |
1897 /* override_gc might have a mask already--we don't want to nuke it. | |
1898 Maybe we can insist that override_gc have no mask, or use | |
1899 one of the suggestions above. */ | |
1900 } | |
1901 | |
1902 #ifdef THIS_IS_X | |
1903 /* depth of 0 means it's a bitmap, not a pixmap, and we should use | |
1904 XCopyPlane (1 = current foreground color, 0 = background) instead | |
1905 of XCopyArea, which means that the bits in the pixmap are actual | |
1906 pixel values, instead of symbolic of fg/bg. */ | |
1907 #endif /* THIS_IS_X */ | |
1908 if (IMAGE_INSTANCE_PIXMAP_DEPTH (p) > 0) | |
1909 { | |
1910 #ifdef THIS_IS_X | |
1911 XCopyArea (dpy, | |
1912 IMAGE_INSTANCE_X_PIXMAP_SLICE | |
1913 (p, IMAGE_INSTANCE_PIXMAP_SLICE (p)), x_win, gc, xoffset, | |
1914 yoffset, width, | |
1915 height, x, y); | |
1916 #else /* THIS_IS_GTK */ | |
1917 gdk_draw_pixmap (GDK_DRAWABLE (x_win), gc, | |
1918 IMAGE_INSTANCE_GTK_PIXMAP (p), | |
1919 xoffset, yoffset, x, y, width, height); | |
1920 #endif /* THIS_IS_GTK */ | |
1921 } | |
1922 else | |
1923 { | |
1924 #ifdef THIS_IS_X | |
1925 XCopyPlane (dpy, IMAGE_INSTANCE_X_PIXMAP_SLICE | |
1926 (p, IMAGE_INSTANCE_PIXMAP_SLICE (p)), x_win, gc, | |
1927 xoffset, yoffset, width, height, x, y, 1L); | |
1928 #else /* THIS_IS_GTK */ | |
1929 our_draw_bitmap (GDK_DRAWABLE (x_win), gc, | |
1930 IMAGE_INSTANCE_GTK_PIXMAP (p), | |
1931 xoffset, yoffset, x, y, width, height); | |
1932 #endif /* THIS_IS_GTK */ | |
1933 } | |
1934 } | |
1935 | |
1936 static void | |
1937 XLIKE_output_pixmap (struct window *w, Lisp_Object image_instance, | |
1938 struct display_box *db, struct display_glyph_area *dga, | |
1939 face_index findex, int cursor_start, int cursor_width, | |
1940 int cursor_height, int UNUSED (bg_pixmap)) | |
1941 { | |
1942 struct frame *f = XFRAME (w->frame); | |
1943 struct device *d = XDEVICE (f->device); | |
1944 Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance); | |
1945 XLIKE_DISPLAY dpy = GET_XLIKE_DISPLAY (d); | |
1946 XLIKE_WINDOW x_win = GET_XLIKE_WINDOW (f); | |
1947 | |
1948 /* Output the pixmap. */ | |
1949 { | |
1950 Lisp_Object tmp_pixel; | |
1951 XLIKE_COLOR tmp_bcolor, tmp_fcolor; | |
1952 | |
1953 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex); | |
1954 tmp_fcolor = XCOLOR_INSTANCE_XLIKE_COLOR (tmp_pixel); | |
1955 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex); | |
1956 tmp_bcolor = XCOLOR_INSTANCE_XLIKE_COLOR (tmp_pixel); | |
1957 | |
1958 XLIKE_OUTPUT_XLIKE_PIXMAP (f, p, db->xpos, db->ypos, | |
1959 dga->xoffset, dga->yoffset, | |
1960 dga->width, dga->height, | |
1961 XLIKE_COLOR_TO_PIXCOLOR (tmp_fcolor), | |
1962 XLIKE_COLOR_TO_PIXCOLOR (tmp_bcolor), 0); | |
1963 } | |
1964 | |
1965 /* Draw a cursor over top of the pixmap. */ | |
1966 if (cursor_width && cursor_height && (cursor_start >= db->xpos) | |
1967 && !NILP (w->text_cursor_visible_p) | |
1968 && (cursor_start < db->xpos + dga->width)) | |
1969 { | |
1970 XLIKE_GC gc; | |
1971 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d)); | |
1972 struct face_cachel *cursor_cachel = | |
1973 WINDOW_FACE_CACHEL (w, | |
1974 get_builtin_face_cache_index | |
1975 (w, Vtext_cursor_face)); | |
1976 | |
1977 gc = XLIKE_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil); | |
1978 | |
1979 if (cursor_width > db->xpos + dga->width - cursor_start) | |
1980 cursor_width = db->xpos + dga->width - cursor_start; | |
1981 | |
1982 if (focus) | |
1983 XLIKE_FILL_RECTANGLE (dpy, x_win, gc, cursor_start, db->ypos, | |
1984 cursor_width, cursor_height); | |
1985 else | |
1986 { | |
1987 XLIKE_DRAW_RECTANGLE (dpy, x_win, gc, cursor_start, db->ypos, | |
1988 cursor_width, cursor_height); | |
1989 } | |
1990 } | |
1991 } | |
1992 | |
1993 /***************************************************************************** | |
1994 XLIKE_output_vertical_divider | |
1995 | |
1996 Draw a vertical divider down the right side of the given window. | |
1997 ****************************************************************************/ | |
1998 static void | |
1999 XLIKE_output_vertical_divider (struct window *w, int USED_IF_X(clear)) | |
2000 { | |
2001 struct frame *f = XFRAME (w->frame); | |
2002 struct device *d = XDEVICE (f->device); | |
2003 | |
2004 XLIKE_DISPLAY dpy = GET_XLIKE_DISPLAY (d); | |
2005 XLIKE_WINDOW x_win = GET_XLIKE_WINDOW (f); | |
2006 Lisp_Object tmp_pixel; | |
2007 XLIKE_GCVALUES gcv; | |
2008 XLIKE_GC background_gc; | |
2009 #ifdef THIS_IS_X | |
2010 enum edge_style style; | |
2011 #endif /* THIS_IS_X */ | |
2012 unsigned long mask; | |
2013 int x, y1, y2, width, shadow_thickness, spacing, line_width; | |
2014 face_index div_face = | |
2015 get_builtin_face_cache_index (w, Vvertical_divider_face); | |
2016 | |
2017 width = window_divider_width (w); | |
2018 shadow_thickness = XINT (w->vertical_divider_shadow_thickness); | |
2019 spacing = XINT (w->vertical_divider_spacing); | |
2020 line_width = XINT (w->vertical_divider_line_width); | |
2021 x = WINDOW_RIGHT (w) - width; | |
2022 y1 = WINDOW_TOP (w); | |
2023 y2 = WINDOW_BOTTOM (w); | |
2024 | |
2025 memset (&gcv, ~0, sizeof (gcv)); | |
2026 | |
2027 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, div_face); | |
2028 | |
2029 /* First, get the GC's. */ | |
2030 XLIKE_SET_PIXCOLOR_COPY | |
2031 (gcv.background, | |
2032 XLIKE_COLOR_TO_PIXCOLOR (XCOLOR_INSTANCE_XLIKE_COLOR (tmp_pixel))); | |
2033 gcv.foreground = gcv.background; | |
2034 gcv.graphics_exposures = XLIKE_FALSE; | |
2035 mask = XLIKE_GC_FOREGROUND | XLIKE_GC_BACKGROUND | XLIKE_GC_EXPOSURES; | |
2036 | |
2037 background_gc = gc_cache_lookup (DEVICE_XLIKE_GC_CACHE (d), &gcv, mask); | |
2038 | |
2039 /* Clear the divider area first. This needs to be done when a | |
2040 window split occurs. */ | |
2041 #ifdef THIS_IS_X | |
2042 if (clear) | |
2043 XClearArea (dpy, x_win, x, y1, width, y2 - y1, False); | |
2044 #else /* THIS_IS_GTK */ | |
2045 /* if (clear) */ | |
2046 gdk_draw_rectangle (GDK_DRAWABLE (x_win), background_gc, TRUE, | |
2047 x, y1, width, y2 - y1); | |
2048 #endif /* THIS_IS_GTK */ | |
2049 | |
2050 #ifndef THIS_IS_GTK | |
2051 /* #### FIXME Why not? Formerly '#if 0' in the GDK code */ | |
2052 /* Draw the divider line. */ | |
2053 XLIKE_FILL_RECTANGLE (dpy, x_win, background_gc, | |
2054 x + spacing + shadow_thickness, y1, | |
2055 line_width, y2 - y1); | |
2056 | |
2057 /* This code not formerly present in GTK version, maybe the omittal | |
2058 is intentional? */ | |
2059 if (shadow_thickness < 0) | |
2060 { | |
2061 shadow_thickness = -shadow_thickness; | |
2062 style = EDGE_BEVEL_IN; | |
2063 } | |
2064 else | |
2065 { | |
2066 style = EDGE_BEVEL_OUT; | |
2067 } | |
2068 #endif /* not THIS_IS_GTK */ | |
2069 | |
2070 /* Draw the shadows around the divider line */ | |
2071 #ifdef THIS_IS_X | |
2072 x_bevel_area (w, div_face, x + spacing, y1, | |
2073 width - 2 * spacing, y2 - y1, | |
2074 shadow_thickness, EDGE_ALL, style); | |
2075 #else /* THIS_IS_GTK */ | |
2076 gtk_output_shadows (f, x + spacing, y1, | |
2077 width - 2 * spacing, y2 - y1, | |
2078 shadow_thickness); | |
2079 #endif /* THIS_IS_GTK */ | |
2080 } | |
2081 | |
2082 /***************************************************************************** | |
2083 XLIKE_output_blank | |
2084 | |
2085 Output a blank by clearing the area it covers in the foreground color | |
2086 of its face. | |
2087 ****************************************************************************/ | |
2088 static void | |
2089 XLIKE_output_blank (struct window *w, struct display_line *dl, struct rune *rb, | |
2090 int start_pixpos, int cursor_start, int cursor_width) | |
2091 { | |
2092 struct frame *f = XFRAME (w->frame); | |
2093 struct device *d = XDEVICE (f->device); | |
2094 | |
2095 XLIKE_DISPLAY dpy = GET_XLIKE_DISPLAY (d); | |
2096 XLIKE_WINDOW x_win = GET_XLIKE_WINDOW (f); | |
2097 XLIKE_GC gc; | |
2098 struct face_cachel *cursor_cachel = | |
2099 WINDOW_FACE_CACHEL (w, | |
2100 get_builtin_face_cache_index | |
2101 (w, Vtext_cursor_face)); | |
2102 Lisp_Object bg_pmap; | |
2103 Lisp_Object buffer = WINDOW_BUFFER (w); | |
2104 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor, | |
2105 buffer); | |
2106 | |
2107 int x = rb->xpos; | |
2108 int y = XLIKE_DISPLAY_LINE_YPOS (dl); | |
2109 int height = XLIKE_DISPLAY_LINE_HEIGHT (dl); | |
2110 int width = rb->width; | |
2111 | |
2112 /* Unmap all subwindows in the area we are going to blank. */ | |
2113 redisplay_unmap_subwindows_maybe (f, x, y, width, height); | |
2114 | |
2115 if (start_pixpos > x) | |
2116 { | |
2117 if (start_pixpos >= (x + width)) | |
2118 return; | |
2119 else | |
2120 { | |
2121 width -= (start_pixpos - x); | |
2122 x = start_pixpos; | |
2123 } | |
2124 } | |
2125 | |
2126 bg_pmap = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, rb->findex); | |
2127 if (!IMAGE_INSTANCEP (bg_pmap) | |
2128 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap))) | |
2129 bg_pmap = Qnil; | |
2130 | |
2131 if (NILP (bg_pmap)) | |
2132 gc = XLIKE_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex), | |
2133 Qnil, Qnil, Qnil); | |
2134 else | |
2135 gc = XLIKE_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex), | |
2136 WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex), bg_pmap, | |
2137 Qnil); | |
2138 | |
2139 XLIKE_FILL_RECTANGLE (dpy, x_win, gc, x, y, width, height); | |
2140 | |
2141 /* If this rune is marked as having the cursor, then it is actually | |
2142 representing a tab. */ | |
2143 if (!NILP (w->text_cursor_visible_p) | |
2144 && (rb->cursor_type == CURSOR_ON | |
2145 || (cursor_width | |
2146 && (cursor_start + cursor_width > x) | |
2147 && cursor_start < (x + width)))) | |
2148 { | |
2149 int cursor_height, cursor_y; | |
2150 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d)); | |
2151 Lisp_Font_Instance *fi; | |
2152 | |
2153 fi = XFONT_INSTANCE (FACE_CACHEL_FONT | |
2154 (WINDOW_FACE_CACHEL (w, rb->findex), | |
2155 Vcharset_ascii)); | |
2156 | |
2157 gc = XLIKE_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil); | |
2158 | |
2159 cursor_y = dl->ypos - fi->ascent; | |
2160 cursor_height = fi->height; | |
2161 if (cursor_y + cursor_height > y + height) | |
2162 cursor_height = y + height - cursor_y; | |
2163 | |
2164 if (focus) | |
2165 { | |
2166 if (NILP (bar_cursor_value)) | |
2167 { | |
2168 XLIKE_FILL_RECTANGLE (dpy, x_win, gc, cursor_start, cursor_y, | |
2169 fi->width, cursor_height); | |
2170 } | |
2171 else | |
2172 { | |
2173 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2; | |
2174 | |
2175 gc = XLIKE_get_gc (d, Qnil, cursor_cachel->background, | |
2176 Qnil, Qnil, make_int (bar_width)); | |
2177 XLIKE_DRAW_LINE (dpy, x_win, gc, cursor_start + bar_width - 1, | |
2178 cursor_y, cursor_start + bar_width - 1, | |
2179 cursor_y + cursor_height - 1); | |
2180 } | |
2181 } | |
2182 else if (NILP (bar_cursor_value)) | |
2183 { | |
2184 XLIKE_DRAW_RECTANGLE (dpy, x_win, gc, cursor_start, cursor_y, | |
2185 fi->width - 1, cursor_height - 1); | |
2186 } | |
2187 } | |
2188 } | |
2189 | |
2190 /***************************************************************************** | |
2191 XLIKE_output_horizontal_line | |
2192 | |
2193 Output a horizontal line in the foreground of its face. | |
2194 ****************************************************************************/ | |
2195 static void | |
2196 XLIKE_output_horizontal_line (struct window *w, struct display_line *dl, | |
2197 struct rune *rb) | |
2198 { | |
2199 struct frame *f = XFRAME (w->frame); | |
2200 struct device *d = XDEVICE (f->device); | |
2201 | |
2202 XLIKE_DISPLAY dpy = GET_XLIKE_DISPLAY (d); | |
2203 XLIKE_WINDOW x_win = GET_XLIKE_WINDOW (f); | |
2204 XLIKE_GC gc; | |
2205 | |
2206 int x = rb->xpos; | |
2207 int width = rb->width; | |
2208 int height = XLIKE_DISPLAY_LINE_HEIGHT (dl); | |
2209 int ypos1, ypos2, ypos3, ypos4; | |
2210 | |
2211 ypos1 = XLIKE_DISPLAY_LINE_YPOS (dl); | |
2212 ypos2 = ypos1 + rb->object.hline.yoffset; | |
2213 ypos3 = ypos2 + rb->object.hline.thickness; | |
2214 ypos4 = dl->ypos + dl->descent - dl->clip; | |
2215 | |
2216 /* First clear the area not covered by the line. */ | |
2217 if (height - rb->object.hline.thickness > 0) | |
2218 { | |
2219 gc = XLIKE_get_gc (d, Qnil, | |
2220 WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex), | |
2221 Qnil, Qnil, Qnil); | |
2222 | |
2223 if (ypos2 - ypos1 > 0) | |
2224 XLIKE_FILL_RECTANGLE (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1); | |
2225 if (ypos4 - ypos3 > 0) | |
2226 XLIKE_FILL_RECTANGLE (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1); | |
2227 } | |
2228 | |
2229 #ifdef THIS_IS_GTK | |
2230 { | |
2231 GtkStyle *style = FRAME_GTK_TEXT_WIDGET (f)->style; | |
2232 gtk_paint_hline (style, x_win, GTK_STATE_NORMAL, NULL, | |
2233 FRAME_GTK_TEXT_WIDGET (f), "hline", x, x + width, ypos2); | |
2234 } | |
2235 #else /* THIS_IS_X */ | |
2236 /* Now draw the line. */ | |
2237 gc = XLIKE_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex), | |
2238 Qnil, Qnil, Qnil); | |
2239 | |
2240 if (ypos2 < ypos1) | |
2241 ypos2 = ypos1; | |
2242 if (ypos3 > ypos4) | |
2243 ypos3 = ypos4; | |
2244 | |
2245 if (ypos3 - ypos2 > 0) | |
2246 XLIKE_FILL_RECTANGLE (dpy, x_win, gc, x, ypos2, width, ypos3 - ypos2); | |
2247 #endif /* THIS_IS_X */ | |
2248 } | |
2249 | |
2250 /**************************************************************************** | |
2251 XLIKE_clear_region | |
2252 | |
2253 Clear the area in the box defined by the given parameters using the | |
2254 given face. | |
2255 ****************************************************************************/ | |
2256 static void | |
2257 XLIKE_clear_region (Lisp_Object UNUSED (locale), struct device* d, | |
2258 struct frame* f, face_index UNUSED (findex), int x, int y, | |
2259 int width, int height, Lisp_Object fcolor, | |
2260 Lisp_Object bcolor, Lisp_Object background_pixmap) | |
2261 { | |
2262 XLIKE_DISPLAY dpy = GET_XLIKE_DISPLAY (d); | |
2263 XLIKE_WINDOW x_win = GET_XLIKE_WINDOW (f); | |
2264 XLIKE_GC gc = NULL; | |
2265 | |
2266 if (!UNBOUNDP (background_pixmap)) | |
2267 { | |
2268 gc = XLIKE_get_gc (d, Qnil, fcolor, bcolor, background_pixmap, Qnil); | |
2269 } | |
2270 | |
2271 if (gc) | |
2272 XLIKE_FILL_RECTANGLE (dpy, x_win, gc, x, y, width, height); | |
2273 else | |
2274 XLIKE_CLEAR_AREA (dpy, x_win, x, y, width, height); | |
2275 } | |
2276 | |
2277 /***************************************************************************** | |
2278 xlike_output_eol_cursor | |
2279 | |
2280 Draw a cursor at the end of a line. The end-of-line cursor is | |
2281 narrower than the normal cursor. | |
2282 ****************************************************************************/ | |
2283 static void | |
2284 XLIKE_output_eol_cursor (struct window *w, struct display_line *dl, int xpos, | |
2285 face_index findex) | |
2286 { | |
2287 struct frame *f = XFRAME (w->frame); | |
2288 struct device *d = XDEVICE (f->device); | |
2289 Lisp_Object window; | |
2290 | |
2291 XLIKE_DISPLAY dpy = GET_XLIKE_DISPLAY (d); | |
2292 XLIKE_WINDOW x_win = GET_XLIKE_WINDOW (f); | |
2293 XLIKE_GC gc = NULL; | |
2294 face_index elt = get_builtin_face_cache_index (w, Vtext_cursor_face); | |
2295 struct face_cachel *cursor_cachel = WINDOW_FACE_CACHEL (w, elt); | |
2296 | |
2297 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d)); | |
2298 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor, | |
2299 WINDOW_BUFFER (w)); | |
2300 | |
2301 int x = xpos; | |
2302 int y = XLIKE_DISPLAY_LINE_YPOS (dl); | |
2303 int width = EOL_CURSOR_WIDTH; | |
2304 int height = XLIKE_DISPLAY_LINE_HEIGHT (dl); | |
2305 int cursor_height, cursor_y; | |
2306 int defheight, defascent; | |
2307 | |
2308 window = wrap_window (w); | |
2309 redisplay_clear_region (window, findex, x, y, width, height); | |
2310 | |
2311 if (NILP (w->text_cursor_visible_p)) | |
2312 return; | |
2313 | |
2314 gc = XLIKE_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil); | |
2315 | |
2316 default_face_font_info (window, &defascent, 0, &defheight, 0, 0); | |
2317 | |
2318 /* make sure the cursor is entirely contained between y and y+height */ | |
2319 cursor_height = min (defheight, height); | |
2320 cursor_y = max (y, min (y + height - cursor_height, | |
2321 dl->ypos - defascent)); | |
2322 | |
2323 if (focus) | |
2324 { | |
2325 #ifdef HAVE_XIM | |
2326 XIM_SetSpotLocation (f, x - 2 , cursor_y + cursor_height - 2); | |
2327 #endif /* HAVE_XIM */ | |
2328 | |
2329 if (NILP (bar_cursor_value)) | |
2330 { | |
2331 XLIKE_FILL_RECTANGLE (dpy, x_win, gc, x, cursor_y, width, | |
2332 cursor_height); | |
2333 } | |
2334 else | |
2335 { | |
2336 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2; | |
2337 | |
2338 gc = XLIKE_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, | |
2339 make_int (bar_width)); | |
2340 XLIKE_DRAW_LINE (dpy, x_win, gc, x + bar_width - 1, cursor_y, | |
2341 x + bar_width - 1, cursor_y + cursor_height - 1); | |
2342 } | |
2343 } | |
2344 else if (NILP (bar_cursor_value)) | |
2345 { | |
2346 XLIKE_DRAW_RECTANGLE (dpy, x_win, gc, x, cursor_y, width - 1, | |
2347 cursor_height - 1); | |
2348 } | |
2349 } | |
2350 | |
2351 static void | |
2352 XLIKE_clear_frame_window (Lisp_Object window) | |
2353 { | |
2354 struct window *w = XWINDOW (window); | |
2355 | |
2356 if (!NILP (w->vchild)) | |
2357 { | |
2358 XLIKE_clear_frame_windows (w->vchild); | |
2359 return; | |
2360 } | |
2361 | |
2362 if (!NILP (w->hchild)) | |
2363 { | |
2364 XLIKE_clear_frame_windows (w->hchild); | |
2365 return; | |
2366 } | |
2367 | |
2368 redisplay_clear_to_window_end (w, WINDOW_TEXT_TOP (w), | |
2369 WINDOW_TEXT_BOTTOM (w)); | |
2370 } | |
2371 | |
2372 static void | |
2373 XLIKE_clear_frame_windows (Lisp_Object window) | |
2374 { | |
2375 for (; !NILP (window); window = XWINDOW (window)->next) | |
2376 XLIKE_clear_frame_window (window); | |
2377 } | |
2378 | |
2379 static void | |
2380 XLIKE_clear_frame (struct frame *f) | |
2381 { | |
2382 XLIKE_DISPLAY dpy = GET_XLIKE_DISPLAY (XDEVICE (f->device)); | |
2383 XLIKE_WINDOW x_win = GET_XLIKE_WINDOW (f); | |
2384 int x, y, width, height; | |
2385 Lisp_Object frame; | |
2386 | |
2387 x = FRAME_LEFT_BORDER_START (f); | |
2388 width = (FRAME_PIXWIDTH (f) - FRAME_REAL_LEFT_TOOLBAR_WIDTH (f) - | |
2389 FRAME_REAL_RIGHT_TOOLBAR_WIDTH (f) - | |
2390 2 * FRAME_REAL_LEFT_TOOLBAR_BORDER_WIDTH (f) - | |
2391 2 * FRAME_REAL_RIGHT_TOOLBAR_BORDER_WIDTH (f)); | |
2392 /* #### This adjustment by 1 should be being done in the macros. | |
2393 There is some small differences between when the menubar is on | |
2394 and off that we still need to deal with. */ | |
2395 y = FRAME_TOP_BORDER_START (f) - 1; | |
2396 height = (FRAME_PIXHEIGHT (f) - FRAME_REAL_TOP_TOOLBAR_HEIGHT (f) - | |
2397 FRAME_REAL_BOTTOM_TOOLBAR_HEIGHT (f) - | |
2398 2 * FRAME_REAL_TOP_TOOLBAR_BORDER_WIDTH (f) - | |
2399 2 * FRAME_REAL_BOTTOM_TOOLBAR_BORDER_WIDTH (f)) + 1; | |
2400 | |
2401 XLIKE_CLEAR_AREA (dpy, x_win, x, y, width, height); | |
2402 | |
2403 frame = wrap_frame (f); | |
2404 | |
2405 if (!UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vdefault_face, frame)) | |
2406 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vleft_margin_face, frame)) | |
2407 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vright_margin_face, frame))) | |
2408 { | |
2409 XLIKE_clear_frame_windows (f->root_window); | |
2410 } | |
2411 #ifdef THIS_IS_X | |
2412 { | |
2413 struct device *d = XDEVICE (f->device); | |
2414 if (!(check_if_pending_expose_event (d))) | |
2415 XFlush (DEVICE_X_DISPLAY (d)); | |
2416 } | |
2417 #endif /* THIS_IS_X */ | |
2418 } | |
2419 | |
2420 /* briefly swap the foreground and background colors. | |
2421 */ | |
2422 | |
2423 static int | |
2424 XLIKE_flash (struct device *d) | |
2425 { | |
2426 struct frame *f = device_selected_frame (d); | |
2427 XLIKE_DISPLAY dpy = GET_XLIKE_DISPLAY (d); | |
2428 XLIKE_WINDOW win = GET_XLIKE_WINDOW (f); | |
2429 XLIKE_GC gc = NULL; | |
2430 XLIKE_GCVALUES gcv; | |
2431 XLIKE_COLOR tmp_fcolor, tmp_bcolor; | |
2432 Lisp_Object tmp_pixel, frame; | |
2433 struct window *w = XWINDOW (FRAME_ROOT_WINDOW (f)); | |
2434 int flash_height; | |
2435 | |
2436 frame = wrap_frame (f); | |
2437 | |
2438 tmp_pixel = FACE_FOREGROUND (Vdefault_face, frame); | |
2439 XLIKE_SET_PIXCOLOR_COPY (tmp_fcolor, | |
2440 XCOLOR_INSTANCE_XLIKE_COLOR (tmp_pixel)); | |
2441 tmp_pixel = FACE_BACKGROUND (Vdefault_face, frame); | |
2442 XLIKE_SET_PIXCOLOR_COPY (tmp_bcolor, | |
2443 XCOLOR_INSTANCE_XLIKE_COLOR (tmp_pixel)); | |
2444 memset (&gcv, ~0, sizeof (gcv)); /* initialize all slots to ~0 */ | |
2445 XLIKE_SET_PIXCOLOR_NUM (gcv.foreground, | |
2446 (tmp_fcolor.pixel ^ tmp_bcolor.pixel)); | |
2447 gcv.function = XLIKE_GX_XOR; | |
2448 gcv.graphics_exposures = XLIKE_FALSE; | |
2449 gc = gc_cache_lookup (DEVICE_XLIKE_GC_CACHE (XDEVICE (f->device)), &gcv, | |
2450 XLIKE_GC_FOREGROUND | XLIKE_GC_FUNCTION | XLIKE_GC_EXPOSURES); | |
2451 default_face_height_and_width (frame, &flash_height, 0); | |
2452 | |
2453 /* If window is tall, flash top and bottom line. */ | |
2454 if (EQ (Vvisible_bell, Qtop_bottom) && w->pixel_height > 3 * flash_height) | |
2455 { | |
2456 XLIKE_FILL_RECTANGLE (dpy, win, gc, w->pixel_left, w->pixel_top, | |
2457 w->pixel_width, flash_height); | |
2458 XLIKE_FILL_RECTANGLE (dpy, win, gc, w->pixel_left, | |
2459 w->pixel_top + w->pixel_height - flash_height, | |
2460 w->pixel_width, flash_height); | |
2461 } | |
2462 else | |
2463 /* If it is short, flash it all. */ | |
2464 XLIKE_FILL_RECTANGLE (dpy, win, gc, w->pixel_left, w->pixel_top, | |
2465 w->pixel_width, w->pixel_height); | |
2466 | |
2467 XLIKE_FLUSH (dpy); | |
2468 | |
2469 #ifdef HAVE_SELECT | |
2470 { | |
2471 int usecs = 100000; | |
2472 struct timeval tv; | |
2473 tv.tv_sec = usecs / 1000000L; | |
2474 tv.tv_usec = usecs % 1000000L; | |
2475 /* I'm sure someone is going to complain about this... */ | |
2476 select (0, 0, 0, 0, &tv); | |
2477 } | |
2478 #else | |
2479 #ifdef HAVE_POLL | |
2480 poll (0, 0, 100); | |
2481 #else /* !HAVE_POLL */ | |
2482 #error bite me | |
2483 #endif /* HAVE_POLL */ | |
2484 #endif /* HAVE_SELECT */ | |
2485 | |
2486 /* If window is tall, flash top and bottom line. */ | |
2487 if (EQ (Vvisible_bell, Qtop_bottom) && w->pixel_height > 3 * flash_height) | |
2488 { | |
2489 XLIKE_FILL_RECTANGLE (dpy, win, gc, w->pixel_left, w->pixel_top, | |
2490 w->pixel_width, flash_height); | |
2491 XLIKE_FILL_RECTANGLE (dpy, win, gc, w->pixel_left, | |
2492 w->pixel_top + w->pixel_height - flash_height, | |
2493 w->pixel_width, flash_height); | |
2494 } | |
2495 else | |
2496 /* If it is short, flash it all. */ | |
2497 XLIKE_FILL_RECTANGLE (dpy, win, gc, w->pixel_left, w->pixel_top, | |
2498 w->pixel_width, w->pixel_height); | |
2499 | |
2500 XLIKE_FLUSH (dpy); | |
2501 | |
2502 return 1; | |
2503 } | |
2504 | |
2505 | |
2506 /************************************************************************/ | |
2507 /* initialization */ | |
2508 /************************************************************************/ | |
2509 | |
2510 void | |
2511 console_type_create_redisplay_XLIKE (void) | |
2512 { | |
2513 /* redisplay methods */ | |
2514 XLIKE_CONSOLE_HAS_METHOD (text_width); | |
2515 XLIKE_CONSOLE_HAS_METHOD (output_display_block); | |
2516 XLIKE_CONSOLE_HAS_METHOD (divider_height); | |
2517 XLIKE_CONSOLE_HAS_METHOD (eol_cursor_width); | |
2518 XLIKE_CONSOLE_HAS_METHOD (output_vertical_divider); | |
2519 XLIKE_CONSOLE_HAS_METHOD (clear_region); | |
2520 XLIKE_CONSOLE_HAS_METHOD (clear_frame); | |
2521 XLIKE_CONSOLE_HAS_METHOD (flash); | |
2522 XLIKE_CONSOLE_HAS_METHOD (ring_bell); | |
2523 XLIKE_CONSOLE_HAS_METHOD (bevel_area); | |
2524 XLIKE_CONSOLE_HAS_METHOD (output_string); | |
2525 XLIKE_CONSOLE_HAS_METHOD (output_pixmap); | |
2526 | |
2527 #ifdef THIS_IS_X | |
2528 XLIKE_CONSOLE_HAS_METHOD (window_output_begin); | |
2529 XLIKE_CONSOLE_HAS_METHOD (window_output_end); | |
2530 #endif | |
2531 } |