Mercurial > emacs
comparison src/macterm.c @ 44890:01b93e5e53a7
Patch for building Emacs on Mac OS X. April 26, 2002. See ChangeLog,
lisp/ChangeLog, and src/ChangeLog for list of changes.
author | Andrew Choi <akochoi@shaw.ca> |
---|---|
date | Fri, 26 Apr 2002 23:39:06 +0000 |
parents | |
children | cb1679526984 |
comparison
equal
deleted
inserted
replaced
44889:e3b9f45140a5 | 44890:01b93e5e53a7 |
---|---|
1 /* Implementation of GUI terminal on the Mac OS. | |
2 Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. | |
3 | |
4 This file is part of GNU Emacs. | |
5 | |
6 GNU Emacs is free software; you can redistribute it and/or modify | |
7 it under the terms of the GNU General Public License as published by | |
8 the Free Software Foundation; either version 2, or (at your option) | |
9 any later version. | |
10 | |
11 GNU Emacs is distributed in the hope that it will be useful, | |
12 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 GNU General Public License for more details. | |
15 | |
16 You should have received a copy of the GNU General Public License | |
17 along with GNU Emacs; see the file COPYING. If not, write to | |
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
19 Boston, MA 02111-1307, USA. */ | |
20 | |
21 /* Contributed by Andrew Choi (akochoi@mac.com). */ | |
22 | |
23 #include <config.h> | |
24 #include <signal.h> | |
25 #include <stdio.h> | |
26 #include <stdlib.h> | |
27 #include "lisp.h" | |
28 #include "charset.h" | |
29 #include "blockinput.h" | |
30 | |
31 #include "macterm.h" | |
32 | |
33 #ifndef MAC_OSX | |
34 #include <alloca.h> | |
35 #endif | |
36 | |
37 #ifdef MAC_OSX | |
38 #undef mktime | |
39 #undef DEBUG | |
40 #undef free | |
41 #undef malloc | |
42 #undef realloc | |
43 /* Macros max and min defined in lisp.h conflict with those in | |
44 precompiled header Carbon.h. */ | |
45 #undef max | |
46 #undef min | |
47 #include <Carbon/Carbon.h> | |
48 #undef free | |
49 #define free unexec_free | |
50 #undef malloc | |
51 #define malloc unexec_malloc | |
52 #undef realloc | |
53 #define realloc unexec_realloc | |
54 #undef min | |
55 #define min(a, b) ((a) < (b) ? (a) : (b)) | |
56 #undef max | |
57 #define max(a, b) ((a) > (b) ? (a) : (b)) | |
58 #else /* not MAC_OSX */ | |
59 #include <Quickdraw.h> | |
60 #include <ToolUtils.h> | |
61 #include <Sound.h> | |
62 #include <Events.h> | |
63 #include <Script.h> | |
64 #include <Resources.h> | |
65 #include <Fonts.h> | |
66 #include <TextUtils.h> | |
67 #include <LowMem.h> | |
68 #include <Controls.h> | |
69 #if defined (__MRC__) || (__MSL__ >= 0x6000) | |
70 #include <ControlDefinitions.h> | |
71 #endif | |
72 #include <Gestalt.h> | |
73 | |
74 #if __profile__ | |
75 #include <profiler.h> | |
76 #endif | |
77 #endif /* not MAC_OSX */ | |
78 | |
79 #include "systty.h" | |
80 #include "systime.h" | |
81 #include "atimer.h" | |
82 #include "keymap.h" | |
83 | |
84 #include <ctype.h> | |
85 #include <errno.h> | |
86 #include <setjmp.h> | |
87 #include <sys/stat.h> | |
88 | |
89 #include "keyboard.h" | |
90 #include "frame.h" | |
91 #include "dispextern.h" | |
92 #include "fontset.h" | |
93 #include "termhooks.h" | |
94 #include "termopts.h" | |
95 #include "termchar.h" | |
96 #include "gnu.h" | |
97 #include "disptab.h" | |
98 #include "buffer.h" | |
99 #include "window.h" | |
100 #include "intervals.h" | |
101 #include "composite.h" | |
102 #include "coding.h" | |
103 | |
104 #define BETWEEN(X, LOWER, UPPER) ((X) >= (LOWER) && (X) < (UPPER)) | |
105 | |
106 | |
107 /* Fringe bitmaps. */ | |
108 | |
109 enum fringe_bitmap_type | |
110 { | |
111 NO_FRINGE_BITMAP, | |
112 LEFT_TRUNCATION_BITMAP, | |
113 RIGHT_TRUNCATION_BITMAP, | |
114 OVERLAY_ARROW_BITMAP, | |
115 CONTINUED_LINE_BITMAP, | |
116 CONTINUATION_LINE_BITMAP, | |
117 ZV_LINE_BITMAP | |
118 }; | |
119 | |
120 /* Bitmap drawn to indicate lines not displaying text if | |
121 `indicate-empty-lines' is non-nil. */ | |
122 | |
123 #define zv_width 8 | |
124 #define zv_height 72 | |
125 #define zv_period 3 | |
126 static unsigned char zv_bits[] = { | |
127 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, | |
128 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, | |
129 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, | |
130 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, | |
131 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, | |
132 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, | |
133 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, | |
134 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00}; | |
135 | |
136 /* An arrow like this: `<-'. */ | |
137 | |
138 #define left_width 8 | |
139 #define left_height 8 | |
140 static unsigned char left_bits[] = { | |
141 0x18, 0x30, 0x60, 0xfc, 0xfc, 0x60, 0x30, 0x18}; | |
142 | |
143 /* Right truncation arrow bitmap `->'. */ | |
144 | |
145 #define right_width 8 | |
146 #define right_height 8 | |
147 static unsigned char right_bits[] = { | |
148 0x18, 0x0c, 0x06, 0x3f, 0x3f, 0x06, 0x0c, 0x18}; | |
149 | |
150 /* Marker for continued lines. */ | |
151 | |
152 #define continued_width 8 | |
153 #define continued_height 8 | |
154 static unsigned char continued_bits[] = { | |
155 0x3c, 0x3e, 0x03, 0x27, 0x3f, 0x3e, 0x3c, 0x3e}; | |
156 | |
157 /* Marker for continuation lines. */ | |
158 | |
159 #define continuation_width 8 | |
160 #define continuation_height 8 | |
161 static unsigned char continuation_bits[] = { | |
162 0x3c, 0x7c, 0xc0, 0xe4, 0xfc, 0x7c, 0x3c, 0x7c}; | |
163 | |
164 /* Overlay arrow bitmap. */ | |
165 | |
166 #if 0 | |
167 /* A bomb. */ | |
168 #define ov_width 8 | |
169 #define ov_height 8 | |
170 static unsigned char ov_bits[] = { | |
171 0x0c, 0x10, 0x3c, 0x7e, 0x5e, 0x5e, 0x46, 0x3c}; | |
172 #else | |
173 /* A triangular arrow. */ | |
174 #define ov_width 8 | |
175 #define ov_height 8 | |
176 static unsigned char ov_bits[] = { | |
177 0xc0, 0xf0, 0xf8, 0xfc, 0xfc, 0xf8, 0xf0, 0xc0}; | |
178 #endif | |
179 | |
180 extern Lisp_Object Qhelp_echo; | |
181 | |
182 | |
183 /* Non-nil means Emacs uses toolkit scroll bars. */ | |
184 | |
185 Lisp_Object Vx_toolkit_scroll_bars; | |
186 | |
187 /* If a string, XTread_socket generates an event to display that string. | |
188 (The display is done in read_char.) */ | |
189 | |
190 static Lisp_Object help_echo; | |
191 static Lisp_Object help_echo_window; | |
192 static Lisp_Object help_echo_object; | |
193 static int help_echo_pos; | |
194 | |
195 /* Temporary variable for XTread_socket. */ | |
196 | |
197 static Lisp_Object previous_help_echo; | |
198 | |
199 /* Non-zero means that a HELP_EVENT has been generated since Emacs | |
200 start. */ | |
201 | |
202 static int any_help_event_p; | |
203 | |
204 /* Non-zero means autoselect window with the mouse cursor. */ | |
205 | |
206 int x_autoselect_window_p; | |
207 | |
208 /* Non-zero means draw block and hollow cursor as wide as the glyph | |
209 under it. For example, if a block cursor is over a tab, it will be | |
210 drawn as wide as that tab on the display. */ | |
211 | |
212 int x_stretch_cursor_p; | |
213 | |
214 /* Non-zero means make use of UNDERLINE_POSITION font properties. */ | |
215 | |
216 int x_use_underline_position_properties; | |
217 | |
218 /* This is a chain of structures for all the X displays currently in | |
219 use. */ | |
220 | |
221 struct x_display_info *x_display_list; | |
222 | |
223 /* This is a list of cons cells, each of the form (NAME | |
224 . FONT-LIST-CACHE), one for each element of x_display_list and in | |
225 the same order. NAME is the name of the frame. FONT-LIST-CACHE | |
226 records previous values returned by x-list-fonts. */ | |
227 | |
228 Lisp_Object x_display_name_list; | |
229 | |
230 /* This is display since Mac does not support multiple ones. */ | |
231 struct mac_display_info one_mac_display_info; | |
232 | |
233 /* Frame being updated by update_frame. This is declared in term.c. | |
234 This is set by update_begin and looked at by all the XT functions. | |
235 It is zero while not inside an update. In that case, the XT | |
236 functions assume that `selected_frame' is the frame to apply to. */ | |
237 | |
238 extern struct frame *updating_frame; | |
239 | |
240 extern int waiting_for_input; | |
241 | |
242 /* This is a frame waiting to be auto-raised, within XTread_socket. */ | |
243 | |
244 struct frame *pending_autoraise_frame; | |
245 | |
246 /* Nominal cursor position -- where to draw output. | |
247 HPOS and VPOS are window relative glyph matrix coordinates. | |
248 X and Y are window relative pixel coordinates. */ | |
249 | |
250 struct cursor_pos output_cursor; | |
251 | |
252 /* Non-zero means user is interacting with a toolkit scroll bar. */ | |
253 | |
254 static int toolkit_scroll_bar_interaction; | |
255 | |
256 /* Mouse movement. | |
257 | |
258 Formerly, we used PointerMotionHintMask (in standard_event_mask) | |
259 so that we would have to call XQueryPointer after each MotionNotify | |
260 event to ask for another such event. However, this made mouse tracking | |
261 slow, and there was a bug that made it eventually stop. | |
262 | |
263 Simply asking for MotionNotify all the time seems to work better. | |
264 | |
265 In order to avoid asking for motion events and then throwing most | |
266 of them away or busy-polling the server for mouse positions, we ask | |
267 the server for pointer motion hints. This means that we get only | |
268 one event per group of mouse movements. "Groups" are delimited by | |
269 other kinds of events (focus changes and button clicks, for | |
270 example), or by XQueryPointer calls; when one of these happens, we | |
271 get another MotionNotify event the next time the mouse moves. This | |
272 is at least as efficient as getting motion events when mouse | |
273 tracking is on, and I suspect only negligibly worse when tracking | |
274 is off. */ | |
275 | |
276 /* Where the mouse was last time we reported a mouse event. */ | |
277 | |
278 FRAME_PTR last_mouse_frame; | |
279 static Rect last_mouse_glyph; | |
280 static Lisp_Object last_mouse_press_frame; | |
281 | |
282 /* The scroll bar in which the last X motion event occurred. | |
283 | |
284 If the last X motion event occurred in a scroll bar, we set this so | |
285 XTmouse_position can know whether to report a scroll bar motion or | |
286 an ordinary motion. | |
287 | |
288 If the last X motion event didn't occur in a scroll bar, we set | |
289 this to Qnil, to tell XTmouse_position to return an ordinary motion | |
290 event. */ | |
291 | |
292 static Lisp_Object last_mouse_scroll_bar; | |
293 | |
294 /* This is a hack. We would really prefer that XTmouse_position would | |
295 return the time associated with the position it returns, but there | |
296 doesn't seem to be any way to wrest the time-stamp from the server | |
297 along with the position query. So, we just keep track of the time | |
298 of the last movement we received, and return that in hopes that | |
299 it's somewhat accurate. */ | |
300 | |
301 static Time last_mouse_movement_time; | |
302 | |
303 enum mouse_tracking_type { | |
304 mouse_tracking_none, | |
305 mouse_tracking_mouse_movement, | |
306 mouse_tracking_scroll_bar | |
307 }; | |
308 | |
309 enum mouse_tracking_type mouse_tracking_in_progress = mouse_tracking_none; | |
310 | |
311 struct scroll_bar *tracked_scroll_bar = NULL; | |
312 | |
313 /* Incremented by XTread_socket whenever it really tries to read | |
314 events. */ | |
315 | |
316 #ifdef __STDC__ | |
317 static int volatile input_signal_count; | |
318 #else | |
319 static int input_signal_count; | |
320 #endif | |
321 | |
322 /* Used locally within XTread_socket. */ | |
323 | |
324 static int x_noop_count; | |
325 | |
326 /* Initial values of argv and argc. */ | |
327 | |
328 extern char **initial_argv; | |
329 extern int initial_argc; | |
330 | |
331 extern Lisp_Object Vcommand_line_args, Vsystem_name; | |
332 | |
333 /* Tells if a window manager is present or not. */ | |
334 | |
335 extern Lisp_Object Vx_no_window_manager; | |
336 | |
337 extern Lisp_Object Qface, Qmouse_face; | |
338 | |
339 extern int errno; | |
340 | |
341 /* A mask of extra modifier bits to put into every keyboard char. */ | |
342 | |
343 extern int extra_keyboard_modifiers; | |
344 | |
345 static Lisp_Object Qvendor_specific_keysyms; | |
346 | |
347 #if 0 | |
348 extern XrmDatabase x_load_resources P_ ((Display *, char *, char *, char *)); | |
349 #endif | |
350 | |
351 extern Lisp_Object x_icon_type P_ ((struct frame *)); | |
352 | |
353 | |
354 #if __MRC__ | |
355 QDGlobals qd; /* QuickDraw global information structure. */ | |
356 #endif | |
357 | |
358 | |
359 /* Enumeration for overriding/changing the face to use for drawing | |
360 glyphs in x_draw_glyphs. */ | |
361 | |
362 enum draw_glyphs_face | |
363 { | |
364 DRAW_NORMAL_TEXT, | |
365 DRAW_INVERSE_VIDEO, | |
366 DRAW_CURSOR, | |
367 DRAW_MOUSE_FACE, | |
368 DRAW_IMAGE_RAISED, | |
369 DRAW_IMAGE_SUNKEN | |
370 }; | |
371 | |
372 struct frame * x_window_to_frame (struct mac_display_info *, WindowPtr); | |
373 struct mac_display_info *mac_display_info_for_display (Display *); | |
374 static void x_update_window_end P_ ((struct window *, int, int)); | |
375 static void frame_to_window_pixel_xy P_ ((struct window *, int *, int *)); | |
376 static int fast_find_position P_ ((struct window *, int, int *, int *, | |
377 int *, int *, Lisp_Object)); | |
378 static int fast_find_string_pos P_ ((struct window *, int, Lisp_Object, | |
379 int *, int *, int *, int *, int)); | |
380 static void set_output_cursor P_ ((struct cursor_pos *)); | |
381 static struct glyph *x_y_to_hpos_vpos P_ ((struct window *, int, int, | |
382 int *, int *, int *, int)); | |
383 static void note_mode_line_highlight P_ ((struct window *, int, int)); | |
384 static void note_mouse_highlight P_ ((struct frame *, int, int)); | |
385 static void note_tool_bar_highlight P_ ((struct frame *f, int, int)); | |
386 static void x_handle_tool_bar_click P_ ((struct frame *, EventRecord *)); | |
387 static void show_mouse_face P_ ((struct x_display_info *, | |
388 enum draw_glyphs_face)); | |
389 static int cursor_in_mouse_face_p P_ ((struct window *)); | |
390 static int clear_mouse_face P_ ((struct mac_display_info *)); | |
391 static int x_io_error_quitter P_ ((Display *)); | |
392 int x_catch_errors P_ ((Display *)); | |
393 void x_uncatch_errors P_ ((Display *, int)); | |
394 void x_lower_frame P_ ((struct frame *)); | |
395 void x_scroll_bar_clear P_ ((struct frame *)); | |
396 int x_had_errors_p P_ ((Display *)); | |
397 void x_wm_set_size_hint P_ ((struct frame *, long, int)); | |
398 void x_raise_frame P_ ((struct frame *)); | |
399 void x_set_window_size P_ ((struct frame *, int, int, int)); | |
400 void x_wm_set_window_state P_ ((struct frame *, int)); | |
401 void x_wm_set_icon_pixmap P_ ((struct frame *, int)); | |
402 void mac_initialize P_ ((void)); | |
403 static void x_font_min_bounds P_ ((XFontStruct *, int *, int *)); | |
404 static int x_compute_min_glyph_bounds P_ ((struct frame *)); | |
405 enum text_cursor_kinds x_specified_cursor_type P_ ((Lisp_Object, int *)); | |
406 static void x_draw_phys_cursor_glyph P_ ((struct window *, | |
407 struct glyph_row *, | |
408 enum draw_glyphs_face)); | |
409 static void x_update_end P_ ((struct frame *)); | |
410 static void XTframe_up_to_date P_ ((struct frame *)); | |
411 static void XTreassert_line_highlight P_ ((int, int)); | |
412 static void x_change_line_highlight P_ ((int, int, int, int)); | |
413 static void XTset_terminal_modes P_ ((void)); | |
414 static void XTreset_terminal_modes P_ ((void)); | |
415 static void XTcursor_to P_ ((int, int, int, int)); | |
416 static void x_write_glyphs P_ ((struct glyph *, int)); | |
417 static void x_clear_end_of_line P_ ((int)); | |
418 static void x_clear_frame P_ ((void)); | |
419 static void x_clear_cursor P_ ((struct window *)); | |
420 static void frame_highlight P_ ((struct frame *)); | |
421 static void frame_unhighlight P_ ((struct frame *)); | |
422 static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *)); | |
423 static void XTframe_rehighlight P_ ((struct frame *)); | |
424 static void x_frame_rehighlight P_ ((struct x_display_info *)); | |
425 static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *)); | |
426 static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int)); | |
427 static int x_intersect_rectangles P_ ((Rect *, Rect *, Rect *)); | |
428 static void expose_frame P_ ((struct frame *, int, int, int, int)); | |
429 static int expose_window_tree P_ ((struct window *, Rect *)); | |
430 static int expose_window P_ ((struct window *, Rect *)); | |
431 static void expose_area P_ ((struct window *, struct glyph_row *, | |
432 Rect *, enum glyph_row_area)); | |
433 static int expose_line P_ ((struct window *, struct glyph_row *, | |
434 Rect *)); | |
435 void x_display_cursor (struct window *, int, int, int, int, int); | |
436 void x_update_cursor P_ ((struct frame *, int)); | |
437 static void x_update_cursor_in_window_tree P_ ((struct window *, int)); | |
438 static void x_update_window_cursor P_ ((struct window *, int)); | |
439 static void x_erase_phys_cursor P_ ((struct window *)); | |
440 void x_display_and_set_cursor P_ ((struct window *, int, int, int, int, int)); | |
441 static void x_draw_fringe_bitmap P_ ((struct window *, struct glyph_row *, | |
442 enum fringe_bitmap_type, int left_p)); | |
443 static void x_clip_to_row P_ ((struct window *, struct glyph_row *, | |
444 GC, int)); | |
445 static int x_phys_cursor_in_rect_p P_ ((struct window *, Rect *)); | |
446 static void x_draw_row_fringe_bitmaps P_ ((struct window *, struct glyph_row *)); | |
447 static void notice_overwritten_cursor P_ ((struct window *, | |
448 enum glyph_row_area, | |
449 int, int, int, int)); | |
450 static void x_flush P_ ((struct frame *f)); | |
451 static void x_update_begin P_ ((struct frame *)); | |
452 static void x_update_window_begin P_ ((struct window *)); | |
453 static void x_draw_vertical_border P_ ((struct window *)); | |
454 static void x_after_update_window_line P_ ((struct glyph_row *)); | |
455 static INLINE void take_vertical_position_into_account P_ ((struct it *)); | |
456 static void x_produce_stretch_glyph P_ ((struct it *)); | |
457 | |
458 static void activate_scroll_bars (FRAME_PTR); | |
459 static void deactivate_scroll_bars (FRAME_PTR); | |
460 | |
461 extern int image_ascent (struct image *, struct face *); | |
462 void x_set_offset (struct frame *, int, int, int); | |
463 int x_bitmap_icon (struct frame *, Lisp_Object); | |
464 void x_make_frame_visible (struct frame *); | |
465 | |
466 extern void window_scroll (Lisp_Object, int, int, int); | |
467 | |
468 /* Defined in macmenu.h. */ | |
469 extern void menubar_selection_callback (FRAME_PTR, int); | |
470 extern void set_frame_menubar (FRAME_PTR, int, int); | |
471 | |
472 /* X display function emulation */ | |
473 | |
474 /* Structure borrowed from Xlib.h to represent two-byte characters in | |
475 dumpglyphs. */ | |
476 | |
477 typedef struct { | |
478 unsigned char byte1; | |
479 unsigned char byte2; | |
480 } XChar2b; | |
481 | |
482 static void | |
483 XFreePixmap (display, pixmap) | |
484 Display *display; | |
485 Pixmap pixmap; | |
486 { | |
487 PixMap *p = (PixMap *) pixmap; | |
488 | |
489 xfree (p->baseAddr); | |
490 xfree (p); | |
491 } | |
492 | |
493 | |
494 /* Set foreground color for subsequent QuickDraw commands. Assume | |
495 graphic port has already been set. */ | |
496 | |
497 static void | |
498 mac_set_forecolor (unsigned long color) | |
499 { | |
500 RGBColor fg_color; | |
501 | |
502 fg_color.red = RED_FROM_ULONG (color) * 256; | |
503 fg_color.green = GREEN_FROM_ULONG (color) * 256; | |
504 fg_color.blue = BLUE_FROM_ULONG (color) * 256; | |
505 | |
506 RGBForeColor (&fg_color); | |
507 } | |
508 | |
509 | |
510 /* Set background color for subsequent QuickDraw commands. Assume | |
511 graphic port has already been set. */ | |
512 | |
513 static void | |
514 mac_set_backcolor (unsigned long color) | |
515 { | |
516 RGBColor bg_color; | |
517 | |
518 bg_color.red = RED_FROM_ULONG (color) * 256; | |
519 bg_color.green = GREEN_FROM_ULONG (color) * 256; | |
520 bg_color.blue = BLUE_FROM_ULONG (color) * 256; | |
521 | |
522 RGBBackColor (&bg_color); | |
523 } | |
524 | |
525 /* Set foreground and background color for subsequent QuickDraw | |
526 commands. Assume that the graphic port has already been set. */ | |
527 | |
528 static void | |
529 mac_set_colors (GC gc) | |
530 { | |
531 mac_set_forecolor (gc->foreground); | |
532 mac_set_backcolor (gc->background); | |
533 } | |
534 | |
535 /* Mac version of XDrawLine. */ | |
536 | |
537 static void | |
538 XDrawLine (display, w, gc, x1, y1, x2, y2) | |
539 Display *display; | |
540 WindowPtr w; | |
541 GC gc; | |
542 int x1, y1, x2, y2; | |
543 { | |
544 #if TARGET_API_MAC_CARBON | |
545 SetPort (GetWindowPort (w)); | |
546 #else | |
547 SetPort (w); | |
548 #endif | |
549 | |
550 mac_set_colors (gc); | |
551 | |
552 MoveTo (x1, y1); | |
553 LineTo (x2, y2); | |
554 } | |
555 | |
556 /* Mac version of XClearArea. */ | |
557 | |
558 void | |
559 XClearArea (display, w, x, y, width, height, exposures) | |
560 Display *display; | |
561 WindowPtr w; | |
562 int x, y; | |
563 unsigned int width, height; | |
564 int exposures; | |
565 { | |
566 struct mac_output *mwp = (mac_output *) GetWRefCon (w); | |
567 Rect r; | |
568 XGCValues xgc; | |
569 | |
570 xgc.foreground = mwp->x_compatible.foreground_pixel; | |
571 xgc.background = mwp->x_compatible.background_pixel; | |
572 | |
573 #if TARGET_API_MAC_CARBON | |
574 SetPort (GetWindowPort (w)); | |
575 #else | |
576 SetPort (w); | |
577 #endif | |
578 | |
579 mac_set_colors (&xgc); | |
580 SetRect (&r, x, y, x + width, y + height); | |
581 | |
582 EraseRect (&r); | |
583 } | |
584 | |
585 /* Mac version of XClearWindow. */ | |
586 | |
587 static void | |
588 XClearWindow (display, w) | |
589 Display *display; | |
590 WindowPtr w; | |
591 { | |
592 struct mac_output *mwp = (mac_output *) GetWRefCon (w); | |
593 XGCValues xgc; | |
594 | |
595 xgc.foreground = mwp->x_compatible.foreground_pixel; | |
596 xgc.background = mwp->x_compatible.background_pixel; | |
597 | |
598 #if TARGET_API_MAC_CARBON | |
599 SetPort (GetWindowPort (w)); | |
600 #else | |
601 SetPort (w); | |
602 #endif | |
603 | |
604 mac_set_colors (&xgc); | |
605 | |
606 #if TARGET_API_MAC_CARBON | |
607 { | |
608 Rect r; | |
609 | |
610 GetWindowPortBounds (w, &r); | |
611 EraseRect (&r); | |
612 } | |
613 #else /* not TARGET_API_MAC_CARBON */ | |
614 EraseRect (&(w->portRect)); | |
615 #endif /* not TARGET_API_MAC_CARBON */ | |
616 } | |
617 | |
618 | |
619 /* Mac replacement for XCopyArea. */ | |
620 | |
621 static void | |
622 mac_draw_bitmap (display, w, gc, x, y, bitmap) | |
623 Display *display; | |
624 WindowPtr w; | |
625 GC gc; | |
626 int x, y; | |
627 BitMap *bitmap; | |
628 { | |
629 Rect r; | |
630 | |
631 #if TARGET_API_MAC_CARBON | |
632 SetPort (GetWindowPort (w)); | |
633 #else | |
634 SetPort (w); | |
635 #endif | |
636 | |
637 mac_set_colors (gc); | |
638 SetRect (&r, x, y, x + bitmap->bounds.right, y + bitmap->bounds.bottom); | |
639 | |
640 #if TARGET_API_MAC_CARBON | |
641 { | |
642 PixMapHandle pmh; | |
643 | |
644 LockPortBits (GetWindowPort (w)); | |
645 pmh = GetPortPixMap (GetWindowPort (w)); | |
646 CopyBits (bitmap, (BitMap *) *pmh, &(bitmap->bounds), &r, srcCopy, 0); | |
647 UnlockPortBits (GetWindowPort (w)); | |
648 } | |
649 #else /* not TARGET_API_MAC_CARBON */ | |
650 CopyBits (bitmap, &(w->portBits), &(bitmap->bounds), &r, srcCopy, 0); | |
651 #endif /* not TARGET_API_MAC_CARBON */ | |
652 } | |
653 | |
654 | |
655 /* Mac replacement for XSetClipRectangles. */ | |
656 | |
657 static void | |
658 mac_set_clip_rectangle (display, w, r) | |
659 Display *display; | |
660 WindowPtr w; | |
661 Rect *r; | |
662 { | |
663 #if TARGET_API_MAC_CARBON | |
664 SetPort (GetWindowPort (w)); | |
665 #else | |
666 SetPort (w); | |
667 #endif | |
668 | |
669 ClipRect (r); | |
670 } | |
671 | |
672 | |
673 /* Mac replacement for XSetClipMask. */ | |
674 | |
675 static void | |
676 mac_reset_clipping (display, w) | |
677 Display *display; | |
678 WindowPtr w; | |
679 { | |
680 Rect r; | |
681 | |
682 #if TARGET_API_MAC_CARBON | |
683 SetPort (GetWindowPort (w)); | |
684 #else | |
685 SetPort (w); | |
686 #endif | |
687 | |
688 SetRect (&r, -32767, -32767, 32767, 32767); | |
689 ClipRect (&r); | |
690 } | |
691 | |
692 | |
693 /* Mac replacement for XCreateBitmapFromBitmapData. */ | |
694 | |
695 static void | |
696 mac_create_bitmap_from_bitmap_data (bitmap, bits, w, h) | |
697 BitMap *bitmap; | |
698 char *bits; | |
699 int w, h; | |
700 { | |
701 int bytes_per_row, i, j; | |
702 | |
703 bitmap->rowBytes = (w + 15) / 16 * 2; /* must be on word boundary */ | |
704 bitmap->baseAddr = xmalloc (bitmap->rowBytes * h); | |
705 if (!bitmap->baseAddr) | |
706 abort (); | |
707 | |
708 bzero (bitmap->baseAddr, bitmap->rowBytes * h); | |
709 for (i = 0; i < h; i++) | |
710 for (j = 0; j < w; j++) | |
711 if (BitTst (bits, i * w + j)) | |
712 BitSet (bitmap->baseAddr, i * bitmap->rowBytes * 8 + j); | |
713 | |
714 SetRect (&(bitmap->bounds), 0, 0, w, h); | |
715 } | |
716 | |
717 | |
718 static void | |
719 mac_free_bitmap (bitmap) | |
720 BitMap *bitmap; | |
721 { | |
722 xfree (bitmap->baseAddr); | |
723 } | |
724 | |
725 /* Mac replacement for XFillRectangle. */ | |
726 | |
727 static void | |
728 XFillRectangle (display, w, gc, x, y, width, height) | |
729 Display *display; | |
730 WindowPtr w; | |
731 GC gc; | |
732 int x, y; | |
733 unsigned int width, height; | |
734 { | |
735 Rect r; | |
736 | |
737 #if TARGET_API_MAC_CARBON | |
738 SetPort (GetWindowPort (w)); | |
739 #else | |
740 SetPort (w); | |
741 #endif | |
742 | |
743 mac_set_colors (gc); | |
744 SetRect (&r, x, y, x + width, y + height); | |
745 | |
746 PaintRect (&r); /* using foreground color of gc */ | |
747 } | |
748 | |
749 | |
750 /* Mac replacement for XDrawRectangle: dest is a window. */ | |
751 | |
752 static void | |
753 mac_draw_rectangle (display, w, gc, x, y, width, height) | |
754 Display *display; | |
755 WindowPtr w; | |
756 GC gc; | |
757 int x, y; | |
758 unsigned int width, height; | |
759 { | |
760 Rect r; | |
761 | |
762 #if TARGET_API_MAC_CARBON | |
763 SetPort (GetWindowPort (w)); | |
764 #else | |
765 SetPort (w); | |
766 #endif | |
767 | |
768 mac_set_colors (gc); | |
769 SetRect (&r, x, y, x + width + 1, y + height + 1); | |
770 | |
771 FrameRect (&r); /* using foreground color of gc */ | |
772 } | |
773 | |
774 | |
775 /* Mac replacement for XDrawRectangle: dest is a Pixmap. */ | |
776 | |
777 static void | |
778 mac_draw_rectangle_to_pixmap (display, p, gc, x, y, width, height) | |
779 Display *display; | |
780 Pixmap p; | |
781 GC gc; | |
782 int x, y; | |
783 unsigned int width, height; | |
784 { | |
785 #if 0 /* MAC_TODO: draw a rectangle in a PixMap */ | |
786 Rect r; | |
787 | |
788 #if TARGET_API_MAC_CARBON | |
789 SetPort (GetWindowPort (w)); | |
790 #else | |
791 SetPort (w); | |
792 #endif | |
793 | |
794 mac_set_colors (gc); | |
795 SetRect (&r, x, y, x + width, y + height); | |
796 | |
797 FrameRect (&r); /* using foreground color of gc */ | |
798 #endif /* 0 */ | |
799 } | |
800 | |
801 | |
802 static void | |
803 mac_draw_string_common (display, w, gc, x, y, buf, nchars, mode, | |
804 bytes_per_char) | |
805 Display *display; | |
806 WindowPtr w; | |
807 GC gc; | |
808 int x, y; | |
809 char *buf; | |
810 int nchars, mode, bytes_per_char; | |
811 { | |
812 #if TARGET_API_MAC_CARBON | |
813 SetPort (GetWindowPort (w)); | |
814 #else | |
815 SetPort (w); | |
816 #endif | |
817 | |
818 mac_set_colors (gc); | |
819 | |
820 TextFont (gc->font->mac_fontnum); | |
821 TextSize (gc->font->mac_fontsize); | |
822 TextFace (gc->font->mac_fontface); | |
823 TextMode (mode); | |
824 | |
825 MoveTo (x, y); | |
826 DrawText (buf, 0, nchars * bytes_per_char); | |
827 } | |
828 | |
829 | |
830 /* Mac replacement for XDrawString. */ | |
831 | |
832 static void | |
833 XDrawString (display, w, gc, x, y, buf, nchars) | |
834 Display *display; | |
835 WindowPtr w; | |
836 GC gc; | |
837 int x, y; | |
838 char *buf; | |
839 int nchars; | |
840 { | |
841 mac_draw_string_common (display, w, gc, x, y, buf, nchars, srcOr, 1); | |
842 } | |
843 | |
844 | |
845 /* Mac replacement for XDrawString16. */ | |
846 | |
847 static void | |
848 XDrawString16 (display, w, gc, x, y, buf, nchars) | |
849 Display *display; | |
850 WindowPtr w; | |
851 GC gc; | |
852 int x, y; | |
853 XChar2b *buf; | |
854 int nchars; | |
855 { | |
856 mac_draw_string_common (display, w, gc, x, y, (char *) buf, nchars, srcOr, | |
857 2); | |
858 } | |
859 | |
860 | |
861 /* Mac replacement for XDrawImageString. */ | |
862 | |
863 static void | |
864 XDrawImageString (display, w, gc, x, y, buf, nchars) | |
865 Display *display; | |
866 WindowPtr w; | |
867 GC gc; | |
868 int x, y; | |
869 char *buf; | |
870 int nchars; | |
871 { | |
872 mac_draw_string_common (display, w, gc, x, y, buf, nchars, srcCopy, 1); | |
873 } | |
874 | |
875 | |
876 /* Mac replacement for XDrawString16. */ | |
877 | |
878 static void | |
879 XDrawImageString16 (display, w, gc, x, y, buf, nchars) | |
880 Display *display; | |
881 WindowPtr w; | |
882 GC gc; | |
883 int x, y; | |
884 XChar2b *buf; | |
885 int nchars; | |
886 { | |
887 mac_draw_string_common (display, w, gc, x, y, (char *) buf, nchars, srcCopy, | |
888 2); | |
889 } | |
890 | |
891 | |
892 /* Mac replacement for XCopyArea: dest must be window. */ | |
893 | |
894 static void | |
895 mac_copy_area (display, src, dest, gc, src_x, src_y, width, height, dest_x, | |
896 dest_y) | |
897 Display *display; | |
898 Pixmap src; | |
899 WindowPtr dest; | |
900 GC gc; | |
901 int src_x, src_y; | |
902 unsigned int width, height; | |
903 int dest_x, dest_y; | |
904 { | |
905 Rect src_r, dest_r; | |
906 | |
907 #if TARGET_API_MAC_CARBON | |
908 SetPort (GetWindowPort (dest)); | |
909 #else | |
910 SetPort (dest); | |
911 #endif | |
912 | |
913 mac_set_colors (gc); | |
914 | |
915 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height); | |
916 SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height); | |
917 | |
918 #if TARGET_API_MAC_CARBON | |
919 { | |
920 PixMapHandle pmh; | |
921 | |
922 LockPortBits (GetWindowPort (dest)); | |
923 pmh = GetPortPixMap (GetWindowPort (dest)); | |
924 CopyBits ((BitMap *) &src, (BitMap *) *pmh, &src_r, &dest_r, srcCopy, 0); | |
925 UnlockPortBits (GetWindowPort (dest)); | |
926 } | |
927 #else /* not TARGET_API_MAC_CARBON */ | |
928 CopyBits ((BitMap *) &src, &(dest->portBits), &src_r, &dest_r, srcCopy, 0); | |
929 #endif /* not TARGET_API_MAC_CARBON */ | |
930 } | |
931 | |
932 | |
933 #if 0 | |
934 /* Convert a pair of local coordinates to global (screen) coordinates. | |
935 Assume graphic port has been properly set. */ | |
936 static void | |
937 local_to_global_coord (short *h, short *v) | |
938 { | |
939 Point p; | |
940 | |
941 p.h = *h; | |
942 p.v = *v; | |
943 | |
944 LocalToGlobal (&p); | |
945 | |
946 *h = p.h; | |
947 *v = p.v; | |
948 } | |
949 #endif | |
950 | |
951 /* Mac replacement for XCopyArea: used only for scrolling. */ | |
952 | |
953 static void | |
954 mac_scroll_area (display, w, gc, src_x, src_y, width, height, dest_x, dest_y) | |
955 Display *display; | |
956 WindowPtr w; | |
957 GC gc; | |
958 int src_x, src_y; | |
959 unsigned int width, height; | |
960 int dest_x, dest_y; | |
961 { | |
962 #if TARGET_API_MAC_CARBON | |
963 Rect gw_r, src_r, dest_r; | |
964 PixMapHandle pmh; | |
965 | |
966 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height); | |
967 SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height); | |
968 | |
969 SetPort (GetWindowPort (w)); | |
970 mac_set_colors (gc); | |
971 | |
972 LockPortBits (GetWindowPort (w)); | |
973 pmh = GetPortPixMap (GetWindowPort (w)); | |
974 CopyBits ((BitMap *) *pmh, (BitMap *) *pmh, &src_r, &dest_r, srcCopy, 0); | |
975 UnlockPortBits (GetWindowPort (w)); | |
976 #else /* not TARGET_API_MAC_CARBON */ | |
977 Rect src_r, dest_r; | |
978 | |
979 SetPort (w); | |
980 #if 0 | |
981 mac_set_colors (gc); | |
982 #endif | |
983 | |
984 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height); | |
985 SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height); | |
986 | |
987 #if 0 | |
988 /* Need to use global coordinates and screenBits since src and dest | |
989 areas overlap in general. */ | |
990 local_to_global_coord (&src_r.left, &src_r.top); | |
991 local_to_global_coord (&src_r.right, &src_r.bottom); | |
992 local_to_global_coord (&dest_r.left, &dest_r.top); | |
993 local_to_global_coord (&dest_r.right, &dest_r.bottom); | |
994 | |
995 CopyBits (&qd.screenBits, &qd.screenBits, &src_r, &dest_r, srcCopy, 0); | |
996 #else | |
997 /* In Color QuickDraw, set ForeColor and BackColor as follows to avoid | |
998 color mapping in CopyBits. Otherwise, it will be slow. */ | |
999 ForeColor (blackColor); | |
1000 BackColor (whiteColor); | |
1001 CopyBits (&(w->portBits), &(w->portBits), &src_r, &dest_r, srcCopy, 0); | |
1002 | |
1003 mac_set_colors (gc); | |
1004 #endif | |
1005 #endif /* not TARGET_API_MAC_CARBON */ | |
1006 } | |
1007 | |
1008 | |
1009 /* Mac replacement for XCopyArea: dest must be Pixmap. */ | |
1010 | |
1011 static void | |
1012 mac_copy_area_to_pixmap (display, src, dest, gc, src_x, src_y, width, height, | |
1013 dest_x, dest_y) | |
1014 Display *display; | |
1015 Pixmap src; | |
1016 Pixmap dest; | |
1017 GC gc; | |
1018 int src_x, src_y; | |
1019 unsigned int width, height; | |
1020 int dest_x, dest_y; | |
1021 { | |
1022 Rect src_r, dest_r; | |
1023 int src_right = ((PixMap *) src)->bounds.right; | |
1024 int src_bottom = ((PixMap *) src)->bounds.bottom; | |
1025 int w = src_right - src_x; | |
1026 int h = src_bottom - src_y; | |
1027 | |
1028 mac_set_colors (gc); | |
1029 | |
1030 SetRect (&src_r, src_x, src_y, src_right, src_bottom); | |
1031 SetRect (&dest_r, dest_x, dest_y, dest_x + w, dest_y + h); | |
1032 | |
1033 CopyBits ((BitMap *) &src, (BitMap *) &dest, &src_r, &dest_r, srcCopy, 0); | |
1034 } | |
1035 | |
1036 | |
1037 /* Mac replacement for XChangeGC. */ | |
1038 | |
1039 static void | |
1040 XChangeGC (void * ignore, XGCValues* gc, unsigned long mask, | |
1041 XGCValues *xgcv) | |
1042 { | |
1043 if (mask & GCForeground) | |
1044 gc->foreground = xgcv->foreground; | |
1045 if (mask & GCBackground) | |
1046 gc->background = xgcv->background; | |
1047 if (mask & GCFont) | |
1048 gc->font = xgcv->font; | |
1049 } | |
1050 | |
1051 | |
1052 /* Mac replacement for XCreateGC. */ | |
1053 | |
1054 XGCValues * | |
1055 XCreateGC (void * ignore, Window window, unsigned long mask, | |
1056 XGCValues *xgcv) | |
1057 { | |
1058 XGCValues *gc = (XGCValues *) xmalloc (sizeof (XGCValues)); | |
1059 bzero (gc, sizeof (XGCValues)); | |
1060 | |
1061 XChangeGC (ignore, gc, mask, xgcv); | |
1062 | |
1063 return gc; | |
1064 } | |
1065 | |
1066 | |
1067 /* Used in xfaces.c. */ | |
1068 | |
1069 void | |
1070 XFreeGC (display, gc) | |
1071 Display *display; | |
1072 GC gc; | |
1073 { | |
1074 xfree (gc); | |
1075 } | |
1076 | |
1077 | |
1078 /* Mac replacement for XGetGCValues. */ | |
1079 | |
1080 static void | |
1081 XGetGCValues (void* ignore, XGCValues *gc, | |
1082 unsigned long mask, XGCValues *xgcv) | |
1083 { | |
1084 XChangeGC (ignore, xgcv, mask, gc); | |
1085 } | |
1086 | |
1087 | |
1088 /* Mac replacement for XSetForeground. */ | |
1089 | |
1090 static void | |
1091 XSetForeground (display, gc, color) | |
1092 Display *display; | |
1093 GC gc; | |
1094 unsigned long color; | |
1095 { | |
1096 gc->foreground = color; | |
1097 } | |
1098 | |
1099 | |
1100 /* Mac replacement for XSetFont. */ | |
1101 | |
1102 static void | |
1103 XSetFont (display, gc, font) | |
1104 Display *display; | |
1105 GC gc; | |
1106 XFontStruct *font; | |
1107 { | |
1108 gc->font = font; | |
1109 } | |
1110 | |
1111 | |
1112 static void | |
1113 XTextExtents16 (XFontStruct *font, XChar2b *text, int nchars, | |
1114 int *direction,int *font_ascent, | |
1115 int *font_descent, XCharStruct *cs) | |
1116 { | |
1117 /* MAC_TODO: Use GetTextMetrics to do this and inline it below. */ | |
1118 } | |
1119 | |
1120 | |
1121 /* x_sync is a no-op on Mac. */ | |
1122 void | |
1123 x_sync (f) | |
1124 void *f; | |
1125 { | |
1126 } | |
1127 | |
1128 | |
1129 /* Remove calls to XFlush by defining XFlush to an empty replacement. | |
1130 Calls to XFlush should be unnecessary because the X output buffer | |
1131 is flushed automatically as needed by calls to XPending, | |
1132 XNextEvent, or XWindowEvent according to the XFlush man page. | |
1133 XTread_socket calls XPending. Removing XFlush improves | |
1134 performance. */ | |
1135 | |
1136 #if TARGET_API_MAC_CARBON | |
1137 #define XFlush(DISPLAY) QDFlushPortBuffer (GetQDGlobalsThePort (), NULL) | |
1138 #else | |
1139 #define XFlush(DISPLAY) (void) 0 | |
1140 #endif | |
1141 | |
1142 /* Flush display of frame F, or of all frames if F is null. */ | |
1143 | |
1144 void | |
1145 x_flush (f) | |
1146 struct frame *f; | |
1147 { | |
1148 #if TARGET_API_MAC_CARBON | |
1149 BLOCK_INPUT; | |
1150 if (f == NULL) | |
1151 { | |
1152 Lisp_Object rest, frame; | |
1153 FOR_EACH_FRAME (rest, frame) | |
1154 x_flush (XFRAME (frame)); | |
1155 } | |
1156 else if (FRAME_X_P (f)) | |
1157 XFlush (FRAME_MAC_DISPLAY (f)); | |
1158 UNBLOCK_INPUT; | |
1159 #endif /* TARGET_API_MAC_CARBON */ | |
1160 } | |
1161 | |
1162 | |
1163 | |
1164 /* Return the struct mac_display_info corresponding to DPY. There's | |
1165 only one. */ | |
1166 | |
1167 struct mac_display_info * | |
1168 mac_display_info_for_display (dpy) | |
1169 Display *dpy; | |
1170 { | |
1171 return &one_mac_display_info; | |
1172 } | |
1173 | |
1174 | |
1175 | |
1176 /*********************************************************************** | |
1177 Starting and ending an update | |
1178 ***********************************************************************/ | |
1179 | |
1180 /* Start an update of frame F. This function is installed as a hook | |
1181 for update_begin, i.e. it is called when update_begin is called. | |
1182 This function is called prior to calls to x_update_window_begin for | |
1183 each window being updated. */ | |
1184 | |
1185 static void | |
1186 x_update_begin (f) | |
1187 struct frame *f; | |
1188 { | |
1189 /* Nothing to do. */ | |
1190 } | |
1191 | |
1192 | |
1193 /* Start update of window W. Set the global variable updated_window | |
1194 to the window being updated and set output_cursor to the cursor | |
1195 position of W. */ | |
1196 | |
1197 static void | |
1198 x_update_window_begin (w) | |
1199 struct window *w; | |
1200 { | |
1201 struct frame *f = XFRAME (WINDOW_FRAME (w)); | |
1202 struct mac_display_info *display_info = FRAME_MAC_DISPLAY_INFO (f); | |
1203 | |
1204 updated_window = w; | |
1205 set_output_cursor (&w->cursor); | |
1206 | |
1207 BLOCK_INPUT; | |
1208 | |
1209 if (f == display_info->mouse_face_mouse_frame) | |
1210 { | |
1211 /* Don't do highlighting for mouse motion during the update. */ | |
1212 display_info->mouse_face_defer = 1; | |
1213 | |
1214 /* If F needs to be redrawn, simply forget about any prior mouse | |
1215 highlighting. */ | |
1216 if (FRAME_GARBAGED_P (f)) | |
1217 display_info->mouse_face_window = Qnil; | |
1218 | |
1219 #if 0 /* Rows in a current matrix containing glyphs in mouse-face have | |
1220 their mouse_face_p flag set, which means that they are always | |
1221 unequal to rows in a desired matrix which never have that | |
1222 flag set. So, rows containing mouse-face glyphs are never | |
1223 scrolled, and we don't have to switch the mouse highlight off | |
1224 here to prevent it from being scrolled. */ | |
1225 | |
1226 /* Can we tell that this update does not affect the window | |
1227 where the mouse highlight is? If so, no need to turn off. | |
1228 Likewise, don't do anything if the frame is garbaged; | |
1229 in that case, the frame's current matrix that we would use | |
1230 is all wrong, and we will redisplay that line anyway. */ | |
1231 if (!NILP (display_info->mouse_face_window) | |
1232 && w == XWINDOW (display_info->mouse_face_window)) | |
1233 { | |
1234 int i; | |
1235 | |
1236 for (i = 0; i < w->desired_matrix->nrows; ++i) | |
1237 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i)) | |
1238 break; | |
1239 | |
1240 if (i < w->desired_matrix->nrows) | |
1241 clear_mouse_face (display_info); | |
1242 } | |
1243 #endif /* 0 */ | |
1244 } | |
1245 | |
1246 UNBLOCK_INPUT; | |
1247 } | |
1248 | |
1249 | |
1250 /* Draw a vertical window border to the right of window W if W doesn't | |
1251 have vertical scroll bars. */ | |
1252 | |
1253 static void | |
1254 x_draw_vertical_border (w) | |
1255 struct window *w; | |
1256 { | |
1257 struct frame *f = XFRAME (WINDOW_FRAME (w)); | |
1258 | |
1259 /* Redraw borders between horizontally adjacent windows. Don't | |
1260 do it for frames with vertical scroll bars because either the | |
1261 right scroll bar of a window, or the left scroll bar of its | |
1262 neighbor will suffice as a border. */ | |
1263 if (!WINDOW_RIGHTMOST_P (w) | |
1264 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f)) | |
1265 { | |
1266 int x0, x1, y0, y1; | |
1267 | |
1268 window_box_edges (w, -1, &x0, &y0, &x1, &y1); | |
1269 x1 += FRAME_X_RIGHT_FRINGE_WIDTH (f); | |
1270 y1 -= 1; | |
1271 | |
1272 XDrawLine (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), | |
1273 f->output_data.mac->normal_gc, x1, y0, x1, y1); | |
1274 } | |
1275 } | |
1276 | |
1277 | |
1278 /* End update of window W (which is equal to updated_window). | |
1279 | |
1280 Draw vertical borders between horizontally adjacent windows, and | |
1281 display W's cursor if CURSOR_ON_P is non-zero. | |
1282 | |
1283 MOUSE_FACE_OVERWRITTEN_P non-zero means that some row containing | |
1284 glyphs in mouse-face were overwritten. In that case we have to | |
1285 make sure that the mouse-highlight is properly redrawn. | |
1286 | |
1287 W may be a menu bar pseudo-window in case we don't have X toolkit | |
1288 support. Such windows don't have a cursor, so don't display it | |
1289 here. */ | |
1290 | |
1291 static void | |
1292 x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p) | |
1293 struct window *w; | |
1294 int cursor_on_p, mouse_face_overwritten_p; | |
1295 { | |
1296 struct mac_display_info *dpyinfo | |
1297 = FRAME_MAC_DISPLAY_INFO (XFRAME (w->frame)); | |
1298 | |
1299 if (!w->pseudo_window_p) | |
1300 { | |
1301 BLOCK_INPUT; | |
1302 | |
1303 if (cursor_on_p) | |
1304 x_display_and_set_cursor (w, 1, output_cursor.hpos, | |
1305 output_cursor.vpos, | |
1306 output_cursor.x, output_cursor.y); | |
1307 | |
1308 x_draw_vertical_border (w); | |
1309 UNBLOCK_INPUT; | |
1310 } | |
1311 | |
1312 /* If a row with mouse-face was overwritten, arrange for | |
1313 XTframe_up_to_date to redisplay the mouse highlight. */ | |
1314 if (mouse_face_overwritten_p) | |
1315 { | |
1316 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1; | |
1317 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1; | |
1318 dpyinfo->mouse_face_window = Qnil; | |
1319 } | |
1320 | |
1321 #if 0 | |
1322 /* Unhide the caret. This won't actually show the cursor, unless it | |
1323 was visible before the corresponding call to HideCaret in | |
1324 x_update_window_begin. */ | |
1325 if (w32_use_visible_system_caret) | |
1326 SendMessage (w32_system_caret_hwnd, WM_EMACS_SHOW_CARET, 0, 0); | |
1327 #endif | |
1328 | |
1329 updated_window = NULL; | |
1330 } | |
1331 | |
1332 | |
1333 /* End update of frame F. This function is installed as a hook in | |
1334 update_end. */ | |
1335 | |
1336 static void | |
1337 x_update_end (f) | |
1338 struct frame *f; | |
1339 { | |
1340 /* Reset the background color of Mac OS Window to that of the frame after | |
1341 update so that it is used by Mac Toolbox to clear the update region before | |
1342 an update event is generated. */ | |
1343 #if TARGET_API_MAC_CARBON | |
1344 SetPort (GetWindowPort (FRAME_MAC_WINDOW (f))); | |
1345 #else | |
1346 SetPort (FRAME_MAC_WINDOW (f)); | |
1347 #endif | |
1348 | |
1349 mac_set_backcolor (FRAME_BACKGROUND_PIXEL (f)); | |
1350 | |
1351 /* Mouse highlight may be displayed again. */ | |
1352 FRAME_MAC_DISPLAY_INFO (f)->mouse_face_defer = 0; | |
1353 | |
1354 BLOCK_INPUT; | |
1355 XFlush (FRAME_MAC_DISPLAY (f)); | |
1356 UNBLOCK_INPUT; | |
1357 } | |
1358 | |
1359 | |
1360 /* This function is called from various places in xdisp.c whenever a | |
1361 complete update has been performed. The global variable | |
1362 updated_window is not available here. */ | |
1363 | |
1364 static void | |
1365 XTframe_up_to_date (f) | |
1366 struct frame *f; | |
1367 { | |
1368 if (FRAME_X_P (f)) | |
1369 { | |
1370 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); | |
1371 | |
1372 if (dpyinfo->mouse_face_deferred_gc | |
1373 || f == dpyinfo->mouse_face_mouse_frame) | |
1374 { | |
1375 BLOCK_INPUT; | |
1376 if (dpyinfo->mouse_face_mouse_frame) | |
1377 note_mouse_highlight (dpyinfo->mouse_face_mouse_frame, | |
1378 dpyinfo->mouse_face_mouse_x, | |
1379 dpyinfo->mouse_face_mouse_y); | |
1380 dpyinfo->mouse_face_deferred_gc = 0; | |
1381 UNBLOCK_INPUT; | |
1382 } | |
1383 } | |
1384 } | |
1385 | |
1386 | |
1387 /* Draw truncation mark bitmaps, continuation mark bitmaps, overlay | |
1388 arrow bitmaps, or clear the fringes if no bitmaps are required | |
1389 before DESIRED_ROW is made current. The window being updated is | |
1390 found in updated_window. This function is called from | |
1391 update_window_line only if it is known that there are differences | |
1392 between bitmaps to be drawn between current row and DESIRED_ROW. */ | |
1393 | |
1394 static void | |
1395 x_after_update_window_line (desired_row) | |
1396 struct glyph_row *desired_row; | |
1397 { | |
1398 struct window *w = updated_window; | |
1399 struct frame *f; | |
1400 int width, height; | |
1401 | |
1402 xassert (w); | |
1403 | |
1404 if (!desired_row->mode_line_p && !w->pseudo_window_p) | |
1405 { | |
1406 BLOCK_INPUT; | |
1407 x_draw_row_fringe_bitmaps (w, desired_row); | |
1408 UNBLOCK_INPUT; | |
1409 } | |
1410 | |
1411 /* When a window has disappeared, make sure that no rest of | |
1412 full-width rows stays visible in the internal border. Could | |
1413 check here if updated_window is the leftmost/rightmost window, | |
1414 but I guess it's not worth doing since vertically split windows | |
1415 are almost never used, internal border is rarely set, and the | |
1416 overhead is very small. */ | |
1417 if (windows_or_buffers_changed | |
1418 && desired_row->full_width_p | |
1419 && (f = XFRAME (w->frame), | |
1420 width = FRAME_INTERNAL_BORDER_WIDTH (f), | |
1421 width != 0) | |
1422 && (height = desired_row->visible_height, | |
1423 height > 0)) | |
1424 { | |
1425 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y)); | |
1426 /* Internal border is drawn below the tool bar. */ | |
1427 if (WINDOWP (f->tool_bar_window) | |
1428 && w == XWINDOW (f->tool_bar_window)) | |
1429 y -= width; | |
1430 | |
1431 BLOCK_INPUT; | |
1432 | |
1433 XClearArea (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), | |
1434 0, y, width, height, 0); | |
1435 XClearArea (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), | |
1436 f->output_data.mac->pixel_width - width, y, | |
1437 width, height, 0); | |
1438 | |
1439 UNBLOCK_INPUT; | |
1440 } | |
1441 } | |
1442 | |
1443 | |
1444 /* Draw the bitmap WHICH in one of the left or right fringes of | |
1445 window W. ROW is the glyph row for which to display the bitmap; it | |
1446 determines the vertical position at which the bitmap has to be | |
1447 drawn. */ | |
1448 | |
1449 static void | |
1450 x_draw_fringe_bitmap (w, row, which, left_p) | |
1451 struct window *w; | |
1452 struct glyph_row *row; | |
1453 enum fringe_bitmap_type which; | |
1454 int left_p; | |
1455 { | |
1456 struct frame *f = XFRAME (WINDOW_FRAME (w)); | |
1457 Display *display = FRAME_MAC_DISPLAY (f); | |
1458 WindowPtr window = FRAME_MAC_WINDOW (f); | |
1459 int x, y, wd, h, dy; | |
1460 int b1, b2; | |
1461 unsigned char *bits; | |
1462 BitMap bitmap; | |
1463 XGCValues gcv; | |
1464 GC gc = f->output_data.mac->normal_gc; | |
1465 struct face *face; | |
1466 | |
1467 /* Must clip because of partially visible lines. */ | |
1468 x_clip_to_row (w, row, gc, 1); | |
1469 | |
1470 /* Convert row to frame coordinates. */ | |
1471 y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y); | |
1472 | |
1473 switch (which) | |
1474 { | |
1475 case NO_FRINGE_BITMAP: | |
1476 wd = 0; | |
1477 h = 0; | |
1478 break; | |
1479 | |
1480 case LEFT_TRUNCATION_BITMAP: | |
1481 wd = left_width; | |
1482 h = left_height; | |
1483 bits = left_bits; | |
1484 break; | |
1485 | |
1486 case OVERLAY_ARROW_BITMAP: | |
1487 wd = ov_width; | |
1488 h = ov_height; | |
1489 bits = ov_bits; | |
1490 break; | |
1491 | |
1492 case RIGHT_TRUNCATION_BITMAP: | |
1493 wd = right_width; | |
1494 h = right_height; | |
1495 bits = right_bits; | |
1496 break; | |
1497 | |
1498 case CONTINUED_LINE_BITMAP: | |
1499 wd = continued_width; | |
1500 h = continued_height; | |
1501 bits = continued_bits; | |
1502 break; | |
1503 | |
1504 case CONTINUATION_LINE_BITMAP: | |
1505 wd = continuation_width; | |
1506 h = continuation_height; | |
1507 bits = continuation_bits; | |
1508 break; | |
1509 | |
1510 case ZV_LINE_BITMAP: | |
1511 wd = zv_width; | |
1512 h = zv_height - (y % zv_period); | |
1513 bits = zv_bits + (y % zv_period); | |
1514 break; | |
1515 | |
1516 default: | |
1517 abort (); | |
1518 } | |
1519 | |
1520 /* Clip bitmap if too high. */ | |
1521 if (h > row->height) | |
1522 h = row->height; | |
1523 | |
1524 /* Set dy to the offset in the row to start drawing the bitmap. */ | |
1525 dy = (row->height - h) / 2; | |
1526 | |
1527 /* Draw the bitmap. */ | |
1528 face = FACE_FROM_ID (f, FRINGE_FACE_ID); | |
1529 PREPARE_FACE_FOR_DISPLAY (f, face); | |
1530 | |
1531 /* Clear left fringe if no bitmap to draw or if bitmap doesn't fill | |
1532 the fringe. */ | |
1533 b1 = -1; | |
1534 if (left_p) | |
1535 { | |
1536 if (wd > FRAME_X_LEFT_FRINGE_WIDTH (f)) | |
1537 wd = FRAME_X_LEFT_FRINGE_WIDTH (f); | |
1538 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0) | |
1539 - wd | |
1540 - (FRAME_X_LEFT_FRINGE_WIDTH (f) - wd) / 2); | |
1541 if (wd < FRAME_X_LEFT_FRINGE_WIDTH (f) || row->height > h) | |
1542 { | |
1543 /* If W has a vertical border to its left, don't draw over it. */ | |
1544 int border = ((XFASTINT (w->left) > 0 | |
1545 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f)) | |
1546 ? 1 : 0); | |
1547 b1 = (window_box_left (w, -1) | |
1548 - FRAME_X_LEFT_FRINGE_WIDTH (f) | |
1549 + border); | |
1550 b2 = (FRAME_X_LEFT_FRINGE_WIDTH (f) - border); | |
1551 } | |
1552 } | |
1553 else | |
1554 { | |
1555 if (wd > FRAME_X_RIGHT_FRINGE_WIDTH (f)) | |
1556 wd = FRAME_X_RIGHT_FRINGE_WIDTH (f); | |
1557 x = (window_box_right (w, -1) | |
1558 + (FRAME_X_RIGHT_FRINGE_WIDTH (f) - wd) / 2); | |
1559 /* Clear right fringe if no bitmap to draw of if bitmap doesn't fill | |
1560 the fringe. */ | |
1561 if (wd < FRAME_X_RIGHT_FRINGE_WIDTH (f) || row->height > h) | |
1562 { | |
1563 b1 = window_box_right (w, -1); | |
1564 b2 = FRAME_X_RIGHT_FRINGE_WIDTH (f); | |
1565 } | |
1566 } | |
1567 | |
1568 if (b1 >= 0) | |
1569 { | |
1570 int header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w); | |
1571 XGCValues gcv; | |
1572 gcv.foreground = face->background; | |
1573 | |
1574 #if 0 /* MAC_TODO: stipple */ | |
1575 /* In case the same realized face is used for fringes and | |
1576 for something displayed in the text (e.g. face `region' on | |
1577 mono-displays, the fill style may have been changed to | |
1578 FillSolid in x_draw_glyph_string_background. */ | |
1579 if (face->stipple) | |
1580 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled); | |
1581 else | |
1582 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background); | |
1583 #endif | |
1584 | |
1585 XFillRectangle (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), | |
1586 &gcv, | |
1587 b1, | |
1588 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, | |
1589 row->y)), | |
1590 b2, | |
1591 row->visible_height); | |
1592 | |
1593 #if 0 /* MAC_TODO: stipple */ | |
1594 if (!face->stipple) | |
1595 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground); | |
1596 #endif | |
1597 } | |
1598 | |
1599 if (which == NO_FRINGE_BITMAP) | |
1600 { | |
1601 mac_reset_clipping (display, window); | |
1602 return; | |
1603 } | |
1604 | |
1605 mac_create_bitmap_from_bitmap_data (&bitmap, bits, wd, h); | |
1606 gcv.foreground = face->foreground; | |
1607 gcv.background = face->background; | |
1608 | |
1609 mac_draw_bitmap (display, window, &gcv, x, y + dy, &bitmap); | |
1610 | |
1611 mac_free_bitmap (&bitmap); | |
1612 mac_reset_clipping (display, window); | |
1613 } | |
1614 | |
1615 | |
1616 /* Draw fringe bitmaps for glyph row ROW on window W. Call this | |
1617 function with input blocked. */ | |
1618 | |
1619 static void | |
1620 x_draw_row_fringe_bitmaps (w, row) | |
1621 struct window *w; | |
1622 struct glyph_row *row; | |
1623 { | |
1624 struct frame *f = XFRAME (w->frame); | |
1625 enum fringe_bitmap_type bitmap; | |
1626 | |
1627 xassert (interrupt_input_blocked); | |
1628 | |
1629 /* If row is completely invisible, because of vscrolling, we | |
1630 don't have to draw anything. */ | |
1631 if (row->visible_height <= 0) | |
1632 return; | |
1633 | |
1634 if (FRAME_X_LEFT_FRINGE_WIDTH (f) != 0) | |
1635 { | |
1636 /* Decide which bitmap to draw in the left fringe. */ | |
1637 if (row->overlay_arrow_p) | |
1638 bitmap = OVERLAY_ARROW_BITMAP; | |
1639 else if (row->truncated_on_left_p) | |
1640 bitmap = LEFT_TRUNCATION_BITMAP; | |
1641 else if (MATRIX_ROW_CONTINUATION_LINE_P (row)) | |
1642 bitmap = CONTINUATION_LINE_BITMAP; | |
1643 else if (row->indicate_empty_line_p) | |
1644 bitmap = ZV_LINE_BITMAP; | |
1645 else | |
1646 bitmap = NO_FRINGE_BITMAP; | |
1647 | |
1648 x_draw_fringe_bitmap (w, row, bitmap, 1); | |
1649 } | |
1650 | |
1651 if (FRAME_X_RIGHT_FRINGE_WIDTH (f) != 0) | |
1652 { | |
1653 /* Decide which bitmap to draw in the right fringe. */ | |
1654 if (row->truncated_on_right_p) | |
1655 bitmap = RIGHT_TRUNCATION_BITMAP; | |
1656 else if (row->continued_p) | |
1657 bitmap = CONTINUED_LINE_BITMAP; | |
1658 else if (row->indicate_empty_line_p && FRAME_X_LEFT_FRINGE_WIDTH (f) == 0) | |
1659 bitmap = ZV_LINE_BITMAP; | |
1660 else | |
1661 bitmap = NO_FRINGE_BITMAP; | |
1662 | |
1663 x_draw_fringe_bitmap (w, row, bitmap, 0); | |
1664 } | |
1665 } | |
1666 | |
1667 | |
1668 /* This is called when starting Emacs and when restarting after | |
1669 suspend. When starting Emacs, no window is mapped. And nothing | |
1670 must be done to Emacs's own window if it is suspended (though that | |
1671 rarely happens). */ | |
1672 | |
1673 static void | |
1674 XTset_terminal_modes () | |
1675 { | |
1676 } | |
1677 | |
1678 /* This is called when exiting or suspending Emacs. Exiting will make | |
1679 the windows go away, and suspending requires no action. */ | |
1680 | |
1681 static void | |
1682 XTreset_terminal_modes () | |
1683 { | |
1684 } | |
1685 | |
1686 | |
1687 | |
1688 /*********************************************************************** | |
1689 Output Cursor | |
1690 ***********************************************************************/ | |
1691 | |
1692 /* Set the global variable output_cursor to CURSOR. All cursor | |
1693 positions are relative to updated_window. */ | |
1694 | |
1695 static void | |
1696 set_output_cursor (cursor) | |
1697 struct cursor_pos *cursor; | |
1698 { | |
1699 output_cursor.hpos = cursor->hpos; | |
1700 output_cursor.vpos = cursor->vpos; | |
1701 output_cursor.x = cursor->x; | |
1702 output_cursor.y = cursor->y; | |
1703 } | |
1704 | |
1705 | |
1706 /* Set a nominal cursor position. | |
1707 | |
1708 HPOS and VPOS are column/row positions in a window glyph matrix. X | |
1709 and Y are window text area relative pixel positions. | |
1710 | |
1711 If this is done during an update, updated_window will contain the | |
1712 window that is being updated and the position is the future output | |
1713 cursor position for that window. If updated_window is null, use | |
1714 selected_window and display the cursor at the given position. */ | |
1715 | |
1716 static void | |
1717 XTcursor_to (vpos, hpos, y, x) | |
1718 int vpos, hpos, y, x; | |
1719 { | |
1720 struct window *w; | |
1721 | |
1722 /* If updated_window is not set, work on selected_window. */ | |
1723 if (updated_window) | |
1724 w = updated_window; | |
1725 else | |
1726 w = XWINDOW (selected_window); | |
1727 | |
1728 /* Set the output cursor. */ | |
1729 output_cursor.hpos = hpos; | |
1730 output_cursor.vpos = vpos; | |
1731 output_cursor.x = x; | |
1732 output_cursor.y = y; | |
1733 | |
1734 /* If not called as part of an update, really display the cursor. | |
1735 This will also set the cursor position of W. */ | |
1736 if (updated_window == NULL) | |
1737 { | |
1738 BLOCK_INPUT; | |
1739 x_display_cursor (w, 1, hpos, vpos, x, y); | |
1740 XFlush (FRAME_X_DISPLAY (SELECTED_FRAME ())); | |
1741 UNBLOCK_INPUT; | |
1742 } | |
1743 } | |
1744 | |
1745 | |
1746 | |
1747 /*********************************************************************** | |
1748 Display Iterator | |
1749 ***********************************************************************/ | |
1750 | |
1751 /* Function prototypes of this page. */ | |
1752 | |
1753 static struct face *x_get_glyph_face_and_encoding P_ ((struct frame *, | |
1754 struct glyph *, | |
1755 XChar2b *, | |
1756 int *)); | |
1757 static struct face *x_get_char_face_and_encoding P_ ((struct frame *, int, | |
1758 int, XChar2b *, int)); | |
1759 static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *)); | |
1760 static void x_encode_char P_ ((int, XChar2b *, struct font_info *)); | |
1761 static void x_append_glyph P_ ((struct it *)); | |
1762 static void x_append_composite_glyph P_ ((struct it *)); | |
1763 static void x_append_stretch_glyph P_ ((struct it *it, Lisp_Object, | |
1764 int, int, double)); | |
1765 static void x_produce_glyphs P_ ((struct it *)); | |
1766 static void x_produce_image_glyph P_ ((struct it *it)); | |
1767 | |
1768 | |
1769 /* Return a pointer to per-char metric information in FONT of a | |
1770 character pointed by B which is a pointer to an XChar2b. */ | |
1771 | |
1772 #define PER_CHAR_METRIC(font, b) \ | |
1773 ((font)->per_char \ | |
1774 ? ((font)->per_char + (b)->byte2 - (font)->min_char_or_byte2 \ | |
1775 + (((font)->min_byte1 || (font)->max_byte1) \ | |
1776 ? (((b)->byte1 - (font)->min_byte1) \ | |
1777 * ((font)->max_char_or_byte2 - (font)->min_char_or_byte2 + 1)) \ | |
1778 : 0)) \ | |
1779 : &((font)->max_bounds)) | |
1780 | |
1781 | |
1782 /* Get metrics of character CHAR2B in FONT. Value is null if CHAR2B | |
1783 is not contained in the font. */ | |
1784 | |
1785 static INLINE XCharStruct * | |
1786 x_per_char_metric (font, char2b) | |
1787 XFontStruct *font; | |
1788 XChar2b *char2b; | |
1789 { | |
1790 /* The result metric information. */ | |
1791 XCharStruct *pcm = NULL; | |
1792 | |
1793 xassert (font && char2b); | |
1794 | |
1795 if (font->per_char != NULL) | |
1796 { | |
1797 if (font->min_byte1 == 0 && font->max_byte1 == 0) | |
1798 { | |
1799 /* min_char_or_byte2 specifies the linear character index | |
1800 corresponding to the first element of the per_char array, | |
1801 max_char_or_byte2 is the index of the last character. A | |
1802 character with non-zero CHAR2B->byte1 is not in the font. | |
1803 A character with byte2 less than min_char_or_byte2 or | |
1804 greater max_char_or_byte2 is not in the font. */ | |
1805 if (char2b->byte1 == 0 | |
1806 && char2b->byte2 >= font->min_char_or_byte2 | |
1807 && char2b->byte2 <= font->max_char_or_byte2) | |
1808 pcm = font->per_char + char2b->byte2 - font->min_char_or_byte2; | |
1809 } | |
1810 else | |
1811 { | |
1812 /* If either min_byte1 or max_byte1 are nonzero, both | |
1813 min_char_or_byte2 and max_char_or_byte2 are less than | |
1814 256, and the 2-byte character index values corresponding | |
1815 to the per_char array element N (counting from 0) are: | |
1816 | |
1817 byte1 = N/D + min_byte1 | |
1818 byte2 = N\D + min_char_or_byte2 | |
1819 | |
1820 where: | |
1821 | |
1822 D = max_char_or_byte2 - min_char_or_byte2 + 1 | |
1823 / = integer division | |
1824 \ = integer modulus */ | |
1825 if (char2b->byte1 >= font->min_byte1 | |
1826 && char2b->byte1 <= font->max_byte1 | |
1827 && char2b->byte2 >= font->min_char_or_byte2 | |
1828 && char2b->byte2 <= font->max_char_or_byte2) | |
1829 { | |
1830 pcm = (font->per_char | |
1831 + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1) | |
1832 * (char2b->byte1 - font->min_byte1)) | |
1833 + (char2b->byte2 - font->min_char_or_byte2)); | |
1834 } | |
1835 } | |
1836 } | |
1837 else | |
1838 { | |
1839 /* If the per_char pointer is null, all glyphs between the first | |
1840 and last character indexes inclusive have the same | |
1841 information, as given by both min_bounds and max_bounds. */ | |
1842 if (char2b->byte2 >= font->min_char_or_byte2 | |
1843 && char2b->byte2 <= font->max_char_or_byte2) | |
1844 pcm = &font->max_bounds; | |
1845 } | |
1846 | |
1847 return ((pcm == NULL | |
1848 || (pcm->width == 0 && (pcm->rbearing - pcm->lbearing) == 0)) | |
1849 ? NULL : pcm); | |
1850 } | |
1851 | |
1852 | |
1853 /* Encode CHAR2B using encoding information from FONT_INFO. CHAR2B is | |
1854 the two-byte form of C. Encoding is returned in *CHAR2B. */ | |
1855 | |
1856 static INLINE void | |
1857 x_encode_char (c, char2b, font_info) | |
1858 int c; | |
1859 XChar2b *char2b; | |
1860 struct font_info *font_info; | |
1861 { | |
1862 int charset = CHAR_CHARSET (c); | |
1863 XFontStruct *font = font_info->font; | |
1864 | |
1865 /* FONT_INFO may define a scheme by which to encode byte1 and byte2. | |
1866 This may be either a program in a special encoder language or a | |
1867 fixed encoding. */ | |
1868 if (font_info->font_encoder) | |
1869 { | |
1870 /* It's a program. */ | |
1871 struct ccl_program *ccl = font_info->font_encoder; | |
1872 | |
1873 if (CHARSET_DIMENSION (charset) == 1) | |
1874 { | |
1875 ccl->reg[0] = charset; | |
1876 ccl->reg[1] = char2b->byte2; | |
1877 } | |
1878 else | |
1879 { | |
1880 ccl->reg[0] = charset; | |
1881 ccl->reg[1] = char2b->byte1; | |
1882 ccl->reg[2] = char2b->byte2; | |
1883 } | |
1884 | |
1885 ccl_driver (ccl, NULL, NULL, 0, 0, NULL); | |
1886 | |
1887 /* We assume that MSBs are appropriately set/reset by CCL | |
1888 program. */ | |
1889 if (font->max_byte1 == 0) /* 1-byte font */ | |
1890 char2b->byte1 = 0, char2b->byte2 = ccl->reg[1]; | |
1891 else | |
1892 char2b->byte1 = ccl->reg[1], char2b->byte2 = ccl->reg[2]; | |
1893 } | |
1894 else if (font_info->encoding[charset]) | |
1895 { | |
1896 /* Fixed encoding scheme. See fontset.h for the meaning of the | |
1897 encoding numbers. */ | |
1898 int enc = font_info->encoding[charset]; | |
1899 | |
1900 if ((enc == 1 || enc == 2) | |
1901 && CHARSET_DIMENSION (charset) == 2) | |
1902 char2b->byte1 |= 0x80; | |
1903 | |
1904 if (enc == 1 || enc == 3) | |
1905 char2b->byte2 |= 0x80; | |
1906 | |
1907 if (enc == 4) | |
1908 { | |
1909 int sjis1, sjis2; | |
1910 | |
1911 ENCODE_SJIS (char2b->byte1, char2b->byte2, sjis1, sjis2); | |
1912 char2b->byte1 = sjis1; | |
1913 char2b->byte2 = sjis2; | |
1914 } | |
1915 } | |
1916 } | |
1917 | |
1918 | |
1919 /* Get face and two-byte form of character C in face FACE_ID on frame | |
1920 F. The encoding of C is returned in *CHAR2B. MULTIBYTE_P non-zero | |
1921 means we want to display multibyte text. Value is a pointer to a | |
1922 realized face that is ready for display. */ | |
1923 | |
1924 static INLINE struct face * | |
1925 x_get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p) | |
1926 struct frame *f; | |
1927 int c, face_id; | |
1928 XChar2b *char2b; | |
1929 int multibyte_p; | |
1930 { | |
1931 struct face *face = FACE_FROM_ID (f, face_id); | |
1932 | |
1933 if (!multibyte_p) | |
1934 { | |
1935 /* Unibyte case. We don't have to encode, but we have to make | |
1936 sure to use a face suitable for unibyte. */ | |
1937 char2b->byte1 = 0; | |
1938 char2b->byte2 = c; | |
1939 face_id = FACE_FOR_CHAR (f, face, c); | |
1940 face = FACE_FROM_ID (f, face_id); | |
1941 } | |
1942 else if (c < 128 && face_id < BASIC_FACE_ID_SENTINEL) | |
1943 { | |
1944 /* Case of ASCII in a face known to fit ASCII. */ | |
1945 char2b->byte1 = 0; | |
1946 char2b->byte2 = c; | |
1947 } | |
1948 else | |
1949 { | |
1950 int c1, c2, charset; | |
1951 | |
1952 /* Split characters into bytes. If c2 is -1 afterwards, C is | |
1953 really a one-byte character so that byte1 is zero. */ | |
1954 SPLIT_CHAR (c, charset, c1, c2); | |
1955 if (c2 > 0) | |
1956 char2b->byte1 = c1, char2b->byte2 = c2; | |
1957 else | |
1958 char2b->byte1 = 0, char2b->byte2 = c1; | |
1959 | |
1960 /* Maybe encode the character in *CHAR2B. */ | |
1961 if (face->font != NULL) | |
1962 { | |
1963 struct font_info *font_info | |
1964 = FONT_INFO_FROM_ID (f, face->font_info_id); | |
1965 if (font_info) | |
1966 x_encode_char (c, char2b, font_info); | |
1967 } | |
1968 } | |
1969 | |
1970 /* Make sure X resources of the face are allocated. */ | |
1971 xassert (face != NULL); | |
1972 PREPARE_FACE_FOR_DISPLAY (f, face); | |
1973 | |
1974 return face; | |
1975 } | |
1976 | |
1977 | |
1978 /* Get face and two-byte form of character glyph GLYPH on frame F. | |
1979 The encoding of GLYPH->u.ch is returned in *CHAR2B. Value is | |
1980 a pointer to a realized face that is ready for display. */ | |
1981 | |
1982 static INLINE struct face * | |
1983 x_get_glyph_face_and_encoding (f, glyph, char2b, two_byte_p) | |
1984 struct frame *f; | |
1985 struct glyph *glyph; | |
1986 XChar2b *char2b; | |
1987 int *two_byte_p; | |
1988 { | |
1989 struct face *face; | |
1990 | |
1991 xassert (glyph->type == CHAR_GLYPH); | |
1992 face = FACE_FROM_ID (f, glyph->face_id); | |
1993 | |
1994 if (two_byte_p) | |
1995 *two_byte_p = 0; | |
1996 | |
1997 if (!glyph->multibyte_p) | |
1998 { | |
1999 /* Unibyte case. We don't have to encode, but we have to make | |
2000 sure to use a face suitable for unibyte. */ | |
2001 char2b->byte1 = 0; | |
2002 char2b->byte2 = glyph->u.ch; | |
2003 } | |
2004 else if (glyph->u.ch < 128 | |
2005 && glyph->face_id < BASIC_FACE_ID_SENTINEL) | |
2006 { | |
2007 /* Case of ASCII in a face known to fit ASCII. */ | |
2008 char2b->byte1 = 0; | |
2009 char2b->byte2 = glyph->u.ch; | |
2010 } | |
2011 else | |
2012 { | |
2013 int c1, c2, charset; | |
2014 | |
2015 /* Split characters into bytes. If c2 is -1 afterwards, C is | |
2016 really a one-byte character so that byte1 is zero. */ | |
2017 SPLIT_CHAR (glyph->u.ch, charset, c1, c2); | |
2018 if (c2 > 0) | |
2019 char2b->byte1 = c1, char2b->byte2 = c2; | |
2020 else | |
2021 char2b->byte1 = 0, char2b->byte2 = c1; | |
2022 | |
2023 /* Maybe encode the character in *CHAR2B. */ | |
2024 if (charset != CHARSET_ASCII) | |
2025 { | |
2026 struct font_info *font_info | |
2027 = FONT_INFO_FROM_ID (f, face->font_info_id); | |
2028 if (font_info) | |
2029 { | |
2030 x_encode_char (glyph->u.ch, char2b, font_info); | |
2031 if (two_byte_p) | |
2032 *two_byte_p | |
2033 = ((XFontStruct *) (font_info->font))->max_byte1 > 0; | |
2034 } | |
2035 } | |
2036 } | |
2037 | |
2038 /* Make sure X resources of the face are allocated. */ | |
2039 xassert (face != NULL); | |
2040 PREPARE_FACE_FOR_DISPLAY (f, face); | |
2041 return face; | |
2042 } | |
2043 | |
2044 | |
2045 /* Store one glyph for IT->char_to_display in IT->glyph_row. | |
2046 Called from x_produce_glyphs when IT->glyph_row is non-null. */ | |
2047 | |
2048 static INLINE void | |
2049 x_append_glyph (it) | |
2050 struct it *it; | |
2051 { | |
2052 struct glyph *glyph; | |
2053 enum glyph_row_area area = it->area; | |
2054 | |
2055 xassert (it->glyph_row); | |
2056 xassert (it->char_to_display != '\n' && it->char_to_display != '\t'); | |
2057 | |
2058 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area]; | |
2059 if (glyph < it->glyph_row->glyphs[area + 1]) | |
2060 { | |
2061 glyph->charpos = CHARPOS (it->position); | |
2062 glyph->object = it->object; | |
2063 glyph->pixel_width = it->pixel_width; | |
2064 glyph->voffset = it->voffset; | |
2065 glyph->type = CHAR_GLYPH; | |
2066 glyph->multibyte_p = it->multibyte_p; | |
2067 glyph->left_box_line_p = it->start_of_box_run_p; | |
2068 glyph->right_box_line_p = it->end_of_box_run_p; | |
2069 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent | |
2070 || it->phys_descent > it->descent); | |
2071 glyph->padding_p = 0; | |
2072 glyph->glyph_not_available_p = it->glyph_not_available_p; | |
2073 glyph->face_id = it->face_id; | |
2074 glyph->u.ch = it->char_to_display; | |
2075 ++it->glyph_row->used[area]; | |
2076 } | |
2077 } | |
2078 | |
2079 /* Store one glyph for the composition IT->cmp_id in IT->glyph_row. | |
2080 Called from x_produce_glyphs when IT->glyph_row is non-null. */ | |
2081 | |
2082 static INLINE void | |
2083 x_append_composite_glyph (it) | |
2084 struct it *it; | |
2085 { | |
2086 struct glyph *glyph; | |
2087 enum glyph_row_area area = it->area; | |
2088 | |
2089 xassert (it->glyph_row); | |
2090 | |
2091 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area]; | |
2092 if (glyph < it->glyph_row->glyphs[area + 1]) | |
2093 { | |
2094 glyph->charpos = CHARPOS (it->position); | |
2095 glyph->object = it->object; | |
2096 glyph->pixel_width = it->pixel_width; | |
2097 glyph->voffset = it->voffset; | |
2098 glyph->type = COMPOSITE_GLYPH; | |
2099 glyph->multibyte_p = it->multibyte_p; | |
2100 glyph->left_box_line_p = it->start_of_box_run_p; | |
2101 glyph->right_box_line_p = it->end_of_box_run_p; | |
2102 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent | |
2103 || it->phys_descent > it->descent); | |
2104 glyph->padding_p = 0; | |
2105 glyph->glyph_not_available_p = 0; | |
2106 glyph->face_id = it->face_id; | |
2107 glyph->u.cmp_id = it->cmp_id; | |
2108 ++it->glyph_row->used[area]; | |
2109 } | |
2110 } | |
2111 | |
2112 | |
2113 /* Change IT->ascent and IT->height according to the setting of | |
2114 IT->voffset. */ | |
2115 | |
2116 static INLINE void | |
2117 take_vertical_position_into_account (it) | |
2118 struct it *it; | |
2119 { | |
2120 if (it->voffset) | |
2121 { | |
2122 if (it->voffset < 0) | |
2123 /* Increase the ascent so that we can display the text higher | |
2124 in the line. */ | |
2125 it->ascent += abs (it->voffset); | |
2126 else | |
2127 /* Increase the descent so that we can display the text lower | |
2128 in the line. */ | |
2129 it->descent += it->voffset; | |
2130 } | |
2131 } | |
2132 | |
2133 | |
2134 /* Produce glyphs/get display metrics for the image IT is loaded with. | |
2135 See the description of struct display_iterator in dispextern.h for | |
2136 an overview of struct display_iterator. */ | |
2137 | |
2138 static void | |
2139 x_produce_image_glyph (it) | |
2140 struct it *it; | |
2141 { | |
2142 struct image *img; | |
2143 struct face *face; | |
2144 | |
2145 xassert (it->what == IT_IMAGE); | |
2146 | |
2147 face = FACE_FROM_ID (it->f, it->face_id); | |
2148 img = IMAGE_FROM_ID (it->f, it->image_id); | |
2149 xassert (img); | |
2150 | |
2151 /* Make sure X resources of the face and image are loaded. */ | |
2152 PREPARE_FACE_FOR_DISPLAY (it->f, face); | |
2153 prepare_image_for_display (it->f, img); | |
2154 | |
2155 it->ascent = it->phys_ascent = image_ascent (img, face); | |
2156 it->descent = it->phys_descent = img->height + 2 * img->vmargin - it->ascent; | |
2157 it->pixel_width = img->width + 2 * img->hmargin; | |
2158 | |
2159 it->nglyphs = 1; | |
2160 | |
2161 if (face->box != FACE_NO_BOX) | |
2162 { | |
2163 if (face->box_line_width > 0) | |
2164 { | |
2165 it->ascent += face->box_line_width; | |
2166 it->descent += face->box_line_width; | |
2167 } | |
2168 | |
2169 if (it->start_of_box_run_p) | |
2170 it->pixel_width += abs (face->box_line_width); | |
2171 if (it->end_of_box_run_p) | |
2172 it->pixel_width += abs (face->box_line_width); | |
2173 } | |
2174 | |
2175 take_vertical_position_into_account (it); | |
2176 | |
2177 if (it->glyph_row) | |
2178 { | |
2179 struct glyph *glyph; | |
2180 enum glyph_row_area area = it->area; | |
2181 | |
2182 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area]; | |
2183 if (glyph < it->glyph_row->glyphs[area + 1]) | |
2184 { | |
2185 glyph->charpos = CHARPOS (it->position); | |
2186 glyph->object = it->object; | |
2187 glyph->pixel_width = it->pixel_width; | |
2188 glyph->voffset = it->voffset; | |
2189 glyph->type = IMAGE_GLYPH; | |
2190 glyph->multibyte_p = it->multibyte_p; | |
2191 glyph->left_box_line_p = it->start_of_box_run_p; | |
2192 glyph->right_box_line_p = it->end_of_box_run_p; | |
2193 glyph->overlaps_vertically_p = 0; | |
2194 glyph->padding_p = 0; | |
2195 glyph->glyph_not_available_p = 0; | |
2196 glyph->face_id = it->face_id; | |
2197 glyph->u.img_id = img->id; | |
2198 ++it->glyph_row->used[area]; | |
2199 } | |
2200 } | |
2201 } | |
2202 | |
2203 | |
2204 /* Append a stretch glyph to IT->glyph_row. OBJECT is the source | |
2205 of the glyph, WIDTH and HEIGHT are the width and height of the | |
2206 stretch. ASCENT is the percentage/100 of HEIGHT to use for the | |
2207 ascent of the glyph (0 <= ASCENT <= 1). */ | |
2208 | |
2209 static void | |
2210 x_append_stretch_glyph (it, object, width, height, ascent) | |
2211 struct it *it; | |
2212 Lisp_Object object; | |
2213 int width, height; | |
2214 double ascent; | |
2215 { | |
2216 struct glyph *glyph; | |
2217 enum glyph_row_area area = it->area; | |
2218 | |
2219 xassert (ascent >= 0 && ascent <= 1); | |
2220 | |
2221 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area]; | |
2222 if (glyph < it->glyph_row->glyphs[area + 1]) | |
2223 { | |
2224 glyph->charpos = CHARPOS (it->position); | |
2225 glyph->object = object; | |
2226 glyph->pixel_width = width; | |
2227 glyph->voffset = it->voffset; | |
2228 glyph->type = STRETCH_GLYPH; | |
2229 glyph->multibyte_p = it->multibyte_p; | |
2230 glyph->left_box_line_p = it->start_of_box_run_p; | |
2231 glyph->right_box_line_p = it->end_of_box_run_p; | |
2232 glyph->overlaps_vertically_p = 0; | |
2233 glyph->padding_p = 0; | |
2234 glyph->glyph_not_available_p = 0; | |
2235 glyph->face_id = it->face_id; | |
2236 glyph->u.stretch.ascent = height * ascent; | |
2237 glyph->u.stretch.height = height; | |
2238 ++it->glyph_row->used[area]; | |
2239 } | |
2240 } | |
2241 | |
2242 | |
2243 /* Produce a stretch glyph for iterator IT. IT->object is the value | |
2244 of the glyph property displayed. The value must be a list | |
2245 `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs | |
2246 being recognized: | |
2247 | |
2248 1. `:width WIDTH' specifies that the space should be WIDTH * | |
2249 canonical char width wide. WIDTH may be an integer or floating | |
2250 point number. | |
2251 | |
2252 2. `:relative-width FACTOR' specifies that the width of the stretch | |
2253 should be computed from the width of the first character having the | |
2254 `glyph' property, and should be FACTOR times that width. | |
2255 | |
2256 3. `:align-to HPOS' specifies that the space should be wide enough | |
2257 to reach HPOS, a value in canonical character units. | |
2258 | |
2259 Exactly one of the above pairs must be present. | |
2260 | |
2261 4. `:height HEIGHT' specifies that the height of the stretch produced | |
2262 should be HEIGHT, measured in canonical character units. | |
2263 | |
2264 5. `:relative-height FACTOR' specifies that the height of the | |
2265 stretch should be FACTOR times the height of the characters having | |
2266 the glyph property. | |
2267 | |
2268 Either none or exactly one of 4 or 5 must be present. | |
2269 | |
2270 6. `:ascent ASCENT' specifies that ASCENT percent of the height | |
2271 of the stretch should be used for the ascent of the stretch. | |
2272 ASCENT must be in the range 0 <= ASCENT <= 100. */ | |
2273 | |
2274 #define NUMVAL(X) \ | |
2275 ((INTEGERP (X) || FLOATP (X)) \ | |
2276 ? XFLOATINT (X) \ | |
2277 : - 1) | |
2278 | |
2279 | |
2280 static void | |
2281 x_produce_stretch_glyph (it) | |
2282 struct it *it; | |
2283 { | |
2284 /* (space :width WIDTH :height HEIGHT. */ | |
2285 #if GLYPH_DEBUG | |
2286 extern Lisp_Object Qspace; | |
2287 #endif | |
2288 extern Lisp_Object QCwidth, QCheight, QCascent; | |
2289 extern Lisp_Object QCrelative_width, QCrelative_height; | |
2290 extern Lisp_Object QCalign_to; | |
2291 Lisp_Object prop, plist; | |
2292 double width = 0, height = 0, ascent = 0; | |
2293 struct face *face = FACE_FROM_ID (it->f, it->face_id); | |
2294 XFontStruct *font = face->font ? face->font : FRAME_FONT (it->f); | |
2295 | |
2296 PREPARE_FACE_FOR_DISPLAY (it->f, face); | |
2297 | |
2298 /* List should start with `space'. */ | |
2299 xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace)); | |
2300 plist = XCDR (it->object); | |
2301 | |
2302 /* Compute the width of the stretch. */ | |
2303 if (prop = Fplist_get (plist, QCwidth), | |
2304 NUMVAL (prop) > 0) | |
2305 /* Absolute width `:width WIDTH' specified and valid. */ | |
2306 width = NUMVAL (prop) * CANON_X_UNIT (it->f); | |
2307 else if (prop = Fplist_get (plist, QCrelative_width), | |
2308 NUMVAL (prop) > 0) | |
2309 { | |
2310 /* Relative width `:relative-width FACTOR' specified and valid. | |
2311 Compute the width of the characters having the `glyph' | |
2312 property. */ | |
2313 struct it it2; | |
2314 unsigned char *p = BYTE_POS_ADDR (IT_BYTEPOS (*it)); | |
2315 | |
2316 it2 = *it; | |
2317 if (it->multibyte_p) | |
2318 { | |
2319 int maxlen = ((IT_BYTEPOS (*it) >= GPT ? ZV : GPT) | |
2320 - IT_BYTEPOS (*it)); | |
2321 it2.c = STRING_CHAR_AND_LENGTH (p, maxlen, it2.len); | |
2322 } | |
2323 else | |
2324 it2.c = *p, it2.len = 1; | |
2325 | |
2326 it2.glyph_row = NULL; | |
2327 it2.what = IT_CHARACTER; | |
2328 x_produce_glyphs (&it2); | |
2329 width = NUMVAL (prop) * it2.pixel_width; | |
2330 } | |
2331 else if (prop = Fplist_get (plist, QCalign_to), | |
2332 NUMVAL (prop) > 0) | |
2333 width = NUMVAL (prop) * CANON_X_UNIT (it->f) - it->current_x; | |
2334 else | |
2335 /* Nothing specified -> width defaults to canonical char width. */ | |
2336 width = CANON_X_UNIT (it->f); | |
2337 | |
2338 /* Compute height. */ | |
2339 if (prop = Fplist_get (plist, QCheight), | |
2340 NUMVAL (prop) > 0) | |
2341 height = NUMVAL (prop) * CANON_Y_UNIT (it->f); | |
2342 else if (prop = Fplist_get (plist, QCrelative_height), | |
2343 NUMVAL (prop) > 0) | |
2344 height = FONT_HEIGHT (font) * NUMVAL (prop); | |
2345 else | |
2346 height = FONT_HEIGHT (font); | |
2347 | |
2348 /* Compute percentage of height used for ascent. If | |
2349 `:ascent ASCENT' is present and valid, use that. Otherwise, | |
2350 derive the ascent from the font in use. */ | |
2351 if (prop = Fplist_get (plist, QCascent), | |
2352 NUMVAL (prop) > 0 && NUMVAL (prop) <= 100) | |
2353 ascent = NUMVAL (prop) / 100.0; | |
2354 else | |
2355 ascent = (double) FONT_BASE (font) / FONT_HEIGHT (font); | |
2356 | |
2357 if (width <= 0) | |
2358 width = 1; | |
2359 if (height <= 0) | |
2360 height = 1; | |
2361 | |
2362 if (it->glyph_row) | |
2363 { | |
2364 Lisp_Object object = it->stack[it->sp - 1].string; | |
2365 if (!STRINGP (object)) | |
2366 object = it->w->buffer; | |
2367 x_append_stretch_glyph (it, object, width, height, ascent); | |
2368 } | |
2369 | |
2370 it->pixel_width = width; | |
2371 it->ascent = it->phys_ascent = height * ascent; | |
2372 it->descent = it->phys_descent = height - it->ascent; | |
2373 it->nglyphs = 1; | |
2374 | |
2375 if (face->box != FACE_NO_BOX) | |
2376 { | |
2377 if (face->box_line_width > 0) | |
2378 { | |
2379 it->ascent += face->box_line_width; | |
2380 it->descent += face->box_line_width; | |
2381 } | |
2382 | |
2383 if (it->start_of_box_run_p) | |
2384 it->pixel_width += abs (face->box_line_width); | |
2385 if (it->end_of_box_run_p) | |
2386 it->pixel_width += abs (face->box_line_width); | |
2387 } | |
2388 | |
2389 take_vertical_position_into_account (it); | |
2390 } | |
2391 | |
2392 /* Return proper value to be used as baseline offset of font that has | |
2393 ASCENT and DESCENT to draw characters by the font at the vertical | |
2394 center of the line of frame F. | |
2395 | |
2396 Here, out task is to find the value of BOFF in the following figure; | |
2397 | |
2398 -------------------------+-----------+- | |
2399 -+-+---------+-+ | | | |
2400 | | | | | | | |
2401 | | | | F_ASCENT F_HEIGHT | |
2402 | | | ASCENT | | | |
2403 HEIGHT | | | | | | |
2404 | | |-|-+------+-----------|------- baseline | |
2405 | | | | BOFF | | | |
2406 | |---------|-+-+ | | | |
2407 | | | DESCENT | | | |
2408 -+-+---------+-+ F_DESCENT | | |
2409 -------------------------+-----------+- | |
2410 | |
2411 -BOFF + DESCENT + (F_HEIGHT - HEIGHT) / 2 = F_DESCENT | |
2412 BOFF = DESCENT + (F_HEIGHT - HEIGHT) / 2 - F_DESCENT | |
2413 DESCENT = FONT->descent | |
2414 HEIGHT = FONT_HEIGHT (FONT) | |
2415 F_DESCENT = (F->output_data.x->font->descent | |
2416 - F->output_data.x->baseline_offset) | |
2417 F_HEIGHT = FRAME_LINE_HEIGHT (F) | |
2418 */ | |
2419 | |
2420 #define VCENTER_BASELINE_OFFSET(FONT, F) \ | |
2421 (FONT_DESCENT (FONT) \ | |
2422 + (FRAME_LINE_HEIGHT ((F)) - FONT_HEIGHT ((FONT)) \ | |
2423 + (FRAME_LINE_HEIGHT ((F)) > FONT_HEIGHT ((FONT)))) / 2 \ | |
2424 - (FONT_DESCENT (FRAME_FONT (F)) - FRAME_BASELINE_OFFSET (F))) | |
2425 | |
2426 /* Produce glyphs/get display metrics for the display element IT is | |
2427 loaded with. See the description of struct display_iterator in | |
2428 dispextern.h for an overview of struct display_iterator. */ | |
2429 | |
2430 static void | |
2431 x_produce_glyphs (it) | |
2432 struct it *it; | |
2433 { | |
2434 it->glyph_not_available_p = 0; | |
2435 | |
2436 if (it->what == IT_CHARACTER) | |
2437 { | |
2438 XChar2b char2b; | |
2439 XFontStruct *font; | |
2440 struct face *face = FACE_FROM_ID (it->f, it->face_id); | |
2441 XCharStruct *pcm; | |
2442 int font_not_found_p; | |
2443 struct font_info *font_info; | |
2444 int boff; /* baseline offset */ | |
2445 /* We may change it->multibyte_p upon unibyte<->multibyte | |
2446 conversion. So, save the current value now and restore it | |
2447 later. | |
2448 | |
2449 Note: It seems that we don't have to record multibyte_p in | |
2450 struct glyph because the character code itself tells if or | |
2451 not the character is multibyte. Thus, in the future, we must | |
2452 consider eliminating the field `multibyte_p' in the struct | |
2453 glyph. | |
2454 */ | |
2455 int saved_multibyte_p = it->multibyte_p; | |
2456 | |
2457 /* Maybe translate single-byte characters to multibyte, or the | |
2458 other way. */ | |
2459 it->char_to_display = it->c; | |
2460 if (!ASCII_BYTE_P (it->c)) | |
2461 { | |
2462 if (unibyte_display_via_language_environment | |
2463 && SINGLE_BYTE_CHAR_P (it->c) | |
2464 && (it->c >= 0240 | |
2465 || !NILP (Vnonascii_translation_table))) | |
2466 { | |
2467 it->char_to_display = unibyte_char_to_multibyte (it->c); | |
2468 it->multibyte_p = 1; | |
2469 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display); | |
2470 face = FACE_FROM_ID (it->f, it->face_id); | |
2471 } | |
2472 else if (!SINGLE_BYTE_CHAR_P (it->c) | |
2473 && !it->multibyte_p) | |
2474 { | |
2475 it->multibyte_p = 1; | |
2476 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display); | |
2477 face = FACE_FROM_ID (it->f, it->face_id); | |
2478 } | |
2479 } | |
2480 | |
2481 /* Get font to use. Encode IT->char_to_display. */ | |
2482 x_get_char_face_and_encoding (it->f, it->char_to_display, | |
2483 it->face_id, &char2b, | |
2484 it->multibyte_p); | |
2485 font = face->font; | |
2486 | |
2487 /* When no suitable font found, use the default font. */ | |
2488 font_not_found_p = font == NULL; | |
2489 if (font_not_found_p) | |
2490 { | |
2491 font = FRAME_FONT (it->f); | |
2492 boff = it->f->output_data.mac->baseline_offset; | |
2493 font_info = NULL; | |
2494 } | |
2495 else | |
2496 { | |
2497 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id); | |
2498 boff = font_info->baseline_offset; | |
2499 if (font_info->vertical_centering) | |
2500 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff; | |
2501 } | |
2502 | |
2503 if (it->char_to_display >= ' ' | |
2504 && (!it->multibyte_p || it->char_to_display < 128)) | |
2505 { | |
2506 /* Either unibyte or ASCII. */ | |
2507 int stretched_p; | |
2508 | |
2509 it->nglyphs = 1; | |
2510 | |
2511 pcm = x_per_char_metric (font, &char2b); | |
2512 it->ascent = FONT_BASE (font) + boff; | |
2513 it->descent = FONT_DESCENT (font) - boff; | |
2514 | |
2515 if (pcm) | |
2516 { | |
2517 it->phys_ascent = pcm->ascent + boff; | |
2518 it->phys_descent = pcm->descent - boff; | |
2519 it->pixel_width = pcm->width; | |
2520 } | |
2521 else | |
2522 { | |
2523 it->glyph_not_available_p = 1; | |
2524 it->phys_ascent = FONT_BASE (font) + boff; | |
2525 it->phys_descent = FONT_DESCENT (font) - boff; | |
2526 it->pixel_width = FONT_WIDTH (font); | |
2527 } | |
2528 | |
2529 /* If this is a space inside a region of text with | |
2530 `space-width' property, change its width. */ | |
2531 stretched_p = it->char_to_display == ' ' && !NILP (it->space_width); | |
2532 if (stretched_p) | |
2533 it->pixel_width *= XFLOATINT (it->space_width); | |
2534 | |
2535 /* If face has a box, add the box thickness to the character | |
2536 height. If character has a box line to the left and/or | |
2537 right, add the box line width to the character's width. */ | |
2538 if (face->box != FACE_NO_BOX) | |
2539 { | |
2540 int thick = face->box_line_width; | |
2541 | |
2542 if (thick > 0) | |
2543 { | |
2544 it->ascent += thick; | |
2545 it->descent += thick; | |
2546 } | |
2547 else | |
2548 thick = -thick; | |
2549 | |
2550 if (it->start_of_box_run_p) | |
2551 it->pixel_width += thick; | |
2552 if (it->end_of_box_run_p) | |
2553 it->pixel_width += thick; | |
2554 } | |
2555 | |
2556 /* If face has an overline, add the height of the overline | |
2557 (1 pixel) and a 1 pixel margin to the character height. */ | |
2558 if (face->overline_p) | |
2559 it->ascent += 2; | |
2560 | |
2561 take_vertical_position_into_account (it); | |
2562 | |
2563 /* If we have to actually produce glyphs, do it. */ | |
2564 if (it->glyph_row) | |
2565 { | |
2566 if (stretched_p) | |
2567 { | |
2568 /* Translate a space with a `space-width' property | |
2569 into a stretch glyph. */ | |
2570 double ascent = (double) FONT_BASE (font) | |
2571 / FONT_HEIGHT (font); | |
2572 x_append_stretch_glyph (it, it->object, it->pixel_width, | |
2573 it->ascent + it->descent, ascent); | |
2574 } | |
2575 else | |
2576 x_append_glyph (it); | |
2577 | |
2578 /* If characters with lbearing or rbearing are displayed | |
2579 in this line, record that fact in a flag of the | |
2580 glyph row. This is used to optimize X output code. */ | |
2581 if (pcm && (pcm->lbearing < 0 || pcm->rbearing > pcm->width)) | |
2582 it->glyph_row->contains_overlapping_glyphs_p = 1; | |
2583 } | |
2584 } | |
2585 else if (it->char_to_display == '\n') | |
2586 { | |
2587 /* A newline has no width but we need the height of the line. */ | |
2588 it->pixel_width = 0; | |
2589 it->nglyphs = 0; | |
2590 it->ascent = it->phys_ascent = FONT_BASE (font) + boff; | |
2591 it->descent = it->phys_descent = FONT_DESCENT (font) - boff; | |
2592 | |
2593 if (face->box != FACE_NO_BOX | |
2594 && face->box_line_width > 0) | |
2595 { | |
2596 it->ascent += face->box_line_width; | |
2597 it->descent += face->box_line_width; | |
2598 } | |
2599 } | |
2600 else if (it->char_to_display == '\t') | |
2601 { | |
2602 int tab_width = it->tab_width * CANON_X_UNIT (it->f); | |
2603 int x = it->current_x + it->continuation_lines_width; | |
2604 int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * tab_width; | |
2605 | |
2606 /* If the distance from the current position to the next tab | |
2607 stop is less than a canonical character width, use the | |
2608 tab stop after that. */ | |
2609 if (next_tab_x - x < CANON_X_UNIT (it->f)) | |
2610 next_tab_x += tab_width; | |
2611 | |
2612 it->pixel_width = next_tab_x - x; | |
2613 it->nglyphs = 1; | |
2614 it->ascent = it->phys_ascent = FONT_BASE (font) + boff; | |
2615 it->descent = it->phys_descent = FONT_DESCENT (font) - boff; | |
2616 | |
2617 if (it->glyph_row) | |
2618 { | |
2619 double ascent = (double) it->ascent / (it->ascent + it->descent); | |
2620 x_append_stretch_glyph (it, it->object, it->pixel_width, | |
2621 it->ascent + it->descent, ascent); | |
2622 } | |
2623 } | |
2624 else | |
2625 { | |
2626 /* A multi-byte character. Assume that the display width of the | |
2627 character is the width of the character multiplied by the | |
2628 width of the font. */ | |
2629 | |
2630 /* If we found a font, this font should give us the right | |
2631 metrics. If we didn't find a font, use the frame's | |
2632 default font and calculate the width of the character | |
2633 from the charset width; this is what old redisplay code | |
2634 did. */ | |
2635 pcm = x_per_char_metric (font, &char2b); | |
2636 if (font_not_found_p || !pcm) | |
2637 { | |
2638 int charset = CHAR_CHARSET (it->char_to_display); | |
2639 | |
2640 it->glyph_not_available_p = 1; | |
2641 it->pixel_width = (FONT_WIDTH (FRAME_FONT (it->f)) | |
2642 * CHARSET_WIDTH (charset)); | |
2643 it->phys_ascent = FONT_BASE (font) + boff; | |
2644 it->phys_descent = FONT_DESCENT (font) - boff; | |
2645 } | |
2646 else | |
2647 { | |
2648 it->pixel_width = pcm->width; | |
2649 it->phys_ascent = pcm->ascent + boff; | |
2650 it->phys_descent = pcm->descent - boff; | |
2651 if (it->glyph_row | |
2652 && (pcm->lbearing < 0 | |
2653 || pcm->rbearing > pcm->width)) | |
2654 it->glyph_row->contains_overlapping_glyphs_p = 1; | |
2655 } | |
2656 it->nglyphs = 1; | |
2657 it->ascent = FONT_BASE (font) + boff; | |
2658 it->descent = FONT_DESCENT (font) - boff; | |
2659 if (face->box != FACE_NO_BOX) | |
2660 { | |
2661 int thick = face->box_line_width; | |
2662 | |
2663 if (thick > 0) | |
2664 { | |
2665 it->ascent += thick; | |
2666 it->descent += thick; | |
2667 } | |
2668 else | |
2669 thick = - thick; | |
2670 | |
2671 if (it->start_of_box_run_p) | |
2672 it->pixel_width += thick; | |
2673 if (it->end_of_box_run_p) | |
2674 it->pixel_width += thick; | |
2675 } | |
2676 | |
2677 /* If face has an overline, add the height of the overline | |
2678 (1 pixel) and a 1 pixel margin to the character height. */ | |
2679 if (face->overline_p) | |
2680 it->ascent += 2; | |
2681 | |
2682 take_vertical_position_into_account (it); | |
2683 | |
2684 if (it->glyph_row) | |
2685 x_append_glyph (it); | |
2686 } | |
2687 it->multibyte_p = saved_multibyte_p; | |
2688 } | |
2689 else if (it->what == IT_COMPOSITION) | |
2690 { | |
2691 /* Note: A composition is represented as one glyph in the | |
2692 glyph matrix. There are no padding glyphs. */ | |
2693 XChar2b char2b; | |
2694 XFontStruct *font; | |
2695 struct face *face = FACE_FROM_ID (it->f, it->face_id); | |
2696 XCharStruct *pcm; | |
2697 int font_not_found_p; | |
2698 struct font_info *font_info; | |
2699 int boff; /* baseline offset */ | |
2700 struct composition *cmp = composition_table[it->cmp_id]; | |
2701 | |
2702 /* Maybe translate single-byte characters to multibyte. */ | |
2703 it->char_to_display = it->c; | |
2704 if (unibyte_display_via_language_environment | |
2705 && SINGLE_BYTE_CHAR_P (it->c) | |
2706 && (it->c >= 0240 | |
2707 || (it->c >= 0200 | |
2708 && !NILP (Vnonascii_translation_table)))) | |
2709 { | |
2710 it->char_to_display = unibyte_char_to_multibyte (it->c); | |
2711 } | |
2712 | |
2713 /* Get face and font to use. Encode IT->char_to_display. */ | |
2714 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display); | |
2715 face = FACE_FROM_ID (it->f, it->face_id); | |
2716 x_get_char_face_and_encoding (it->f, it->char_to_display, | |
2717 it->face_id, &char2b, it->multibyte_p); | |
2718 font = face->font; | |
2719 | |
2720 /* When no suitable font found, use the default font. */ | |
2721 font_not_found_p = font == NULL; | |
2722 if (font_not_found_p) | |
2723 { | |
2724 font = FRAME_FONT (it->f); | |
2725 boff = it->f->output_data.mac->baseline_offset; | |
2726 font_info = NULL; | |
2727 } | |
2728 else | |
2729 { | |
2730 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id); | |
2731 boff = font_info->baseline_offset; | |
2732 if (font_info->vertical_centering) | |
2733 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff; | |
2734 } | |
2735 | |
2736 /* There are no padding glyphs, so there is only one glyph to | |
2737 produce for the composition. Important is that pixel_width, | |
2738 ascent and descent are the values of what is drawn by | |
2739 draw_glyphs (i.e. the values of the overall glyphs composed). */ | |
2740 it->nglyphs = 1; | |
2741 | |
2742 /* If we have not yet calculated pixel size data of glyphs of | |
2743 the composition for the current face font, calculate them | |
2744 now. Theoretically, we have to check all fonts for the | |
2745 glyphs, but that requires much time and memory space. So, | |
2746 here we check only the font of the first glyph. This leads | |
2747 to incorrect display very rarely, and C-l (recenter) can | |
2748 correct the display anyway. */ | |
2749 if (cmp->font != (void *) font) | |
2750 { | |
2751 /* Ascent and descent of the font of the first character of | |
2752 this composition (adjusted by baseline offset). Ascent | |
2753 and descent of overall glyphs should not be less than | |
2754 them respectively. */ | |
2755 int font_ascent = FONT_BASE (font) + boff; | |
2756 int font_descent = FONT_DESCENT (font) - boff; | |
2757 /* Bounding box of the overall glyphs. */ | |
2758 int leftmost, rightmost, lowest, highest; | |
2759 int i, width, ascent, descent; | |
2760 | |
2761 cmp->font = (void *) font; | |
2762 | |
2763 /* Initialize the bounding box. */ | |
2764 pcm = x_per_char_metric (font, &char2b); | |
2765 if (pcm) | |
2766 { | |
2767 width = pcm->width; | |
2768 ascent = pcm->ascent; | |
2769 descent = pcm->descent; | |
2770 } | |
2771 else | |
2772 { | |
2773 width = FONT_WIDTH (font); | |
2774 ascent = FONT_BASE (font); | |
2775 descent = FONT_DESCENT (font); | |
2776 } | |
2777 | |
2778 rightmost = width; | |
2779 lowest = - descent + boff; | |
2780 highest = ascent + boff; | |
2781 leftmost = 0; | |
2782 | |
2783 if (font_info | |
2784 && font_info->default_ascent | |
2785 && CHAR_TABLE_P (Vuse_default_ascent) | |
2786 && !NILP (Faref (Vuse_default_ascent, | |
2787 make_number (it->char_to_display)))) | |
2788 highest = font_info->default_ascent + boff; | |
2789 | |
2790 /* Draw the first glyph at the normal position. It may be | |
2791 shifted to right later if some other glyphs are drawn at | |
2792 the left. */ | |
2793 cmp->offsets[0] = 0; | |
2794 cmp->offsets[1] = boff; | |
2795 | |
2796 /* Set cmp->offsets for the remaining glyphs. */ | |
2797 for (i = 1; i < cmp->glyph_len; i++) | |
2798 { | |
2799 int left, right, btm, top; | |
2800 int ch = COMPOSITION_GLYPH (cmp, i); | |
2801 int face_id = FACE_FOR_CHAR (it->f, face, ch); | |
2802 | |
2803 face = FACE_FROM_ID (it->f, face_id); | |
2804 x_get_char_face_and_encoding (it->f, ch, face->id, &char2b, | |
2805 it->multibyte_p); | |
2806 font = face->font; | |
2807 if (font == NULL) | |
2808 { | |
2809 font = FRAME_FONT (it->f); | |
2810 boff = it->f->output_data.mac->baseline_offset; | |
2811 font_info = NULL; | |
2812 } | |
2813 else | |
2814 { | |
2815 font_info | |
2816 = FONT_INFO_FROM_ID (it->f, face->font_info_id); | |
2817 boff = font_info->baseline_offset; | |
2818 if (font_info->vertical_centering) | |
2819 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff; | |
2820 } | |
2821 | |
2822 pcm = x_per_char_metric (font, &char2b); | |
2823 if (pcm) | |
2824 { | |
2825 width = pcm->width; | |
2826 ascent = pcm->ascent; | |
2827 descent = pcm->descent; | |
2828 } | |
2829 else | |
2830 { | |
2831 width = FONT_WIDTH (font); | |
2832 ascent = 1; | |
2833 descent = 0; | |
2834 } | |
2835 | |
2836 if (cmp->method != COMPOSITION_WITH_RULE_ALTCHARS) | |
2837 { | |
2838 /* Relative composition with or without | |
2839 alternate chars. */ | |
2840 left = (leftmost + rightmost - width) / 2; | |
2841 btm = - descent + boff; | |
2842 if (font_info && font_info->relative_compose | |
2843 && (! CHAR_TABLE_P (Vignore_relative_composition) | |
2844 || NILP (Faref (Vignore_relative_composition, | |
2845 make_number (ch))))) | |
2846 { | |
2847 | |
2848 if (- descent >= font_info->relative_compose) | |
2849 /* One extra pixel between two glyphs. */ | |
2850 btm = highest + 1; | |
2851 else if (ascent <= 0) | |
2852 /* One extra pixel between two glyphs. */ | |
2853 btm = lowest - 1 - ascent - descent; | |
2854 } | |
2855 } | |
2856 else | |
2857 { | |
2858 /* A composition rule is specified by an integer | |
2859 value that encodes global and new reference | |
2860 points (GREF and NREF). GREF and NREF are | |
2861 specified by numbers as below: | |
2862 | |
2863 0---1---2 -- ascent | |
2864 | | | |
2865 | | | |
2866 | | | |
2867 9--10--11 -- center | |
2868 | | | |
2869 ---3---4---5--- baseline | |
2870 | | | |
2871 6---7---8 -- descent | |
2872 */ | |
2873 int rule = COMPOSITION_RULE (cmp, i); | |
2874 int gref, nref, grefx, grefy, nrefx, nrefy; | |
2875 | |
2876 COMPOSITION_DECODE_RULE (rule, gref, nref); | |
2877 grefx = gref % 3, nrefx = nref % 3; | |
2878 grefy = gref / 3, nrefy = nref / 3; | |
2879 | |
2880 left = (leftmost | |
2881 + grefx * (rightmost - leftmost) / 2 | |
2882 - nrefx * width / 2); | |
2883 btm = ((grefy == 0 ? highest | |
2884 : grefy == 1 ? 0 | |
2885 : grefy == 2 ? lowest | |
2886 : (highest + lowest) / 2) | |
2887 - (nrefy == 0 ? ascent + descent | |
2888 : nrefy == 1 ? descent - boff | |
2889 : nrefy == 2 ? 0 | |
2890 : (ascent + descent) / 2)); | |
2891 } | |
2892 | |
2893 cmp->offsets[i * 2] = left; | |
2894 cmp->offsets[i * 2 + 1] = btm + descent; | |
2895 | |
2896 /* Update the bounding box of the overall glyphs. */ | |
2897 right = left + width; | |
2898 top = btm + descent + ascent; | |
2899 if (left < leftmost) | |
2900 leftmost = left; | |
2901 if (right > rightmost) | |
2902 rightmost = right; | |
2903 if (top > highest) | |
2904 highest = top; | |
2905 if (btm < lowest) | |
2906 lowest = btm; | |
2907 } | |
2908 | |
2909 /* If there are glyphs whose x-offsets are negative, | |
2910 shift all glyphs to the right and make all x-offsets | |
2911 non-negative. */ | |
2912 if (leftmost < 0) | |
2913 { | |
2914 for (i = 0; i < cmp->glyph_len; i++) | |
2915 cmp->offsets[i * 2] -= leftmost; | |
2916 rightmost -= leftmost; | |
2917 } | |
2918 | |
2919 cmp->pixel_width = rightmost; | |
2920 cmp->ascent = highest; | |
2921 cmp->descent = - lowest; | |
2922 if (cmp->ascent < font_ascent) | |
2923 cmp->ascent = font_ascent; | |
2924 if (cmp->descent < font_descent) | |
2925 cmp->descent = font_descent; | |
2926 } | |
2927 | |
2928 it->pixel_width = cmp->pixel_width; | |
2929 it->ascent = it->phys_ascent = cmp->ascent; | |
2930 it->descent = it->phys_descent = cmp->descent; | |
2931 | |
2932 if (face->box != FACE_NO_BOX) | |
2933 { | |
2934 int thick = face->box_line_width; | |
2935 | |
2936 if (thick > 0) | |
2937 { | |
2938 it->ascent += thick; | |
2939 it->descent += thick; | |
2940 } | |
2941 else | |
2942 thick = - thick; | |
2943 | |
2944 if (it->start_of_box_run_p) | |
2945 it->pixel_width += thick; | |
2946 if (it->end_of_box_run_p) | |
2947 it->pixel_width += thick; | |
2948 } | |
2949 | |
2950 /* If face has an overline, add the height of the overline | |
2951 (1 pixel) and a 1 pixel margin to the character height. */ | |
2952 if (face->overline_p) | |
2953 it->ascent += 2; | |
2954 | |
2955 take_vertical_position_into_account (it); | |
2956 | |
2957 if (it->glyph_row) | |
2958 x_append_composite_glyph (it); | |
2959 } | |
2960 else if (it->what == IT_IMAGE) | |
2961 x_produce_image_glyph (it); | |
2962 else if (it->what == IT_STRETCH) | |
2963 x_produce_stretch_glyph (it); | |
2964 | |
2965 /* Accumulate dimensions. Note: can't assume that it->descent > 0 | |
2966 because this isn't true for images with `:ascent 100'. */ | |
2967 xassert (it->ascent >= 0 && it->descent >= 0); | |
2968 if (it->area == TEXT_AREA) | |
2969 it->current_x += it->pixel_width; | |
2970 | |
2971 it->descent += it->extra_line_spacing; | |
2972 | |
2973 it->max_ascent = max (it->max_ascent, it->ascent); | |
2974 it->max_descent = max (it->max_descent, it->descent); | |
2975 it->max_phys_ascent = max (it->max_phys_ascent, it->phys_ascent); | |
2976 it->max_phys_descent = max (it->max_phys_descent, it->phys_descent); | |
2977 } | |
2978 | |
2979 | |
2980 /* Estimate the pixel height of the mode or top line on frame F. | |
2981 FACE_ID specifies what line's height to estimate. */ | |
2982 | |
2983 int | |
2984 x_estimate_mode_line_height (f, face_id) | |
2985 struct frame *f; | |
2986 enum face_id face_id; | |
2987 { | |
2988 int height = FONT_HEIGHT (FRAME_FONT (f)); | |
2989 | |
2990 /* This function is called so early when Emacs starts that the face | |
2991 cache and mode line face are not yet initialized. */ | |
2992 if (FRAME_FACE_CACHE (f)) | |
2993 { | |
2994 struct face *face = FACE_FROM_ID (f, face_id); | |
2995 if (face) | |
2996 { | |
2997 if (face->font) | |
2998 height = FONT_HEIGHT (face->font); | |
2999 if (face->box_line_width > 0) | |
3000 height += 2 * face->box_line_width; | |
3001 } | |
3002 } | |
3003 | |
3004 return height; | |
3005 } | |
3006 | |
3007 | |
3008 /*********************************************************************** | |
3009 Glyph display | |
3010 ***********************************************************************/ | |
3011 | |
3012 /* A sequence of glyphs to be drawn in the same face. | |
3013 | |
3014 This data structure is not really completely X specific, so it | |
3015 could possibly, at least partially, be useful for other systems. It | |
3016 is currently not part of the external redisplay interface because | |
3017 it's not clear what other systems will need. */ | |
3018 | |
3019 struct glyph_string | |
3020 { | |
3021 /* X-origin of the string. */ | |
3022 int x; | |
3023 | |
3024 /* Y-origin and y-position of the base line of this string. */ | |
3025 int y, ybase; | |
3026 | |
3027 /* The width of the string, not including a face extension. */ | |
3028 int width; | |
3029 | |
3030 /* The width of the string, including a face extension. */ | |
3031 int background_width; | |
3032 | |
3033 /* The height of this string. This is the height of the line this | |
3034 string is drawn in, and can be different from the height of the | |
3035 font the string is drawn in. */ | |
3036 int height; | |
3037 | |
3038 /* Number of pixels this string overwrites in front of its x-origin. | |
3039 This number is zero if the string has an lbearing >= 0; it is | |
3040 -lbearing, if the string has an lbearing < 0. */ | |
3041 int left_overhang; | |
3042 | |
3043 /* Number of pixels this string overwrites past its right-most | |
3044 nominal x-position, i.e. x + width. Zero if the string's | |
3045 rbearing is <= its nominal width, rbearing - width otherwise. */ | |
3046 int right_overhang; | |
3047 | |
3048 /* The frame on which the glyph string is drawn. */ | |
3049 struct frame *f; | |
3050 | |
3051 /* The window on which the glyph string is drawn. */ | |
3052 struct window *w; | |
3053 | |
3054 /* X display and window for convenience. */ | |
3055 Display *display; | |
3056 Window window; | |
3057 | |
3058 /* The glyph row for which this string was built. It determines the | |
3059 y-origin and height of the string. */ | |
3060 struct glyph_row *row; | |
3061 | |
3062 /* The area within row. */ | |
3063 enum glyph_row_area area; | |
3064 | |
3065 /* Characters to be drawn, and number of characters. */ | |
3066 XChar2b *char2b; | |
3067 int nchars; | |
3068 | |
3069 /* A face-override for drawing cursors, mouse face and similar. */ | |
3070 enum draw_glyphs_face hl; | |
3071 | |
3072 /* Face in which this string is to be drawn. */ | |
3073 struct face *face; | |
3074 | |
3075 /* Font in which this string is to be drawn. */ | |
3076 XFontStruct *font; | |
3077 | |
3078 /* Font info for this string. */ | |
3079 struct font_info *font_info; | |
3080 | |
3081 /* Non-null means this string describes (part of) a composition. | |
3082 All characters from char2b are drawn composed. */ | |
3083 struct composition *cmp; | |
3084 | |
3085 /* Index of this glyph string's first character in the glyph | |
3086 definition of CMP. If this is zero, this glyph string describes | |
3087 the first character of a composition. */ | |
3088 int gidx; | |
3089 | |
3090 /* 1 means this glyph strings face has to be drawn to the right end | |
3091 of the window's drawing area. */ | |
3092 unsigned extends_to_end_of_line_p : 1; | |
3093 | |
3094 /* 1 means the background of this string has been drawn. */ | |
3095 unsigned background_filled_p : 1; | |
3096 | |
3097 /* 1 means glyph string must be drawn with 16-bit functions. */ | |
3098 unsigned two_byte_p : 1; | |
3099 | |
3100 /* 1 means that the original font determined for drawing this glyph | |
3101 string could not be loaded. The member `font' has been set to | |
3102 the frame's default font in this case. */ | |
3103 unsigned font_not_found_p : 1; | |
3104 | |
3105 /* 1 means that the face in which this glyph string is drawn has a | |
3106 stipple pattern. */ | |
3107 unsigned stippled_p : 1; | |
3108 | |
3109 /* 1 means only the foreground of this glyph string must be drawn, | |
3110 and we should use the physical height of the line this glyph | |
3111 string appears in as clip rect. */ | |
3112 unsigned for_overlaps_p : 1; | |
3113 | |
3114 /* The GC to use for drawing this glyph string. */ | |
3115 GC gc; | |
3116 | |
3117 /* A pointer to the first glyph in the string. This glyph | |
3118 corresponds to char2b[0]. Needed to draw rectangles if | |
3119 font_not_found_p is 1. */ | |
3120 struct glyph *first_glyph; | |
3121 | |
3122 /* Image, if any. */ | |
3123 struct image *img; | |
3124 | |
3125 struct glyph_string *next, *prev; | |
3126 }; | |
3127 | |
3128 | |
3129 #if 0 | |
3130 | |
3131 static void | |
3132 x_dump_glyph_string (s) | |
3133 struct glyph_string *s; | |
3134 { | |
3135 fprintf (stderr, "glyph string\n"); | |
3136 fprintf (stderr, " x, y, w, h = %d, %d, %d, %d\n", | |
3137 s->x, s->y, s->width, s->height); | |
3138 fprintf (stderr, " ybase = %d\n", s->ybase); | |
3139 fprintf (stderr, " hl = %d\n", s->hl); | |
3140 fprintf (stderr, " left overhang = %d, right = %d\n", | |
3141 s->left_overhang, s->right_overhang); | |
3142 fprintf (stderr, " nchars = %d\n", s->nchars); | |
3143 fprintf (stderr, " extends to end of line = %d\n", | |
3144 s->extends_to_end_of_line_p); | |
3145 fprintf (stderr, " font height = %d\n", FONT_HEIGHT (s->font)); | |
3146 fprintf (stderr, " bg width = %d\n", s->background_width); | |
3147 } | |
3148 | |
3149 #endif /* GLYPH_DEBUG */ | |
3150 | |
3151 | |
3152 | |
3153 static void x_append_glyph_string_lists P_ ((struct glyph_string **, | |
3154 struct glyph_string **, | |
3155 struct glyph_string *, | |
3156 struct glyph_string *)); | |
3157 static void x_prepend_glyph_string_lists P_ ((struct glyph_string **, | |
3158 struct glyph_string **, | |
3159 struct glyph_string *, | |
3160 struct glyph_string *)); | |
3161 static void x_append_glyph_string P_ ((struct glyph_string **, | |
3162 struct glyph_string **, | |
3163 struct glyph_string *)); | |
3164 static int x_left_overwritten P_ ((struct glyph_string *)); | |
3165 static int x_left_overwriting P_ ((struct glyph_string *)); | |
3166 static int x_right_overwritten P_ ((struct glyph_string *)); | |
3167 static int x_right_overwriting P_ ((struct glyph_string *)); | |
3168 static int x_fill_glyph_string P_ ((struct glyph_string *, int, int, int, | |
3169 int)); | |
3170 static void x_init_glyph_string P_ ((struct glyph_string *, | |
3171 XChar2b *, struct window *, | |
3172 struct glyph_row *, | |
3173 enum glyph_row_area, int, | |
3174 enum draw_glyphs_face)); | |
3175 static int x_draw_glyphs P_ ((struct window *, int , struct glyph_row *, | |
3176 enum glyph_row_area, int, int, | |
3177 enum draw_glyphs_face, int)); | |
3178 static void x_set_glyph_string_clipping P_ ((struct glyph_string *)); | |
3179 static void x_set_glyph_string_gc P_ ((struct glyph_string *)); | |
3180 static void x_draw_glyph_string_background P_ ((struct glyph_string *, | |
3181 int)); | |
3182 static void x_draw_glyph_string_foreground P_ ((struct glyph_string *)); | |
3183 static void x_draw_composite_glyph_string_foreground P_ ((struct glyph_string *)); | |
3184 static void x_draw_glyph_string_box P_ ((struct glyph_string *)); | |
3185 static void x_draw_glyph_string P_ ((struct glyph_string *)); | |
3186 static void x_compute_glyph_string_overhangs P_ ((struct glyph_string *)); | |
3187 static void x_set_cursor_gc P_ ((struct glyph_string *)); | |
3188 static void x_set_mode_line_face_gc P_ ((struct glyph_string *)); | |
3189 static void x_set_mouse_face_gc P_ ((struct glyph_string *)); | |
3190 static void x_get_glyph_overhangs P_ ((struct glyph *, struct frame *, | |
3191 int *, int *)); | |
3192 static void x_compute_overhangs_and_x P_ ((struct glyph_string *, int, int)); | |
3193 /*static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap, | |
3194 unsigned long *, double, int));*/ | |
3195 static void x_setup_relief_color P_ ((struct frame *, struct relief *, | |
3196 double, int, unsigned long)); | |
3197 static void x_setup_relief_colors P_ ((struct glyph_string *)); | |
3198 static void x_draw_image_glyph_string P_ ((struct glyph_string *)); | |
3199 static void x_draw_image_relief P_ ((struct glyph_string *)); | |
3200 static void x_draw_image_foreground P_ ((struct glyph_string *)); | |
3201 static void x_draw_image_foreground_1 P_ ((struct glyph_string *, Pixmap)); | |
3202 static void x_fill_image_glyph_string P_ ((struct glyph_string *)); | |
3203 static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int, | |
3204 int, int, int)); | |
3205 static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int, | |
3206 int, int, int, int, Rect *)); | |
3207 static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int, | |
3208 int, int, int, Rect *)); | |
3209 static void x_fix_overlapping_area P_ ((struct window *, struct glyph_row *, | |
3210 enum glyph_row_area)); | |
3211 static int x_fill_stretch_glyph_string P_ ((struct glyph_string *, | |
3212 struct glyph_row *, | |
3213 enum glyph_row_area, int, int)); | |
3214 | |
3215 #if GLYPH_DEBUG | |
3216 static void x_check_font P_ ((struct frame *, XFontStruct *)); | |
3217 #endif | |
3218 | |
3219 | |
3220 /* Append the list of glyph strings with head H and tail T to the list | |
3221 with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the result. */ | |
3222 | |
3223 static INLINE void | |
3224 x_append_glyph_string_lists (head, tail, h, t) | |
3225 struct glyph_string **head, **tail; | |
3226 struct glyph_string *h, *t; | |
3227 { | |
3228 if (h) | |
3229 { | |
3230 if (*head) | |
3231 (*tail)->next = h; | |
3232 else | |
3233 *head = h; | |
3234 h->prev = *tail; | |
3235 *tail = t; | |
3236 } | |
3237 } | |
3238 | |
3239 | |
3240 /* Prepend the list of glyph strings with head H and tail T to the | |
3241 list with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the | |
3242 result. */ | |
3243 | |
3244 static INLINE void | |
3245 x_prepend_glyph_string_lists (head, tail, h, t) | |
3246 struct glyph_string **head, **tail; | |
3247 struct glyph_string *h, *t; | |
3248 { | |
3249 if (h) | |
3250 { | |
3251 if (*head) | |
3252 (*head)->prev = t; | |
3253 else | |
3254 *tail = t; | |
3255 t->next = *head; | |
3256 *head = h; | |
3257 } | |
3258 } | |
3259 | |
3260 | |
3261 /* Append glyph string S to the list with head *HEAD and tail *TAIL. | |
3262 Set *HEAD and *TAIL to the resulting list. */ | |
3263 | |
3264 static INLINE void | |
3265 x_append_glyph_string (head, tail, s) | |
3266 struct glyph_string **head, **tail; | |
3267 struct glyph_string *s; | |
3268 { | |
3269 s->next = s->prev = NULL; | |
3270 x_append_glyph_string_lists (head, tail, s, s); | |
3271 } | |
3272 | |
3273 | |
3274 /* Set S->gc to a suitable GC for drawing glyph string S in cursor | |
3275 face. */ | |
3276 | |
3277 static void | |
3278 x_set_cursor_gc (s) | |
3279 struct glyph_string *s; | |
3280 { | |
3281 if (s->font == FRAME_FONT (s->f) | |
3282 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f) | |
3283 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f) | |
3284 && !s->cmp) | |
3285 s->gc = s->f->output_data.mac->cursor_gc; | |
3286 else | |
3287 { | |
3288 /* Cursor on non-default face: must merge. */ | |
3289 XGCValues xgcv; | |
3290 unsigned long mask; | |
3291 | |
3292 xgcv.background = s->f->output_data.mac->cursor_pixel; | |
3293 xgcv.foreground = s->face->background; | |
3294 | |
3295 /* If the glyph would be invisible, try a different foreground. */ | |
3296 if (xgcv.foreground == xgcv.background) | |
3297 xgcv.foreground = s->face->foreground; | |
3298 if (xgcv.foreground == xgcv.background) | |
3299 xgcv.foreground = s->f->output_data.mac->cursor_foreground_pixel; | |
3300 if (xgcv.foreground == xgcv.background) | |
3301 xgcv.foreground = s->face->foreground; | |
3302 | |
3303 /* Make sure the cursor is distinct from text in this face. */ | |
3304 if (xgcv.background == s->face->background | |
3305 && xgcv.foreground == s->face->foreground) | |
3306 { | |
3307 xgcv.background = s->face->foreground; | |
3308 xgcv.foreground = s->face->background; | |
3309 } | |
3310 | |
3311 IF_DEBUG (x_check_font (s->f, s->font)); | |
3312 xgcv.font = s->font; | |
3313 mask = GCForeground | GCBackground | GCFont; | |
3314 | |
3315 if (FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc) | |
3316 XChangeGC (s->display, FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc, | |
3317 mask, &xgcv); | |
3318 else | |
3319 FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc | |
3320 = XCreateGC (s->display, s->window, mask, &xgcv); | |
3321 | |
3322 s->gc = FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc; | |
3323 } | |
3324 } | |
3325 | |
3326 | |
3327 /* Set up S->gc of glyph string S for drawing text in mouse face. */ | |
3328 | |
3329 static void | |
3330 x_set_mouse_face_gc (s) | |
3331 struct glyph_string *s; | |
3332 { | |
3333 int face_id; | |
3334 struct face *face; | |
3335 | |
3336 /* What face has to be used last for the mouse face? */ | |
3337 face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id; | |
3338 face = FACE_FROM_ID (s->f, face_id); | |
3339 if (face == NULL) | |
3340 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); | |
3341 | |
3342 if (s->first_glyph->type == CHAR_GLYPH) | |
3343 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch); | |
3344 else | |
3345 face_id = FACE_FOR_CHAR (s->f, face, 0); | |
3346 s->face = FACE_FROM_ID (s->f, face_id); | |
3347 PREPARE_FACE_FOR_DISPLAY (s->f, s->face); | |
3348 | |
3349 /* If font in this face is same as S->font, use it. */ | |
3350 if (s->font == s->face->font) | |
3351 s->gc = s->face->gc; | |
3352 else | |
3353 { | |
3354 /* Otherwise construct scratch_cursor_gc with values from FACE | |
3355 but font FONT. */ | |
3356 XGCValues xgcv; | |
3357 unsigned long mask; | |
3358 | |
3359 xgcv.background = s->face->background; | |
3360 xgcv.foreground = s->face->foreground; | |
3361 IF_DEBUG (x_check_font (s->f, s->font)); | |
3362 xgcv.font = s->font; | |
3363 mask = GCForeground | GCBackground | GCFont; | |
3364 | |
3365 if (FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc) | |
3366 XChangeGC (s->display, FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc, | |
3367 mask, &xgcv); | |
3368 else | |
3369 FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc | |
3370 = XCreateGC (s->display, s->window, mask, &xgcv); | |
3371 | |
3372 s->gc = FRAME_MAC_DISPLAY_INFO (s->f)->scratch_cursor_gc; | |
3373 } | |
3374 | |
3375 xassert (s->gc != 0); | |
3376 } | |
3377 | |
3378 | |
3379 /* Set S->gc of glyph string S to a GC suitable for drawing a mode line. | |
3380 Faces to use in the mode line have already been computed when the | |
3381 matrix was built, so there isn't much to do, here. */ | |
3382 | |
3383 static INLINE void | |
3384 x_set_mode_line_face_gc (s) | |
3385 struct glyph_string *s; | |
3386 { | |
3387 s->gc = s->face->gc; | |
3388 } | |
3389 | |
3390 | |
3391 /* Set S->gc of glyph string S for drawing that glyph string. Set | |
3392 S->stippled_p to a non-zero value if the face of S has a stipple | |
3393 pattern. */ | |
3394 | |
3395 static INLINE void | |
3396 x_set_glyph_string_gc (s) | |
3397 struct glyph_string *s; | |
3398 { | |
3399 PREPARE_FACE_FOR_DISPLAY (s->f, s->face); | |
3400 | |
3401 if (s->hl == DRAW_NORMAL_TEXT) | |
3402 { | |
3403 s->gc = s->face->gc; | |
3404 s->stippled_p = s->face->stipple != 0; | |
3405 } | |
3406 else if (s->hl == DRAW_INVERSE_VIDEO) | |
3407 { | |
3408 x_set_mode_line_face_gc (s); | |
3409 s->stippled_p = s->face->stipple != 0; | |
3410 } | |
3411 else if (s->hl == DRAW_CURSOR) | |
3412 { | |
3413 x_set_cursor_gc (s); | |
3414 s->stippled_p = 0; | |
3415 } | |
3416 else if (s->hl == DRAW_MOUSE_FACE) | |
3417 { | |
3418 x_set_mouse_face_gc (s); | |
3419 s->stippled_p = s->face->stipple != 0; | |
3420 } | |
3421 else if (s->hl == DRAW_IMAGE_RAISED | |
3422 || s->hl == DRAW_IMAGE_SUNKEN) | |
3423 { | |
3424 s->gc = s->face->gc; | |
3425 s->stippled_p = s->face->stipple != 0; | |
3426 } | |
3427 else | |
3428 { | |
3429 s->gc = s->face->gc; | |
3430 s->stippled_p = s->face->stipple != 0; | |
3431 } | |
3432 | |
3433 /* GC must have been set. */ | |
3434 xassert (s->gc != 0); | |
3435 } | |
3436 | |
3437 | |
3438 /* Return in *R the clipping rectangle for glyph string S. */ | |
3439 | |
3440 static void | |
3441 x_get_glyph_string_clip_rect (s, r) | |
3442 struct glyph_string *s; | |
3443 Rect *r; | |
3444 { | |
3445 int r_height, r_width; | |
3446 | |
3447 if (s->row->full_width_p) | |
3448 { | |
3449 /* Draw full-width. X coordinates are relative to S->w->left. */ | |
3450 int canon_x = CANON_X_UNIT (s->f); | |
3451 | |
3452 r->left = WINDOW_LEFT_MARGIN (s->w) * canon_x; | |
3453 r_width = XFASTINT (s->w->width) * canon_x; | |
3454 | |
3455 if (FRAME_HAS_VERTICAL_SCROLL_BARS (s->f)) | |
3456 { | |
3457 int width = FRAME_SCROLL_BAR_WIDTH (s->f) * canon_x; | |
3458 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (s->f)) | |
3459 r->left -= width; | |
3460 } | |
3461 | |
3462 r->left += FRAME_INTERNAL_BORDER_WIDTH (s->f); | |
3463 | |
3464 /* Unless displaying a mode or menu bar line, which are always | |
3465 fully visible, clip to the visible part of the row. */ | |
3466 if (s->w->pseudo_window_p) | |
3467 r_height = s->row->visible_height; | |
3468 else | |
3469 r_height = s->height; | |
3470 } | |
3471 else | |
3472 { | |
3473 /* This is a text line that may be partially visible. */ | |
3474 r->left = WINDOW_AREA_TO_FRAME_PIXEL_X (s->w, s->area, 0); | |
3475 r_width = window_box_width (s->w, s->area); | |
3476 r_height = s->row->visible_height; | |
3477 } | |
3478 | |
3479 /* If S draws overlapping rows, it's sufficient to use the top and | |
3480 bottom of the window for clipping because this glyph string | |
3481 intentionally draws over other lines. */ | |
3482 if (s->for_overlaps_p) | |
3483 { | |
3484 r->top = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w); | |
3485 r_height = window_text_bottom_y (s->w) - r->top; | |
3486 } | |
3487 else | |
3488 { | |
3489 /* Don't use S->y for clipping because it doesn't take partially | |
3490 visible lines into account. For example, it can be negative for | |
3491 partially visible lines at the top of a window. */ | |
3492 if (!s->row->full_width_p | |
3493 && MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (s->w, s->row)) | |
3494 r->top = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w); | |
3495 else | |
3496 r->top = max (0, s->row->y); | |
3497 | |
3498 /* If drawing a tool-bar window, draw it over the internal border | |
3499 at the top of the window. */ | |
3500 if (s->w == XWINDOW (s->f->tool_bar_window)) | |
3501 r->top -= s->f->output_data.mac->internal_border_width; | |
3502 } | |
3503 | |
3504 r->top = WINDOW_TO_FRAME_PIXEL_Y (s->w, r->top); | |
3505 | |
3506 r->bottom = r->top + r_height; | |
3507 r->right = r->left + r_width; | |
3508 } | |
3509 | |
3510 | |
3511 /* Set clipping for output of glyph string S. S may be part of a mode | |
3512 line or menu if we don't have X toolkit support. */ | |
3513 | |
3514 static INLINE void | |
3515 x_set_glyph_string_clipping (s) | |
3516 struct glyph_string *s; | |
3517 { | |
3518 Rect r; | |
3519 x_get_glyph_string_clip_rect (s, &r); | |
3520 mac_set_clip_rectangle (s->display, s->window, &r); | |
3521 } | |
3522 | |
3523 | |
3524 /* Compute left and right overhang of glyph string S. If S is a glyph | |
3525 string for a composition, assume overhangs don't exist. */ | |
3526 | |
3527 static INLINE void | |
3528 x_compute_glyph_string_overhangs (s) | |
3529 struct glyph_string *s; | |
3530 { | |
3531 if (s->cmp == NULL | |
3532 && s->first_glyph->type == CHAR_GLYPH) | |
3533 { | |
3534 XCharStruct cs; | |
3535 int direction, font_ascent, font_descent; | |
3536 XTextExtents16 (s->font, s->char2b, s->nchars, &direction, | |
3537 &font_ascent, &font_descent, &cs); | |
3538 s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0; | |
3539 s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0; | |
3540 } | |
3541 } | |
3542 | |
3543 | |
3544 /* Compute overhangs and x-positions for glyph string S and its | |
3545 predecessors, or successors. X is the starting x-position for S. | |
3546 BACKWARD_P non-zero means process predecessors. */ | |
3547 | |
3548 static void | |
3549 x_compute_overhangs_and_x (s, x, backward_p) | |
3550 struct glyph_string *s; | |
3551 int x; | |
3552 int backward_p; | |
3553 { | |
3554 if (backward_p) | |
3555 { | |
3556 while (s) | |
3557 { | |
3558 x_compute_glyph_string_overhangs (s); | |
3559 x -= s->width; | |
3560 s->x = x; | |
3561 s = s->prev; | |
3562 } | |
3563 } | |
3564 else | |
3565 { | |
3566 while (s) | |
3567 { | |
3568 x_compute_glyph_string_overhangs (s); | |
3569 s->x = x; | |
3570 x += s->width; | |
3571 s = s->next; | |
3572 } | |
3573 } | |
3574 } | |
3575 | |
3576 | |
3577 /* Set *LEFT and *RIGHT to the left and right overhang of GLYPH on | |
3578 frame F. Overhangs of glyphs other than type CHAR_GLYPH are | |
3579 assumed to be zero. */ | |
3580 | |
3581 void | |
3582 x_get_glyph_overhangs (glyph, f, left, right) | |
3583 struct glyph *glyph; | |
3584 struct frame *f; | |
3585 int *left, *right; | |
3586 { | |
3587 *left = *right = 0; | |
3588 | |
3589 if (glyph->type == CHAR_GLYPH) | |
3590 { | |
3591 XFontStruct *font; | |
3592 struct face *face; | |
3593 struct font_info *font_info; | |
3594 XChar2b char2b; | |
3595 XCharStruct *pcm; | |
3596 | |
3597 face = x_get_glyph_face_and_encoding (f, glyph, &char2b, NULL); | |
3598 font = face->font; | |
3599 font_info = FONT_INFO_FROM_ID (f, face->font_info_id); | |
3600 if (font | |
3601 && (pcm = x_per_char_metric (font, &char2b))) | |
3602 { | |
3603 if (pcm->rbearing > pcm->width) | |
3604 *right = pcm->rbearing - pcm->width; | |
3605 if (pcm->lbearing < 0) | |
3606 *left = -pcm->lbearing; | |
3607 } | |
3608 } | |
3609 } | |
3610 | |
3611 | |
3612 /* Return the index of the first glyph preceding glyph string S that | |
3613 is overwritten by S because of S's left overhang. Value is -1 | |
3614 if no glyphs are overwritten. */ | |
3615 | |
3616 static int | |
3617 x_left_overwritten (s) | |
3618 struct glyph_string *s; | |
3619 { | |
3620 int k; | |
3621 | |
3622 if (s->left_overhang) | |
3623 { | |
3624 int x = 0, i; | |
3625 struct glyph *glyphs = s->row->glyphs[s->area]; | |
3626 int first = s->first_glyph - glyphs; | |
3627 | |
3628 for (i = first - 1; i >= 0 && x > -s->left_overhang; --i) | |
3629 x -= glyphs[i].pixel_width; | |
3630 | |
3631 k = i + 1; | |
3632 } | |
3633 else | |
3634 k = -1; | |
3635 | |
3636 return k; | |
3637 } | |
3638 | |
3639 | |
3640 /* Return the index of the first glyph preceding glyph string S that | |
3641 is overwriting S because of its right overhang. Value is -1 if no | |
3642 glyph in front of S overwrites S. */ | |
3643 | |
3644 static int | |
3645 x_left_overwriting (s) | |
3646 struct glyph_string *s; | |
3647 { | |
3648 int i, k, x; | |
3649 struct glyph *glyphs = s->row->glyphs[s->area]; | |
3650 int first = s->first_glyph - glyphs; | |
3651 | |
3652 k = -1; | |
3653 x = 0; | |
3654 for (i = first - 1; i >= 0; --i) | |
3655 { | |
3656 int left, right; | |
3657 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right); | |
3658 if (x + right > 0) | |
3659 k = i; | |
3660 x -= glyphs[i].pixel_width; | |
3661 } | |
3662 | |
3663 return k; | |
3664 } | |
3665 | |
3666 | |
3667 /* Return the index of the last glyph following glyph string S that is | |
3668 not overwritten by S because of S's right overhang. Value is -1 if | |
3669 no such glyph is found. */ | |
3670 | |
3671 static int | |
3672 x_right_overwritten (s) | |
3673 struct glyph_string *s; | |
3674 { | |
3675 int k = -1; | |
3676 | |
3677 if (s->right_overhang) | |
3678 { | |
3679 int x = 0, i; | |
3680 struct glyph *glyphs = s->row->glyphs[s->area]; | |
3681 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars); | |
3682 int end = s->row->used[s->area]; | |
3683 | |
3684 for (i = first; i < end && s->right_overhang > x; ++i) | |
3685 x += glyphs[i].pixel_width; | |
3686 | |
3687 k = i; | |
3688 } | |
3689 | |
3690 return k; | |
3691 } | |
3692 | |
3693 | |
3694 /* Return the index of the last glyph following glyph string S that | |
3695 overwrites S because of its left overhang. Value is negative | |
3696 if no such glyph is found. */ | |
3697 | |
3698 static int | |
3699 x_right_overwriting (s) | |
3700 struct glyph_string *s; | |
3701 { | |
3702 int i, k, x; | |
3703 int end = s->row->used[s->area]; | |
3704 struct glyph *glyphs = s->row->glyphs[s->area]; | |
3705 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars); | |
3706 | |
3707 k = -1; | |
3708 x = 0; | |
3709 for (i = first; i < end; ++i) | |
3710 { | |
3711 int left, right; | |
3712 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right); | |
3713 if (x - left < 0) | |
3714 k = i; | |
3715 x += glyphs[i].pixel_width; | |
3716 } | |
3717 | |
3718 return k; | |
3719 } | |
3720 | |
3721 | |
3722 /* Fill rectangle X, Y, W, H with background color of glyph string S. */ | |
3723 | |
3724 static INLINE void | |
3725 x_clear_glyph_string_rect (s, x, y, w, h) | |
3726 struct glyph_string *s; | |
3727 int x, y, w, h; | |
3728 { | |
3729 XGCValues xgcv; | |
3730 | |
3731 xgcv.foreground = s->gc->background; | |
3732 XFillRectangle (s->display, s->window, &xgcv, x, y, w, h); | |
3733 } | |
3734 | |
3735 | |
3736 /* Draw the background of glyph_string S. If S->background_filled_p | |
3737 is non-zero don't draw it. FORCE_P non-zero means draw the | |
3738 background even if it wouldn't be drawn normally. This is used | |
3739 when a string preceding S draws into the background of S, or S | |
3740 contains the first component of a composition. */ | |
3741 | |
3742 static void | |
3743 x_draw_glyph_string_background (s, force_p) | |
3744 struct glyph_string *s; | |
3745 int force_p; | |
3746 { | |
3747 /* Nothing to do if background has already been drawn or if it | |
3748 shouldn't be drawn in the first place. */ | |
3749 if (!s->background_filled_p) | |
3750 { | |
3751 int box_line_width = max (s->face->box_line_width, 0); | |
3752 | |
3753 #if 0 /* MAC_TODO: stipple */ | |
3754 if (s->stippled_p) | |
3755 { | |
3756 /* Fill background with a stipple pattern. */ | |
3757 XSetFillStyle (s->display, s->gc, FillOpaqueStippled); | |
3758 XFillRectangle (s->display, s->window, s->gc, s->x, | |
3759 s->y + box_line_width, | |
3760 s->background_width, | |
3761 s->height - 2 * box_line_width); | |
3762 XSetFillStyle (s->display, s->gc, FillSolid); | |
3763 s->background_filled_p = 1; | |
3764 } | |
3765 else | |
3766 #endif | |
3767 if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width | |
3768 || s->font_not_found_p | |
3769 || s->extends_to_end_of_line_p | |
3770 || force_p) | |
3771 { | |
3772 x_clear_glyph_string_rect (s, s->x, s->y + box_line_width, | |
3773 s->background_width, | |
3774 s->height - 2 * box_line_width); | |
3775 s->background_filled_p = 1; | |
3776 } | |
3777 } | |
3778 } | |
3779 | |
3780 | |
3781 /* Draw the foreground of glyph string S. */ | |
3782 | |
3783 static void | |
3784 x_draw_glyph_string_foreground (s) | |
3785 struct glyph_string *s; | |
3786 { | |
3787 int i, x; | |
3788 | |
3789 /* If first glyph of S has a left box line, start drawing the text | |
3790 of S to the right of that box line. */ | |
3791 if (s->face->box != FACE_NO_BOX | |
3792 && s->first_glyph->left_box_line_p) | |
3793 x = s->x + abs (s->face->box_line_width); | |
3794 else | |
3795 x = s->x; | |
3796 | |
3797 /* Draw characters of S as rectangles if S's font could not be | |
3798 loaded. */ | |
3799 if (s->font_not_found_p) | |
3800 { | |
3801 for (i = 0; i < s->nchars; ++i) | |
3802 { | |
3803 struct glyph *g = s->first_glyph + i; | |
3804 mac_draw_rectangle (s->display, s->window, | |
3805 s->gc, x, s->y, g->pixel_width - 1, | |
3806 s->height - 1); | |
3807 x += g->pixel_width; | |
3808 } | |
3809 } | |
3810 else | |
3811 { | |
3812 char *char1b = (char *) s->char2b; | |
3813 int boff = s->font_info->baseline_offset; | |
3814 | |
3815 if (s->font_info->vertical_centering) | |
3816 boff = VCENTER_BASELINE_OFFSET (s->font, s->f) - boff; | |
3817 | |
3818 /* If we can use 8-bit functions, condense S->char2b. */ | |
3819 if (!s->two_byte_p) | |
3820 for (i = 0; i < s->nchars; ++i) | |
3821 char1b[i] = s->char2b[i].byte2; | |
3822 | |
3823 /* Draw text with XDrawString if background has already been | |
3824 filled. Otherwise, use XDrawImageString. (Note that | |
3825 XDrawImageString is usually faster than XDrawString.) Always | |
3826 use XDrawImageString when drawing the cursor so that there is | |
3827 no chance that characters under a box cursor are invisible. */ | |
3828 if (s->for_overlaps_p | |
3829 || (s->background_filled_p && s->hl != DRAW_CURSOR)) | |
3830 { | |
3831 /* Draw characters with 16-bit or 8-bit functions. */ | |
3832 if (s->two_byte_p) | |
3833 XDrawString16 (s->display, s->window, s->gc, x, | |
3834 s->ybase - boff, s->char2b, s->nchars); | |
3835 else | |
3836 XDrawString (s->display, s->window, s->gc, x, | |
3837 s->ybase - boff, char1b, s->nchars); | |
3838 } | |
3839 else | |
3840 { | |
3841 if (s->two_byte_p) | |
3842 XDrawImageString16 (s->display, s->window, s->gc, x, | |
3843 s->ybase - boff, s->char2b, s->nchars); | |
3844 else | |
3845 XDrawImageString (s->display, s->window, s->gc, x, | |
3846 s->ybase - boff, char1b, s->nchars); | |
3847 } | |
3848 } | |
3849 } | |
3850 | |
3851 /* Draw the foreground of composite glyph string S. */ | |
3852 | |
3853 static void | |
3854 x_draw_composite_glyph_string_foreground (s) | |
3855 struct glyph_string *s; | |
3856 { | |
3857 int i, x; | |
3858 | |
3859 /* If first glyph of S has a left box line, start drawing the text | |
3860 of S to the right of that box line. */ | |
3861 if (s->face->box != FACE_NO_BOX | |
3862 && s->first_glyph->left_box_line_p) | |
3863 x = s->x + abs (s->face->box_line_width); | |
3864 else | |
3865 x = s->x; | |
3866 | |
3867 /* S is a glyph string for a composition. S->gidx is the index of | |
3868 the first character drawn for glyphs of this composition. | |
3869 S->gidx == 0 means we are drawing the very first character of | |
3870 this composition. */ | |
3871 | |
3872 /* Draw a rectangle for the composition if the font for the very | |
3873 first character of the composition could not be loaded. */ | |
3874 if (s->font_not_found_p) | |
3875 { | |
3876 if (s->gidx == 0) | |
3877 mac_draw_rectangle (s->display, s->window, s->gc, x, s->y, | |
3878 s->width - 1, s->height - 1); | |
3879 } | |
3880 else | |
3881 { | |
3882 for (i = 0; i < s->nchars; i++, ++s->gidx) | |
3883 XDrawString16 (s->display, s->window, s->gc, | |
3884 x + s->cmp->offsets[s->gidx * 2], | |
3885 s->ybase - s->cmp->offsets[s->gidx * 2 + 1], | |
3886 s->char2b + i, 1); | |
3887 } | |
3888 } | |
3889 | |
3890 | |
3891 #ifdef USE_X_TOOLKIT | |
3892 | |
3893 static struct frame *x_frame_of_widget P_ ((Widget)); | |
3894 | |
3895 | |
3896 /* Return the frame on which widget WIDGET is used.. Abort if frame | |
3897 cannot be determined. */ | |
3898 | |
3899 static struct frame * | |
3900 x_frame_of_widget (widget) | |
3901 Widget widget; | |
3902 { | |
3903 struct x_display_info *dpyinfo; | |
3904 Lisp_Object tail; | |
3905 struct frame *f; | |
3906 | |
3907 dpyinfo = x_display_info_for_display (XtDisplay (widget)); | |
3908 | |
3909 /* Find the top-level shell of the widget. Note that this function | |
3910 can be called when the widget is not yet realized, so XtWindow | |
3911 (widget) == 0. That's the reason we can't simply use | |
3912 x_any_window_to_frame. */ | |
3913 while (!XtIsTopLevelShell (widget)) | |
3914 widget = XtParent (widget); | |
3915 | |
3916 /* Look for a frame with that top-level widget. Allocate the color | |
3917 on that frame to get the right gamma correction value. */ | |
3918 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail)) | |
3919 if (GC_FRAMEP (XCAR (tail)) | |
3920 && (f = XFRAME (XCAR (tail)), | |
3921 (f->output_data.nothing != 1 | |
3922 && FRAME_X_DISPLAY_INFO (f) == dpyinfo)) | |
3923 && f->output_data.x->widget == widget) | |
3924 return f; | |
3925 | |
3926 abort (); | |
3927 } | |
3928 | |
3929 | |
3930 /* Allocate the color COLOR->pixel on the screen and display of | |
3931 widget WIDGET in colormap CMAP. If an exact match cannot be | |
3932 allocated, try the nearest color available. Value is non-zero | |
3933 if successful. This is called from lwlib. */ | |
3934 | |
3935 int | |
3936 x_alloc_nearest_color_for_widget (widget, cmap, color) | |
3937 Widget widget; | |
3938 Colormap cmap; | |
3939 XColor *color; | |
3940 { | |
3941 struct frame *f = x_frame_of_widget (widget); | |
3942 return x_alloc_nearest_color (f, cmap, color); | |
3943 } | |
3944 | |
3945 | |
3946 #endif /* USE_X_TOOLKIT */ | |
3947 | |
3948 #if 0 /* MAC_TODO */ | |
3949 | |
3950 /* Allocate the color COLOR->pixel on SCREEN of DISPLAY, colormap | |
3951 CMAP. If an exact match can't be allocated, try the nearest color | |
3952 available. Value is non-zero if successful. Set *COLOR to the | |
3953 color allocated. */ | |
3954 | |
3955 int | |
3956 x_alloc_nearest_color (f, cmap, color) | |
3957 struct frame *f; | |
3958 Colormap cmap; | |
3959 XColor *color; | |
3960 { | |
3961 Display *display = FRAME_X_DISPLAY (f); | |
3962 Screen *screen = FRAME_X_SCREEN (f); | |
3963 int rc; | |
3964 | |
3965 gamma_correct (f, color); | |
3966 rc = XAllocColor (display, cmap, color); | |
3967 if (rc == 0) | |
3968 { | |
3969 /* If we got to this point, the colormap is full, so we're going | |
3970 to try to get the next closest color. The algorithm used is | |
3971 a least-squares matching, which is what X uses for closest | |
3972 color matching with StaticColor visuals. */ | |
3973 int nearest, i; | |
3974 unsigned long nearest_delta = ~0; | |
3975 int ncells = XDisplayCells (display, XScreenNumberOfScreen (screen)); | |
3976 XColor *cells = (XColor *) alloca (ncells * sizeof *cells); | |
3977 | |
3978 for (i = 0; i < ncells; ++i) | |
3979 cells[i].pixel = i; | |
3980 XQueryColors (display, cmap, cells, ncells); | |
3981 | |
3982 for (nearest = i = 0; i < ncells; ++i) | |
3983 { | |
3984 long dred = (color->red >> 8) - (cells[i].red >> 8); | |
3985 long dgreen = (color->green >> 8) - (cells[i].green >> 8); | |
3986 long dblue = (color->blue >> 8) - (cells[i].blue >> 8); | |
3987 unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue; | |
3988 | |
3989 if (delta < nearest_delta) | |
3990 { | |
3991 nearest = i; | |
3992 nearest_delta = delta; | |
3993 } | |
3994 } | |
3995 | |
3996 color->red = cells[nearest].red; | |
3997 color->green = cells[nearest].green; | |
3998 color->blue = cells[nearest].blue; | |
3999 rc = XAllocColor (display, cmap, color); | |
4000 } | |
4001 | |
4002 #ifdef DEBUG_X_COLORS | |
4003 if (rc) | |
4004 register_color (color->pixel); | |
4005 #endif /* DEBUG_X_COLORS */ | |
4006 | |
4007 return rc; | |
4008 } | |
4009 | |
4010 | |
4011 /* Allocate color PIXEL on frame F. PIXEL must already be allocated. | |
4012 It's necessary to do this instead of just using PIXEL directly to | |
4013 get color reference counts right. */ | |
4014 | |
4015 unsigned long | |
4016 x_copy_color (f, pixel) | |
4017 struct frame *f; | |
4018 unsigned long pixel; | |
4019 { | |
4020 XColor color; | |
4021 | |
4022 color.pixel = pixel; | |
4023 BLOCK_INPUT; | |
4024 XQueryColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color); | |
4025 XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color); | |
4026 UNBLOCK_INPUT; | |
4027 #ifdef DEBUG_X_COLORS | |
4028 register_color (pixel); | |
4029 #endif | |
4030 return color.pixel; | |
4031 } | |
4032 | |
4033 | |
4034 /* Allocate color PIXEL on display DPY. PIXEL must already be allocated. | |
4035 It's necessary to do this instead of just using PIXEL directly to | |
4036 get color reference counts right. */ | |
4037 | |
4038 unsigned long | |
4039 x_copy_dpy_color (dpy, cmap, pixel) | |
4040 Display *dpy; | |
4041 Colormap cmap; | |
4042 unsigned long pixel; | |
4043 { | |
4044 XColor color; | |
4045 | |
4046 color.pixel = pixel; | |
4047 BLOCK_INPUT; | |
4048 XQueryColor (dpy, cmap, &color); | |
4049 XAllocColor (dpy, cmap, &color); | |
4050 UNBLOCK_INPUT; | |
4051 #ifdef DEBUG_X_COLORS | |
4052 register_color (pixel); | |
4053 #endif | |
4054 return color.pixel; | |
4055 } | |
4056 | |
4057 #endif /* MAC_TODO */ | |
4058 | |
4059 /* Allocate a color which is lighter or darker than *COLOR by FACTOR | |
4060 or DELTA. Try a color with RGB values multiplied by FACTOR first. | |
4061 If this produces the same color as COLOR, try a color where all RGB | |
4062 values have DELTA added. Return the allocated color in *COLOR. | |
4063 DISPLAY is the X display, CMAP is the colormap to operate on. | |
4064 Value is non-zero if successful. */ | |
4065 | |
4066 static int | |
4067 mac_alloc_lighter_color (f, color, factor, delta) | |
4068 struct frame *f; | |
4069 unsigned long *color; | |
4070 double factor; | |
4071 int delta; | |
4072 { | |
4073 unsigned long new; | |
4074 | |
4075 /* Change RGB values by specified FACTOR. Avoid overflow! */ | |
4076 xassert (factor >= 0); | |
4077 new = RGB_TO_ULONG (min (0xff, (int) (factor * RED_FROM_ULONG (*color))), | |
4078 min (0xff, (int) (factor * GREEN_FROM_ULONG (*color))), | |
4079 min (0xff, (int) (factor * BLUE_FROM_ULONG (*color)))); | |
4080 if (new == *color) | |
4081 new = RGB_TO_ULONG (max (0, min (0xff, (int) (delta + RED_FROM_ULONG (*color)))), | |
4082 max (0, min (0xff, (int) (delta + GREEN_FROM_ULONG (*color)))), | |
4083 max (0, min (0xff, (int) (delta + BLUE_FROM_ULONG (*color))))); | |
4084 | |
4085 /* MAC_TODO: Map to palette and retry with delta if same? */ | |
4086 /* MAC_TODO: Free colors (if using palette)? */ | |
4087 | |
4088 if (new == *color) | |
4089 return 0; | |
4090 | |
4091 *color = new; | |
4092 | |
4093 return 1; | |
4094 } | |
4095 | |
4096 | |
4097 /* Set up the foreground color for drawing relief lines of glyph | |
4098 string S. RELIEF is a pointer to a struct relief containing the GC | |
4099 with which lines will be drawn. Use a color that is FACTOR or | |
4100 DELTA lighter or darker than the relief's background which is found | |
4101 in S->f->output_data.x->relief_background. If such a color cannot | |
4102 be allocated, use DEFAULT_PIXEL, instead. */ | |
4103 | |
4104 static void | |
4105 x_setup_relief_color (f, relief, factor, delta, default_pixel) | |
4106 struct frame *f; | |
4107 struct relief *relief; | |
4108 double factor; | |
4109 int delta; | |
4110 unsigned long default_pixel; | |
4111 { | |
4112 XGCValues xgcv; | |
4113 struct mac_output *di = f->output_data.mac; | |
4114 unsigned long mask = GCForeground; | |
4115 unsigned long pixel; | |
4116 unsigned long background = di->relief_background; | |
4117 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); | |
4118 | |
4119 /* MAC_TODO: Free colors (if using palette)? */ | |
4120 | |
4121 /* Allocate new color. */ | |
4122 xgcv.foreground = default_pixel; | |
4123 pixel = background; | |
4124 if (mac_alloc_lighter_color (f, &pixel, factor, delta)) | |
4125 { | |
4126 relief->allocated_p = 1; | |
4127 xgcv.foreground = relief->pixel = pixel; | |
4128 } | |
4129 | |
4130 if (relief->gc == 0) | |
4131 { | |
4132 #if 0 /* MAC_TODO: stipple */ | |
4133 xgcv.stipple = dpyinfo->gray; | |
4134 mask |= GCStipple; | |
4135 #endif | |
4136 relief->gc = XCreateGC (NULL, FRAME_MAC_WINDOW (f), mask, &xgcv); | |
4137 } | |
4138 else | |
4139 XChangeGC (NULL, relief->gc, mask, &xgcv); | |
4140 } | |
4141 | |
4142 | |
4143 /* Set up colors for the relief lines around glyph string S. */ | |
4144 | |
4145 static void | |
4146 x_setup_relief_colors (s) | |
4147 struct glyph_string *s; | |
4148 { | |
4149 struct mac_output *di = s->f->output_data.mac; | |
4150 unsigned long color; | |
4151 | |
4152 if (s->face->use_box_color_for_shadows_p) | |
4153 color = s->face->box_color; | |
4154 else | |
4155 { | |
4156 XGCValues xgcv; | |
4157 | |
4158 /* Get the background color of the face. */ | |
4159 XGetGCValues (s->display, s->gc, GCBackground, &xgcv); | |
4160 color = xgcv.background; | |
4161 } | |
4162 | |
4163 if (di->white_relief.gc == 0 | |
4164 || color != di->relief_background) | |
4165 { | |
4166 di->relief_background = color; | |
4167 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000, | |
4168 WHITE_PIX_DEFAULT (s->f)); | |
4169 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000, | |
4170 BLACK_PIX_DEFAULT (s->f)); | |
4171 } | |
4172 } | |
4173 | |
4174 | |
4175 /* Draw a relief on frame F inside the rectangle given by LEFT_X, | |
4176 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief | |
4177 to draw, it must be >= 0. RAISED_P non-zero means draw a raised | |
4178 relief. LEFT_P non-zero means draw a relief on the left side of | |
4179 the rectangle. RIGHT_P non-zero means draw a relief on the right | |
4180 side of the rectangle. CLIP_RECT is the clipping rectangle to use | |
4181 when drawing. */ | |
4182 | |
4183 static void | |
4184 x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width, | |
4185 raised_p, left_p, right_p, clip_rect) | |
4186 struct frame *f; | |
4187 int left_x, top_y, right_x, bottom_y, left_p, right_p, raised_p; | |
4188 Rect *clip_rect; | |
4189 { | |
4190 int i; | |
4191 GC gc; | |
4192 | |
4193 if (raised_p) | |
4194 gc = f->output_data.mac->white_relief.gc; | |
4195 else | |
4196 gc = f->output_data.mac->black_relief.gc; | |
4197 mac_set_clip_rectangle (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), clip_rect); | |
4198 | |
4199 /* Top. */ | |
4200 for (i = 0; i < width; ++i) | |
4201 XDrawLine (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), gc, | |
4202 left_x + i * left_p, top_y + i, | |
4203 right_x + 1 - i * right_p, top_y + i); | |
4204 | |
4205 /* Left. */ | |
4206 if (left_p) | |
4207 for (i = 0; i < width; ++i) | |
4208 XDrawLine (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), gc, | |
4209 left_x + i, top_y + i, left_x + i, bottom_y - i); | |
4210 | |
4211 mac_reset_clipping (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f)); | |
4212 if (raised_p) | |
4213 gc = f->output_data.mac->black_relief.gc; | |
4214 else | |
4215 gc = f->output_data.mac->white_relief.gc; | |
4216 mac_set_clip_rectangle (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), | |
4217 clip_rect); | |
4218 | |
4219 /* Bottom. */ | |
4220 for (i = 0; i < width; ++i) | |
4221 XDrawLine (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), gc, | |
4222 left_x + i * left_p, bottom_y - i, | |
4223 right_x + 1 - i * right_p, bottom_y - i); | |
4224 | |
4225 /* Right. */ | |
4226 if (right_p) | |
4227 for (i = 0; i < width; ++i) | |
4228 XDrawLine (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), gc, | |
4229 right_x - i, top_y + i + 1, right_x - i, bottom_y - i); | |
4230 | |
4231 mac_reset_clipping (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f)); | |
4232 } | |
4233 | |
4234 | |
4235 /* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y, | |
4236 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to | |
4237 draw, it must be >= 0. LEFT_P non-zero means draw a line on the | |
4238 left side of the rectangle. RIGHT_P non-zero means draw a line | |
4239 on the right side of the rectangle. CLIP_RECT is the clipping | |
4240 rectangle to use when drawing. */ | |
4241 | |
4242 static void | |
4243 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width, | |
4244 left_p, right_p, clip_rect) | |
4245 struct glyph_string *s; | |
4246 int left_x, top_y, right_x, bottom_y, left_p, right_p; | |
4247 Rect *clip_rect; | |
4248 { | |
4249 XGCValues xgcv; | |
4250 | |
4251 xgcv.foreground = s->face->box_color; | |
4252 mac_set_clip_rectangle (s->display, s->window, clip_rect); | |
4253 | |
4254 /* Top. */ | |
4255 XFillRectangle (s->display, s->window, &xgcv, | |
4256 left_x, top_y, right_x - left_x, width); | |
4257 | |
4258 /* Left. */ | |
4259 if (left_p) | |
4260 XFillRectangle (s->display, s->window, &xgcv, | |
4261 left_x, top_y, width, bottom_y - top_y); | |
4262 | |
4263 /* Bottom. */ | |
4264 XFillRectangle (s->display, s->window, &xgcv, | |
4265 left_x, bottom_y - width, right_x - left_x, width); | |
4266 | |
4267 /* Right. */ | |
4268 if (right_p) | |
4269 XFillRectangle (s->display, s->window, &xgcv, | |
4270 right_x - width, top_y, width, bottom_y - top_y); | |
4271 | |
4272 mac_reset_clipping (s->display, s->window); | |
4273 } | |
4274 | |
4275 | |
4276 /* Draw a box around glyph string S. */ | |
4277 | |
4278 static void | |
4279 x_draw_glyph_string_box (s) | |
4280 struct glyph_string *s; | |
4281 { | |
4282 int width, left_x, right_x, top_y, bottom_y, last_x, raised_p; | |
4283 int left_p, right_p; | |
4284 struct glyph *last_glyph; | |
4285 Rect clip_rect; | |
4286 | |
4287 last_x = window_box_right (s->w, s->area); | |
4288 if (s->row->full_width_p | |
4289 && !s->w->pseudo_window_p) | |
4290 { | |
4291 last_x += FRAME_X_RIGHT_FRINGE_WIDTH (s->f); | |
4292 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (s->f)) | |
4293 last_x += FRAME_SCROLL_BAR_WIDTH (s->f) * CANON_X_UNIT (s->f); | |
4294 } | |
4295 | |
4296 /* The glyph that may have a right box line. */ | |
4297 last_glyph = (s->cmp || s->img | |
4298 ? s->first_glyph | |
4299 : s->first_glyph + s->nchars - 1); | |
4300 | |
4301 width = abs (s->face->box_line_width); | |
4302 raised_p = s->face->box == FACE_RAISED_BOX; | |
4303 left_x = s->x; | |
4304 right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p | |
4305 ? last_x - 1 | |
4306 : min (last_x, s->x + s->background_width) - 1)); | |
4307 top_y = s->y; | |
4308 bottom_y = top_y + s->height - 1; | |
4309 | |
4310 left_p = (s->first_glyph->left_box_line_p | |
4311 || (s->hl == DRAW_MOUSE_FACE | |
4312 && (s->prev == NULL | |
4313 || s->prev->hl != s->hl))); | |
4314 right_p = (last_glyph->right_box_line_p | |
4315 || (s->hl == DRAW_MOUSE_FACE | |
4316 && (s->next == NULL | |
4317 || s->next->hl != s->hl))); | |
4318 | |
4319 x_get_glyph_string_clip_rect (s, &clip_rect); | |
4320 | |
4321 if (s->face->box == FACE_SIMPLE_BOX) | |
4322 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width, | |
4323 left_p, right_p, &clip_rect); | |
4324 else | |
4325 { | |
4326 x_setup_relief_colors (s); | |
4327 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y, | |
4328 width, raised_p, left_p, right_p, &clip_rect); | |
4329 } | |
4330 } | |
4331 | |
4332 | |
4333 /* Draw foreground of image glyph string S. */ | |
4334 | |
4335 static void | |
4336 x_draw_image_foreground (s) | |
4337 struct glyph_string *s; | |
4338 { | |
4339 int x; | |
4340 int y = s->ybase - image_ascent (s->img, s->face); | |
4341 | |
4342 /* If first glyph of S has a left box line, start drawing it to the | |
4343 right of that line. */ | |
4344 if (s->face->box != FACE_NO_BOX | |
4345 && s->first_glyph->left_box_line_p) | |
4346 x = s->x + abs (s->face->box_line_width); | |
4347 else | |
4348 x = s->x; | |
4349 | |
4350 /* If there is a margin around the image, adjust x- and y-position | |
4351 by that margin. */ | |
4352 x += s->img->hmargin; | |
4353 y += s->img->vmargin; | |
4354 | |
4355 if (s->img->pixmap) | |
4356 { | |
4357 #if 0 /* MAC_TODO: image mask */ | |
4358 if (s->img->mask) | |
4359 { | |
4360 /* We can't set both a clip mask and use XSetClipRectangles | |
4361 because the latter also sets a clip mask. We also can't | |
4362 trust on the shape extension to be available | |
4363 (XShapeCombineRegion). So, compute the rectangle to draw | |
4364 manually. */ | |
4365 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin | |
4366 | GCFunction); | |
4367 XGCValues xgcv; | |
4368 XRectangle clip_rect, image_rect, r; | |
4369 | |
4370 xgcv.clip_mask = s->img->mask; | |
4371 xgcv.clip_x_origin = x; | |
4372 xgcv.clip_y_origin = y; | |
4373 xgcv.function = GXcopy; | |
4374 XChangeGC (s->display, s->gc, mask, &xgcv); | |
4375 | |
4376 x_get_glyph_string_clip_rect (s, &clip_rect); | |
4377 image_rect.x = x; | |
4378 image_rect.y = y; | |
4379 image_rect.width = s->img->width; | |
4380 image_rect.height = s->img->height; | |
4381 if (x_intersect_rectangles (&clip_rect, &image_rect, &r)) | |
4382 XCopyArea (s->display, s->img->pixmap, s->window, s->gc, | |
4383 r.x - x, r.y - y, r.width, r.height, r.x, r.y); | |
4384 } | |
4385 else | |
4386 #endif /* MAC_TODO */ | |
4387 { | |
4388 mac_copy_area (s->display, s->img->pixmap, s->window, s->gc, | |
4389 0, 0, s->img->width, s->img->height, x, y); | |
4390 | |
4391 /* When the image has a mask, we can expect that at | |
4392 least part of a mouse highlight or a block cursor will | |
4393 be visible. If the image doesn't have a mask, make | |
4394 a block cursor visible by drawing a rectangle around | |
4395 the image. I believe it's looking better if we do | |
4396 nothing here for mouse-face. */ | |
4397 if (s->hl == DRAW_CURSOR) | |
4398 mac_draw_rectangle (s->display, s->window, s->gc, x, y, | |
4399 s->img->width - 1, s->img->height - 1); | |
4400 } | |
4401 } | |
4402 else | |
4403 /* Draw a rectangle if image could not be loaded. */ | |
4404 mac_draw_rectangle (s->display, s->window, s->gc, x, y, | |
4405 s->img->width - 1, s->img->height - 1); | |
4406 } | |
4407 | |
4408 | |
4409 | |
4410 /* Draw a relief around the image glyph string S. */ | |
4411 | |
4412 static void | |
4413 x_draw_image_relief (s) | |
4414 struct glyph_string *s; | |
4415 { | |
4416 int x0, y0, x1, y1, thick, raised_p; | |
4417 Rect r; | |
4418 int x; | |
4419 int y = s->ybase - image_ascent (s->img, s->face); | |
4420 | |
4421 /* If first glyph of S has a left box line, start drawing it to the | |
4422 right of that line. */ | |
4423 if (s->face->box != FACE_NO_BOX | |
4424 && s->first_glyph->left_box_line_p) | |
4425 x = s->x + abs (s->face->box_line_width); | |
4426 else | |
4427 x = s->x; | |
4428 | |
4429 /* If there is a margin around the image, adjust x- and y-position | |
4430 by that margin. */ | |
4431 x += s->img->hmargin; | |
4432 y += s->img->vmargin; | |
4433 | |
4434 if (s->hl == DRAW_IMAGE_SUNKEN | |
4435 || s->hl == DRAW_IMAGE_RAISED) | |
4436 { | |
4437 thick = tool_bar_button_relief >= 0 ? tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF; | |
4438 raised_p = s->hl == DRAW_IMAGE_RAISED; | |
4439 } | |
4440 else | |
4441 { | |
4442 thick = abs (s->img->relief); | |
4443 raised_p = s->img->relief > 0; | |
4444 } | |
4445 | |
4446 x0 = x - thick; | |
4447 y0 = y - thick; | |
4448 x1 = x + s->img->width + thick - 1; | |
4449 y1 = y + s->img->height + thick - 1; | |
4450 | |
4451 x_setup_relief_colors (s); | |
4452 x_get_glyph_string_clip_rect (s, &r); | |
4453 x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p, 1, 1, &r); | |
4454 } | |
4455 | |
4456 | |
4457 /* Draw the foreground of image glyph string S to PIXMAP. */ | |
4458 | |
4459 static void | |
4460 x_draw_image_foreground_1 (s, pixmap) | |
4461 struct glyph_string *s; | |
4462 Pixmap pixmap; | |
4463 { | |
4464 int x; | |
4465 int y = s->ybase - s->y - image_ascent (s->img, s->face); | |
4466 | |
4467 /* If first glyph of S has a left box line, start drawing it to the | |
4468 right of that line. */ | |
4469 if (s->face->box != FACE_NO_BOX | |
4470 && s->first_glyph->left_box_line_p) | |
4471 x = abs (s->face->box_line_width); | |
4472 else | |
4473 x = 0; | |
4474 | |
4475 /* If there is a margin around the image, adjust x- and y-position | |
4476 by that margin. */ | |
4477 x += s->img->hmargin; | |
4478 y += s->img->vmargin; | |
4479 | |
4480 if (s->img->pixmap) | |
4481 { | |
4482 #if 0 /* MAC_TODO: image mask */ | |
4483 if (s->img->mask) | |
4484 { | |
4485 /* We can't set both a clip mask and use XSetClipRectangles | |
4486 because the latter also sets a clip mask. We also can't | |
4487 trust on the shape extension to be available | |
4488 (XShapeCombineRegion). So, compute the rectangle to draw | |
4489 manually. */ | |
4490 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin | |
4491 | GCFunction); | |
4492 XGCValues xgcv; | |
4493 | |
4494 xgcv.clip_mask = s->img->mask; | |
4495 xgcv.clip_x_origin = x; | |
4496 xgcv.clip_y_origin = y; | |
4497 xgcv.function = GXcopy; | |
4498 XChangeGC (s->display, s->gc, mask, &xgcv); | |
4499 | |
4500 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc, | |
4501 0, 0, s->img->width, s->img->height, x, y); | |
4502 XSetClipMask (s->display, s->gc, None); | |
4503 } | |
4504 else | |
4505 #endif /* MAC_TODO */ | |
4506 { | |
4507 mac_copy_area_to_pixmap (s->display, s->img->pixmap, pixmap, s->gc, | |
4508 0, 0, s->img->width, s->img->height, x, y); | |
4509 | |
4510 /* When the image has a mask, we can expect that at | |
4511 least part of a mouse highlight or a block cursor will | |
4512 be visible. If the image doesn't have a mask, make | |
4513 a block cursor visible by drawing a rectangle around | |
4514 the image. I believe it's looking better if we do | |
4515 nothing here for mouse-face. */ | |
4516 if (s->hl == DRAW_CURSOR) | |
4517 mac_draw_rectangle_to_pixmap (s->display, pixmap, s->gc, x, y, | |
4518 s->img->width - 1, s->img->height - 1); | |
4519 } | |
4520 } | |
4521 else | |
4522 /* Draw a rectangle if image could not be loaded. */ | |
4523 mac_draw_rectangle_to_pixmap (s->display, pixmap, s->gc, x, y, | |
4524 s->img->width - 1, s->img->height - 1); | |
4525 } | |
4526 | |
4527 | |
4528 /* Draw part of the background of glyph string S. X, Y, W, and H | |
4529 give the rectangle to draw. */ | |
4530 | |
4531 static void | |
4532 x_draw_glyph_string_bg_rect (s, x, y, w, h) | |
4533 struct glyph_string *s; | |
4534 int x, y, w, h; | |
4535 { | |
4536 #if 0 /* MAC_TODO: stipple */ | |
4537 if (s->stippled_p) | |
4538 { | |
4539 /* Fill background with a stipple pattern. */ | |
4540 XSetFillStyle (s->display, s->gc, FillOpaqueStippled); | |
4541 XFillRectangle (s->display, s->window, s->gc, x, y, w, h); | |
4542 XSetFillStyle (s->display, s->gc, FillSolid); | |
4543 } | |
4544 else | |
4545 #endif /* MAC_TODO */ | |
4546 x_clear_glyph_string_rect (s, x, y, w, h); | |
4547 } | |
4548 | |
4549 | |
4550 /* Draw image glyph string S. | |
4551 | |
4552 s->y | |
4553 s->x +------------------------- | |
4554 | s->face->box | |
4555 | | |
4556 | +------------------------- | |
4557 | | s->img->vmargin | |
4558 | | | |
4559 | | +------------------- | |
4560 | | | the image | |
4561 | |
4562 */ | |
4563 | |
4564 static void | |
4565 x_draw_image_glyph_string (s) | |
4566 struct glyph_string *s; | |
4567 { | |
4568 int x, y; | |
4569 int box_line_hwidth = abs (s->face->box_line_width); | |
4570 int box_line_vwidth = max (s->face->box_line_width, 0); | |
4571 int height; | |
4572 Pixmap pixmap = 0; | |
4573 | |
4574 height = s->height - 2 * box_line_vwidth; | |
4575 | |
4576 /* Fill background with face under the image. Do it only if row is | |
4577 taller than image or if image has a clip mask to reduce | |
4578 flickering. */ | |
4579 s->stippled_p = s->face->stipple != 0; | |
4580 if (height > s->img->height | |
4581 || s->img->hmargin | |
4582 || s->img->vmargin | |
4583 #if 0 /* TODO: image mask */ | |
4584 || s->img->mask | |
4585 #endif | |
4586 || s->img->pixmap == 0 | |
4587 || s->width != s->background_width) | |
4588 { | |
4589 if (box_line_hwidth && s->first_glyph->left_box_line_p) | |
4590 x = s->x + box_line_hwidth; | |
4591 else | |
4592 x = s->x; | |
4593 | |
4594 y = s->y + box_line_vwidth; | |
4595 #if 0 /* TODO: image mask */ | |
4596 if (s->img->mask) | |
4597 { | |
4598 /* Create a pixmap as large as the glyph string. Fill it | |
4599 with the background color. Copy the image to it, using | |
4600 its mask. Copy the temporary pixmap to the display. */ | |
4601 Screen *screen = FRAME_X_SCREEN (s->f); | |
4602 int depth = DefaultDepthOfScreen (screen); | |
4603 | |
4604 /* Create a pixmap as large as the glyph string. */ | |
4605 pixmap = XCreatePixmap (s->display, s->window, | |
4606 s->background_width, | |
4607 s->height, depth); | |
4608 | |
4609 /* Don't clip in the following because we're working on the | |
4610 pixmap. */ | |
4611 XSetClipMask (s->display, s->gc, None); | |
4612 | |
4613 /* Fill the pixmap with the background color/stipple. */ | |
4614 if (s->stippled_p) | |
4615 { | |
4616 /* Fill background with a stipple pattern. */ | |
4617 XSetFillStyle (s->display, s->gc, FillOpaqueStippled); | |
4618 XFillRectangle (s->display, pixmap, s->gc, | |
4619 0, 0, s->background_width, s->height); | |
4620 XSetFillStyle (s->display, s->gc, FillSolid); | |
4621 } | |
4622 else | |
4623 { | |
4624 XGCValues xgcv; | |
4625 XGetGCValues (s->display, s->gc, GCForeground | GCBackground, | |
4626 &xgcv); | |
4627 XSetForeground (s->display, s->gc, xgcv.background); | |
4628 XFillRectangle (s->display, pixmap, s->gc, | |
4629 0, 0, s->background_width, s->height); | |
4630 XSetForeground (s->display, s->gc, xgcv.foreground); | |
4631 } | |
4632 } | |
4633 else | |
4634 #endif | |
4635 x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height); | |
4636 | |
4637 s->background_filled_p = 1; | |
4638 } | |
4639 | |
4640 /* Draw the foreground. */ | |
4641 if (pixmap != 0) | |
4642 { | |
4643 x_draw_image_foreground_1 (s, pixmap); | |
4644 x_set_glyph_string_clipping (s); | |
4645 mac_copy_area (s->display, pixmap, s->window, s->gc, | |
4646 0, 0, s->background_width, s->height, s->x, s->y); | |
4647 mac_reset_clipping (s->display, s->window); | |
4648 XFreePixmap (s->display, pixmap); | |
4649 } | |
4650 else | |
4651 x_draw_image_foreground (s); | |
4652 | |
4653 /* If we must draw a relief around the image, do it. */ | |
4654 if (s->img->relief | |
4655 || s->hl == DRAW_IMAGE_RAISED | |
4656 || s->hl == DRAW_IMAGE_SUNKEN) | |
4657 x_draw_image_relief (s); | |
4658 } | |
4659 | |
4660 | |
4661 /* Draw stretch glyph string S. */ | |
4662 | |
4663 static void | |
4664 x_draw_stretch_glyph_string (s) | |
4665 struct glyph_string *s; | |
4666 { | |
4667 xassert (s->first_glyph->type == STRETCH_GLYPH); | |
4668 s->stippled_p = s->face->stipple != 0; | |
4669 | |
4670 if (s->hl == DRAW_CURSOR | |
4671 && !x_stretch_cursor_p) | |
4672 { | |
4673 /* If `x-stretch-block-cursor' is nil, don't draw a block cursor | |
4674 as wide as the stretch glyph. */ | |
4675 int width = min (CANON_X_UNIT (s->f), s->background_width); | |
4676 | |
4677 /* Draw cursor. */ | |
4678 x_draw_glyph_string_bg_rect (s, s->x, s->y, width, s->height); | |
4679 | |
4680 /* Clear rest using the GC of the original non-cursor face. */ | |
4681 if (width < s->background_width) | |
4682 { | |
4683 GC gc = s->face->gc; | |
4684 int x = s->x + width, y = s->y; | |
4685 int w = s->background_width - width, h = s->height; | |
4686 Rect r; | |
4687 | |
4688 if (s->row->mouse_face_p | |
4689 && cursor_in_mouse_face_p (s->w)) | |
4690 { | |
4691 x_set_mouse_face_gc (s); | |
4692 gc = s->gc; | |
4693 } | |
4694 else | |
4695 gc = s->face->gc; | |
4696 | |
4697 x_get_glyph_string_clip_rect (s, &r); | |
4698 mac_set_clip_rectangle (s->display, s->window, &r); | |
4699 | |
4700 #if 0 /* MAC_TODO: stipple */ | |
4701 if (s->face->stipple) | |
4702 { | |
4703 /* Fill background with a stipple pattern. */ | |
4704 XSetFillStyle (s->display, gc, FillOpaqueStippled); | |
4705 XFillRectangle (s->display, s->window, gc, x, y, w, h); | |
4706 XSetFillStyle (s->display, gc, FillSolid); | |
4707 } | |
4708 else | |
4709 #endif /* MAC_TODO */ | |
4710 { | |
4711 XGCValues xgcv; | |
4712 XGetGCValues (s->display, gc, GCForeground | GCBackground, &xgcv); | |
4713 XSetForeground (s->display, gc, xgcv.background); | |
4714 XFillRectangle (s->display, s->window, gc, x, y, w, h); | |
4715 XSetForeground (s->display, gc, xgcv.foreground); | |
4716 } | |
4717 | |
4718 mac_reset_clipping (s->display, s->window); | |
4719 } | |
4720 } | |
4721 else if (!s->background_filled_p) | |
4722 x_draw_glyph_string_bg_rect (s, s->x, s->y, s->background_width, | |
4723 s->height); | |
4724 | |
4725 s->background_filled_p = 1; | |
4726 } | |
4727 | |
4728 | |
4729 /* Draw glyph string S. */ | |
4730 | |
4731 static void | |
4732 x_draw_glyph_string (s) | |
4733 struct glyph_string *s; | |
4734 { | |
4735 int relief_drawn_p = 0; | |
4736 | |
4737 /* If S draws into the background of its successor, draw the | |
4738 background of the successor first so that S can draw into it. | |
4739 This makes S->next use XDrawString instead of XDrawImageString. */ | |
4740 if (s->next && s->right_overhang && !s->for_overlaps_p) | |
4741 { | |
4742 xassert (s->next->img == NULL); | |
4743 x_set_glyph_string_gc (s->next); | |
4744 x_set_glyph_string_clipping (s->next); | |
4745 x_draw_glyph_string_background (s->next, 1); | |
4746 | |
4747 } | |
4748 | |
4749 /* Set up S->gc, set clipping and draw S. */ | |
4750 x_set_glyph_string_gc (s); | |
4751 | |
4752 /* Draw relief (if any) in advance for char/composition so that the | |
4753 glyph string can be drawn over it. */ | |
4754 if (!s->for_overlaps_p | |
4755 && s->face->box != FACE_NO_BOX | |
4756 && (s->first_glyph->type == CHAR_GLYPH | |
4757 || s->first_glyph->type == COMPOSITE_GLYPH)) | |
4758 | |
4759 { | |
4760 x_set_glyph_string_clipping (s); | |
4761 x_draw_glyph_string_background (s, 1); | |
4762 x_draw_glyph_string_box (s); | |
4763 x_set_glyph_string_clipping (s); | |
4764 relief_drawn_p = 1; | |
4765 } | |
4766 else | |
4767 x_set_glyph_string_clipping (s); | |
4768 | |
4769 switch (s->first_glyph->type) | |
4770 { | |
4771 case IMAGE_GLYPH: | |
4772 x_draw_image_glyph_string (s); | |
4773 break; | |
4774 | |
4775 case STRETCH_GLYPH: | |
4776 x_draw_stretch_glyph_string (s); | |
4777 break; | |
4778 | |
4779 case CHAR_GLYPH: | |
4780 if (s->for_overlaps_p) | |
4781 s->background_filled_p = 1; | |
4782 else | |
4783 x_draw_glyph_string_background (s, 0); | |
4784 x_draw_glyph_string_foreground (s); | |
4785 break; | |
4786 | |
4787 case COMPOSITE_GLYPH: | |
4788 if (s->for_overlaps_p || s->gidx > 0) | |
4789 s->background_filled_p = 1; | |
4790 else | |
4791 x_draw_glyph_string_background (s, 1); | |
4792 x_draw_composite_glyph_string_foreground (s); | |
4793 break; | |
4794 | |
4795 default: | |
4796 abort (); | |
4797 } | |
4798 | |
4799 if (!s->for_overlaps_p) | |
4800 { | |
4801 /* Draw underline. */ | |
4802 if (s->face->underline_p) | |
4803 { | |
4804 unsigned long h = 1; | |
4805 unsigned long dy = s->height - h; | |
4806 | |
4807 if (s->face->underline_defaulted_p) | |
4808 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy, | |
4809 s->width, h); | |
4810 else | |
4811 { | |
4812 XGCValues xgcv; | |
4813 XGetGCValues (s->display, s->gc, GCForeground, &xgcv); | |
4814 XSetForeground (s->display, s->gc, s->face->underline_color); | |
4815 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy, | |
4816 s->width, h); | |
4817 XSetForeground (s->display, s->gc, xgcv.foreground); | |
4818 } | |
4819 } | |
4820 | |
4821 /* Draw overline. */ | |
4822 if (s->face->overline_p) | |
4823 { | |
4824 unsigned long dy = 0, h = 1; | |
4825 | |
4826 if (s->face->overline_color_defaulted_p) | |
4827 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy, | |
4828 s->width, h); | |
4829 else | |
4830 { | |
4831 XGCValues xgcv; | |
4832 XGetGCValues (s->display, s->gc, GCForeground, &xgcv); | |
4833 XSetForeground (s->display, s->gc, s->face->overline_color); | |
4834 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy, | |
4835 s->width, h); | |
4836 XSetForeground (s->display, s->gc, xgcv.foreground); | |
4837 } | |
4838 } | |
4839 | |
4840 /* Draw strike-through. */ | |
4841 if (s->face->strike_through_p) | |
4842 { | |
4843 unsigned long h = 1; | |
4844 unsigned long dy = (s->height - h) / 2; | |
4845 | |
4846 if (s->face->strike_through_color_defaulted_p) | |
4847 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy, | |
4848 s->width, h); | |
4849 else | |
4850 { | |
4851 XGCValues xgcv; | |
4852 XGetGCValues (s->display, s->gc, GCForeground, &xgcv); | |
4853 XSetForeground (s->display, s->gc, s->face->strike_through_color); | |
4854 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy, | |
4855 s->width, h); | |
4856 XSetForeground (s->display, s->gc, xgcv.foreground); | |
4857 } | |
4858 } | |
4859 | |
4860 /* Draw relief. */ | |
4861 if (!relief_drawn_p && s->face->box != FACE_NO_BOX) | |
4862 x_draw_glyph_string_box (s); | |
4863 } | |
4864 | |
4865 /* Reset clipping. */ | |
4866 mac_reset_clipping (s->display, s->window); | |
4867 } | |
4868 | |
4869 | |
4870 static int x_fill_composite_glyph_string P_ ((struct glyph_string *, | |
4871 struct face **, int)); | |
4872 | |
4873 | |
4874 /* Fill glyph string S with composition components specified by S->cmp. | |
4875 | |
4876 FACES is an array of faces for all components of this composition. | |
4877 S->gidx is the index of the first component for S. | |
4878 OVERLAPS_P non-zero means S should draw the foreground only, and | |
4879 use its physical height for clipping. | |
4880 | |
4881 Value is the index of a component not in S. */ | |
4882 | |
4883 static int | |
4884 x_fill_composite_glyph_string (s, faces, overlaps_p) | |
4885 struct glyph_string *s; | |
4886 struct face **faces; | |
4887 int overlaps_p; | |
4888 { | |
4889 int i; | |
4890 | |
4891 xassert (s); | |
4892 | |
4893 s->for_overlaps_p = overlaps_p; | |
4894 | |
4895 s->face = faces[s->gidx]; | |
4896 s->font = s->face->font; | |
4897 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id); | |
4898 | |
4899 /* For all glyphs of this composition, starting at the offset | |
4900 S->gidx, until we reach the end of the definition or encounter a | |
4901 glyph that requires the different face, add it to S. */ | |
4902 ++s->nchars; | |
4903 for (i = s->gidx + 1; i < s->cmp->glyph_len && faces[i] == s->face; ++i) | |
4904 ++s->nchars; | |
4905 | |
4906 /* All glyph strings for the same composition has the same width, | |
4907 i.e. the width set for the first component of the composition. */ | |
4908 | |
4909 s->width = s->first_glyph->pixel_width; | |
4910 | |
4911 /* If the specified font could not be loaded, use the frame's | |
4912 default font, but record the fact that we couldn't load it in | |
4913 the glyph string so that we can draw rectangles for the | |
4914 characters of the glyph string. */ | |
4915 if (s->font == NULL) | |
4916 { | |
4917 s->font_not_found_p = 1; | |
4918 s->font = FRAME_FONT (s->f); | |
4919 } | |
4920 | |
4921 /* Adjust base line for subscript/superscript text. */ | |
4922 s->ybase += s->first_glyph->voffset; | |
4923 | |
4924 xassert (s->face && s->face->gc); | |
4925 | |
4926 /* This glyph string must always be drawn with 16-bit functions. */ | |
4927 s->two_byte_p = 1; | |
4928 | |
4929 return s->gidx + s->nchars; | |
4930 } | |
4931 | |
4932 | |
4933 /* Fill glyph string S from a sequence of character glyphs. | |
4934 | |
4935 FACE_ID is the face id of the string. START is the index of the | |
4936 first glyph to consider, END is the index of the last + 1. | |
4937 OVERLAPS_P non-zero means S should draw the foreground only, and | |
4938 use its physical height for clipping. | |
4939 | |
4940 Value is the index of the first glyph not in S. */ | |
4941 | |
4942 static int | |
4943 x_fill_glyph_string (s, face_id, start, end, overlaps_p) | |
4944 struct glyph_string *s; | |
4945 int face_id; | |
4946 int start, end, overlaps_p; | |
4947 { | |
4948 struct glyph *glyph, *last; | |
4949 int voffset; | |
4950 int glyph_not_available_p; | |
4951 | |
4952 xassert (s->f == XFRAME (s->w->frame)); | |
4953 xassert (s->nchars == 0); | |
4954 xassert (start >= 0 && end > start); | |
4955 | |
4956 s->for_overlaps_p = overlaps_p; | |
4957 glyph = s->row->glyphs[s->area] + start; | |
4958 last = s->row->glyphs[s->area] + end; | |
4959 voffset = glyph->voffset; | |
4960 | |
4961 glyph_not_available_p = glyph->glyph_not_available_p; | |
4962 | |
4963 while (glyph < last | |
4964 && glyph->type == CHAR_GLYPH | |
4965 && glyph->voffset == voffset | |
4966 /* Same face id implies same font, nowadays. */ | |
4967 && glyph->face_id == face_id | |
4968 && glyph->glyph_not_available_p == glyph_not_available_p) | |
4969 { | |
4970 int two_byte_p; | |
4971 | |
4972 s->face = x_get_glyph_face_and_encoding (s->f, glyph, | |
4973 s->char2b + s->nchars, | |
4974 &two_byte_p); | |
4975 s->two_byte_p = two_byte_p; | |
4976 ++s->nchars; | |
4977 xassert (s->nchars <= end - start); | |
4978 s->width += glyph->pixel_width; | |
4979 ++glyph; | |
4980 } | |
4981 | |
4982 s->font = s->face->font; | |
4983 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id); | |
4984 | |
4985 /* If the specified font could not be loaded, use the frame's font, | |
4986 but record the fact that we couldn't load it in | |
4987 S->font_not_found_p so that we can draw rectangles for the | |
4988 characters of the glyph string. */ | |
4989 if (s->font == NULL || glyph_not_available_p) | |
4990 { | |
4991 s->font_not_found_p = 1; | |
4992 s->font = FRAME_FONT (s->f); | |
4993 } | |
4994 | |
4995 /* Adjust base line for subscript/superscript text. */ | |
4996 s->ybase += voffset; | |
4997 | |
4998 xassert (s->face && s->face->gc); | |
4999 return glyph - s->row->glyphs[s->area]; | |
5000 } | |
5001 | |
5002 | |
5003 /* Fill glyph string S from image glyph S->first_glyph. */ | |
5004 | |
5005 static void | |
5006 x_fill_image_glyph_string (s) | |
5007 struct glyph_string *s; | |
5008 { | |
5009 xassert (s->first_glyph->type == IMAGE_GLYPH); | |
5010 s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img_id); | |
5011 xassert (s->img); | |
5012 s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id); | |
5013 s->font = s->face->font; | |
5014 s->width = s->first_glyph->pixel_width; | |
5015 | |
5016 /* Adjust base line for subscript/superscript text. */ | |
5017 s->ybase += s->first_glyph->voffset; | |
5018 } | |
5019 | |
5020 | |
5021 /* Fill glyph string S from a sequence of stretch glyphs. | |
5022 | |
5023 ROW is the glyph row in which the glyphs are found, AREA is the | |
5024 area within the row. START is the index of the first glyph to | |
5025 consider, END is the index of the last + 1. | |
5026 | |
5027 Value is the index of the first glyph not in S. */ | |
5028 | |
5029 static int | |
5030 x_fill_stretch_glyph_string (s, row, area, start, end) | |
5031 struct glyph_string *s; | |
5032 struct glyph_row *row; | |
5033 enum glyph_row_area area; | |
5034 int start, end; | |
5035 { | |
5036 struct glyph *glyph, *last; | |
5037 int voffset, face_id; | |
5038 | |
5039 xassert (s->first_glyph->type == STRETCH_GLYPH); | |
5040 | |
5041 glyph = s->row->glyphs[s->area] + start; | |
5042 last = s->row->glyphs[s->area] + end; | |
5043 face_id = glyph->face_id; | |
5044 s->face = FACE_FROM_ID (s->f, face_id); | |
5045 s->font = s->face->font; | |
5046 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id); | |
5047 s->width = glyph->pixel_width; | |
5048 voffset = glyph->voffset; | |
5049 | |
5050 for (++glyph; | |
5051 (glyph < last | |
5052 && glyph->type == STRETCH_GLYPH | |
5053 && glyph->voffset == voffset | |
5054 && glyph->face_id == face_id); | |
5055 ++glyph) | |
5056 s->width += glyph->pixel_width; | |
5057 | |
5058 /* Adjust base line for subscript/superscript text. */ | |
5059 s->ybase += voffset; | |
5060 | |
5061 xassert (s->face); | |
5062 return glyph - s->row->glyphs[s->area]; | |
5063 } | |
5064 | |
5065 | |
5066 /* Initialize glyph string S. CHAR2B is a suitably allocated vector | |
5067 of XChar2b structures for S; it can't be allocated in | |
5068 x_init_glyph_string because it must be allocated via `alloca'. W | |
5069 is the window on which S is drawn. ROW and AREA are the glyph row | |
5070 and area within the row from which S is constructed. START is the | |
5071 index of the first glyph structure covered by S. HL is a | |
5072 face-override for drawing S. */ | |
5073 | |
5074 static void | |
5075 x_init_glyph_string (s, char2b, w, row, area, start, hl) | |
5076 struct glyph_string *s; | |
5077 XChar2b *char2b; | |
5078 struct window *w; | |
5079 struct glyph_row *row; | |
5080 enum glyph_row_area area; | |
5081 int start; | |
5082 enum draw_glyphs_face hl; | |
5083 { | |
5084 bzero (s, sizeof *s); | |
5085 s->w = w; | |
5086 s->f = XFRAME (w->frame); | |
5087 s->display = FRAME_MAC_DISPLAY (s->f); | |
5088 s->window = FRAME_MAC_WINDOW (s->f); | |
5089 s->char2b = char2b; | |
5090 s->hl = hl; | |
5091 s->row = row; | |
5092 s->area = area; | |
5093 s->first_glyph = row->glyphs[area] + start; | |
5094 s->height = row->height; | |
5095 s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y); | |
5096 | |
5097 /* Display the internal border below the tool-bar window. */ | |
5098 if (s->w == XWINDOW (s->f->tool_bar_window)) | |
5099 s->y -= s->f->output_data.mac->internal_border_width; | |
5100 | |
5101 s->ybase = s->y + row->ascent; | |
5102 } | |
5103 | |
5104 | |
5105 /* Set background width of glyph string S. START is the index of the | |
5106 first glyph following S. LAST_X is the right-most x-position + 1 | |
5107 in the drawing area. */ | |
5108 | |
5109 static INLINE void | |
5110 x_set_glyph_string_background_width (s, start, last_x) | |
5111 struct glyph_string *s; | |
5112 int start; | |
5113 int last_x; | |
5114 { | |
5115 /* If the face of this glyph string has to be drawn to the end of | |
5116 the drawing area, set S->extends_to_end_of_line_p. */ | |
5117 struct face *default_face = FACE_FROM_ID (s->f, DEFAULT_FACE_ID); | |
5118 | |
5119 if (start == s->row->used[s->area] | |
5120 && s->area == TEXT_AREA | |
5121 && ((s->hl == DRAW_NORMAL_TEXT | |
5122 && (s->row->fill_line_p | |
5123 || s->face->background != default_face->background | |
5124 || s->face->stipple != default_face->stipple | |
5125 || s->row->mouse_face_p)) | |
5126 || s->hl == DRAW_MOUSE_FACE | |
5127 || ((s->hl == DRAW_IMAGE_RAISED || s->hl == DRAW_IMAGE_SUNKEN) | |
5128 && s->row->fill_line_p))) | |
5129 s->extends_to_end_of_line_p = 1; | |
5130 | |
5131 /* If S extends its face to the end of the line, set its | |
5132 background_width to the distance to the right edge of the drawing | |
5133 area. */ | |
5134 if (s->extends_to_end_of_line_p) | |
5135 s->background_width = last_x - s->x + 1; | |
5136 else | |
5137 s->background_width = s->width; | |
5138 } | |
5139 | |
5140 | |
5141 /* Add a glyph string for a stretch glyph to the list of strings | |
5142 between HEAD and TAIL. START is the index of the stretch glyph in | |
5143 row area AREA of glyph row ROW. END is the index of the last glyph | |
5144 in that glyph row area. X is the current output position assigned | |
5145 to the new glyph string constructed. HL overrides that face of the | |
5146 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X | |
5147 is the right-most x-position of the drawing area. */ | |
5148 | |
5149 /* SunOS 4 bundled cc, barfed on continuations in the arg lists here | |
5150 and below -- keep them on one line. */ | |
5151 #define BUILD_STRETCH_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \ | |
5152 do \ | |
5153 { \ | |
5154 s = (struct glyph_string *) alloca (sizeof *s); \ | |
5155 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \ | |
5156 START = x_fill_stretch_glyph_string (s, ROW, AREA, START, END); \ | |
5157 x_append_glyph_string (&HEAD, &TAIL, s); \ | |
5158 s->x = (X); \ | |
5159 } \ | |
5160 while (0) | |
5161 | |
5162 | |
5163 /* Add a glyph string for an image glyph to the list of strings | |
5164 between HEAD and TAIL. START is the index of the image glyph in | |
5165 row area AREA of glyph row ROW. END is the index of the last glyph | |
5166 in that glyph row area. X is the current output position assigned | |
5167 to the new glyph string constructed. HL overrides that face of the | |
5168 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X | |
5169 is the right-most x-position of the drawing area. */ | |
5170 | |
5171 #define BUILD_IMAGE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \ | |
5172 do \ | |
5173 { \ | |
5174 s = (struct glyph_string *) alloca (sizeof *s); \ | |
5175 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \ | |
5176 x_fill_image_glyph_string (s); \ | |
5177 x_append_glyph_string (&HEAD, &TAIL, s); \ | |
5178 ++START; \ | |
5179 s->x = (X); \ | |
5180 } \ | |
5181 while (0) | |
5182 | |
5183 | |
5184 /* Add a glyph string for a sequence of character glyphs to the list | |
5185 of strings between HEAD and TAIL. START is the index of the first | |
5186 glyph in row area AREA of glyph row ROW that is part of the new | |
5187 glyph string. END is the index of the last glyph in that glyph row | |
5188 area. X is the current output position assigned to the new glyph | |
5189 string constructed. HL overrides that face of the glyph; e.g. it | |
5190 is DRAW_CURSOR if a cursor has to be drawn. LAST_X is the | |
5191 right-most x-position of the drawing area. */ | |
5192 | |
5193 #define BUILD_CHAR_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \ | |
5194 do \ | |
5195 { \ | |
5196 int c, face_id; \ | |
5197 XChar2b *char2b; \ | |
5198 \ | |
5199 c = (ROW)->glyphs[AREA][START].u.ch; \ | |
5200 face_id = (ROW)->glyphs[AREA][START].face_id; \ | |
5201 \ | |
5202 s = (struct glyph_string *) alloca (sizeof *s); \ | |
5203 char2b = (XChar2b *) alloca ((END - START) * sizeof *char2b); \ | |
5204 x_init_glyph_string (s, char2b, W, ROW, AREA, START, HL); \ | |
5205 x_append_glyph_string (&HEAD, &TAIL, s); \ | |
5206 s->x = (X); \ | |
5207 START = x_fill_glyph_string (s, face_id, START, END, \ | |
5208 OVERLAPS_P); \ | |
5209 } \ | |
5210 while (0) | |
5211 | |
5212 | |
5213 /* Add a glyph string for a composite sequence to the list of strings | |
5214 between HEAD and TAIL. START is the index of the first glyph in | |
5215 row area AREA of glyph row ROW that is part of the new glyph | |
5216 string. END is the index of the last glyph in that glyph row area. | |
5217 X is the current output position assigned to the new glyph string | |
5218 constructed. HL overrides that face of the glyph; e.g. it is | |
5219 DRAW_CURSOR if a cursor has to be drawn. LAST_X is the right-most | |
5220 x-position of the drawing area. */ | |
5221 | |
5222 #define BUILD_COMPOSITE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \ | |
5223 do { \ | |
5224 int cmp_id = (ROW)->glyphs[AREA][START].u.cmp_id; \ | |
5225 int face_id = (ROW)->glyphs[AREA][START].face_id; \ | |
5226 struct face *base_face = FACE_FROM_ID (XFRAME (w->frame), face_id); \ | |
5227 struct composition *cmp = composition_table[cmp_id]; \ | |
5228 int glyph_len = cmp->glyph_len; \ | |
5229 XChar2b *char2b; \ | |
5230 struct face **faces; \ | |
5231 struct glyph_string *first_s = NULL; \ | |
5232 int n; \ | |
5233 \ | |
5234 base_face = base_face->ascii_face; \ | |
5235 char2b = (XChar2b *) alloca ((sizeof *char2b) * glyph_len); \ | |
5236 faces = (struct face **) alloca ((sizeof *faces) * glyph_len); \ | |
5237 /* At first, fill in `char2b' and `faces'. */ \ | |
5238 for (n = 0; n < glyph_len; n++) \ | |
5239 { \ | |
5240 int c = COMPOSITION_GLYPH (cmp, n); \ | |
5241 int this_face_id = FACE_FOR_CHAR (XFRAME (w->frame), base_face, c); \ | |
5242 faces[n] = FACE_FROM_ID (XFRAME (w->frame), this_face_id); \ | |
5243 x_get_char_face_and_encoding (XFRAME (w->frame), c, \ | |
5244 this_face_id, char2b + n, 1); \ | |
5245 } \ | |
5246 \ | |
5247 /* Make glyph_strings for each glyph sequence that is drawable by \ | |
5248 the same face, and append them to HEAD/TAIL. */ \ | |
5249 for (n = 0; n < cmp->glyph_len;) \ | |
5250 { \ | |
5251 s = (struct glyph_string *) alloca (sizeof *s); \ | |
5252 x_init_glyph_string (s, char2b + n, W, ROW, AREA, START, HL); \ | |
5253 x_append_glyph_string (&(HEAD), &(TAIL), s); \ | |
5254 s->cmp = cmp; \ | |
5255 s->gidx = n; \ | |
5256 s->x = (X); \ | |
5257 \ | |
5258 if (n == 0) \ | |
5259 first_s = s; \ | |
5260 \ | |
5261 n = x_fill_composite_glyph_string (s, faces, OVERLAPS_P); \ | |
5262 } \ | |
5263 \ | |
5264 ++START; \ | |
5265 s = first_s; \ | |
5266 } while (0) | |
5267 | |
5268 | |
5269 /* Build a list of glyph strings between HEAD and TAIL for the glyphs | |
5270 of AREA of glyph row ROW on window W between indices START and END. | |
5271 HL overrides the face for drawing glyph strings, e.g. it is | |
5272 DRAW_CURSOR to draw a cursor. X and LAST_X are start and end | |
5273 x-positions of the drawing area. | |
5274 | |
5275 This is an ugly monster macro construct because we must use alloca | |
5276 to allocate glyph strings (because x_draw_glyphs can be called | |
5277 asynchronously). */ | |
5278 | |
5279 #define BUILD_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \ | |
5280 do \ | |
5281 { \ | |
5282 HEAD = TAIL = NULL; \ | |
5283 while (START < END) \ | |
5284 { \ | |
5285 struct glyph *first_glyph = (ROW)->glyphs[AREA] + START; \ | |
5286 switch (first_glyph->type) \ | |
5287 { \ | |
5288 case CHAR_GLYPH: \ | |
5289 BUILD_CHAR_GLYPH_STRINGS (W, ROW, AREA, START, END, HEAD, \ | |
5290 TAIL, HL, X, LAST_X, \ | |
5291 OVERLAPS_P); \ | |
5292 break; \ | |
5293 \ | |
5294 case COMPOSITE_GLYPH: \ | |
5295 BUILD_COMPOSITE_GLYPH_STRING (W, ROW, AREA, START, END, \ | |
5296 HEAD, TAIL, HL, X, LAST_X,\ | |
5297 OVERLAPS_P); \ | |
5298 break; \ | |
5299 \ | |
5300 case STRETCH_GLYPH: \ | |
5301 BUILD_STRETCH_GLYPH_STRING (W, ROW, AREA, START, END, \ | |
5302 HEAD, TAIL, HL, X, LAST_X); \ | |
5303 break; \ | |
5304 \ | |
5305 case IMAGE_GLYPH: \ | |
5306 BUILD_IMAGE_GLYPH_STRING (W, ROW, AREA, START, END, HEAD, \ | |
5307 TAIL, HL, X, LAST_X); \ | |
5308 break; \ | |
5309 \ | |
5310 default: \ | |
5311 abort (); \ | |
5312 } \ | |
5313 \ | |
5314 x_set_glyph_string_background_width (s, START, LAST_X); \ | |
5315 (X) += s->width; \ | |
5316 } \ | |
5317 } \ | |
5318 while (0) | |
5319 | |
5320 | |
5321 /* Draw glyphs between START and END in AREA of ROW on window W, | |
5322 starting at x-position X. X is relative to AREA in W. HL is a | |
5323 face-override with the following meaning: | |
5324 | |
5325 DRAW_NORMAL_TEXT draw normally | |
5326 DRAW_CURSOR draw in cursor face | |
5327 DRAW_MOUSE_FACE draw in mouse face. | |
5328 DRAW_INVERSE_VIDEO draw in mode line face | |
5329 DRAW_IMAGE_SUNKEN draw an image with a sunken relief around it | |
5330 DRAW_IMAGE_RAISED draw an image with a raised relief around it | |
5331 | |
5332 If OVERLAPS_P is non-zero, draw only the foreground of characters | |
5333 and clip to the physical height of ROW. | |
5334 | |
5335 Value is the x-position reached, relative to AREA of W. */ | |
5336 | |
5337 static int | |
5338 x_draw_glyphs (w, x, row, area, start, end, hl, overlaps_p) | |
5339 struct window *w; | |
5340 int x; | |
5341 struct glyph_row *row; | |
5342 enum glyph_row_area area; | |
5343 int start, end; | |
5344 enum draw_glyphs_face hl; | |
5345 int overlaps_p; | |
5346 { | |
5347 struct glyph_string *head, *tail; | |
5348 struct glyph_string *s; | |
5349 int last_x, area_width; | |
5350 int x_reached; | |
5351 int i, j; | |
5352 | |
5353 /* Let's rather be paranoid than getting a SEGV. */ | |
5354 end = min (end, row->used[area]); | |
5355 start = max (0, start); | |
5356 start = min (end, start); | |
5357 | |
5358 /* Translate X to frame coordinates. Set last_x to the right | |
5359 end of the drawing area. */ | |
5360 if (row->full_width_p) | |
5361 { | |
5362 /* X is relative to the left edge of W, without scroll bars | |
5363 or fringes. */ | |
5364 struct frame *f = XFRAME (WINDOW_FRAME (w)); | |
5365 int window_left_x = WINDOW_LEFT_MARGIN (w) * CANON_X_UNIT (f); | |
5366 | |
5367 x += window_left_x; | |
5368 area_width = XFASTINT (w->width) * CANON_X_UNIT (f); | |
5369 last_x = window_left_x + area_width; | |
5370 | |
5371 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f)) | |
5372 { | |
5373 int width = FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f); | |
5374 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f)) | |
5375 last_x += width; | |
5376 else | |
5377 x -= width; | |
5378 } | |
5379 | |
5380 x += FRAME_INTERNAL_BORDER_WIDTH (f); | |
5381 last_x -= FRAME_INTERNAL_BORDER_WIDTH (f); | |
5382 } | |
5383 else | |
5384 { | |
5385 x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, x); | |
5386 area_width = window_box_width (w, area); | |
5387 last_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, area_width); | |
5388 } | |
5389 | |
5390 /* Build a doubly-linked list of glyph_string structures between | |
5391 head and tail from what we have to draw. Note that the macro | |
5392 BUILD_GLYPH_STRINGS will modify its start parameter. That's | |
5393 the reason we use a separate variable `i'. */ | |
5394 i = start; | |
5395 BUILD_GLYPH_STRINGS (w, row, area, i, end, head, tail, hl, x, last_x, | |
5396 overlaps_p); | |
5397 if (tail) | |
5398 x_reached = tail->x + tail->background_width; | |
5399 else | |
5400 x_reached = x; | |
5401 | |
5402 /* If there are any glyphs with lbearing < 0 or rbearing > width in | |
5403 the row, redraw some glyphs in front or following the glyph | |
5404 strings built above. */ | |
5405 if (head && !overlaps_p && row->contains_overlapping_glyphs_p) | |
5406 { | |
5407 int dummy_x = 0; | |
5408 struct glyph_string *h, *t; | |
5409 | |
5410 /* Compute overhangs for all glyph strings. */ | |
5411 for (s = head; s; s = s->next) | |
5412 x_compute_glyph_string_overhangs (s); | |
5413 | |
5414 /* Prepend glyph strings for glyphs in front of the first glyph | |
5415 string that are overwritten because of the first glyph | |
5416 string's left overhang. The background of all strings | |
5417 prepended must be drawn because the first glyph string | |
5418 draws over it. */ | |
5419 i = x_left_overwritten (head); | |
5420 if (i >= 0) | |
5421 { | |
5422 j = i; | |
5423 BUILD_GLYPH_STRINGS (w, row, area, j, start, h, t, | |
5424 DRAW_NORMAL_TEXT, dummy_x, last_x, | |
5425 overlaps_p); | |
5426 start = i; | |
5427 x_compute_overhangs_and_x (t, head->x, 1); | |
5428 x_prepend_glyph_string_lists (&head, &tail, h, t); | |
5429 } | |
5430 | |
5431 /* Prepend glyph strings for glyphs in front of the first glyph | |
5432 string that overwrite that glyph string because of their | |
5433 right overhang. For these strings, only the foreground must | |
5434 be drawn, because it draws over the glyph string at `head'. | |
5435 The background must not be drawn because this would overwrite | |
5436 right overhangs of preceding glyphs for which no glyph | |
5437 strings exist. */ | |
5438 i = x_left_overwriting (head); | |
5439 if (i >= 0) | |
5440 { | |
5441 BUILD_GLYPH_STRINGS (w, row, area, i, start, h, t, | |
5442 DRAW_NORMAL_TEXT, dummy_x, last_x, | |
5443 overlaps_p); | |
5444 for (s = h; s; s = s->next) | |
5445 s->background_filled_p = 1; | |
5446 x_compute_overhangs_and_x (t, head->x, 1); | |
5447 x_prepend_glyph_string_lists (&head, &tail, h, t); | |
5448 } | |
5449 | |
5450 /* Append glyphs strings for glyphs following the last glyph | |
5451 string tail that are overwritten by tail. The background of | |
5452 these strings has to be drawn because tail's foreground draws | |
5453 over it. */ | |
5454 i = x_right_overwritten (tail); | |
5455 if (i >= 0) | |
5456 { | |
5457 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t, | |
5458 DRAW_NORMAL_TEXT, x, last_x, | |
5459 overlaps_p); | |
5460 x_compute_overhangs_and_x (h, tail->x + tail->width, 0); | |
5461 x_append_glyph_string_lists (&head, &tail, h, t); | |
5462 } | |
5463 | |
5464 /* Append glyph strings for glyphs following the last glyph | |
5465 string tail that overwrite tail. The foreground of such | |
5466 glyphs has to be drawn because it writes into the background | |
5467 of tail. The background must not be drawn because it could | |
5468 paint over the foreground of following glyphs. */ | |
5469 i = x_right_overwriting (tail); | |
5470 if (i >= 0) | |
5471 { | |
5472 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t, | |
5473 DRAW_NORMAL_TEXT, x, last_x, | |
5474 overlaps_p); | |
5475 for (s = h; s; s = s->next) | |
5476 s->background_filled_p = 1; | |
5477 x_compute_overhangs_and_x (h, tail->x + tail->width, 0); | |
5478 x_append_glyph_string_lists (&head, &tail, h, t); | |
5479 } | |
5480 } | |
5481 | |
5482 /* Draw all strings. */ | |
5483 for (s = head; s; s = s->next) | |
5484 x_draw_glyph_string (s); | |
5485 | |
5486 if (area == TEXT_AREA | |
5487 && !row->full_width_p | |
5488 /* When drawing overlapping rows, only the glyph strings' | |
5489 foreground is drawn, which doesn't erase a cursor | |
5490 completely. */ | |
5491 && !overlaps_p) | |
5492 { | |
5493 int x0 = head ? head->x : x; | |
5494 int x1 = tail ? tail->x + tail->background_width : x; | |
5495 | |
5496 x0 = FRAME_TO_WINDOW_PIXEL_X (w, x0); | |
5497 x1 = FRAME_TO_WINDOW_PIXEL_X (w, x1); | |
5498 | |
5499 if (!row->full_width_p && XFASTINT (w->left_margin_width) != 0) | |
5500 { | |
5501 int left_area_width = window_box_width (w, LEFT_MARGIN_AREA); | |
5502 x0 -= left_area_width; | |
5503 x1 -= left_area_width; | |
5504 } | |
5505 | |
5506 notice_overwritten_cursor (w, area, x0, x1, | |
5507 row->y, MATRIX_ROW_BOTTOM_Y (row)); | |
5508 } | |
5509 | |
5510 /* Value is the x-position up to which drawn, relative to AREA of W. | |
5511 This doesn't include parts drawn because of overhangs. */ | |
5512 x_reached = FRAME_TO_WINDOW_PIXEL_X (w, x_reached); | |
5513 if (!row->full_width_p) | |
5514 { | |
5515 if (area > LEFT_MARGIN_AREA) | |
5516 x_reached -= window_box_width (w, LEFT_MARGIN_AREA); | |
5517 if (area > TEXT_AREA) | |
5518 x_reached -= window_box_width (w, TEXT_AREA); | |
5519 } | |
5520 | |
5521 return x_reached; | |
5522 } | |
5523 | |
5524 | |
5525 /* Fix the display of area AREA of overlapping row ROW in window W. */ | |
5526 | |
5527 static void | |
5528 x_fix_overlapping_area (w, row, area) | |
5529 struct window *w; | |
5530 struct glyph_row *row; | |
5531 enum glyph_row_area area; | |
5532 { | |
5533 int i, x; | |
5534 | |
5535 BLOCK_INPUT; | |
5536 | |
5537 if (area == LEFT_MARGIN_AREA) | |
5538 x = 0; | |
5539 else if (area == TEXT_AREA) | |
5540 x = row->x + window_box_width (w, LEFT_MARGIN_AREA); | |
5541 else | |
5542 x = (window_box_width (w, LEFT_MARGIN_AREA) | |
5543 + window_box_width (w, TEXT_AREA)); | |
5544 | |
5545 for (i = 0; i < row->used[area];) | |
5546 { | |
5547 if (row->glyphs[area][i].overlaps_vertically_p) | |
5548 { | |
5549 int start = i, start_x = x; | |
5550 | |
5551 do | |
5552 { | |
5553 x += row->glyphs[area][i].pixel_width; | |
5554 ++i; | |
5555 } | |
5556 while (i < row->used[area] | |
5557 && row->glyphs[area][i].overlaps_vertically_p); | |
5558 | |
5559 x_draw_glyphs (w, start_x, row, area, start, i, | |
5560 DRAW_NORMAL_TEXT, 1); | |
5561 } | |
5562 else | |
5563 { | |
5564 x += row->glyphs[area][i].pixel_width; | |
5565 ++i; | |
5566 } | |
5567 } | |
5568 | |
5569 UNBLOCK_INPUT; | |
5570 } | |
5571 | |
5572 | |
5573 /* Output LEN glyphs starting at START at the nominal cursor position. | |
5574 Advance the nominal cursor over the text. The global variable | |
5575 updated_window contains the window being updated, updated_row is | |
5576 the glyph row being updated, and updated_area is the area of that | |
5577 row being updated. */ | |
5578 | |
5579 static void | |
5580 x_write_glyphs (start, len) | |
5581 struct glyph *start; | |
5582 int len; | |
5583 { | |
5584 int x, hpos; | |
5585 | |
5586 xassert (updated_window && updated_row); | |
5587 BLOCK_INPUT; | |
5588 | |
5589 /* Write glyphs. */ | |
5590 | |
5591 hpos = start - updated_row->glyphs[updated_area]; | |
5592 x = x_draw_glyphs (updated_window, output_cursor.x, | |
5593 updated_row, updated_area, | |
5594 hpos, hpos + len, | |
5595 DRAW_NORMAL_TEXT, 0); | |
5596 | |
5597 UNBLOCK_INPUT; | |
5598 | |
5599 /* Advance the output cursor. */ | |
5600 output_cursor.hpos += len; | |
5601 output_cursor.x = x; | |
5602 } | |
5603 | |
5604 | |
5605 /* Insert LEN glyphs from START at the nominal cursor position. */ | |
5606 | |
5607 static void | |
5608 x_insert_glyphs (start, len) | |
5609 struct glyph *start; | |
5610 register int len; | |
5611 { | |
5612 struct frame *f; | |
5613 struct window *w; | |
5614 int line_height, shift_by_width, shifted_region_width; | |
5615 struct glyph_row *row; | |
5616 struct glyph *glyph; | |
5617 int frame_x, frame_y, hpos; | |
5618 | |
5619 xassert (updated_window && updated_row); | |
5620 BLOCK_INPUT; | |
5621 w = updated_window; | |
5622 f = XFRAME (WINDOW_FRAME (w)); | |
5623 | |
5624 /* Get the height of the line we are in. */ | |
5625 row = updated_row; | |
5626 line_height = row->height; | |
5627 | |
5628 /* Get the width of the glyphs to insert. */ | |
5629 shift_by_width = 0; | |
5630 for (glyph = start; glyph < start + len; ++glyph) | |
5631 shift_by_width += glyph->pixel_width; | |
5632 | |
5633 /* Get the width of the region to shift right. */ | |
5634 shifted_region_width = (window_box_width (w, updated_area) | |
5635 - output_cursor.x | |
5636 - shift_by_width); | |
5637 | |
5638 /* Shift right. */ | |
5639 frame_x = window_box_left (w, updated_area) + output_cursor.x; | |
5640 frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, output_cursor.y); | |
5641 | |
5642 mac_scroll_area (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), | |
5643 f->output_data.mac->normal_gc, | |
5644 frame_x, frame_y, | |
5645 shifted_region_width, line_height, | |
5646 frame_x + shift_by_width, frame_y); | |
5647 | |
5648 /* Write the glyphs. */ | |
5649 hpos = start - row->glyphs[updated_area]; | |
5650 x_draw_glyphs (w, output_cursor.x, row, updated_area, hpos, hpos + len, | |
5651 DRAW_NORMAL_TEXT, 0); | |
5652 | |
5653 /* Advance the output cursor. */ | |
5654 output_cursor.hpos += len; | |
5655 output_cursor.x += shift_by_width; | |
5656 UNBLOCK_INPUT; | |
5657 } | |
5658 | |
5659 | |
5660 /* Delete N glyphs at the nominal cursor position. Not implemented | |
5661 for X frames. */ | |
5662 | |
5663 static void | |
5664 x_delete_glyphs (n) | |
5665 register int n; | |
5666 { | |
5667 abort (); | |
5668 } | |
5669 | |
5670 | |
5671 /* Erase the current text line from the nominal cursor position | |
5672 (inclusive) to pixel column TO_X (exclusive). The idea is that | |
5673 everything from TO_X onward is already erased. | |
5674 | |
5675 TO_X is a pixel position relative to updated_area of | |
5676 updated_window. TO_X == -1 means clear to the end of this area. */ | |
5677 | |
5678 static void | |
5679 x_clear_end_of_line (to_x) | |
5680 int to_x; | |
5681 { | |
5682 struct frame *f; | |
5683 struct window *w = updated_window; | |
5684 int max_x, min_y, max_y; | |
5685 int from_x, from_y, to_y; | |
5686 | |
5687 xassert (updated_window && updated_row); | |
5688 f = XFRAME (w->frame); | |
5689 | |
5690 if (updated_row->full_width_p) | |
5691 { | |
5692 max_x = XFASTINT (w->width) * CANON_X_UNIT (f); | |
5693 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f) | |
5694 && !w->pseudo_window_p) | |
5695 max_x += FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f); | |
5696 } | |
5697 else | |
5698 max_x = window_box_width (w, updated_area); | |
5699 max_y = window_text_bottom_y (w); | |
5700 | |
5701 /* TO_X == 0 means don't do anything. TO_X < 0 means clear to end | |
5702 of window. For TO_X > 0, truncate to end of drawing area. */ | |
5703 if (to_x == 0) | |
5704 return; | |
5705 else if (to_x < 0) | |
5706 to_x = max_x; | |
5707 else | |
5708 to_x = min (to_x, max_x); | |
5709 | |
5710 to_y = min (max_y, output_cursor.y + updated_row->height); | |
5711 | |
5712 /* Notice if the cursor will be cleared by this operation. */ | |
5713 if (!updated_row->full_width_p) | |
5714 notice_overwritten_cursor (w, updated_area, | |
5715 output_cursor.x, -1, | |
5716 updated_row->y, | |
5717 MATRIX_ROW_BOTTOM_Y (updated_row)); | |
5718 | |
5719 from_x = output_cursor.x; | |
5720 | |
5721 /* Translate to frame coordinates. */ | |
5722 if (updated_row->full_width_p) | |
5723 { | |
5724 from_x = WINDOW_TO_FRAME_PIXEL_X (w, from_x); | |
5725 to_x = WINDOW_TO_FRAME_PIXEL_X (w, to_x); | |
5726 } | |
5727 else | |
5728 { | |
5729 from_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, from_x); | |
5730 to_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, to_x); | |
5731 } | |
5732 | |
5733 min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w); | |
5734 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, max (min_y, output_cursor.y)); | |
5735 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, to_y); | |
5736 | |
5737 /* Prevent inadvertently clearing to end of the X window. */ | |
5738 if (to_x > from_x && to_y > from_y) | |
5739 { | |
5740 BLOCK_INPUT; | |
5741 XClearArea (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), | |
5742 from_x, from_y, to_x - from_x, to_y - from_y, | |
5743 0); | |
5744 UNBLOCK_INPUT; | |
5745 } | |
5746 } | |
5747 | |
5748 | |
5749 /* Clear entire frame. If updating_frame is non-null, clear that | |
5750 frame. Otherwise clear the selected frame. */ | |
5751 | |
5752 static void | |
5753 x_clear_frame () | |
5754 { | |
5755 struct frame *f; | |
5756 | |
5757 if (updating_frame) | |
5758 f = updating_frame; | |
5759 else | |
5760 f = SELECTED_FRAME (); | |
5761 | |
5762 /* Clearing the frame will erase any cursor, so mark them all as no | |
5763 longer visible. */ | |
5764 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f))); | |
5765 output_cursor.hpos = output_cursor.vpos = 0; | |
5766 output_cursor.x = -1; | |
5767 | |
5768 /* We don't set the output cursor here because there will always | |
5769 follow an explicit cursor_to. */ | |
5770 BLOCK_INPUT; | |
5771 XClearWindow (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f)); | |
5772 | |
5773 #if 0 /* Clearing frame on Mac OS clears scroll bars. */ | |
5774 /* We have to clear the scroll bars, too. If we have changed | |
5775 colors or something like that, then they should be notified. */ | |
5776 x_scroll_bar_clear (f); | |
5777 #endif | |
5778 | |
5779 XFlush (FRAME_MAC_DISPLAY (f)); | |
5780 UNBLOCK_INPUT; | |
5781 } | |
5782 | |
5783 | |
5784 | |
5785 /* Invert the middle quarter of the frame for .15 sec. */ | |
5786 | |
5787 /* We use the select system call to do the waiting, so we have to make | |
5788 sure it's available. If it isn't, we just won't do visual bells. */ | |
5789 | |
5790 #if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) | |
5791 | |
5792 /* Subtract the `struct timeval' values X and Y, storing the result in | |
5793 *RESULT. Return 1 if the difference is negative, otherwise 0. */ | |
5794 | |
5795 static int | |
5796 timeval_subtract (result, x, y) | |
5797 struct timeval *result, x, y; | |
5798 { | |
5799 /* Perform the carry for the later subtraction by updating y. This | |
5800 is safer because on some systems the tv_sec member is unsigned. */ | |
5801 if (x.tv_usec < y.tv_usec) | |
5802 { | |
5803 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1; | |
5804 y.tv_usec -= 1000000 * nsec; | |
5805 y.tv_sec += nsec; | |
5806 } | |
5807 | |
5808 if (x.tv_usec - y.tv_usec > 1000000) | |
5809 { | |
5810 int nsec = (y.tv_usec - x.tv_usec) / 1000000; | |
5811 y.tv_usec += 1000000 * nsec; | |
5812 y.tv_sec -= nsec; | |
5813 } | |
5814 | |
5815 /* Compute the time remaining to wait. tv_usec is certainly | |
5816 positive. */ | |
5817 result->tv_sec = x.tv_sec - y.tv_sec; | |
5818 result->tv_usec = x.tv_usec - y.tv_usec; | |
5819 | |
5820 /* Return indication of whether the result should be considered | |
5821 negative. */ | |
5822 return x.tv_sec < y.tv_sec; | |
5823 } | |
5824 | |
5825 void | |
5826 XTflash (f) | |
5827 struct frame *f; | |
5828 { | |
5829 BLOCK_INPUT; | |
5830 | |
5831 FlashMenuBar (0); | |
5832 | |
5833 { | |
5834 struct timeval wakeup; | |
5835 | |
5836 EMACS_GET_TIME (wakeup); | |
5837 | |
5838 /* Compute time to wait until, propagating carry from usecs. */ | |
5839 wakeup.tv_usec += 150000; | |
5840 wakeup.tv_sec += (wakeup.tv_usec / 1000000); | |
5841 wakeup.tv_usec %= 1000000; | |
5842 | |
5843 /* Keep waiting until past the time wakeup. */ | |
5844 while (1) | |
5845 { | |
5846 struct timeval timeout; | |
5847 | |
5848 EMACS_GET_TIME (timeout); | |
5849 | |
5850 /* In effect, timeout = wakeup - timeout. | |
5851 Break if result would be negative. */ | |
5852 if (timeval_subtract (&timeout, wakeup, timeout)) | |
5853 break; | |
5854 | |
5855 /* Try to wait that long--but we might wake up sooner. */ | |
5856 select (0, NULL, NULL, NULL, &timeout); | |
5857 } | |
5858 } | |
5859 | |
5860 FlashMenuBar (0); | |
5861 | |
5862 UNBLOCK_INPUT; | |
5863 } | |
5864 | |
5865 #endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */ | |
5866 | |
5867 | |
5868 /* Make audible bell. */ | |
5869 | |
5870 void | |
5871 XTring_bell () | |
5872 { | |
5873 struct frame *f = SELECTED_FRAME (); | |
5874 | |
5875 #if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) | |
5876 if (visible_bell) | |
5877 XTflash (f); | |
5878 else | |
5879 #endif | |
5880 { | |
5881 BLOCK_INPUT; | |
5882 SysBeep (1); | |
5883 XFlush (FRAME_MAC_DISPLAY (f)); | |
5884 UNBLOCK_INPUT; | |
5885 } | |
5886 } | |
5887 | |
5888 | |
5889 | |
5890 /* Specify how many text lines, from the top of the window, | |
5891 should be affected by insert-lines and delete-lines operations. | |
5892 This, and those operations, are used only within an update | |
5893 that is bounded by calls to x_update_begin and x_update_end. */ | |
5894 | |
5895 void | |
5896 XTset_terminal_window (n) | |
5897 register int n; | |
5898 { | |
5899 /* This function intentionally left blank. */ | |
5900 } | |
5901 | |
5902 | |
5903 | |
5904 /*********************************************************************** | |
5905 Line Dance | |
5906 ***********************************************************************/ | |
5907 | |
5908 /* Perform an insert-lines or delete-lines operation, inserting N | |
5909 lines or deleting -N lines at vertical position VPOS. */ | |
5910 | |
5911 static void | |
5912 x_ins_del_lines (vpos, n) | |
5913 int vpos, n; | |
5914 { | |
5915 abort (); | |
5916 } | |
5917 | |
5918 | |
5919 /* Scroll part of the display as described by RUN. */ | |
5920 | |
5921 static void | |
5922 x_scroll_run (w, run) | |
5923 struct window *w; | |
5924 struct run *run; | |
5925 { | |
5926 struct frame *f = XFRAME (w->frame); | |
5927 int x, y, width, height, from_y, to_y, bottom_y; | |
5928 | |
5929 /* Get frame-relative bounding box of the text display area of W, | |
5930 without mode lines. Include in this box the left and right | |
5931 fringes of W. */ | |
5932 window_box (w, -1, &x, &y, &width, &height); | |
5933 width += FRAME_X_FRINGE_WIDTH (f); | |
5934 x -= FRAME_X_LEFT_FRINGE_WIDTH (f); | |
5935 | |
5936 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y); | |
5937 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y); | |
5938 bottom_y = y + height; | |
5939 | |
5940 if (to_y < from_y) | |
5941 { | |
5942 /* Scrolling up. Make sure we don't copy part of the mode | |
5943 line at the bottom. */ | |
5944 if (from_y + run->height > bottom_y) | |
5945 height = bottom_y - from_y; | |
5946 else | |
5947 height = run->height; | |
5948 } | |
5949 else | |
5950 { | |
5951 /* Scolling down. Make sure we don't copy over the mode line. | |
5952 at the bottom. */ | |
5953 if (to_y + run->height > bottom_y) | |
5954 height = bottom_y - to_y; | |
5955 else | |
5956 height = run->height; | |
5957 } | |
5958 | |
5959 BLOCK_INPUT; | |
5960 | |
5961 /* Cursor off. Will be switched on again in x_update_window_end. */ | |
5962 updated_window = w; | |
5963 x_clear_cursor (w); | |
5964 | |
5965 mac_scroll_area (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), | |
5966 f->output_data.mac->normal_gc, | |
5967 x, from_y, | |
5968 width, height, | |
5969 x, to_y); | |
5970 | |
5971 UNBLOCK_INPUT; | |
5972 } | |
5973 | |
5974 | |
5975 | |
5976 /*********************************************************************** | |
5977 Exposure Events | |
5978 ***********************************************************************/ | |
5979 | |
5980 /* Redisplay an exposed area of frame F. X and Y are the upper-left | |
5981 corner of the exposed rectangle. W and H are width and height of | |
5982 the exposed area. All are pixel values. W or H zero means redraw | |
5983 the entire frame. */ | |
5984 | |
5985 static void | |
5986 expose_frame (f, x, y, w, h) | |
5987 struct frame *f; | |
5988 int x, y, w, h; | |
5989 { | |
5990 Rect r; | |
5991 int mouse_face_overwritten_p = 0; | |
5992 | |
5993 TRACE ((stderr, "expose_frame ")); | |
5994 | |
5995 /* No need to redraw if frame will be redrawn soon. */ | |
5996 if (FRAME_GARBAGED_P (f)) | |
5997 { | |
5998 TRACE ((stderr, " garbaged\n")); | |
5999 return; | |
6000 } | |
6001 | |
6002 /* MAC_TODO: this is a kludge, but if scroll bars are not activated | |
6003 or deactivated here, for unknown reasons, activated scroll bars | |
6004 are shown in deactivated frames in some instances. */ | |
6005 if (f == FRAME_MAC_DISPLAY_INFO (f)->x_focus_frame) | |
6006 activate_scroll_bars (f); | |
6007 else | |
6008 deactivate_scroll_bars (f); | |
6009 | |
6010 /* If basic faces haven't been realized yet, there is no point in | |
6011 trying to redraw anything. This can happen when we get an expose | |
6012 event while Emacs is starting, e.g. by moving another window. */ | |
6013 if (FRAME_FACE_CACHE (f) == NULL | |
6014 || FRAME_FACE_CACHE (f)->used < BASIC_FACE_ID_SENTINEL) | |
6015 { | |
6016 TRACE ((stderr, " no faces\n")); | |
6017 return; | |
6018 } | |
6019 | |
6020 if (w == 0 || h == 0) | |
6021 { | |
6022 r.left = r.top = 0; | |
6023 r.right = CANON_X_UNIT (f) * f->width; | |
6024 r.bottom = CANON_Y_UNIT (f) * f->height; | |
6025 } | |
6026 else | |
6027 { | |
6028 r.left = x; | |
6029 r.top = y; | |
6030 r.right = x + w; | |
6031 r.bottom = y + h; | |
6032 } | |
6033 | |
6034 TRACE ((stderr, "(%d, %d, %d, %d)\n", r.left, r.top, r.right, r.bottom)); | |
6035 mouse_face_overwritten_p = expose_window_tree (XWINDOW (f->root_window), &r); | |
6036 | |
6037 if (WINDOWP (f->tool_bar_window)) | |
6038 mouse_face_overwritten_p | |
6039 |= expose_window (XWINDOW (f->tool_bar_window), &r); | |
6040 | |
6041 /* Some window managers support a focus-follows-mouse style with | |
6042 delayed raising of frames. Imagine a partially obscured frame, | |
6043 and moving the mouse into partially obscured mouse-face on that | |
6044 frame. The visible part of the mouse-face will be highlighted, | |
6045 then the WM raises the obscured frame. With at least one WM, KDE | |
6046 2.1, Emacs is not getting any event for the raising of the frame | |
6047 (even tried with SubstructureRedirectMask), only Expose events. | |
6048 These expose events will draw text normally, i.e. not | |
6049 highlighted. Which means we must redo the highlight here. | |
6050 Subsume it under ``we love X''. --gerd 2001-08-15 */ | |
6051 /* Included in Windows version because Windows most likely does not | |
6052 do the right thing if any third party tool offers | |
6053 focus-follows-mouse with delayed raise. --jason 2001-10-12 */ | |
6054 if (mouse_face_overwritten_p && !FRAME_GARBAGED_P (f)) | |
6055 { | |
6056 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); | |
6057 if (f == dpyinfo->mouse_face_mouse_frame) | |
6058 { | |
6059 int x = dpyinfo->mouse_face_mouse_x; | |
6060 int y = dpyinfo->mouse_face_mouse_y; | |
6061 clear_mouse_face (dpyinfo); | |
6062 note_mouse_highlight (f, x, y); | |
6063 } | |
6064 } | |
6065 } | |
6066 | |
6067 | |
6068 /* Redraw (parts) of all windows in the window tree rooted at W that | |
6069 intersect R. R contains frame pixel coordinates. */ | |
6070 | |
6071 static int | |
6072 expose_window_tree (w, r) | |
6073 struct window *w; | |
6074 Rect *r; | |
6075 { | |
6076 struct frame *f = XFRAME (w->frame); | |
6077 int mouse_face_overwritten_p = 0; | |
6078 | |
6079 while (w && !FRAME_GARBAGED_P (f)) | |
6080 { | |
6081 if (!NILP (w->hchild)) | |
6082 mouse_face_overwritten_p | |
6083 |= expose_window_tree (XWINDOW (w->hchild), r); | |
6084 else if (!NILP (w->vchild)) | |
6085 mouse_face_overwritten_p | |
6086 |= expose_window_tree (XWINDOW (w->vchild), r); | |
6087 else | |
6088 mouse_face_overwritten_p |= expose_window (w, r); | |
6089 | |
6090 w = NILP (w->next) ? NULL : XWINDOW (w->next); | |
6091 } | |
6092 | |
6093 return mouse_face_overwritten_p; | |
6094 } | |
6095 | |
6096 | |
6097 /* Redraw the part of glyph row area AREA of glyph row ROW on window W | |
6098 which intersects rectangle R. R is in window-relative coordinates. */ | |
6099 | |
6100 static void | |
6101 expose_area (w, row, r, area) | |
6102 struct window *w; | |
6103 struct glyph_row *row; | |
6104 Rect *r; | |
6105 enum glyph_row_area area; | |
6106 { | |
6107 struct glyph *first = row->glyphs[area]; | |
6108 struct glyph *end = row->glyphs[area] + row->used[area]; | |
6109 struct glyph *last; | |
6110 int first_x, start_x, x; | |
6111 | |
6112 if (area == TEXT_AREA && row->fill_line_p) | |
6113 /* If row extends face to end of line write the whole line. */ | |
6114 x_draw_glyphs (w, 0, row, area, | |
6115 0, row->used[area], | |
6116 DRAW_NORMAL_TEXT, 0); | |
6117 else | |
6118 { | |
6119 /* Set START_X to the window-relative start position for drawing glyphs of | |
6120 AREA. The first glyph of the text area can be partially visible. | |
6121 The first glyphs of other areas cannot. */ | |
6122 if (area == LEFT_MARGIN_AREA) | |
6123 start_x = 0; | |
6124 else if (area == TEXT_AREA) | |
6125 start_x = row->x + window_box_width (w, LEFT_MARGIN_AREA); | |
6126 else | |
6127 start_x = (window_box_width (w, LEFT_MARGIN_AREA) | |
6128 + window_box_width (w, TEXT_AREA)); | |
6129 x = start_x; | |
6130 | |
6131 /* Find the first glyph that must be redrawn. */ | |
6132 while (first < end | |
6133 && x + first->pixel_width < r->left) | |
6134 { | |
6135 x += first->pixel_width; | |
6136 ++first; | |
6137 } | |
6138 | |
6139 /* Find the last one. */ | |
6140 last = first; | |
6141 first_x = x; | |
6142 while (last < end | |
6143 && x < r->right) | |
6144 { | |
6145 x += last->pixel_width; | |
6146 ++last; | |
6147 } | |
6148 | |
6149 /* Repaint. */ | |
6150 if (last > first) | |
6151 x_draw_glyphs (w, first_x - start_x, row, area, | |
6152 first - row->glyphs[area], | |
6153 last - row->glyphs[area], | |
6154 DRAW_NORMAL_TEXT, 0); | |
6155 } | |
6156 } | |
6157 | |
6158 | |
6159 /* Redraw the parts of the glyph row ROW on window W intersecting | |
6160 rectangle R. R is in window-relative coordinates. Value is | |
6161 non-zero if mouse face was overwritten. */ | |
6162 | |
6163 static int | |
6164 expose_line (w, row, r) | |
6165 struct window *w; | |
6166 struct glyph_row *row; | |
6167 Rect *r; | |
6168 { | |
6169 xassert (row->enabled_p); | |
6170 | |
6171 if (row->mode_line_p || w->pseudo_window_p) | |
6172 x_draw_glyphs (w, 0, row, TEXT_AREA, 0, row->used[TEXT_AREA], | |
6173 DRAW_NORMAL_TEXT, 0); | |
6174 else | |
6175 { | |
6176 if (row->used[LEFT_MARGIN_AREA]) | |
6177 expose_area (w, row, r, LEFT_MARGIN_AREA); | |
6178 if (row->used[TEXT_AREA]) | |
6179 expose_area (w, row, r, TEXT_AREA); | |
6180 if (row->used[RIGHT_MARGIN_AREA]) | |
6181 expose_area (w, row, r, RIGHT_MARGIN_AREA); | |
6182 x_draw_row_fringe_bitmaps (w, row); | |
6183 } | |
6184 | |
6185 return row->mouse_face_p; | |
6186 } | |
6187 | |
6188 | |
6189 /* Return non-zero if W's cursor intersects rectangle R. */ | |
6190 | |
6191 static int | |
6192 x_phys_cursor_in_rect_p (w, r) | |
6193 struct window *w; | |
6194 Rect *r; | |
6195 { | |
6196 Rect cr, result; | |
6197 struct glyph *cursor_glyph; | |
6198 | |
6199 cursor_glyph = get_phys_cursor_glyph (w); | |
6200 if (cursor_glyph) | |
6201 { | |
6202 cr.left = w->phys_cursor.x; | |
6203 cr.top = w->phys_cursor.y; | |
6204 cr.right = cr.left + cursor_glyph->pixel_width; | |
6205 cr.bottom = cr.top + w->phys_cursor_height; | |
6206 return x_intersect_rectangles (&cr, r, &result); | |
6207 } | |
6208 else | |
6209 return 0; | |
6210 } | |
6211 | |
6212 | |
6213 /* Redraw the part of window W intersection rectagle FR. Pixel | |
6214 coordinates in FR are frame relative. Call this function with | |
6215 input blocked. Value is non-zero if the exposure overwrites | |
6216 mouse-face. */ | |
6217 | |
6218 static int | |
6219 expose_window (w, fr) | |
6220 struct window *w; | |
6221 Rect *fr; | |
6222 { | |
6223 struct frame *f = XFRAME (w->frame); | |
6224 Rect wr, r; | |
6225 int mouse_face_overwritten_p = 0; | |
6226 | |
6227 /* If window is not yet fully initialized, do nothing. This can | |
6228 happen when toolkit scroll bars are used and a window is split. | |
6229 Reconfiguring the scroll bar will generate an expose for a newly | |
6230 created window. */ | |
6231 if (w->current_matrix == NULL) | |
6232 return 0; | |
6233 | |
6234 /* When we're currently updating the window, display and current | |
6235 matrix usually don't agree. Arrange for a thorough display | |
6236 later. */ | |
6237 if (w == updated_window) | |
6238 { | |
6239 SET_FRAME_GARBAGED (f); | |
6240 return 0; | |
6241 } | |
6242 | |
6243 /* Frame-relative pixel rectangle of W. */ | |
6244 wr.left = XFASTINT (w->left) * CANON_X_UNIT (f); | |
6245 wr.top = XFASTINT (w->top) * CANON_Y_UNIT (f); | |
6246 wr.right = wr.left + XFASTINT (w->width) * CANON_X_UNIT (f); | |
6247 wr.bottom = wr.top + XFASTINT (w->height) * CANON_Y_UNIT (f); | |
6248 | |
6249 if (x_intersect_rectangles (fr, &wr, &r)) | |
6250 { | |
6251 int yb = window_text_bottom_y (w); | |
6252 struct glyph_row *row; | |
6253 int cursor_cleared_p; | |
6254 | |
6255 TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n", | |
6256 r.left, r.top, r.right, r.bottom)); | |
6257 | |
6258 /* Convert to window coordinates. */ | |
6259 r.left = FRAME_TO_WINDOW_PIXEL_X (w, r.left); | |
6260 r.right = FRAME_TO_WINDOW_PIXEL_X (w, r.right); | |
6261 r.top = FRAME_TO_WINDOW_PIXEL_Y (w, r.top); | |
6262 r.bottom = FRAME_TO_WINDOW_PIXEL_Y (w, r.bottom); | |
6263 | |
6264 /* Turn off the cursor. */ | |
6265 if (!w->pseudo_window_p | |
6266 && x_phys_cursor_in_rect_p (w, &r)) | |
6267 { | |
6268 x_clear_cursor (w); | |
6269 cursor_cleared_p = 1; | |
6270 } | |
6271 else | |
6272 cursor_cleared_p = 0; | |
6273 | |
6274 /* Find the first row intersecting the rectangle R. */ | |
6275 for (row = w->current_matrix->rows; | |
6276 row->enabled_p; | |
6277 ++row) | |
6278 { | |
6279 int y0 = row->y; | |
6280 int y1 = MATRIX_ROW_BOTTOM_Y (row); | |
6281 | |
6282 if ((y0 >= r.top && y0 < r.bottom) | |
6283 || (y1 > r.top && y1 < r.bottom) | |
6284 || (r.top >= y0 && r.top < y1) | |
6285 || (r.bottom > y0 && r.bottom < y1)) | |
6286 { | |
6287 if (expose_line (w, row, &r)) | |
6288 mouse_face_overwritten_p = 1; | |
6289 } | |
6290 | |
6291 if (y1 >= yb) | |
6292 break; | |
6293 } | |
6294 | |
6295 /* Display the mode line if there is one. */ | |
6296 if (WINDOW_WANTS_MODELINE_P (w) | |
6297 && (row = MATRIX_MODE_LINE_ROW (w->current_matrix), | |
6298 row->enabled_p) | |
6299 && row->y < r.bottom) | |
6300 { | |
6301 if (expose_line (w, row, &r)) | |
6302 mouse_face_overwritten_p = 1; | |
6303 } | |
6304 | |
6305 if (!w->pseudo_window_p) | |
6306 { | |
6307 /* Draw border between windows. */ | |
6308 x_draw_vertical_border (w); | |
6309 | |
6310 /* Turn the cursor on again. */ | |
6311 if (cursor_cleared_p) | |
6312 x_update_window_cursor (w, 1); | |
6313 } | |
6314 } | |
6315 | |
6316 /* Display scroll bar for this window. */ | |
6317 if (!NILP (w->vertical_scroll_bar)) | |
6318 { | |
6319 ControlHandle ch | |
6320 = SCROLL_BAR_CONTROL_HANDLE (XSCROLL_BAR (w->vertical_scroll_bar)); | |
6321 | |
6322 Draw1Control (ch); | |
6323 } | |
6324 | |
6325 return mouse_face_overwritten_p; | |
6326 } | |
6327 | |
6328 static int | |
6329 x_intersect_rectangles (r1, r2, result) | |
6330 Rect *r1, *r2, *result; | |
6331 { | |
6332 Rect *left, *right; | |
6333 Rect *upper, *lower; | |
6334 int intersection_p = 0; | |
6335 | |
6336 /* Rerrange so that R1 is the left-most rectangle. */ | |
6337 if (r1->left < r2->left) | |
6338 left = r1, right = r2; | |
6339 else | |
6340 left = r2, right = r1; | |
6341 | |
6342 /* X0 of the intersection is right.x0, if this is inside R1, | |
6343 otherwise there is no intersection. */ | |
6344 if (right->left <= left->right) | |
6345 { | |
6346 result->left = right->left; | |
6347 | |
6348 /* The right end of the intersection is the minimum of the | |
6349 the right ends of left and right. */ | |
6350 result->right = min (left->right, right->right); | |
6351 | |
6352 /* Same game for Y. */ | |
6353 if (r1->top < r2->top) | |
6354 upper = r1, lower = r2; | |
6355 else | |
6356 upper = r2, lower = r1; | |
6357 | |
6358 /* The upper end of the intersection is lower.y0, if this is inside | |
6359 of upper. Otherwise, there is no intersection. */ | |
6360 if (lower->top <= upper->bottom) | |
6361 { | |
6362 result->top = lower->top; | |
6363 | |
6364 /* The lower end of the intersection is the minimum of the lower | |
6365 ends of upper and lower. */ | |
6366 result->bottom = min (lower->bottom, upper->bottom); | |
6367 intersection_p = 1; | |
6368 } | |
6369 } | |
6370 | |
6371 return intersection_p; | |
6372 } | |
6373 | |
6374 | |
6375 | |
6376 | |
6377 | |
6378 static void | |
6379 frame_highlight (f) | |
6380 struct frame *f; | |
6381 { | |
6382 x_update_cursor (f, 1); | |
6383 } | |
6384 | |
6385 static void | |
6386 frame_unhighlight (f) | |
6387 struct frame *f; | |
6388 { | |
6389 x_update_cursor (f, 1); | |
6390 } | |
6391 | |
6392 /* The focus has changed. Update the frames as necessary to reflect | |
6393 the new situation. Note that we can't change the selected frame | |
6394 here, because the Lisp code we are interrupting might become confused. | |
6395 Each event gets marked with the frame in which it occurred, so the | |
6396 Lisp code can tell when the switch took place by examining the events. */ | |
6397 | |
6398 static void | |
6399 x_new_focus_frame (dpyinfo, frame) | |
6400 struct x_display_info *dpyinfo; | |
6401 struct frame *frame; | |
6402 { | |
6403 struct frame *old_focus = dpyinfo->x_focus_frame; | |
6404 | |
6405 if (frame != dpyinfo->x_focus_frame) | |
6406 { | |
6407 /* Set this before calling other routines, so that they see | |
6408 the correct value of x_focus_frame. */ | |
6409 dpyinfo->x_focus_frame = frame; | |
6410 | |
6411 if (old_focus && old_focus->auto_lower) | |
6412 x_lower_frame (old_focus); | |
6413 | |
6414 #if 0 | |
6415 selected_frame = frame; | |
6416 XSETFRAME (XWINDOW (selected_frame->selected_window)->frame, | |
6417 selected_frame); | |
6418 Fselect_window (selected_frame->selected_window); | |
6419 choose_minibuf_frame (); | |
6420 #endif /* ! 0 */ | |
6421 | |
6422 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise) | |
6423 pending_autoraise_frame = dpyinfo->x_focus_frame; | |
6424 else | |
6425 pending_autoraise_frame = 0; | |
6426 } | |
6427 | |
6428 x_frame_rehighlight (dpyinfo); | |
6429 } | |
6430 | |
6431 /* Handle an event saying the mouse has moved out of an Emacs frame. */ | |
6432 | |
6433 void | |
6434 x_mouse_leave (dpyinfo) | |
6435 struct x_display_info *dpyinfo; | |
6436 { | |
6437 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame); | |
6438 } | |
6439 | |
6440 /* The focus has changed, or we have redirected a frame's focus to | |
6441 another frame (this happens when a frame uses a surrogate | |
6442 mini-buffer frame). Shift the highlight as appropriate. | |
6443 | |
6444 The FRAME argument doesn't necessarily have anything to do with which | |
6445 frame is being highlighted or un-highlighted; we only use it to find | |
6446 the appropriate X display info. */ | |
6447 | |
6448 static void | |
6449 XTframe_rehighlight (frame) | |
6450 struct frame *frame; | |
6451 { | |
6452 x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame)); | |
6453 } | |
6454 | |
6455 static void | |
6456 x_frame_rehighlight (dpyinfo) | |
6457 struct x_display_info *dpyinfo; | |
6458 { | |
6459 struct frame *old_highlight = dpyinfo->x_highlight_frame; | |
6460 | |
6461 if (dpyinfo->x_focus_frame) | |
6462 { | |
6463 dpyinfo->x_highlight_frame | |
6464 = ((GC_FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))) | |
6465 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)) | |
6466 : dpyinfo->x_focus_frame); | |
6467 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame)) | |
6468 { | |
6469 FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil; | |
6470 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame; | |
6471 } | |
6472 } | |
6473 else | |
6474 dpyinfo->x_highlight_frame = 0; | |
6475 | |
6476 if (dpyinfo->x_highlight_frame != old_highlight) | |
6477 { | |
6478 if (old_highlight) | |
6479 frame_unhighlight (old_highlight); | |
6480 if (dpyinfo->x_highlight_frame) | |
6481 frame_highlight (dpyinfo->x_highlight_frame); | |
6482 } | |
6483 } | |
6484 | |
6485 | |
6486 | |
6487 /* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */ | |
6488 | |
6489 #if 0 /* MAC_TODO */ | |
6490 /* Initialize mode_switch_bit and modifier_meaning. */ | |
6491 static void | |
6492 x_find_modifier_meanings (dpyinfo) | |
6493 struct x_display_info *dpyinfo; | |
6494 { | |
6495 int min_code, max_code; | |
6496 KeySym *syms; | |
6497 int syms_per_code; | |
6498 XModifierKeymap *mods; | |
6499 | |
6500 dpyinfo->meta_mod_mask = 0; | |
6501 dpyinfo->shift_lock_mask = 0; | |
6502 dpyinfo->alt_mod_mask = 0; | |
6503 dpyinfo->super_mod_mask = 0; | |
6504 dpyinfo->hyper_mod_mask = 0; | |
6505 | |
6506 #ifdef HAVE_X11R4 | |
6507 XDisplayKeycodes (dpyinfo->display, &min_code, &max_code); | |
6508 #else | |
6509 min_code = dpyinfo->display->min_keycode; | |
6510 max_code = dpyinfo->display->max_keycode; | |
6511 #endif | |
6512 | |
6513 syms = XGetKeyboardMapping (dpyinfo->display, | |
6514 min_code, max_code - min_code + 1, | |
6515 &syms_per_code); | |
6516 mods = XGetModifierMapping (dpyinfo->display); | |
6517 | |
6518 /* Scan the modifier table to see which modifier bits the Meta and | |
6519 Alt keysyms are on. */ | |
6520 { | |
6521 int row, col; /* The row and column in the modifier table. */ | |
6522 | |
6523 for (row = 3; row < 8; row++) | |
6524 for (col = 0; col < mods->max_keypermod; col++) | |
6525 { | |
6526 KeyCode code | |
6527 = mods->modifiermap[(row * mods->max_keypermod) + col]; | |
6528 | |
6529 /* Zeroes are used for filler. Skip them. */ | |
6530 if (code == 0) | |
6531 continue; | |
6532 | |
6533 /* Are any of this keycode's keysyms a meta key? */ | |
6534 { | |
6535 int code_col; | |
6536 | |
6537 for (code_col = 0; code_col < syms_per_code; code_col++) | |
6538 { | |
6539 int sym = syms[((code - min_code) * syms_per_code) + code_col]; | |
6540 | |
6541 switch (sym) | |
6542 { | |
6543 case XK_Meta_L: | |
6544 case XK_Meta_R: | |
6545 dpyinfo->meta_mod_mask |= (1 << row); | |
6546 break; | |
6547 | |
6548 case XK_Alt_L: | |
6549 case XK_Alt_R: | |
6550 dpyinfo->alt_mod_mask |= (1 << row); | |
6551 break; | |
6552 | |
6553 case XK_Hyper_L: | |
6554 case XK_Hyper_R: | |
6555 dpyinfo->hyper_mod_mask |= (1 << row); | |
6556 break; | |
6557 | |
6558 case XK_Super_L: | |
6559 case XK_Super_R: | |
6560 dpyinfo->super_mod_mask |= (1 << row); | |
6561 break; | |
6562 | |
6563 case XK_Shift_Lock: | |
6564 /* Ignore this if it's not on the lock modifier. */ | |
6565 if ((1 << row) == LockMask) | |
6566 dpyinfo->shift_lock_mask = LockMask; | |
6567 break; | |
6568 } | |
6569 } | |
6570 } | |
6571 } | |
6572 } | |
6573 | |
6574 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */ | |
6575 if (! dpyinfo->meta_mod_mask) | |
6576 { | |
6577 dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask; | |
6578 dpyinfo->alt_mod_mask = 0; | |
6579 } | |
6580 | |
6581 /* If some keys are both alt and meta, | |
6582 make them just meta, not alt. */ | |
6583 if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask) | |
6584 { | |
6585 dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask; | |
6586 } | |
6587 | |
6588 XFree ((char *) syms); | |
6589 XFreeModifiermap (mods); | |
6590 } | |
6591 | |
6592 #endif /* MAC_TODO */ | |
6593 | |
6594 /* Convert between the modifier bits X uses and the modifier bits | |
6595 Emacs uses. */ | |
6596 | |
6597 static unsigned int | |
6598 x_mac_to_emacs_modifiers (dpyinfo, state) | |
6599 struct x_display_info *dpyinfo; | |
6600 unsigned short state; | |
6601 { | |
6602 return (((state & shiftKey) ? shift_modifier : 0) | |
6603 | ((state & controlKey) ? ctrl_modifier : 0) | |
6604 | ((state & cmdKey) ? meta_modifier : 0) | |
6605 | ((state & optionKey) ? alt_modifier : 0)); | |
6606 } | |
6607 | |
6608 #if 0 /* MAC_TODO */ | |
6609 static unsigned short | |
6610 x_emacs_to_x_modifiers (dpyinfo, state) | |
6611 struct x_display_info *dpyinfo; | |
6612 unsigned int state; | |
6613 { | |
6614 return ( ((state & alt_modifier) ? dpyinfo->alt_mod_mask : 0) | |
6615 | ((state & super_modifier) ? dpyinfo->super_mod_mask : 0) | |
6616 | ((state & hyper_modifier) ? dpyinfo->hyper_mod_mask : 0) | |
6617 | ((state & shift_modifier) ? ShiftMask : 0) | |
6618 | ((state & ctrl_modifier) ? ControlMask : 0) | |
6619 | ((state & meta_modifier) ? dpyinfo->meta_mod_mask : 0)); | |
6620 } | |
6621 #endif /* MAC_TODO */ | |
6622 | |
6623 /* Convert a keysym to its name. */ | |
6624 | |
6625 char * | |
6626 x_get_keysym_name (keysym) | |
6627 int keysym; | |
6628 { | |
6629 char *value; | |
6630 | |
6631 BLOCK_INPUT; | |
6632 #if 0 | |
6633 value = XKeysymToString (keysym); | |
6634 #else | |
6635 value = 0; | |
6636 #endif | |
6637 UNBLOCK_INPUT; | |
6638 | |
6639 return value; | |
6640 } | |
6641 | |
6642 | |
6643 | |
6644 /* Mouse clicks and mouse movement. Rah. */ | |
6645 | |
6646 /* Given a pixel position (PIX_X, PIX_Y) on frame F, return glyph | |
6647 co-ordinates in (*X, *Y). Set *BOUNDS to the rectangle that the | |
6648 glyph at X, Y occupies, if BOUNDS != 0. If NOCLIP is non-zero, do | |
6649 not force the value into range. */ | |
6650 | |
6651 void | |
6652 pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip) | |
6653 FRAME_PTR f; | |
6654 register int pix_x, pix_y; | |
6655 register int *x, *y; | |
6656 Rect *bounds; | |
6657 int noclip; | |
6658 { | |
6659 /* Support tty mode: if Vwindow_system is nil, behave correctly. */ | |
6660 if (NILP (Vwindow_system)) | |
6661 { | |
6662 *x = pix_x; | |
6663 *y = pix_y; | |
6664 return; | |
6665 } | |
6666 | |
6667 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to round down | |
6668 even for negative values. */ | |
6669 if (pix_x < 0) | |
6670 pix_x -= FONT_WIDTH (FRAME_FONT (f)) - 1; | |
6671 if (pix_y < 0) | |
6672 pix_y -= (f)->output_data.mac->line_height - 1; | |
6673 | |
6674 pix_x = PIXEL_TO_CHAR_COL (f, pix_x); | |
6675 pix_y = PIXEL_TO_CHAR_ROW (f, pix_y); | |
6676 | |
6677 if (bounds) | |
6678 { | |
6679 bounds->left = CHAR_TO_PIXEL_COL (f, pix_x); | |
6680 bounds->top = CHAR_TO_PIXEL_ROW (f, pix_y); | |
6681 bounds->right = bounds->left + FONT_WIDTH (FRAME_FONT (f)) - 1; | |
6682 bounds->bottom = bounds->top + f->output_data.mac->line_height - 1; | |
6683 } | |
6684 | |
6685 if (!noclip) | |
6686 { | |
6687 if (pix_x < 0) | |
6688 pix_x = 0; | |
6689 else if (pix_x > FRAME_WINDOW_WIDTH (f)) | |
6690 pix_x = FRAME_WINDOW_WIDTH (f); | |
6691 | |
6692 if (pix_y < 0) | |
6693 pix_y = 0; | |
6694 else if (pix_y > f->height) | |
6695 pix_y = f->height; | |
6696 } | |
6697 | |
6698 *x = pix_x; | |
6699 *y = pix_y; | |
6700 } | |
6701 | |
6702 | |
6703 /* Given HPOS/VPOS in the current matrix of W, return corresponding | |
6704 frame-relative pixel positions in *FRAME_X and *FRAME_Y. If we | |
6705 can't tell the positions because W's display is not up to date, | |
6706 return 0. */ | |
6707 | |
6708 int | |
6709 glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y) | |
6710 struct window *w; | |
6711 int hpos, vpos; | |
6712 int *frame_x, *frame_y; | |
6713 { | |
6714 int success_p; | |
6715 | |
6716 xassert (hpos >= 0 && hpos < w->current_matrix->matrix_w); | |
6717 xassert (vpos >= 0 && vpos < w->current_matrix->matrix_h); | |
6718 | |
6719 if (display_completed) | |
6720 { | |
6721 struct glyph_row *row = MATRIX_ROW (w->current_matrix, vpos); | |
6722 struct glyph *glyph = row->glyphs[TEXT_AREA]; | |
6723 struct glyph *end = glyph + min (hpos, row->used[TEXT_AREA]); | |
6724 | |
6725 *frame_y = row->y; | |
6726 *frame_x = row->x; | |
6727 while (glyph < end) | |
6728 { | |
6729 *frame_x += glyph->pixel_width; | |
6730 ++glyph; | |
6731 } | |
6732 | |
6733 success_p = 1; | |
6734 } | |
6735 else | |
6736 { | |
6737 *frame_y = *frame_x = 0; | |
6738 success_p = 0; | |
6739 } | |
6740 | |
6741 *frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, *frame_y); | |
6742 *frame_x = WINDOW_TO_FRAME_PIXEL_X (w, *frame_x); | |
6743 return success_p; | |
6744 } | |
6745 | |
6746 | |
6747 /* Prepare a mouse-event in *RESULT for placement in the input queue. | |
6748 | |
6749 If the event is a button press, then note that we have grabbed | |
6750 the mouse. */ | |
6751 | |
6752 static Lisp_Object | |
6753 construct_mouse_click (result, event, f) | |
6754 struct input_event *result; | |
6755 EventRecord *event; | |
6756 struct frame *f; | |
6757 { | |
6758 Point mouseLoc; | |
6759 | |
6760 result->kind = mouse_click; | |
6761 result->code = 0; /* only one mouse button */ | |
6762 result->timestamp = event->when; | |
6763 result->modifiers = event->what == mouseDown ? down_modifier : up_modifier; | |
6764 | |
6765 mouseLoc = event->where; | |
6766 | |
6767 #if TARGET_API_MAC_CARBON | |
6768 SetPort (GetWindowPort (FRAME_MAC_WINDOW (f))); | |
6769 #else | |
6770 SetPort (FRAME_MAC_WINDOW (f)); | |
6771 #endif | |
6772 | |
6773 GlobalToLocal (&mouseLoc); | |
6774 XSETINT (result->x, mouseLoc.h); | |
6775 XSETINT (result->y, mouseLoc.v); | |
6776 | |
6777 XSETFRAME (result->frame_or_window, f); | |
6778 | |
6779 result->arg = Qnil; | |
6780 return Qnil; | |
6781 } | |
6782 | |
6783 | |
6784 /* Function to report a mouse movement to the mainstream Emacs code. | |
6785 The input handler calls this. | |
6786 | |
6787 We have received a mouse movement event, which is given in *event. | |
6788 If the mouse is over a different glyph than it was last time, tell | |
6789 the mainstream emacs code by setting mouse_moved. If not, ask for | |
6790 another motion event, so we can check again the next time it moves. */ | |
6791 | |
6792 static Point last_mouse_motion_position; | |
6793 static Lisp_Object last_mouse_motion_frame; | |
6794 | |
6795 static void | |
6796 note_mouse_movement (frame, pos) | |
6797 FRAME_PTR frame; | |
6798 Point *pos; | |
6799 { | |
6800 #if TARGET_API_MAC_CARBON | |
6801 Rect r; | |
6802 #endif | |
6803 | |
6804 last_mouse_movement_time = TickCount () * (1000 / 60); /* to milliseconds */ | |
6805 last_mouse_motion_position = *pos; | |
6806 XSETFRAME (last_mouse_motion_frame, frame); | |
6807 | |
6808 #if TARGET_API_MAC_CARBON | |
6809 if (!PtInRect (*pos, GetWindowPortBounds (FRAME_MAC_WINDOW (frame), &r))) | |
6810 #else | |
6811 if (!PtInRect (*pos, &FRAME_MAC_WINDOW (frame)->portRect)) | |
6812 #endif | |
6813 { | |
6814 frame->mouse_moved = 1; | |
6815 last_mouse_scroll_bar = Qnil; | |
6816 note_mouse_highlight (frame, -1, -1); | |
6817 } | |
6818 /* Has the mouse moved off the glyph it was on at the last sighting? */ | |
6819 else if (pos->h < last_mouse_glyph.left | |
6820 || pos->h >= last_mouse_glyph.right | |
6821 || pos->v < last_mouse_glyph.top | |
6822 || pos->v >= last_mouse_glyph.bottom) | |
6823 { | |
6824 frame->mouse_moved = 1; | |
6825 last_mouse_scroll_bar = Qnil; | |
6826 note_mouse_highlight (frame, pos->h, pos->v); | |
6827 } | |
6828 } | |
6829 | |
6830 /* This is used for debugging, to turn off note_mouse_highlight. */ | |
6831 | |
6832 int disable_mouse_highlight; | |
6833 | |
6834 | |
6835 | |
6836 /************************************************************************ | |
6837 Mouse Face | |
6838 ************************************************************************/ | |
6839 | |
6840 /* Find the glyph under window-relative coordinates X/Y in window W. | |
6841 Consider only glyphs from buffer text, i.e. no glyphs from overlay | |
6842 strings. Return in *HPOS and *VPOS the row and column number of | |
6843 the glyph found. Return in *AREA the glyph area containing X. | |
6844 Value is a pointer to the glyph found or null if X/Y is not on | |
6845 text, or we can't tell because W's current matrix is not up to | |
6846 date. */ | |
6847 | |
6848 static struct glyph * | |
6849 x_y_to_hpos_vpos (w, x, y, hpos, vpos, area, buffer_only_p) | |
6850 struct window *w; | |
6851 int x, y; | |
6852 int *hpos, *vpos, *area; | |
6853 int buffer_only_p; | |
6854 { | |
6855 struct glyph *glyph, *end; | |
6856 struct glyph_row *row = NULL; | |
6857 int x0, i, left_area_width; | |
6858 | |
6859 /* Find row containing Y. Give up if some row is not enabled. */ | |
6860 for (i = 0; i < w->current_matrix->nrows; ++i) | |
6861 { | |
6862 row = MATRIX_ROW (w->current_matrix, i); | |
6863 if (!row->enabled_p) | |
6864 return NULL; | |
6865 if (y >= row->y && y < MATRIX_ROW_BOTTOM_Y (row)) | |
6866 break; | |
6867 } | |
6868 | |
6869 *vpos = i; | |
6870 *hpos = 0; | |
6871 | |
6872 /* Give up if Y is not in the window. */ | |
6873 if (i == w->current_matrix->nrows) | |
6874 return NULL; | |
6875 | |
6876 /* Get the glyph area containing X. */ | |
6877 if (w->pseudo_window_p) | |
6878 { | |
6879 *area = TEXT_AREA; | |
6880 x0 = 0; | |
6881 } | |
6882 else | |
6883 { | |
6884 left_area_width = window_box_width (w, LEFT_MARGIN_AREA); | |
6885 if (x < left_area_width) | |
6886 { | |
6887 *area = LEFT_MARGIN_AREA; | |
6888 x0 = 0; | |
6889 } | |
6890 else if (x < left_area_width + window_box_width (w, TEXT_AREA)) | |
6891 { | |
6892 *area = TEXT_AREA; | |
6893 x0 = row->x + left_area_width; | |
6894 } | |
6895 else | |
6896 { | |
6897 *area = RIGHT_MARGIN_AREA; | |
6898 x0 = left_area_width + window_box_width (w, TEXT_AREA); | |
6899 } | |
6900 } | |
6901 | |
6902 /* Find glyph containing X. */ | |
6903 glyph = row->glyphs[*area]; | |
6904 end = glyph + row->used[*area]; | |
6905 while (glyph < end) | |
6906 { | |
6907 if (x < x0 + glyph->pixel_width) | |
6908 { | |
6909 if (w->pseudo_window_p) | |
6910 break; | |
6911 else if (!buffer_only_p || BUFFERP (glyph->object)) | |
6912 break; | |
6913 } | |
6914 | |
6915 x0 += glyph->pixel_width; | |
6916 ++glyph; | |
6917 } | |
6918 | |
6919 if (glyph == end) | |
6920 return NULL; | |
6921 | |
6922 *hpos = glyph - row->glyphs[*area]; | |
6923 return glyph; | |
6924 } | |
6925 | |
6926 | |
6927 /* Convert frame-relative x/y to coordinates relative to window W. | |
6928 Takes pseudo-windows into account. */ | |
6929 | |
6930 static void | |
6931 frame_to_window_pixel_xy (w, x, y) | |
6932 struct window *w; | |
6933 int *x, *y; | |
6934 { | |
6935 if (w->pseudo_window_p) | |
6936 { | |
6937 /* A pseudo-window is always full-width, and starts at the | |
6938 left edge of the frame, plus a frame border. */ | |
6939 struct frame *f = XFRAME (w->frame); | |
6940 *x -= FRAME_INTERNAL_BORDER_WIDTH_SAFE (f); | |
6941 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y); | |
6942 } | |
6943 else | |
6944 { | |
6945 *x = FRAME_TO_WINDOW_PIXEL_X (w, *x); | |
6946 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y); | |
6947 } | |
6948 } | |
6949 | |
6950 | |
6951 /* Take proper action when mouse has moved to the mode or header line of | |
6952 window W, x-position X. MODE_LINE_P non-zero means mouse is on the | |
6953 mode line. X is relative to the start of the text display area of | |
6954 W, so the width of fringes and scroll bars must be subtracted | |
6955 to get a position relative to the start of the mode line. */ | |
6956 | |
6957 static void | |
6958 note_mode_line_highlight (w, x, mode_line_p) | |
6959 struct window *w; | |
6960 int x, mode_line_p; | |
6961 { | |
6962 struct frame *f = XFRAME (w->frame); | |
6963 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); | |
6964 struct Cursor *cursor = dpyinfo->vertical_scroll_bar_cursor; | |
6965 struct glyph_row *row; | |
6966 | |
6967 if (mode_line_p) | |
6968 row = MATRIX_MODE_LINE_ROW (w->current_matrix); | |
6969 else | |
6970 row = MATRIX_HEADER_LINE_ROW (w->current_matrix); | |
6971 | |
6972 if (row->enabled_p) | |
6973 { | |
6974 struct glyph *glyph, *end; | |
6975 Lisp_Object help, map; | |
6976 int x0; | |
6977 | |
6978 /* Find the glyph under X. */ | |
6979 glyph = row->glyphs[TEXT_AREA]; | |
6980 end = glyph + row->used[TEXT_AREA]; | |
6981 x0 = - (FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f) | |
6982 + FRAME_X_LEFT_FRINGE_WIDTH (f)); | |
6983 | |
6984 while (glyph < end | |
6985 && x >= x0 + glyph->pixel_width) | |
6986 { | |
6987 x0 += glyph->pixel_width; | |
6988 ++glyph; | |
6989 } | |
6990 | |
6991 if (glyph < end | |
6992 && STRINGP (glyph->object) | |
6993 && XSTRING (glyph->object)->intervals | |
6994 && glyph->charpos >= 0 | |
6995 && glyph->charpos < XSTRING (glyph->object)->size) | |
6996 { | |
6997 /* If we're on a string with `help-echo' text property, | |
6998 arrange for the help to be displayed. This is done by | |
6999 setting the global variable help_echo to the help string. */ | |
7000 help = Fget_text_property (make_number (glyph->charpos), | |
7001 Qhelp_echo, glyph->object); | |
7002 if (!NILP (help)) | |
7003 { | |
7004 help_echo = help; | |
7005 XSETWINDOW (help_echo_window, w); | |
7006 help_echo_object = glyph->object; | |
7007 help_echo_pos = glyph->charpos; | |
7008 } | |
7009 | |
7010 /* Change the mouse pointer according to what is under X/Y. */ | |
7011 map = Fget_text_property (make_number (glyph->charpos), | |
7012 Qlocal_map, glyph->object); | |
7013 if (KEYMAPP (map)) | |
7014 cursor = f->output_data.mac->nontext_cursor; | |
7015 else | |
7016 { | |
7017 map = Fget_text_property (make_number (glyph->charpos), | |
7018 Qkeymap, glyph->object); | |
7019 if (KEYMAPP (map)) | |
7020 cursor = f->output_data.mac->nontext_cursor; | |
7021 } | |
7022 } | |
7023 } | |
7024 | |
7025 #if 0 /* MAC_TODO: mouse cursor */ | |
7026 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor); | |
7027 #endif | |
7028 } | |
7029 | |
7030 | |
7031 /* Take proper action when the mouse has moved to position X, Y on | |
7032 frame F as regards highlighting characters that have mouse-face | |
7033 properties. Also de-highlighting chars where the mouse was before. | |
7034 X and Y can be negative or out of range. */ | |
7035 | |
7036 static void | |
7037 note_mouse_highlight (f, x, y) | |
7038 struct frame *f; | |
7039 int x, y; | |
7040 { | |
7041 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); | |
7042 int portion; | |
7043 Lisp_Object window; | |
7044 struct window *w; | |
7045 struct buffer *b; | |
7046 | |
7047 #if 0 | |
7048 /* When a menu is active, don't highlight because this looks odd. */ | |
7049 if (popup_activated ()) | |
7050 return; | |
7051 #endif | |
7052 | |
7053 if (NILP (Vmouse_highlight) | |
7054 || !f->glyphs_initialized_p) | |
7055 return; | |
7056 | |
7057 dpyinfo->mouse_face_mouse_x = x; | |
7058 dpyinfo->mouse_face_mouse_y = y; | |
7059 dpyinfo->mouse_face_mouse_frame = f; | |
7060 | |
7061 if (dpyinfo->mouse_face_defer) | |
7062 return; | |
7063 | |
7064 if (gc_in_progress) | |
7065 { | |
7066 dpyinfo->mouse_face_deferred_gc = 1; | |
7067 return; | |
7068 } | |
7069 | |
7070 /* Which window is that in? */ | |
7071 window = window_from_coordinates (f, x, y, &portion, 1); | |
7072 | |
7073 /* If we were displaying active text in another window, clear that. */ | |
7074 if (! EQ (window, dpyinfo->mouse_face_window)) | |
7075 clear_mouse_face (dpyinfo); | |
7076 | |
7077 /* Not on a window -> return. */ | |
7078 if (!WINDOWP (window)) | |
7079 return; | |
7080 | |
7081 /* Reset help_echo. It will get recomputed below. */ | |
7082 help_echo = Qnil; | |
7083 | |
7084 /* Convert to window-relative pixel coordinates. */ | |
7085 w = XWINDOW (window); | |
7086 frame_to_window_pixel_xy (w, &x, &y); | |
7087 | |
7088 /* Handle tool-bar window differently since it doesn't display a | |
7089 buffer. */ | |
7090 if (EQ (window, f->tool_bar_window)) | |
7091 { | |
7092 note_tool_bar_highlight (f, x, y); | |
7093 return; | |
7094 } | |
7095 | |
7096 /* Mouse is on the mode or header line? */ | |
7097 if (portion == 1 || portion == 3) | |
7098 { | |
7099 note_mode_line_highlight (w, x, portion == 1); | |
7100 return; | |
7101 } | |
7102 #if 0 /* TODO: mouse cursor */ | |
7103 if (portion == 2) | |
7104 cursor = f->output_data.x->horizontal_drag_cursor; | |
7105 else | |
7106 cursor = f->output_data.x->text_cursor; | |
7107 #endif | |
7108 /* Are we in a window whose display is up to date? | |
7109 And verify the buffer's text has not changed. */ | |
7110 b = XBUFFER (w->buffer); | |
7111 if (/* Within text portion of the window. */ | |
7112 portion == 0 | |
7113 && EQ (w->window_end_valid, w->buffer) | |
7114 && XFASTINT (w->last_modified) == BUF_MODIFF (b) | |
7115 && XFASTINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b)) | |
7116 { | |
7117 int hpos, vpos, pos, i, area; | |
7118 struct glyph *glyph; | |
7119 Lisp_Object object; | |
7120 Lisp_Object mouse_face = Qnil, overlay = Qnil, position; | |
7121 Lisp_Object *overlay_vec = NULL; | |
7122 int len, noverlays; | |
7123 struct buffer *obuf; | |
7124 int obegv, ozv, same_region; | |
7125 | |
7126 /* Find the glyph under X/Y. */ | |
7127 glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area, 0); | |
7128 | |
7129 /* Clear mouse face if X/Y not over text. */ | |
7130 if (glyph == NULL | |
7131 || area != TEXT_AREA | |
7132 || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p) | |
7133 { | |
7134 clear_mouse_face (dpyinfo); | |
7135 /* TODO: mouse cursor */ | |
7136 goto set_cursor; | |
7137 } | |
7138 | |
7139 pos = glyph->charpos; | |
7140 object = glyph->object; | |
7141 if (!STRINGP (object) && !BUFFERP (object)) | |
7142 goto set_cursor; | |
7143 | |
7144 /* If we get an out-of-range value, return now; avoid an error. */ | |
7145 if (BUFFERP (object) && pos > BUF_Z (b)) | |
7146 goto set_cursor; | |
7147 | |
7148 /* Make the window's buffer temporarily current for | |
7149 overlays_at and compute_char_face. */ | |
7150 obuf = current_buffer; | |
7151 current_buffer = b; | |
7152 obegv = BEGV; | |
7153 ozv = ZV; | |
7154 BEGV = BEG; | |
7155 ZV = Z; | |
7156 | |
7157 /* Is this char mouse-active or does it have help-echo? */ | |
7158 position = make_number (pos); | |
7159 | |
7160 if (BUFFERP (object)) | |
7161 { | |
7162 /* Put all the overlays we want in a vector in overlay_vec. | |
7163 Store the length in len. If there are more than 10, make | |
7164 enough space for all, and try again. */ | |
7165 len = 10; | |
7166 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object)); | |
7167 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL, 0); | |
7168 if (noverlays > len) | |
7169 { | |
7170 len = noverlays; | |
7171 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object)); | |
7172 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL,0); | |
7173 } | |
7174 | |
7175 /* Sort overlays into increasing priority order. */ | |
7176 noverlays = sort_overlays (overlay_vec, noverlays, w); | |
7177 } | |
7178 else | |
7179 noverlays = 0; | |
7180 | |
7181 same_region = (EQ (window, dpyinfo->mouse_face_window) | |
7182 && vpos >= dpyinfo->mouse_face_beg_row | |
7183 && vpos <= dpyinfo->mouse_face_end_row | |
7184 && (vpos > dpyinfo->mouse_face_beg_row | |
7185 || hpos >= dpyinfo->mouse_face_beg_col) | |
7186 && (vpos < dpyinfo->mouse_face_end_row | |
7187 || hpos < dpyinfo->mouse_face_end_col | |
7188 || dpyinfo->mouse_face_past_end)); | |
7189 | |
7190 /* TODO: if (same_region) | |
7191 mouse cursor */ | |
7192 | |
7193 /* Check mouse-face highlighting. */ | |
7194 if (! same_region | |
7195 /* If there exists an overlay with mouse-face overlapping | |
7196 the one we are currently highlighting, we have to | |
7197 check if we enter the overlapping overlay, and then | |
7198 highlight that. */ | |
7199 || (OVERLAYP (dpyinfo->mouse_face_overlay) | |
7200 && mouse_face_overlay_overlaps (dpyinfo->mouse_face_overlay))) | |
7201 { | |
7202 /* Find the highest priority overlay that has a mouse-face | |
7203 property. */ | |
7204 overlay = Qnil; | |
7205 for (i = noverlays - 1; i >= 0 && NILP (overlay); --i) | |
7206 { | |
7207 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face); | |
7208 if (!NILP (mouse_face)) | |
7209 overlay = overlay_vec[i]; | |
7210 } | |
7211 | |
7212 /* If we're actually highlighting the same overlay as | |
7213 before, there's no need to do that again. */ | |
7214 if (!NILP (overlay) | |
7215 && EQ (overlay, dpyinfo->mouse_face_overlay)) | |
7216 goto check_help_echo; | |
7217 | |
7218 dpyinfo->mouse_face_overlay = overlay; | |
7219 | |
7220 /* Clear the display of the old active region, if any. */ | |
7221 clear_mouse_face (dpyinfo); | |
7222 /* TODO: mouse cursor changes. */ | |
7223 | |
7224 /* If no overlay applies, get a text property. */ | |
7225 if (NILP (overlay)) | |
7226 mouse_face = Fget_text_property (position, Qmouse_face, object); | |
7227 | |
7228 /* Handle the overlay case. */ | |
7229 if (!NILP (overlay)) | |
7230 { | |
7231 /* Find the range of text around this char that | |
7232 should be active. */ | |
7233 Lisp_Object before, after; | |
7234 int ignore; | |
7235 | |
7236 before = Foverlay_start (overlay); | |
7237 after = Foverlay_end (overlay); | |
7238 /* Record this as the current active region. */ | |
7239 fast_find_position (w, XFASTINT (before), | |
7240 &dpyinfo->mouse_face_beg_col, | |
7241 &dpyinfo->mouse_face_beg_row, | |
7242 &dpyinfo->mouse_face_beg_x, | |
7243 &dpyinfo->mouse_face_beg_y, Qnil); | |
7244 | |
7245 dpyinfo->mouse_face_past_end | |
7246 = !fast_find_position (w, XFASTINT (after), | |
7247 &dpyinfo->mouse_face_end_col, | |
7248 &dpyinfo->mouse_face_end_row, | |
7249 &dpyinfo->mouse_face_end_x, | |
7250 &dpyinfo->mouse_face_end_y, Qnil); | |
7251 dpyinfo->mouse_face_window = window; | |
7252 | |
7253 dpyinfo->mouse_face_face_id | |
7254 = face_at_buffer_position (w, pos, 0, 0, | |
7255 &ignore, pos + 1, 1); | |
7256 | |
7257 /* Display it as active. */ | |
7258 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE); | |
7259 /* TODO: mouse cursor changes. */ | |
7260 } | |
7261 /* Handle the text property case. */ | |
7262 else if (! NILP (mouse_face) && BUFFERP (object)) | |
7263 { | |
7264 /* Find the range of text around this char that | |
7265 should be active. */ | |
7266 Lisp_Object before, after, beginning, end; | |
7267 int ignore; | |
7268 | |
7269 beginning = Fmarker_position (w->start); | |
7270 end = make_number (BUF_Z (XBUFFER (object)) | |
7271 - XFASTINT (w->window_end_pos)); | |
7272 before | |
7273 = Fprevious_single_property_change (make_number (pos + 1), | |
7274 Qmouse_face, | |
7275 object, beginning); | |
7276 after | |
7277 = Fnext_single_property_change (position, Qmouse_face, | |
7278 object, end); | |
7279 | |
7280 /* Record this as the current active region. */ | |
7281 fast_find_position (w, XFASTINT (before), | |
7282 &dpyinfo->mouse_face_beg_col, | |
7283 &dpyinfo->mouse_face_beg_row, | |
7284 &dpyinfo->mouse_face_beg_x, | |
7285 &dpyinfo->mouse_face_beg_y, Qnil); | |
7286 dpyinfo->mouse_face_past_end | |
7287 = !fast_find_position (w, XFASTINT (after), | |
7288 &dpyinfo->mouse_face_end_col, | |
7289 &dpyinfo->mouse_face_end_row, | |
7290 &dpyinfo->mouse_face_end_x, | |
7291 &dpyinfo->mouse_face_end_y, Qnil); | |
7292 dpyinfo->mouse_face_window = window; | |
7293 | |
7294 if (BUFFERP (object)) | |
7295 dpyinfo->mouse_face_face_id | |
7296 = face_at_buffer_position (w, pos, 0, 0, | |
7297 &ignore, pos + 1, 1); | |
7298 | |
7299 /* Display it as active. */ | |
7300 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE); | |
7301 /* TODO: mouse cursor changes. */ | |
7302 } | |
7303 else if (!NILP (mouse_face) && STRINGP (object)) | |
7304 { | |
7305 Lisp_Object b, e; | |
7306 int ignore; | |
7307 | |
7308 b = Fprevious_single_property_change (make_number (pos + 1), | |
7309 Qmouse_face, | |
7310 object, Qnil); | |
7311 e = Fnext_single_property_change (position, Qmouse_face, | |
7312 object, Qnil); | |
7313 if (NILP (b)) | |
7314 b = make_number (0); | |
7315 if (NILP (e)) | |
7316 e = make_number (XSTRING (object)->size - 1); | |
7317 fast_find_string_pos (w, XINT (b), object, | |
7318 &dpyinfo->mouse_face_beg_col, | |
7319 &dpyinfo->mouse_face_beg_row, | |
7320 &dpyinfo->mouse_face_beg_x, | |
7321 &dpyinfo->mouse_face_beg_y, 0); | |
7322 fast_find_string_pos (w, XINT (e), object, | |
7323 &dpyinfo->mouse_face_end_col, | |
7324 &dpyinfo->mouse_face_end_row, | |
7325 &dpyinfo->mouse_face_end_x, | |
7326 &dpyinfo->mouse_face_end_y, 1); | |
7327 dpyinfo->mouse_face_past_end = 0; | |
7328 dpyinfo->mouse_face_window = window; | |
7329 dpyinfo->mouse_face_face_id | |
7330 = face_at_string_position (w, object, pos, 0, 0, 0, &ignore, | |
7331 glyph->face_id, 1); | |
7332 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE); | |
7333 /* TODO: mouse cursor changes. */ | |
7334 } | |
7335 else if (STRINGP (object) && NILP (mouse_face)) | |
7336 { | |
7337 /* A string which doesn't have mouse-face, but | |
7338 the text ``under'' it might have. */ | |
7339 struct glyph_row *r = MATRIX_ROW (w->current_matrix, vpos); | |
7340 int start = MATRIX_ROW_START_CHARPOS (r); | |
7341 | |
7342 pos = string_buffer_position (w, object, start); | |
7343 if (pos > 0) | |
7344 mouse_face = get_char_property_and_overlay (make_number (pos), | |
7345 Qmouse_face, | |
7346 w->buffer, | |
7347 &overlay); | |
7348 if (!NILP (mouse_face) && !NILP (overlay)) | |
7349 { | |
7350 Lisp_Object before = Foverlay_start (overlay); | |
7351 Lisp_Object after = Foverlay_end (overlay); | |
7352 int ignore; | |
7353 | |
7354 /* Note that we might not be able to find position | |
7355 BEFORE in the glyph matrix if the overlay is | |
7356 entirely covered by a `display' property. In | |
7357 this case, we overshoot. So let's stop in | |
7358 the glyph matrix before glyphs for OBJECT. */ | |
7359 fast_find_position (w, XFASTINT (before), | |
7360 &dpyinfo->mouse_face_beg_col, | |
7361 &dpyinfo->mouse_face_beg_row, | |
7362 &dpyinfo->mouse_face_beg_x, | |
7363 &dpyinfo->mouse_face_beg_y, | |
7364 object); | |
7365 | |
7366 dpyinfo->mouse_face_past_end | |
7367 = !fast_find_position (w, XFASTINT (after), | |
7368 &dpyinfo->mouse_face_end_col, | |
7369 &dpyinfo->mouse_face_end_row, | |
7370 &dpyinfo->mouse_face_end_x, | |
7371 &dpyinfo->mouse_face_end_y, | |
7372 Qnil); | |
7373 dpyinfo->mouse_face_window = window; | |
7374 dpyinfo->mouse_face_face_id | |
7375 = face_at_buffer_position (w, pos, 0, 0, | |
7376 &ignore, pos + 1, 1); | |
7377 | |
7378 /* Display it as active. */ | |
7379 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE); | |
7380 /* TODO: mouse cursor changes. */ | |
7381 } | |
7382 } | |
7383 } | |
7384 | |
7385 check_help_echo: | |
7386 | |
7387 /* Look for a `help-echo' property. */ | |
7388 { | |
7389 Lisp_Object help, overlay; | |
7390 | |
7391 /* Check overlays first. */ | |
7392 help = overlay = Qnil; | |
7393 for (i = noverlays - 1; i >= 0 && NILP (help); --i) | |
7394 { | |
7395 overlay = overlay_vec[i]; | |
7396 help = Foverlay_get (overlay, Qhelp_echo); | |
7397 } | |
7398 | |
7399 if (!NILP (help)) | |
7400 { | |
7401 help_echo = help; | |
7402 help_echo_window = window; | |
7403 help_echo_object = overlay; | |
7404 help_echo_pos = pos; | |
7405 } | |
7406 else | |
7407 { | |
7408 Lisp_Object object = glyph->object; | |
7409 int charpos = glyph->charpos; | |
7410 | |
7411 /* Try text properties. */ | |
7412 if (STRINGP (object) | |
7413 && charpos >= 0 | |
7414 && charpos < XSTRING (object)->size) | |
7415 { | |
7416 help = Fget_text_property (make_number (charpos), | |
7417 Qhelp_echo, object); | |
7418 if (NILP (help)) | |
7419 { | |
7420 /* If the string itself doesn't specify a help-echo, | |
7421 see if the buffer text ``under'' it does. */ | |
7422 struct glyph_row *r | |
7423 = MATRIX_ROW (w->current_matrix, vpos); | |
7424 int start = MATRIX_ROW_START_CHARPOS (r); | |
7425 int pos = string_buffer_position (w, object, start); | |
7426 if (pos > 0) | |
7427 { | |
7428 help = Fget_char_property (make_number (pos), | |
7429 Qhelp_echo, w->buffer); | |
7430 if (!NILP (help)) | |
7431 { | |
7432 charpos = pos; | |
7433 object = w->buffer; | |
7434 } | |
7435 } | |
7436 } | |
7437 } | |
7438 else if (BUFFERP (object) | |
7439 && charpos >= BEGV | |
7440 && charpos < ZV) | |
7441 help = Fget_text_property (make_number (charpos), Qhelp_echo, | |
7442 object); | |
7443 | |
7444 if (!NILP (help)) | |
7445 { | |
7446 help_echo = help; | |
7447 help_echo_window = window; | |
7448 help_echo_object = object; | |
7449 help_echo_pos = charpos; | |
7450 } | |
7451 } | |
7452 } | |
7453 | |
7454 BEGV = obegv; | |
7455 ZV = ozv; | |
7456 current_buffer = obuf; | |
7457 } | |
7458 | |
7459 set_cursor: | |
7460 /* TODO: mouse cursor changes. */ | |
7461 ; | |
7462 } | |
7463 | |
7464 static void | |
7465 redo_mouse_highlight () | |
7466 { | |
7467 if (!NILP (last_mouse_motion_frame) | |
7468 && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame))) | |
7469 note_mouse_highlight (XFRAME (last_mouse_motion_frame), | |
7470 last_mouse_motion_position.h, | |
7471 last_mouse_motion_position.v); | |
7472 } | |
7473 | |
7474 | |
7475 | |
7476 /*********************************************************************** | |
7477 Tool-bars | |
7478 ***********************************************************************/ | |
7479 | |
7480 static int x_tool_bar_item P_ ((struct frame *, int, int, | |
7481 struct glyph **, int *, int *, int *)); | |
7482 | |
7483 /* Tool-bar item index of the item on which a mouse button was pressed | |
7484 or -1. */ | |
7485 | |
7486 static int last_tool_bar_item; | |
7487 | |
7488 | |
7489 /* Get information about the tool-bar item at position X/Y on frame F. | |
7490 Return in *GLYPH a pointer to the glyph of the tool-bar item in | |
7491 the current matrix of the tool-bar window of F, or NULL if not | |
7492 on a tool-bar item. Return in *PROP_IDX the index of the tool-bar | |
7493 item in F->current_tool_bar_items. Value is | |
7494 | |
7495 -1 if X/Y is not on a tool-bar item | |
7496 0 if X/Y is on the same item that was highlighted before. | |
7497 1 otherwise. */ | |
7498 | |
7499 static int | |
7500 x_tool_bar_item (f, x, y, glyph, hpos, vpos, prop_idx) | |
7501 struct frame *f; | |
7502 int x, y; | |
7503 struct glyph **glyph; | |
7504 int *hpos, *vpos, *prop_idx; | |
7505 { | |
7506 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); | |
7507 struct window *w = XWINDOW (f->tool_bar_window); | |
7508 int area; | |
7509 | |
7510 /* Find the glyph under X/Y. */ | |
7511 *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area, 0); | |
7512 if (*glyph == NULL) | |
7513 return -1; | |
7514 | |
7515 /* Get the start of this tool-bar item's properties in | |
7516 f->current_tool_bar_items. */ | |
7517 if (!tool_bar_item_info (f, *glyph, prop_idx)) | |
7518 return -1; | |
7519 | |
7520 /* Is mouse on the highlighted item? */ | |
7521 if (EQ (f->tool_bar_window, dpyinfo->mouse_face_window) | |
7522 && *vpos >= dpyinfo->mouse_face_beg_row | |
7523 && *vpos <= dpyinfo->mouse_face_end_row | |
7524 && (*vpos > dpyinfo->mouse_face_beg_row | |
7525 || *hpos >= dpyinfo->mouse_face_beg_col) | |
7526 && (*vpos < dpyinfo->mouse_face_end_row | |
7527 || *hpos < dpyinfo->mouse_face_end_col | |
7528 || dpyinfo->mouse_face_past_end)) | |
7529 return 0; | |
7530 | |
7531 return 1; | |
7532 } | |
7533 | |
7534 | |
7535 /* Handle mouse button event on the tool-bar of frame F, at | |
7536 frame-relative coordinates X/Y. EVENT_TYPE is either ButtionPress | |
7537 or ButtonRelase. */ | |
7538 | |
7539 static void | |
7540 x_handle_tool_bar_click (f, button_event) | |
7541 struct frame *f; | |
7542 EventRecord *button_event; | |
7543 { | |
7544 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); | |
7545 struct window *w = XWINDOW (f->tool_bar_window); | |
7546 int hpos, vpos, prop_idx; | |
7547 struct glyph *glyph; | |
7548 Lisp_Object enabled_p; | |
7549 int x = button_event->where.h; | |
7550 int y = button_event->where.v; | |
7551 | |
7552 /* If not on the highlighted tool-bar item, return. */ | |
7553 frame_to_window_pixel_xy (w, &x, &y); | |
7554 if (x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx) != 0) | |
7555 return; | |
7556 | |
7557 /* If item is disabled, do nothing. */ | |
7558 enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P); | |
7559 if (NILP (enabled_p)) | |
7560 return; | |
7561 | |
7562 if (button_event->what == mouseDown) | |
7563 { | |
7564 /* Show item in pressed state. */ | |
7565 show_mouse_face (dpyinfo, DRAW_IMAGE_SUNKEN); | |
7566 dpyinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN; | |
7567 last_tool_bar_item = prop_idx; | |
7568 } | |
7569 else | |
7570 { | |
7571 Lisp_Object key, frame; | |
7572 struct input_event event; | |
7573 | |
7574 /* Show item in released state. */ | |
7575 show_mouse_face (dpyinfo, DRAW_IMAGE_RAISED); | |
7576 dpyinfo->mouse_face_image_state = DRAW_IMAGE_RAISED; | |
7577 | |
7578 key = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_KEY); | |
7579 | |
7580 XSETFRAME (frame, f); | |
7581 event.kind = TOOL_BAR_EVENT; | |
7582 event.frame_or_window = frame; | |
7583 event.arg = frame; | |
7584 kbd_buffer_store_event (&event); | |
7585 | |
7586 event.kind = TOOL_BAR_EVENT; | |
7587 event.frame_or_window = frame; | |
7588 event.arg = key; | |
7589 event.modifiers = x_mac_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f), | |
7590 button_event->modifiers); | |
7591 kbd_buffer_store_event (&event); | |
7592 last_tool_bar_item = -1; | |
7593 } | |
7594 } | |
7595 | |
7596 | |
7597 /* Possibly highlight a tool-bar item on frame F when mouse moves to | |
7598 tool-bar window-relative coordinates X/Y. Called from | |
7599 note_mouse_highlight. */ | |
7600 | |
7601 static void | |
7602 note_tool_bar_highlight (f, x, y) | |
7603 struct frame *f; | |
7604 int x, y; | |
7605 { | |
7606 Lisp_Object window = f->tool_bar_window; | |
7607 struct window *w = XWINDOW (window); | |
7608 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); | |
7609 int hpos, vpos; | |
7610 struct glyph *glyph; | |
7611 struct glyph_row *row; | |
7612 int i; | |
7613 Lisp_Object enabled_p; | |
7614 int prop_idx; | |
7615 enum draw_glyphs_face draw = DRAW_IMAGE_RAISED; | |
7616 int mouse_down_p, rc; | |
7617 | |
7618 /* Function note_mouse_highlight is called with negative x(y | |
7619 values when mouse moves outside of the frame. */ | |
7620 if (x <= 0 || y <= 0) | |
7621 { | |
7622 clear_mouse_face (dpyinfo); | |
7623 return; | |
7624 } | |
7625 | |
7626 rc = x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx); | |
7627 if (rc < 0) | |
7628 { | |
7629 /* Not on tool-bar item. */ | |
7630 clear_mouse_face (dpyinfo); | |
7631 return; | |
7632 } | |
7633 else if (rc == 0) | |
7634 /* On same tool-bar item as before. */ | |
7635 goto set_help_echo; | |
7636 | |
7637 clear_mouse_face (dpyinfo); | |
7638 | |
7639 /* Mouse is down, but on different tool-bar item? */ | |
7640 mouse_down_p = (dpyinfo->grabbed | |
7641 && f == last_mouse_frame | |
7642 && FRAME_LIVE_P (f)); | |
7643 if (mouse_down_p | |
7644 && last_tool_bar_item != prop_idx) | |
7645 return; | |
7646 | |
7647 dpyinfo->mouse_face_image_state = DRAW_NORMAL_TEXT; | |
7648 draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED; | |
7649 | |
7650 /* If tool-bar item is not enabled, don't highlight it. */ | |
7651 enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P); | |
7652 if (!NILP (enabled_p)) | |
7653 { | |
7654 /* Compute the x-position of the glyph. In front and past the | |
7655 image is a space. We include this is the highlighted area. */ | |
7656 row = MATRIX_ROW (w->current_matrix, vpos); | |
7657 for (i = x = 0; i < hpos; ++i) | |
7658 x += row->glyphs[TEXT_AREA][i].pixel_width; | |
7659 | |
7660 /* Record this as the current active region. */ | |
7661 dpyinfo->mouse_face_beg_col = hpos; | |
7662 dpyinfo->mouse_face_beg_row = vpos; | |
7663 dpyinfo->mouse_face_beg_x = x; | |
7664 dpyinfo->mouse_face_beg_y = row->y; | |
7665 dpyinfo->mouse_face_past_end = 0; | |
7666 | |
7667 dpyinfo->mouse_face_end_col = hpos + 1; | |
7668 dpyinfo->mouse_face_end_row = vpos; | |
7669 dpyinfo->mouse_face_end_x = x + glyph->pixel_width; | |
7670 dpyinfo->mouse_face_end_y = row->y; | |
7671 dpyinfo->mouse_face_window = window; | |
7672 dpyinfo->mouse_face_face_id = TOOL_BAR_FACE_ID; | |
7673 | |
7674 /* Display it as active. */ | |
7675 show_mouse_face (dpyinfo, draw); | |
7676 dpyinfo->mouse_face_image_state = draw; | |
7677 } | |
7678 | |
7679 set_help_echo: | |
7680 | |
7681 /* Set help_echo to a help string.to display for this tool-bar item. | |
7682 XTread_socket does the rest. */ | |
7683 help_echo_object = help_echo_window = Qnil; | |
7684 help_echo_pos = -1; | |
7685 help_echo = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_HELP); | |
7686 if (NILP (help_echo)) | |
7687 help_echo = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_CAPTION); | |
7688 } | |
7689 | |
7690 | |
7691 | |
7692 /* Find the glyph matrix position of buffer position CHARPOS in window | |
7693 *W. HPOS, *VPOS, *X, and *Y are set to the positions found. W's | |
7694 current glyphs must be up to date. If CHARPOS is above window | |
7695 start return (0, 0, 0, 0). If CHARPOS is after end of W, return end | |
7696 of last line in W. In the row containing CHARPOS, stop before glyphs | |
7697 having STOP as object. */ | |
7698 | |
7699 #if 0 /* This is a version of fast_find_position that's more correct | |
7700 in the presence of hscrolling, for example. I didn't install | |
7701 it right away because the problem fixed is minor, it failed | |
7702 in 20.x as well, and I think it's too risky to install | |
7703 so near the release of 21.1. 2001-09-25 gerd. */ | |
7704 | |
7705 static int | |
7706 fast_find_position (w, charpos, hpos, vpos, x, y, stop) | |
7707 struct window *w; | |
7708 int charpos; | |
7709 int *hpos, *vpos, *x, *y; | |
7710 Lisp_Object stop; | |
7711 { | |
7712 struct glyph_row *row, *first; | |
7713 struct glyph *glyph, *end; | |
7714 int i, past_end = 0; | |
7715 | |
7716 first = MATRIX_FIRST_TEXT_ROW (w->current_matrix); | |
7717 row = row_containing_pos (w, charpos, first, NULL, 0); | |
7718 if (row == NULL) | |
7719 { | |
7720 if (charpos < MATRIX_ROW_START_CHARPOS (first)) | |
7721 { | |
7722 *x = *y = *hpos = *vpos = 0; | |
7723 return 0; | |
7724 } | |
7725 else | |
7726 { | |
7727 row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos)); | |
7728 past_end = 1; | |
7729 } | |
7730 } | |
7731 | |
7732 *x = row->x; | |
7733 *y = row->y; | |
7734 *vpos = MATRIX_ROW_VPOS (row, w->current_matrix); | |
7735 | |
7736 glyph = row->glyphs[TEXT_AREA]; | |
7737 end = glyph + row->used[TEXT_AREA]; | |
7738 | |
7739 /* Skip over glyphs not having an object at the start of the row. | |
7740 These are special glyphs like truncation marks on terminal | |
7741 frames. */ | |
7742 if (row->displays_text_p) | |
7743 while (glyph < end | |
7744 && INTEGERP (glyph->object) | |
7745 && !EQ (stop, glyph->object) | |
7746 && glyph->charpos < 0) | |
7747 { | |
7748 *x += glyph->pixel_width; | |
7749 ++glyph; | |
7750 } | |
7751 | |
7752 while (glyph < end | |
7753 && !INTEGERP (glyph->object) | |
7754 && !EQ (stop, glyph->object) | |
7755 && (!BUFFERP (glyph->object) | |
7756 || glyph->charpos < charpos)) | |
7757 { | |
7758 *x += glyph->pixel_width; | |
7759 ++glyph; | |
7760 } | |
7761 | |
7762 *hpos = glyph - row->glyphs[TEXT_AREA]; | |
7763 return past_end; | |
7764 } | |
7765 | |
7766 #else /* not 0 */ | |
7767 | |
7768 static int | |
7769 fast_find_position (w, pos, hpos, vpos, x, y, stop) | |
7770 struct window *w; | |
7771 int pos; | |
7772 int *hpos, *vpos, *x, *y; | |
7773 Lisp_Object stop; | |
7774 { | |
7775 int i; | |
7776 int lastcol; | |
7777 int maybe_next_line_p = 0; | |
7778 int line_start_position; | |
7779 int yb = window_text_bottom_y (w); | |
7780 struct glyph_row *row, *best_row; | |
7781 int row_vpos, best_row_vpos; | |
7782 int current_x; | |
7783 | |
7784 row = best_row = MATRIX_FIRST_TEXT_ROW (w->current_matrix); | |
7785 row_vpos = best_row_vpos = MATRIX_ROW_VPOS (row, w->current_matrix); | |
7786 | |
7787 while (row->y < yb) | |
7788 { | |
7789 if (row->used[TEXT_AREA]) | |
7790 line_start_position = row->glyphs[TEXT_AREA]->charpos; | |
7791 else | |
7792 line_start_position = 0; | |
7793 | |
7794 if (line_start_position > pos) | |
7795 break; | |
7796 /* If the position sought is the end of the buffer, | |
7797 don't include the blank lines at the bottom of the window. */ | |
7798 else if (line_start_position == pos | |
7799 && pos == BUF_ZV (XBUFFER (w->buffer))) | |
7800 { | |
7801 maybe_next_line_p = 1; | |
7802 break; | |
7803 } | |
7804 else if (line_start_position > 0) | |
7805 { | |
7806 best_row = row; | |
7807 best_row_vpos = row_vpos; | |
7808 } | |
7809 | |
7810 if (row->y + row->height >= yb) | |
7811 break; | |
7812 | |
7813 ++row; | |
7814 ++row_vpos; | |
7815 } | |
7816 | |
7817 /* Find the right column within BEST_ROW. */ | |
7818 lastcol = 0; | |
7819 current_x = best_row->x; | |
7820 for (i = 0; i < best_row->used[TEXT_AREA]; i++) | |
7821 { | |
7822 struct glyph *glyph = best_row->glyphs[TEXT_AREA] + i; | |
7823 int charpos = glyph->charpos; | |
7824 | |
7825 if (BUFFERP (glyph->object)) | |
7826 { | |
7827 if (charpos == pos) | |
7828 { | |
7829 *hpos = i; | |
7830 *vpos = best_row_vpos; | |
7831 *x = current_x; | |
7832 *y = best_row->y; | |
7833 return 1; | |
7834 } | |
7835 else if (charpos > pos) | |
7836 break; | |
7837 } | |
7838 else if (EQ (glyph->object, stop)) | |
7839 break; | |
7840 | |
7841 if (charpos > 0) | |
7842 lastcol = i; | |
7843 current_x += glyph->pixel_width; | |
7844 } | |
7845 | |
7846 /* If we're looking for the end of the buffer, | |
7847 and we didn't find it in the line we scanned, | |
7848 use the start of the following line. */ | |
7849 if (maybe_next_line_p) | |
7850 { | |
7851 ++best_row; | |
7852 ++best_row_vpos; | |
7853 lastcol = 0; | |
7854 current_x = best_row->x; | |
7855 } | |
7856 | |
7857 *vpos = best_row_vpos; | |
7858 *hpos = lastcol + 1; | |
7859 *x = current_x; | |
7860 *y = best_row->y; | |
7861 return 0; | |
7862 } | |
7863 | |
7864 #endif /* not 0 */ | |
7865 | |
7866 | |
7867 /* Find the position of the glyph for position POS in OBJECT in | |
7868 window W's current matrix, and return in *X/*Y the pixel | |
7869 coordinates, and return in *HPOS/*VPOS the column/row of the glyph. | |
7870 | |
7871 RIGHT_P non-zero means return the position of the right edge of the | |
7872 glyph, RIGHT_P zero means return the left edge position. | |
7873 | |
7874 If no glyph for POS exists in the matrix, return the position of | |
7875 the glyph with the next smaller position that is in the matrix, if | |
7876 RIGHT_P is zero. If RIGHT_P is non-zero, and no glyph for POS | |
7877 exists in the matrix, return the position of the glyph with the | |
7878 next larger position in OBJECT. | |
7879 | |
7880 Value is non-zero if a glyph was found. */ | |
7881 | |
7882 static int | |
7883 fast_find_string_pos (w, pos, object, hpos, vpos, x, y, right_p) | |
7884 struct window *w; | |
7885 int pos; | |
7886 Lisp_Object object; | |
7887 int *hpos, *vpos, *x, *y; | |
7888 int right_p; | |
7889 { | |
7890 int yb = window_text_bottom_y (w); | |
7891 struct glyph_row *r; | |
7892 struct glyph *best_glyph = NULL; | |
7893 struct glyph_row *best_row = NULL; | |
7894 int best_x = 0; | |
7895 | |
7896 for (r = MATRIX_FIRST_TEXT_ROW (w->current_matrix); | |
7897 r->enabled_p && r->y < yb; | |
7898 ++r) | |
7899 { | |
7900 struct glyph *g = r->glyphs[TEXT_AREA]; | |
7901 struct glyph *e = g + r->used[TEXT_AREA]; | |
7902 int gx; | |
7903 | |
7904 for (gx = r->x; g < e; gx += g->pixel_width, ++g) | |
7905 if (EQ (g->object, object)) | |
7906 { | |
7907 if (g->charpos == pos) | |
7908 { | |
7909 best_glyph = g; | |
7910 best_x = gx; | |
7911 best_row = r; | |
7912 goto found; | |
7913 } | |
7914 else if (best_glyph == NULL | |
7915 || ((abs (g->charpos - pos) | |
7916 < abs (best_glyph->charpos - pos)) | |
7917 && (right_p | |
7918 ? g->charpos < pos | |
7919 : g->charpos > pos))) | |
7920 { | |
7921 best_glyph = g; | |
7922 best_x = gx; | |
7923 best_row = r; | |
7924 } | |
7925 } | |
7926 } | |
7927 | |
7928 found: | |
7929 | |
7930 if (best_glyph) | |
7931 { | |
7932 *x = best_x; | |
7933 *hpos = best_glyph - best_row->glyphs[TEXT_AREA]; | |
7934 | |
7935 if (right_p) | |
7936 { | |
7937 *x += best_glyph->pixel_width; | |
7938 ++*hpos; | |
7939 } | |
7940 | |
7941 *y = best_row->y; | |
7942 *vpos = best_row - w->current_matrix->rows; | |
7943 } | |
7944 | |
7945 return best_glyph != NULL; | |
7946 } | |
7947 | |
7948 | |
7949 /* Display the active region described by mouse_face_* | |
7950 in its mouse-face if HL > 0, in its normal face if HL = 0. */ | |
7951 | |
7952 static void | |
7953 show_mouse_face (dpyinfo, draw) | |
7954 struct mac_display_info *dpyinfo; | |
7955 enum draw_glyphs_face draw; | |
7956 { | |
7957 struct window *w = XWINDOW (dpyinfo->mouse_face_window); | |
7958 struct frame *f = XFRAME (WINDOW_FRAME (w)); | |
7959 | |
7960 if (/* If window is in the process of being destroyed, don't bother | |
7961 to do anything. */ | |
7962 w->current_matrix != NULL | |
7963 /* Don't update mouse highlight if hidden */ | |
7964 && (draw != DRAW_MOUSE_FACE || !dpyinfo->mouse_face_hidden) | |
7965 /* Recognize when we are called to operate on rows that don't exist | |
7966 anymore. This can happen when a window is split. */ | |
7967 && dpyinfo->mouse_face_end_row < w->current_matrix->nrows) | |
7968 { | |
7969 int phys_cursor_on_p = w->phys_cursor_on_p; | |
7970 struct glyph_row *row, *first, *last; | |
7971 | |
7972 first = MATRIX_ROW (w->current_matrix, dpyinfo->mouse_face_beg_row); | |
7973 last = MATRIX_ROW (w->current_matrix, dpyinfo->mouse_face_end_row); | |
7974 | |
7975 for (row = first; row <= last && row->enabled_p; ++row) | |
7976 { | |
7977 int start_hpos, end_hpos, start_x; | |
7978 | |
7979 /* For all but the first row, the highlight starts at column 0. */ | |
7980 if (row == first) | |
7981 { | |
7982 start_hpos = dpyinfo->mouse_face_beg_col; | |
7983 start_x = dpyinfo->mouse_face_beg_x; | |
7984 } | |
7985 else | |
7986 { | |
7987 start_hpos = 0; | |
7988 start_x = 0; | |
7989 } | |
7990 | |
7991 if (row == last) | |
7992 end_hpos = dpyinfo->mouse_face_end_col; | |
7993 else | |
7994 end_hpos = row->used[TEXT_AREA]; | |
7995 | |
7996 if (end_hpos > start_hpos) | |
7997 { | |
7998 x_draw_glyphs (w, start_x, row, TEXT_AREA, | |
7999 start_hpos, end_hpos, draw, 0); | |
8000 | |
8001 row->mouse_face_p | |
8002 = draw == DRAW_MOUSE_FACE || draw == DRAW_IMAGE_RAISED; | |
8003 } | |
8004 } | |
8005 | |
8006 /* When we've written over the cursor, arrange for it to | |
8007 be displayed again. */ | |
8008 if (phys_cursor_on_p && !w->phys_cursor_on_p) | |
8009 x_display_cursor (w, 1, | |
8010 w->phys_cursor.hpos, w->phys_cursor.vpos, | |
8011 w->phys_cursor.x, w->phys_cursor.y); | |
8012 } | |
8013 | |
8014 #if 0 /* MAC_TODO: mouse cursor */ | |
8015 /* Change the mouse cursor. */ | |
8016 if (draw == DRAW_NORMAL_TEXT) | |
8017 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), | |
8018 f->output_data.x->text_cursor); | |
8019 else if (draw == DRAW_MOUSE_FACE) | |
8020 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), | |
8021 f->output_data.x->cross_cursor); | |
8022 else | |
8023 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), | |
8024 f->output_data.x->nontext_cursor); | |
8025 #endif | |
8026 } | |
8027 | |
8028 /* Clear out the mouse-highlighted active region. | |
8029 Redraw it un-highlighted first. */ | |
8030 | |
8031 static int | |
8032 clear_mouse_face (dpyinfo) | |
8033 struct mac_display_info *dpyinfo; | |
8034 { | |
8035 int cleared = 0; | |
8036 | |
8037 if (! NILP (dpyinfo->mouse_face_window)) | |
8038 { | |
8039 show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT); | |
8040 cleared = 1; | |
8041 } | |
8042 | |
8043 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1; | |
8044 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1; | |
8045 dpyinfo->mouse_face_window = Qnil; | |
8046 dpyinfo->mouse_face_overlay = Qnil; | |
8047 return cleared; | |
8048 } | |
8049 | |
8050 | |
8051 /* Clear any mouse-face on window W. This function is part of the | |
8052 redisplay interface, and is called from try_window_id and similar | |
8053 functions to ensure the mouse-highlight is off. */ | |
8054 | |
8055 static void | |
8056 x_clear_mouse_face (w) | |
8057 struct window *w; | |
8058 { | |
8059 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (XFRAME (w->frame)); | |
8060 Lisp_Object window; | |
8061 | |
8062 BLOCK_INPUT; | |
8063 XSETWINDOW (window, w); | |
8064 if (EQ (window, dpyinfo->mouse_face_window)) | |
8065 clear_mouse_face (dpyinfo); | |
8066 UNBLOCK_INPUT; | |
8067 } | |
8068 | |
8069 | |
8070 /* Just discard the mouse face information for frame F, if any. | |
8071 This is used when the size of F is changed. */ | |
8072 | |
8073 void | |
8074 cancel_mouse_face (f) | |
8075 FRAME_PTR f; | |
8076 { | |
8077 Lisp_Object window; | |
8078 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); | |
8079 | |
8080 window = dpyinfo->mouse_face_window; | |
8081 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f) | |
8082 { | |
8083 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1; | |
8084 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1; | |
8085 dpyinfo->mouse_face_window = Qnil; | |
8086 } | |
8087 } | |
8088 | |
8089 static struct scroll_bar *x_window_to_scroll_bar (); | |
8090 static void x_scroll_bar_report_motion (); | |
8091 static void x_check_fullscreen P_ ((struct frame *)); | |
8092 static void x_check_fullscreen_move P_ ((struct frame *)); | |
8093 static int glyph_rect P_ ((struct frame *f, int, int, Rect *)); | |
8094 | |
8095 | |
8096 /* Try to determine frame pixel position and size of the glyph under | |
8097 frame pixel coordinates X/Y on frame F . Return the position and | |
8098 size in *RECT. Value is non-zero if we could compute these | |
8099 values. */ | |
8100 | |
8101 static int | |
8102 glyph_rect (f, x, y, rect) | |
8103 struct frame *f; | |
8104 int x, y; | |
8105 Rect *rect; | |
8106 { | |
8107 Lisp_Object window; | |
8108 int part; | |
8109 | |
8110 window = window_from_coordinates (f, x, y, &part, 0); | |
8111 if (!NILP (window)) | |
8112 { | |
8113 struct window *w = XWINDOW (window); | |
8114 struct glyph_row *r = MATRIX_FIRST_TEXT_ROW (w->current_matrix); | |
8115 struct glyph_row *end = r + w->current_matrix->nrows - 1; | |
8116 | |
8117 frame_to_window_pixel_xy (w, &x, &y); | |
8118 | |
8119 for (; r < end && r->enabled_p; ++r) | |
8120 if (r->y <= y && r->y + r->height > y) | |
8121 { | |
8122 /* Found the row at y. */ | |
8123 struct glyph *g = r->glyphs[TEXT_AREA]; | |
8124 struct glyph *end = g + r->used[TEXT_AREA]; | |
8125 int gx; | |
8126 | |
8127 rect->top = WINDOW_TO_FRAME_PIXEL_Y (w, r->y); | |
8128 rect->bottom = rect->top + r->height; | |
8129 | |
8130 if (x < r->x) | |
8131 { | |
8132 /* x is to the left of the first glyph in the row. */ | |
8133 rect->left = XINT (w->left); | |
8134 rect->right = WINDOW_TO_FRAME_PIXEL_X (w, r->x); | |
8135 return 1; | |
8136 } | |
8137 | |
8138 for (gx = r->x; g < end; gx += g->pixel_width, ++g) | |
8139 if (gx <= x && gx + g->pixel_width > x) | |
8140 { | |
8141 /* x is on a glyph. */ | |
8142 rect->left = WINDOW_TO_FRAME_PIXEL_X (w, gx); | |
8143 rect->right = rect->left + g->pixel_width; | |
8144 return 1; | |
8145 } | |
8146 | |
8147 /* x is to the right of the last glyph in the row. */ | |
8148 rect->left = WINDOW_TO_FRAME_PIXEL_X (w, gx); | |
8149 rect->right = XINT (w->left) + XINT (w->width); | |
8150 return 1; | |
8151 } | |
8152 } | |
8153 | |
8154 /* The y is not on any row. */ | |
8155 return 0; | |
8156 } | |
8157 | |
8158 /* Record the position of the mouse in last_mouse_glyph. */ | |
8159 static void | |
8160 remember_mouse_glyph (f1, gx, gy) | |
8161 struct frame * f1; | |
8162 int gx, gy; | |
8163 { | |
8164 if (!glyph_rect (f1, gx, gy, &last_mouse_glyph)) | |
8165 { | |
8166 int width = FRAME_SMALLEST_CHAR_WIDTH (f1); | |
8167 int height = FRAME_SMALLEST_FONT_HEIGHT (f1); | |
8168 | |
8169 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to | |
8170 round down even for negative values. */ | |
8171 if (gx < 0) | |
8172 gx -= width - 1; | |
8173 if (gy < 0) | |
8174 gy -= height - 1; | |
8175 #if 0 | |
8176 /* This was the original code from XTmouse_position, but it seems | |
8177 to give the position of the glyph diagonally next to the one | |
8178 the mouse is over. */ | |
8179 gx = (gx + width - 1) / width * width; | |
8180 gy = (gy + height - 1) / height * height; | |
8181 #else | |
8182 gx = gx / width * width; | |
8183 gy = gy / height * height; | |
8184 #endif | |
8185 | |
8186 last_mouse_glyph.left = gx; | |
8187 last_mouse_glyph.top = gy; | |
8188 last_mouse_glyph.right = gx + width; | |
8189 last_mouse_glyph.bottom = gy + height; | |
8190 } | |
8191 } | |
8192 | |
8193 /* Return the current position of the mouse. | |
8194 *fp should be a frame which indicates which display to ask about. | |
8195 | |
8196 If the mouse movement started in a scroll bar, set *fp, *bar_window, | |
8197 and *part to the frame, window, and scroll bar part that the mouse | |
8198 is over. Set *x and *y to the portion and whole of the mouse's | |
8199 position on the scroll bar. | |
8200 | |
8201 If the mouse movement started elsewhere, set *fp to the frame the | |
8202 mouse is on, *bar_window to nil, and *x and *y to the character cell | |
8203 the mouse is over. | |
8204 | |
8205 Set *time to the server time-stamp for the time at which the mouse | |
8206 was at this position. | |
8207 | |
8208 Don't store anything if we don't have a valid set of values to report. | |
8209 | |
8210 This clears the mouse_moved flag, so we can wait for the next mouse | |
8211 movement. */ | |
8212 | |
8213 static void | |
8214 XTmouse_position (fp, insist, bar_window, part, x, y, time) | |
8215 FRAME_PTR *fp; | |
8216 int insist; | |
8217 Lisp_Object *bar_window; | |
8218 enum scroll_bar_part *part; | |
8219 Lisp_Object *x, *y; | |
8220 unsigned long *time; | |
8221 { | |
8222 Point mouse_pos; | |
8223 int ignore1, ignore2; | |
8224 WindowPtr wp = FrontWindow (); | |
8225 struct frame *f = ((mac_output *) GetWRefCon (wp))->mFP; | |
8226 Lisp_Object frame, tail; | |
8227 | |
8228 BLOCK_INPUT; | |
8229 | |
8230 if (! NILP (last_mouse_scroll_bar) && insist == 0) | |
8231 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time); | |
8232 else | |
8233 { | |
8234 /* Clear the mouse-moved flag for every frame on this display. */ | |
8235 FOR_EACH_FRAME (tail, frame) | |
8236 XFRAME (frame)->mouse_moved = 0; | |
8237 | |
8238 last_mouse_scroll_bar = Qnil; | |
8239 | |
8240 #if TARGET_API_MAC_CARBON | |
8241 SetPort (GetWindowPort (wp)); | |
8242 #else | |
8243 SetPort (wp); | |
8244 #endif | |
8245 | |
8246 GetMouse (&mouse_pos); | |
8247 | |
8248 pixel_to_glyph_coords (f, mouse_pos.h, mouse_pos.v, &ignore1, &ignore2, | |
8249 &last_mouse_glyph, insist); | |
8250 | |
8251 *bar_window = Qnil; | |
8252 *part = scroll_bar_handle; | |
8253 *fp = f; | |
8254 XSETINT (*x, mouse_pos.h); | |
8255 XSETINT (*y, mouse_pos.v); | |
8256 *time = last_mouse_movement_time; | |
8257 } | |
8258 | |
8259 UNBLOCK_INPUT; | |
8260 } | |
8261 | |
8262 | |
8263 /************************************************************************ | |
8264 Scroll bars, general | |
8265 ************************************************************************/ | |
8266 | |
8267 /* Create a scroll bar and return the scroll bar vector for it. W is | |
8268 the Emacs window on which to create the scroll bar. TOP, LEFT, | |
8269 WIDTH and HEIGHT are the pixel coordinates and dimensions of the | |
8270 scroll bar. */ | |
8271 | |
8272 static struct scroll_bar * | |
8273 x_scroll_bar_create (w, top, left, width, height, disp_top, disp_height) | |
8274 struct window *w; | |
8275 int top, left, width, height, disp_top, disp_height; | |
8276 { | |
8277 struct frame *f = XFRAME (w->frame); | |
8278 struct scroll_bar *bar | |
8279 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil)); | |
8280 Rect r; | |
8281 ControlHandle ch; | |
8282 | |
8283 BLOCK_INPUT; | |
8284 | |
8285 r.left = left; | |
8286 r.top = disp_top; | |
8287 r.right = left + width; | |
8288 r.bottom = disp_top + disp_height; | |
8289 | |
8290 #ifdef TARGET_API_MAC_CARBON | |
8291 ch = NewControl (FRAME_MAC_WINDOW (f), &r, "\p", 1, 0, 0, 0, | |
8292 kControlScrollBarProc, 0L); | |
8293 #else | |
8294 ch = NewControl (FRAME_MAC_WINDOW (f), &r, "\p", 1, 0, 0, 0, scrollBarProc, | |
8295 0L); | |
8296 #endif | |
8297 SET_SCROLL_BAR_CONTROL_HANDLE (bar, ch); | |
8298 SetControlReference (ch, (long) bar); | |
8299 | |
8300 XSETWINDOW (bar->window, w); | |
8301 XSETINT (bar->top, top); | |
8302 XSETINT (bar->left, left); | |
8303 XSETINT (bar->width, width); | |
8304 XSETINT (bar->height, height); | |
8305 XSETINT (bar->start, 0); | |
8306 XSETINT (bar->end, 0); | |
8307 bar->dragging = Qnil; | |
8308 | |
8309 /* Add bar to its frame's list of scroll bars. */ | |
8310 bar->next = FRAME_SCROLL_BARS (f); | |
8311 bar->prev = Qnil; | |
8312 XSETVECTOR (FRAME_SCROLL_BARS (f), bar); | |
8313 if (!NILP (bar->next)) | |
8314 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar); | |
8315 | |
8316 UNBLOCK_INPUT; | |
8317 return bar; | |
8318 } | |
8319 | |
8320 | |
8321 /* Draw BAR's handle in the proper position. | |
8322 | |
8323 If the handle is already drawn from START to END, don't bother | |
8324 redrawing it, unless REBUILD is non-zero; in that case, always | |
8325 redraw it. (REBUILD is handy for drawing the handle after expose | |
8326 events.) | |
8327 | |
8328 Normally, we want to constrain the start and end of the handle to | |
8329 fit inside its rectangle, but if the user is dragging the scroll | |
8330 bar handle, we want to let them drag it down all the way, so that | |
8331 the bar's top is as far down as it goes; otherwise, there's no way | |
8332 to move to the very end of the buffer. */ | |
8333 | |
8334 static void | |
8335 x_scroll_bar_set_handle (bar, start, end, rebuild) | |
8336 struct scroll_bar *bar; | |
8337 int start, end; | |
8338 int rebuild; | |
8339 { | |
8340 int dragging = ! NILP (bar->dragging); | |
8341 ControlHandle ch = SCROLL_BAR_CONTROL_HANDLE (bar); | |
8342 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window))); | |
8343 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height)); | |
8344 int length = end - start; | |
8345 | |
8346 /* If the display is already accurate, do nothing. */ | |
8347 if (! rebuild | |
8348 && start == XINT (bar->start) | |
8349 && end == XINT (bar->end)) | |
8350 return; | |
8351 | |
8352 BLOCK_INPUT; | |
8353 | |
8354 /* Make sure the values are reasonable, and try to preserve the | |
8355 distance between start and end. */ | |
8356 if (start < 0) | |
8357 start = 0; | |
8358 else if (start > top_range) | |
8359 start = top_range; | |
8360 end = start + length; | |
8361 | |
8362 if (end < start) | |
8363 end = start; | |
8364 else if (end > top_range && ! dragging) | |
8365 end = top_range; | |
8366 | |
8367 /* Store the adjusted setting in the scroll bar. */ | |
8368 XSETINT (bar->start, start); | |
8369 XSETINT (bar->end, end); | |
8370 | |
8371 /* Clip the end position, just for display. */ | |
8372 if (end > top_range) | |
8373 end = top_range; | |
8374 | |
8375 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels below | |
8376 top positions, to make sure the handle is always at least that | |
8377 many pixels tall. */ | |
8378 end += VERTICAL_SCROLL_BAR_MIN_HANDLE; | |
8379 | |
8380 SetControlMinimum (ch, 0); | |
8381 /* Don't inadvertently activate deactivated scroll bars */ | |
8382 if (GetControlMaximum (ch) != -1) | |
8383 SetControlMaximum (ch, top_range + VERTICAL_SCROLL_BAR_MIN_HANDLE | |
8384 - (end - start)); | |
8385 SetControlValue (ch, start); | |
8386 #if TARGET_API_MAC_CARBON | |
8387 SetControlViewSize (ch, end - start); | |
8388 #endif | |
8389 | |
8390 UNBLOCK_INPUT; | |
8391 } | |
8392 | |
8393 | |
8394 /* Destroy scroll bar BAR, and set its Emacs window's scroll bar to | |
8395 nil. */ | |
8396 | |
8397 static void | |
8398 x_scroll_bar_remove (bar) | |
8399 struct scroll_bar *bar; | |
8400 { | |
8401 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window))); | |
8402 | |
8403 BLOCK_INPUT; | |
8404 | |
8405 /* Destroy the Mac scroll bar control */ | |
8406 DisposeControl (SCROLL_BAR_CONTROL_HANDLE (bar)); | |
8407 | |
8408 /* Disassociate this scroll bar from its window. */ | |
8409 XWINDOW (bar->window)->vertical_scroll_bar = Qnil; | |
8410 | |
8411 UNBLOCK_INPUT; | |
8412 } | |
8413 | |
8414 /* Set the handle of the vertical scroll bar for WINDOW to indicate | |
8415 that we are displaying PORTION characters out of a total of WHOLE | |
8416 characters, starting at POSITION. If WINDOW has no scroll bar, | |
8417 create one. */ | |
8418 static void | |
8419 XTset_vertical_scroll_bar (w, portion, whole, position) | |
8420 struct window *w; | |
8421 int portion, whole, position; | |
8422 { | |
8423 struct frame *f = XFRAME (w->frame); | |
8424 struct scroll_bar *bar; | |
8425 int top, height, left, sb_left, width, sb_width, disp_top, disp_height; | |
8426 int window_x, window_y, window_width, window_height; | |
8427 | |
8428 /* Get window dimensions. */ | |
8429 window_box (w, -1, &window_x, &window_y, &window_width, &window_height); | |
8430 top = window_y; | |
8431 #ifdef MAC_OSX | |
8432 width = 16; | |
8433 #else | |
8434 width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f); | |
8435 #endif | |
8436 height = window_height; | |
8437 | |
8438 /* Compute the left edge of the scroll bar area. */ | |
8439 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f)) | |
8440 left = XINT (w->left) + XINT (w->width) - FRAME_SCROLL_BAR_COLS (f); | |
8441 else | |
8442 left = XFASTINT (w->left); | |
8443 left *= CANON_X_UNIT (f); | |
8444 left += FRAME_INTERNAL_BORDER_WIDTH (f); | |
8445 | |
8446 /* Compute the width of the scroll bar which might be less than | |
8447 the width of the area reserved for the scroll bar. */ | |
8448 if (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0) | |
8449 sb_width = FRAME_SCROLL_BAR_PIXEL_WIDTH (f); | |
8450 else | |
8451 sb_width = width; | |
8452 | |
8453 /* Compute the left edge of the scroll bar. */ | |
8454 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f)) | |
8455 sb_left = left + width - sb_width - (width - sb_width) / 2; | |
8456 else | |
8457 sb_left = left + (width - sb_width) / 2; | |
8458 | |
8459 /* Adjustments according to Inside Macintosh to make it look nice */ | |
8460 disp_top = top; | |
8461 disp_height = height; | |
8462 if (disp_top == 0) | |
8463 { | |
8464 disp_top = -1; | |
8465 disp_height++; | |
8466 } | |
8467 else if (disp_top == PIXEL_HEIGHT (f) - 16) | |
8468 { | |
8469 disp_top++; | |
8470 disp_height--; | |
8471 } | |
8472 | |
8473 if (sb_left + sb_width == PIXEL_WIDTH (f)) | |
8474 sb_left++; | |
8475 | |
8476 /* Does the scroll bar exist yet? */ | |
8477 if (NILP (w->vertical_scroll_bar)) | |
8478 { | |
8479 BLOCK_INPUT; | |
8480 XClearArea (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), | |
8481 left, top, width, height, 0); | |
8482 UNBLOCK_INPUT; | |
8483 bar = x_scroll_bar_create (w, top, sb_left, sb_width, height, disp_top, | |
8484 disp_height); | |
8485 XSETVECTOR (w->vertical_scroll_bar, bar); | |
8486 } | |
8487 else | |
8488 { | |
8489 /* It may just need to be moved and resized. */ | |
8490 ControlHandle ch; | |
8491 | |
8492 bar = XSCROLL_BAR (w->vertical_scroll_bar); | |
8493 ch = SCROLL_BAR_CONTROL_HANDLE (bar); | |
8494 | |
8495 BLOCK_INPUT; | |
8496 | |
8497 /* If already correctly positioned, do nothing. */ | |
8498 if (XINT (bar->left) == sb_left | |
8499 && XINT (bar->top) == top | |
8500 && XINT (bar->width) == sb_width | |
8501 && XINT (bar->height) == height) | |
8502 Draw1Control (ch); | |
8503 else | |
8504 { | |
8505 /* Clear areas not covered by the scroll bar because it's not as | |
8506 wide as the area reserved for it . This makes sure a | |
8507 previous mode line display is cleared after C-x 2 C-x 1, for | |
8508 example. */ | |
8509 int area_width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f); | |
8510 XClearArea (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), | |
8511 left, top, area_width, height, 0); | |
8512 | |
8513 #if 0 | |
8514 if (sb_left + sb_width >= PIXEL_WIDTH (f)) | |
8515 XClearArea (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), | |
8516 sb_left - 1, top, 1, height, 0); | |
8517 #endif | |
8518 | |
8519 HideControl (ch); | |
8520 MoveControl (ch, sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM, disp_top); | |
8521 SizeControl (ch, sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2, | |
8522 disp_height); | |
8523 ShowControl (ch); | |
8524 | |
8525 /* Remember new settings. */ | |
8526 XSETINT (bar->left, sb_left); | |
8527 XSETINT (bar->top, top); | |
8528 XSETINT (bar->width, sb_width); | |
8529 XSETINT (bar->height, height); | |
8530 } | |
8531 | |
8532 UNBLOCK_INPUT; | |
8533 } | |
8534 | |
8535 /* Set the scroll bar's current state, unless we're currently being | |
8536 dragged. */ | |
8537 if (NILP (bar->dragging)) | |
8538 { | |
8539 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height); | |
8540 | |
8541 if (whole == 0) | |
8542 x_scroll_bar_set_handle (bar, 0, top_range, 0); | |
8543 else | |
8544 { | |
8545 int start = ((double) position * top_range) / whole; | |
8546 int end = ((double) (position + portion) * top_range) / whole; | |
8547 x_scroll_bar_set_handle (bar, start, end, 0); | |
8548 } | |
8549 } | |
8550 } | |
8551 | |
8552 | |
8553 /* The following three hooks are used when we're doing a thorough | |
8554 redisplay of the frame. We don't explicitly know which scroll bars | |
8555 are going to be deleted, because keeping track of when windows go | |
8556 away is a real pain - "Can you say set-window-configuration, boys | |
8557 and girls?" Instead, we just assert at the beginning of redisplay | |
8558 that *all* scroll bars are to be removed, and then save a scroll bar | |
8559 from the fiery pit when we actually redisplay its window. */ | |
8560 | |
8561 /* Arrange for all scroll bars on FRAME to be removed at the next call | |
8562 to `*judge_scroll_bars_hook'. A scroll bar may be spared if | |
8563 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */ | |
8564 | |
8565 static void | |
8566 XTcondemn_scroll_bars (frame) | |
8567 FRAME_PTR frame; | |
8568 { | |
8569 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */ | |
8570 while (! NILP (FRAME_SCROLL_BARS (frame))) | |
8571 { | |
8572 Lisp_Object bar; | |
8573 bar = FRAME_SCROLL_BARS (frame); | |
8574 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next; | |
8575 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame); | |
8576 XSCROLL_BAR (bar)->prev = Qnil; | |
8577 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame))) | |
8578 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar; | |
8579 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar; | |
8580 } | |
8581 } | |
8582 | |
8583 | |
8584 /* Un-mark WINDOW's scroll bar for deletion in this judgment cycle. | |
8585 Note that WINDOW isn't necessarily condemned at all. */ | |
8586 | |
8587 static void | |
8588 XTredeem_scroll_bar (window) | |
8589 struct window *window; | |
8590 { | |
8591 struct scroll_bar *bar; | |
8592 | |
8593 /* We can't redeem this window's scroll bar if it doesn't have one. */ | |
8594 if (NILP (window->vertical_scroll_bar)) | |
8595 abort (); | |
8596 | |
8597 bar = XSCROLL_BAR (window->vertical_scroll_bar); | |
8598 | |
8599 /* Unlink it from the condemned list. */ | |
8600 { | |
8601 FRAME_PTR f = XFRAME (WINDOW_FRAME (window)); | |
8602 | |
8603 if (NILP (bar->prev)) | |
8604 { | |
8605 /* If the prev pointer is nil, it must be the first in one of | |
8606 the lists. */ | |
8607 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar)) | |
8608 /* It's not condemned. Everything's fine. */ | |
8609 return; | |
8610 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f), | |
8611 window->vertical_scroll_bar)) | |
8612 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next; | |
8613 else | |
8614 /* If its prev pointer is nil, it must be at the front of | |
8615 one or the other! */ | |
8616 abort (); | |
8617 } | |
8618 else | |
8619 XSCROLL_BAR (bar->prev)->next = bar->next; | |
8620 | |
8621 if (! NILP (bar->next)) | |
8622 XSCROLL_BAR (bar->next)->prev = bar->prev; | |
8623 | |
8624 bar->next = FRAME_SCROLL_BARS (f); | |
8625 bar->prev = Qnil; | |
8626 XSETVECTOR (FRAME_SCROLL_BARS (f), bar); | |
8627 if (! NILP (bar->next)) | |
8628 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar); | |
8629 } | |
8630 } | |
8631 | |
8632 /* Remove all scroll bars on FRAME that haven't been saved since the | |
8633 last call to `*condemn_scroll_bars_hook'. */ | |
8634 | |
8635 static void | |
8636 XTjudge_scroll_bars (f) | |
8637 FRAME_PTR f; | |
8638 { | |
8639 Lisp_Object bar, next; | |
8640 | |
8641 bar = FRAME_CONDEMNED_SCROLL_BARS (f); | |
8642 | |
8643 /* Clear out the condemned list now so we won't try to process any | |
8644 more events on the hapless scroll bars. */ | |
8645 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil; | |
8646 | |
8647 for (; ! NILP (bar); bar = next) | |
8648 { | |
8649 struct scroll_bar *b = XSCROLL_BAR (bar); | |
8650 | |
8651 x_scroll_bar_remove (b); | |
8652 | |
8653 next = b->next; | |
8654 b->next = b->prev = Qnil; | |
8655 } | |
8656 | |
8657 /* Now there should be no references to the condemned scroll bars, | |
8658 and they should get garbage-collected. */ | |
8659 } | |
8660 | |
8661 | |
8662 static void | |
8663 activate_scroll_bars (frame) | |
8664 FRAME_PTR frame; | |
8665 { | |
8666 Lisp_Object bar; | |
8667 ControlHandle ch; | |
8668 | |
8669 bar = FRAME_SCROLL_BARS (frame); | |
8670 while (! NILP (bar)) | |
8671 { | |
8672 ch = SCROLL_BAR_CONTROL_HANDLE (XSCROLL_BAR (bar)); | |
8673 #ifdef TARGET_API_MAC_CARBON | |
8674 ActivateControl (ch); | |
8675 #else | |
8676 SetControlMaximum (ch, | |
8677 VERTICAL_SCROLL_BAR_TOP_RANGE (frame, | |
8678 XINT (XSCROLL_BAR (bar) | |
8679 ->height)) - 1); | |
8680 #endif | |
8681 bar = XSCROLL_BAR (bar)->next; | |
8682 } | |
8683 } | |
8684 | |
8685 | |
8686 static void | |
8687 deactivate_scroll_bars (frame) | |
8688 FRAME_PTR frame; | |
8689 { | |
8690 Lisp_Object bar; | |
8691 ControlHandle ch; | |
8692 | |
8693 bar = FRAME_SCROLL_BARS (frame); | |
8694 while (! NILP (bar)) | |
8695 { | |
8696 ch = SCROLL_BAR_CONTROL_HANDLE (XSCROLL_BAR (bar)); | |
8697 #ifdef TARGET_API_MAC_CARBON | |
8698 DeactivateControl (ch); | |
8699 #else | |
8700 SetControlMaximum (ch, XINT (-1)); | |
8701 #endif | |
8702 bar = XSCROLL_BAR (bar)->next; | |
8703 } | |
8704 } | |
8705 | |
8706 /* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind | |
8707 is set to something other than no_event, it is enqueued. | |
8708 | |
8709 This may be called from a signal handler, so we have to ignore GC | |
8710 mark bits. */ | |
8711 | |
8712 static void | |
8713 x_scroll_bar_handle_click (bar, part_code, er, bufp) | |
8714 struct scroll_bar *bar; | |
8715 int part_code; | |
8716 EventRecord *er; | |
8717 struct input_event *bufp; | |
8718 { | |
8719 if (! GC_WINDOWP (bar->window)) | |
8720 abort (); | |
8721 | |
8722 bufp->kind = scroll_bar_click; | |
8723 bufp->frame_or_window = bar->window; | |
8724 bufp->arg = Qnil; | |
8725 | |
8726 bar->dragging = Qnil; | |
8727 | |
8728 switch (part_code) | |
8729 { | |
8730 case kControlUpButtonPart: | |
8731 bufp->part = scroll_bar_up_arrow; | |
8732 break; | |
8733 case kControlDownButtonPart: | |
8734 bufp->part = scroll_bar_down_arrow; | |
8735 break; | |
8736 case kControlPageUpPart: | |
8737 bufp->part = scroll_bar_above_handle; | |
8738 break; | |
8739 case kControlPageDownPart: | |
8740 bufp->part = scroll_bar_below_handle; | |
8741 break; | |
8742 #ifdef TARGET_API_MAC_CARBON | |
8743 default: | |
8744 #else | |
8745 case kControlIndicatorPart: | |
8746 #endif | |
8747 if (er->what == mouseDown) | |
8748 bar->dragging = make_number (0); | |
8749 XSETVECTOR (last_mouse_scroll_bar, bar); | |
8750 bufp->part = scroll_bar_handle; | |
8751 break; | |
8752 } | |
8753 } | |
8754 | |
8755 | |
8756 /* Handle some mouse motion while someone is dragging the scroll bar. | |
8757 | |
8758 This may be called from a signal handler, so we have to ignore GC | |
8759 mark bits. */ | |
8760 | |
8761 static void | |
8762 x_scroll_bar_note_movement (bar, y_pos, t) | |
8763 struct scroll_bar *bar; | |
8764 int y_pos; | |
8765 Time t; | |
8766 { | |
8767 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame); | |
8768 | |
8769 last_mouse_movement_time = t; | |
8770 | |
8771 f->mouse_moved = 1; | |
8772 XSETVECTOR (last_mouse_scroll_bar, bar); | |
8773 | |
8774 /* If we're dragging the bar, display it. */ | |
8775 if (! GC_NILP (bar->dragging)) | |
8776 { | |
8777 /* Where should the handle be now? */ | |
8778 int new_start = y_pos - 24; | |
8779 | |
8780 if (new_start != XINT (bar->start)) | |
8781 { | |
8782 int new_end = new_start + (XINT (bar->end) - XINT (bar->start)); | |
8783 | |
8784 x_scroll_bar_set_handle (bar, new_start, new_end, 0); | |
8785 } | |
8786 } | |
8787 } | |
8788 | |
8789 | |
8790 /* Return information to the user about the current position of the | |
8791 mouse on the scroll bar. */ | |
8792 | |
8793 static void | |
8794 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time) | |
8795 FRAME_PTR *fp; | |
8796 Lisp_Object *bar_window; | |
8797 enum scroll_bar_part *part; | |
8798 Lisp_Object *x, *y; | |
8799 unsigned long *time; | |
8800 { | |
8801 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar); | |
8802 WindowPtr wp = FrontWindow (); | |
8803 Point mouse_pos; | |
8804 struct frame *f = ((mac_output *) GetWRefCon (wp))->mFP; | |
8805 int win_y, top_range; | |
8806 | |
8807 #if TARGET_API_MAC_CARBON | |
8808 SetPort (GetWindowPort (wp)); | |
8809 #else | |
8810 SetPort (wp); | |
8811 #endif | |
8812 | |
8813 GetMouse (&mouse_pos); | |
8814 | |
8815 win_y = mouse_pos.v - XINT (bar->top); | |
8816 top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height)); | |
8817 | |
8818 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER; | |
8819 | |
8820 win_y -= 24; | |
8821 | |
8822 if (! NILP (bar->dragging)) | |
8823 win_y -= XINT (bar->dragging); | |
8824 | |
8825 if (win_y < 0) | |
8826 win_y = 0; | |
8827 if (win_y > top_range) | |
8828 win_y = top_range; | |
8829 | |
8830 *fp = f; | |
8831 *bar_window = bar->window; | |
8832 | |
8833 if (! NILP (bar->dragging)) | |
8834 *part = scroll_bar_handle; | |
8835 else if (win_y < XINT (bar->start)) | |
8836 *part = scroll_bar_above_handle; | |
8837 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE) | |
8838 *part = scroll_bar_handle; | |
8839 else | |
8840 *part = scroll_bar_below_handle; | |
8841 | |
8842 XSETINT (*x, win_y); | |
8843 XSETINT (*y, top_range); | |
8844 | |
8845 f->mouse_moved = 0; | |
8846 last_mouse_scroll_bar = Qnil; | |
8847 | |
8848 *time = last_mouse_movement_time; | |
8849 } | |
8850 | |
8851 /*********************************************************************** | |
8852 Text Cursor | |
8853 ***********************************************************************/ | |
8854 | |
8855 /* Notice if the text cursor of window W has been overwritten by a | |
8856 drawing operation that outputs glyphs starting at START_X and | |
8857 ending at END_X in the line given by output_cursor.vpos. | |
8858 Coordinates are area-relative. END_X < 0 means all the rest | |
8859 of the line after START_X has been written. */ | |
8860 | |
8861 static void | |
8862 notice_overwritten_cursor (w, area, x0, x1, y0, y1) | |
8863 struct window *w; | |
8864 enum glyph_row_area area; | |
8865 int x0, x1, y0, y1; | |
8866 { | |
8867 if (area == TEXT_AREA | |
8868 && w->phys_cursor_on_p | |
8869 && y0 <= w->phys_cursor.y | |
8870 && y1 >= w->phys_cursor.y + w->phys_cursor_height | |
8871 && x0 <= w->phys_cursor.x | |
8872 && (x1 < 0 || x1 > w->phys_cursor.x)) | |
8873 w->phys_cursor_on_p = 0; | |
8874 } | |
8875 | |
8876 | |
8877 /* Set clipping for output in glyph row ROW. W is the window in which | |
8878 we operate. GC is the graphics context to set clipping in. | |
8879 WHOLE_LINE_P non-zero means include the areas used for truncation | |
8880 mark display and alike in the clipping rectangle. | |
8881 | |
8882 ROW may be a text row or, e.g., a mode line. Text rows must be | |
8883 clipped to the interior of the window dedicated to text display, | |
8884 mode lines must be clipped to the whole window. */ | |
8885 | |
8886 static void | |
8887 x_clip_to_row (w, row, gc, whole_line_p) | |
8888 struct window *w; | |
8889 struct glyph_row *row; | |
8890 GC gc; | |
8891 int whole_line_p; | |
8892 { | |
8893 struct frame *f = XFRAME (WINDOW_FRAME (w)); | |
8894 Rect clip_rect; | |
8895 int window_x, window_y, window_width, window_height; | |
8896 | |
8897 window_box (w, -1, &window_x, &window_y, &window_width, &window_height); | |
8898 | |
8899 clip_rect.left = WINDOW_TO_FRAME_PIXEL_X (w, 0); | |
8900 clip_rect.top = WINDOW_TO_FRAME_PIXEL_Y (w, row->y); | |
8901 clip_rect.top = max (clip_rect.top, window_y); | |
8902 clip_rect.right = clip_rect.left + window_width; | |
8903 clip_rect.bottom = clip_rect.top + row->visible_height; | |
8904 | |
8905 /* If clipping to the whole line, including trunc marks, extend | |
8906 the rectangle to the left and increase its width. */ | |
8907 if (whole_line_p) | |
8908 { | |
8909 clip_rect.left -= FRAME_X_LEFT_FRINGE_WIDTH (f); | |
8910 clip_rect.right += FRAME_X_FRINGE_WIDTH (f); | |
8911 } | |
8912 | |
8913 mac_set_clip_rectangle (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), &clip_rect); | |
8914 } | |
8915 | |
8916 | |
8917 /* Draw a hollow box cursor on window W in glyph row ROW. */ | |
8918 | |
8919 static void | |
8920 x_draw_hollow_cursor (w, row) | |
8921 struct window *w; | |
8922 struct glyph_row *row; | |
8923 { | |
8924 struct frame *f = XFRAME (WINDOW_FRAME (w)); | |
8925 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); | |
8926 Display *dpy = FRAME_MAC_DISPLAY (f); | |
8927 int x, y, wd, h; | |
8928 XGCValues xgcv; | |
8929 struct glyph *cursor_glyph; | |
8930 GC gc; | |
8931 | |
8932 /* Compute frame-relative coordinates from window-relative | |
8933 coordinates. */ | |
8934 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x); | |
8935 y = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y) | |
8936 + row->ascent - w->phys_cursor_ascent); | |
8937 h = row->height - 1; | |
8938 | |
8939 /* Get the glyph the cursor is on. If we can't tell because | |
8940 the current matrix is invalid or such, give up. */ | |
8941 cursor_glyph = get_phys_cursor_glyph (w); | |
8942 if (cursor_glyph == NULL) | |
8943 return; | |
8944 | |
8945 /* Compute the width of the rectangle to draw. If on a stretch | |
8946 glyph, and `x-stretch-block-cursor' is nil, don't draw a | |
8947 rectangle as wide as the glyph, but use a canonical character | |
8948 width instead. */ | |
8949 wd = cursor_glyph->pixel_width - 1; | |
8950 if (cursor_glyph->type == STRETCH_GLYPH | |
8951 && !x_stretch_cursor_p) | |
8952 wd = min (CANON_X_UNIT (f), wd); | |
8953 | |
8954 /* The foreground of cursor_gc is typically the same as the normal | |
8955 background color, which can cause the cursor box to be invisible. */ | |
8956 xgcv.foreground = f->output_data.mac->cursor_pixel; | |
8957 if (dpyinfo->scratch_cursor_gc) | |
8958 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv); | |
8959 else | |
8960 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_MAC_WINDOW (f), | |
8961 GCForeground, &xgcv); | |
8962 gc = dpyinfo->scratch_cursor_gc; | |
8963 | |
8964 /* Set clipping, draw the rectangle, and reset clipping again. */ | |
8965 x_clip_to_row (w, row, gc, 0); | |
8966 mac_draw_rectangle (dpy, FRAME_MAC_WINDOW (f), gc, x, y, wd, h); | |
8967 mac_reset_clipping (dpy, FRAME_MAC_WINDOW (f)); | |
8968 } | |
8969 | |
8970 | |
8971 /* Draw a bar cursor on window W in glyph row ROW. | |
8972 | |
8973 Implementation note: One would like to draw a bar cursor with an | |
8974 angle equal to the one given by the font property XA_ITALIC_ANGLE. | |
8975 Unfortunately, I didn't find a font yet that has this property set. | |
8976 --gerd. */ | |
8977 | |
8978 static void | |
8979 x_draw_bar_cursor (w, row, width) | |
8980 struct window *w; | |
8981 struct glyph_row *row; | |
8982 int width; | |
8983 { | |
8984 /* If cursor hpos is out of bounds, don't draw garbage. This can | |
8985 happen in mini-buffer windows when switching between echo area | |
8986 glyphs and mini-buffer. */ | |
8987 if (w->phys_cursor.hpos < row->used[TEXT_AREA]) | |
8988 { | |
8989 struct frame *f = XFRAME (w->frame); | |
8990 struct glyph *cursor_glyph; | |
8991 GC gc; | |
8992 int x; | |
8993 unsigned long mask; | |
8994 XGCValues xgcv; | |
8995 Display *dpy; | |
8996 Window window; | |
8997 | |
8998 cursor_glyph = get_phys_cursor_glyph (w); | |
8999 if (cursor_glyph == NULL) | |
9000 return; | |
9001 | |
9002 xgcv.background = f->output_data.mac->cursor_pixel; | |
9003 xgcv.foreground = f->output_data.mac->cursor_pixel; | |
9004 mask = GCForeground | GCBackground; | |
9005 dpy = FRAME_MAC_DISPLAY (f); | |
9006 window = FRAME_MAC_WINDOW (f); | |
9007 gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc; | |
9008 | |
9009 if (gc) | |
9010 XChangeGC (dpy, gc, mask, &xgcv); | |
9011 else | |
9012 { | |
9013 gc = XCreateGC (dpy, window, mask, &xgcv); | |
9014 FRAME_MAC_DISPLAY_INFO (f)->scratch_cursor_gc = gc; | |
9015 } | |
9016 | |
9017 if (width < 0) | |
9018 width = f->output_data.mac->cursor_width; | |
9019 | |
9020 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x); | |
9021 x_clip_to_row (w, row, gc, 0); | |
9022 XFillRectangle (dpy, window, gc, | |
9023 x, | |
9024 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y), | |
9025 min (cursor_glyph->pixel_width, width), | |
9026 row->height); | |
9027 mac_reset_clipping (dpy, FRAME_MAC_WINDOW (f)); | |
9028 } | |
9029 } | |
9030 | |
9031 | |
9032 /* Clear the cursor of window W to background color, and mark the | |
9033 cursor as not shown. This is used when the text where the cursor | |
9034 is is about to be rewritten. */ | |
9035 | |
9036 static void | |
9037 x_clear_cursor (w) | |
9038 struct window *w; | |
9039 { | |
9040 if (FRAME_VISIBLE_P (XFRAME (w->frame)) && w->phys_cursor_on_p) | |
9041 x_update_window_cursor (w, 0); | |
9042 } | |
9043 | |
9044 | |
9045 /* Draw the cursor glyph of window W in glyph row ROW. See the | |
9046 comment of x_draw_glyphs for the meaning of HL. */ | |
9047 | |
9048 static void | |
9049 x_draw_phys_cursor_glyph (w, row, hl) | |
9050 struct window *w; | |
9051 struct glyph_row *row; | |
9052 enum draw_glyphs_face hl; | |
9053 { | |
9054 /* If cursor hpos is out of bounds, don't draw garbage. This can | |
9055 happen in mini-buffer windows when switching between echo area | |
9056 glyphs and mini-buffer. */ | |
9057 if (w->phys_cursor.hpos < row->used[TEXT_AREA]) | |
9058 { | |
9059 int on_p = w->phys_cursor_on_p; | |
9060 x_draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA, | |
9061 w->phys_cursor.hpos, w->phys_cursor.hpos + 1, | |
9062 hl, 0); | |
9063 w->phys_cursor_on_p = on_p; | |
9064 | |
9065 /* When we erase the cursor, and ROW is overlapped by other | |
9066 rows, make sure that these overlapping parts of other rows | |
9067 are redrawn. */ | |
9068 if (hl == DRAW_NORMAL_TEXT && row->overlapped_p) | |
9069 { | |
9070 if (row > w->current_matrix->rows | |
9071 && MATRIX_ROW_OVERLAPS_SUCC_P (row - 1)) | |
9072 x_fix_overlapping_area (w, row - 1, TEXT_AREA); | |
9073 | |
9074 if (MATRIX_ROW_BOTTOM_Y (row) < window_text_bottom_y (w) | |
9075 && MATRIX_ROW_OVERLAPS_PRED_P (row + 1)) | |
9076 x_fix_overlapping_area (w, row + 1, TEXT_AREA); | |
9077 } | |
9078 } | |
9079 } | |
9080 | |
9081 | |
9082 /* Erase the image of a cursor of window W from the screen. */ | |
9083 | |
9084 static void | |
9085 x_erase_phys_cursor (w) | |
9086 struct window *w; | |
9087 { | |
9088 struct frame *f = XFRAME (w->frame); | |
9089 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f); | |
9090 int hpos = w->phys_cursor.hpos; | |
9091 int vpos = w->phys_cursor.vpos; | |
9092 int mouse_face_here_p = 0; | |
9093 struct glyph_matrix *active_glyphs = w->current_matrix; | |
9094 struct glyph_row *cursor_row; | |
9095 struct glyph *cursor_glyph; | |
9096 enum draw_glyphs_face hl; | |
9097 | |
9098 /* No cursor displayed or row invalidated => nothing to do on the | |
9099 screen. */ | |
9100 if (w->phys_cursor_type == NO_CURSOR) | |
9101 goto mark_cursor_off; | |
9102 | |
9103 /* VPOS >= active_glyphs->nrows means that window has been resized. | |
9104 Don't bother to erase the cursor. */ | |
9105 if (vpos >= active_glyphs->nrows) | |
9106 goto mark_cursor_off; | |
9107 | |
9108 /* If row containing cursor is marked invalid, there is nothing we | |
9109 can do. */ | |
9110 cursor_row = MATRIX_ROW (active_glyphs, vpos); | |
9111 if (!cursor_row->enabled_p) | |
9112 goto mark_cursor_off; | |
9113 | |
9114 /* If row is completely invisible, don't attempt to delete a cursor which | |
9115 isn't there. This may happen if cursor is at top of window, and | |
9116 we switch to a buffer with a header line in that window. */ | |
9117 if (cursor_row->visible_height <= 0) | |
9118 goto mark_cursor_off; | |
9119 | |
9120 /* This can happen when the new row is shorter than the old one. | |
9121 In this case, either x_draw_glyphs or clear_end_of_line | |
9122 should have cleared the cursor. Note that we wouldn't be | |
9123 able to erase the cursor in this case because we don't have a | |
9124 cursor glyph at hand. */ | |
9125 if (w->phys_cursor.hpos >= cursor_row->used[TEXT_AREA]) | |
9126 goto mark_cursor_off; | |
9127 | |
9128 /* If the cursor is in the mouse face area, redisplay that when | |
9129 we clear the cursor. */ | |
9130 if (! NILP (dpyinfo->mouse_face_window) | |
9131 && w == XWINDOW (dpyinfo->mouse_face_window) | |
9132 && (vpos > dpyinfo->mouse_face_beg_row | |
9133 || (vpos == dpyinfo->mouse_face_beg_row | |
9134 && hpos >= dpyinfo->mouse_face_beg_col)) | |
9135 && (vpos < dpyinfo->mouse_face_end_row | |
9136 || (vpos == dpyinfo->mouse_face_end_row | |
9137 && hpos < dpyinfo->mouse_face_end_col)) | |
9138 /* Don't redraw the cursor's spot in mouse face if it is at the | |
9139 end of a line (on a newline). The cursor appears there, but | |
9140 mouse highlighting does not. */ | |
9141 && cursor_row->used[TEXT_AREA] > hpos) | |
9142 mouse_face_here_p = 1; | |
9143 | |
9144 /* Maybe clear the display under the cursor. */ | |
9145 if (w->phys_cursor_type == HOLLOW_BOX_CURSOR) | |
9146 { | |
9147 int x; | |
9148 int header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w); | |
9149 | |
9150 cursor_glyph = get_phys_cursor_glyph (w); | |
9151 if (cursor_glyph == NULL) | |
9152 goto mark_cursor_off; | |
9153 | |
9154 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x), | |
9155 | |
9156 XClearArea (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), | |
9157 x, | |
9158 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, | |
9159 cursor_row->y)), | |
9160 cursor_glyph->pixel_width, | |
9161 cursor_row->visible_height, | |
9162 0); | |
9163 } | |
9164 | |
9165 /* Erase the cursor by redrawing the character underneath it. */ | |
9166 if (mouse_face_here_p) | |
9167 hl = DRAW_MOUSE_FACE; | |
9168 else | |
9169 hl = DRAW_NORMAL_TEXT; | |
9170 x_draw_phys_cursor_glyph (w, cursor_row, hl); | |
9171 | |
9172 mark_cursor_off: | |
9173 w->phys_cursor_on_p = 0; | |
9174 w->phys_cursor_type = NO_CURSOR; | |
9175 } | |
9176 | |
9177 | |
9178 /* Non-zero if physical cursor of window W is within mouse face. */ | |
9179 | |
9180 static int | |
9181 cursor_in_mouse_face_p (w) | |
9182 struct window *w; | |
9183 { | |
9184 struct mac_display_info *dpyinfo | |
9185 = FRAME_MAC_DISPLAY_INFO (XFRAME (w->frame)); | |
9186 int in_mouse_face = 0; | |
9187 | |
9188 if (WINDOWP (dpyinfo->mouse_face_window) | |
9189 && XWINDOW (dpyinfo->mouse_face_window) == w) | |
9190 { | |
9191 int hpos = w->phys_cursor.hpos; | |
9192 int vpos = w->phys_cursor.vpos; | |
9193 | |
9194 if (vpos >= dpyinfo->mouse_face_beg_row | |
9195 && vpos <= dpyinfo->mouse_face_end_row | |
9196 && (vpos > dpyinfo->mouse_face_beg_row | |
9197 || hpos >= dpyinfo->mouse_face_beg_col) | |
9198 && (vpos < dpyinfo->mouse_face_end_row | |
9199 || hpos < dpyinfo->mouse_face_end_col | |
9200 || dpyinfo->mouse_face_past_end)) | |
9201 in_mouse_face = 1; | |
9202 } | |
9203 | |
9204 return in_mouse_face; | |
9205 } | |
9206 | |
9207 | |
9208 /* Display or clear cursor of window W. If ON is zero, clear the | |
9209 cursor. If it is non-zero, display the cursor. If ON is nonzero, | |
9210 where to put the cursor is specified by HPOS, VPOS, X and Y. */ | |
9211 | |
9212 void | |
9213 x_display_and_set_cursor (w, on, hpos, vpos, x, y) | |
9214 struct window *w; | |
9215 int on, hpos, vpos, x, y; | |
9216 { | |
9217 struct frame *f = XFRAME (w->frame); | |
9218 int new_cursor_type; | |
9219 int new_cursor_width; | |
9220 struct glyph_matrix *current_glyphs; | |
9221 struct glyph_row *glyph_row; | |
9222 struct glyph *glyph; | |
9223 int cursor_non_selected; | |
9224 int active_cursor = 1; | |
9225 | |
9226 /* This is pointless on invisible frames, and dangerous on garbaged | |
9227 windows and frames; in the latter case, the frame or window may | |
9228 be in the midst of changing its size, and x and y may be off the | |
9229 window. */ | |
9230 if (! FRAME_VISIBLE_P (f) | |
9231 || FRAME_GARBAGED_P (f) | |
9232 || vpos >= w->current_matrix->nrows | |
9233 || hpos >= w->current_matrix->matrix_w) | |
9234 return; | |
9235 | |
9236 /* If cursor is off and we want it off, return quickly. */ | |
9237 if (!on && !w->phys_cursor_on_p) | |
9238 return; | |
9239 | |
9240 current_glyphs = w->current_matrix; | |
9241 glyph_row = MATRIX_ROW (current_glyphs, vpos); | |
9242 glyph = glyph_row->glyphs[TEXT_AREA] + hpos; | |
9243 | |
9244 /* If cursor row is not enabled, we don't really know where to | |
9245 display the cursor. */ | |
9246 if (!glyph_row->enabled_p) | |
9247 { | |
9248 w->phys_cursor_on_p = 0; | |
9249 return; | |
9250 } | |
9251 | |
9252 xassert (interrupt_input_blocked); | |
9253 | |
9254 /* Set new_cursor_type to the cursor we want to be displayed. In a | |
9255 mini-buffer window, we want the cursor only to appear if we are | |
9256 reading input from this window. For the selected window, we want | |
9257 the cursor type given by the frame parameter. If explicitly | |
9258 marked off, draw no cursor. In all other cases, we want a hollow | |
9259 box cursor. */ | |
9260 cursor_non_selected | |
9261 = !NILP (Fbuffer_local_value (Qcursor_in_non_selected_windows, | |
9262 w->buffer)); | |
9263 new_cursor_width = -1; | |
9264 if (cursor_in_echo_area | |
9265 && FRAME_HAS_MINIBUF_P (f) | |
9266 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window)) | |
9267 { | |
9268 if (w == XWINDOW (echo_area_window)) | |
9269 new_cursor_type = FRAME_DESIRED_CURSOR (f); | |
9270 else | |
9271 { | |
9272 if (cursor_non_selected) | |
9273 new_cursor_type = HOLLOW_BOX_CURSOR; | |
9274 else | |
9275 new_cursor_type = NO_CURSOR; | |
9276 active_cursor = 0; | |
9277 } | |
9278 } | |
9279 else | |
9280 { | |
9281 if (f != FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame | |
9282 || w != XWINDOW (f->selected_window)) | |
9283 { | |
9284 active_cursor = 0; | |
9285 | |
9286 if (MINI_WINDOW_P (w) | |
9287 || !cursor_non_selected | |
9288 || NILP (XBUFFER (w->buffer)->cursor_type)) | |
9289 new_cursor_type = NO_CURSOR; | |
9290 else | |
9291 new_cursor_type = HOLLOW_BOX_CURSOR; | |
9292 } | |
9293 else | |
9294 { | |
9295 struct buffer *b = XBUFFER (w->buffer); | |
9296 | |
9297 if (EQ (b->cursor_type, Qt)) | |
9298 new_cursor_type = FRAME_DESIRED_CURSOR (f); | |
9299 else | |
9300 new_cursor_type = x_specified_cursor_type (b->cursor_type, | |
9301 &new_cursor_width); | |
9302 if (w->cursor_off_p) | |
9303 { | |
9304 if (new_cursor_type == FILLED_BOX_CURSOR) | |
9305 new_cursor_type = HOLLOW_BOX_CURSOR; | |
9306 else if (new_cursor_type == BAR_CURSOR && new_cursor_width > 1) | |
9307 new_cursor_width = 1; | |
9308 else | |
9309 new_cursor_type = NO_CURSOR; | |
9310 } | |
9311 } | |
9312 } | |
9313 | |
9314 /* If cursor is currently being shown and we don't want it to be or | |
9315 it is in the wrong place, or the cursor type is not what we want, | |
9316 erase it. */ | |
9317 if (w->phys_cursor_on_p | |
9318 && (!on | |
9319 || w->phys_cursor.x != x | |
9320 || w->phys_cursor.y != y | |
9321 || new_cursor_type != w->phys_cursor_type | |
9322 || (new_cursor_type == BAR_CURSOR | |
9323 && new_cursor_width != w->phys_cursor_width))) | |
9324 x_erase_phys_cursor (w); | |
9325 | |
9326 /* If the cursor is now invisible and we want it to be visible, | |
9327 display it. */ | |
9328 if (on && !w->phys_cursor_on_p) | |
9329 { | |
9330 w->phys_cursor_ascent = glyph_row->ascent; | |
9331 w->phys_cursor_height = glyph_row->height; | |
9332 | |
9333 /* Set phys_cursor_.* before x_draw_.* is called because some | |
9334 of them may need the information. */ | |
9335 w->phys_cursor.x = x; | |
9336 w->phys_cursor.y = glyph_row->y; | |
9337 w->phys_cursor.hpos = hpos; | |
9338 w->phys_cursor.vpos = vpos; | |
9339 w->phys_cursor_type = new_cursor_type; | |
9340 w->phys_cursor_width = new_cursor_width; | |
9341 w->phys_cursor_on_p = 1; | |
9342 | |
9343 switch (new_cursor_type) | |
9344 { | |
9345 case HOLLOW_BOX_CURSOR: | |
9346 x_draw_hollow_cursor (w, glyph_row); | |
9347 break; | |
9348 | |
9349 case FILLED_BOX_CURSOR: | |
9350 x_draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR); | |
9351 break; | |
9352 | |
9353 case BAR_CURSOR: | |
9354 x_draw_bar_cursor (w, glyph_row, new_cursor_width); | |
9355 break; | |
9356 | |
9357 case NO_CURSOR: | |
9358 break; | |
9359 | |
9360 default: | |
9361 abort (); | |
9362 } | |
9363 } | |
9364 } | |
9365 | |
9366 | |
9367 /* Display the cursor on window W, or clear it. X and Y are window | |
9368 relative pixel coordinates. HPOS and VPOS are glyph matrix | |
9369 positions. If W is not the selected window, display a hollow | |
9370 cursor. ON non-zero means display the cursor at X, Y which | |
9371 correspond to HPOS, VPOS, otherwise it is cleared. */ | |
9372 | |
9373 void | |
9374 x_display_cursor (w, on, hpos, vpos, x, y) | |
9375 struct window *w; | |
9376 int on, hpos, vpos, x, y; | |
9377 { | |
9378 BLOCK_INPUT; | |
9379 x_display_and_set_cursor (w, on, hpos, vpos, x, y); | |
9380 UNBLOCK_INPUT; | |
9381 } | |
9382 | |
9383 | |
9384 /* Display the cursor on window W, or clear it, according to ON_P. | |
9385 Don't change the cursor's position. */ | |
9386 | |
9387 void | |
9388 x_update_cursor (f, on_p) | |
9389 struct frame *f; | |
9390 int on_p; | |
9391 { | |
9392 x_update_cursor_in_window_tree (XWINDOW (f->root_window), on_p); | |
9393 } | |
9394 | |
9395 | |
9396 /* Call x_update_window_cursor with parameter ON_P on all leaf windows | |
9397 in the window tree rooted at W. */ | |
9398 | |
9399 static void | |
9400 x_update_cursor_in_window_tree (w, on_p) | |
9401 struct window *w; | |
9402 int on_p; | |
9403 { | |
9404 while (w) | |
9405 { | |
9406 if (!NILP (w->hchild)) | |
9407 x_update_cursor_in_window_tree (XWINDOW (w->hchild), on_p); | |
9408 else if (!NILP (w->vchild)) | |
9409 x_update_cursor_in_window_tree (XWINDOW (w->vchild), on_p); | |
9410 else | |
9411 x_update_window_cursor (w, on_p); | |
9412 | |
9413 w = NILP (w->next) ? 0 : XWINDOW (w->next); | |
9414 } | |
9415 } | |
9416 | |
9417 | |
9418 /* Switch the display of W's cursor on or off, according to the value | |
9419 of ON. */ | |
9420 | |
9421 static void | |
9422 x_update_window_cursor (w, on) | |
9423 struct window *w; | |
9424 int on; | |
9425 { | |
9426 /* Don't update cursor in windows whose frame is in the process | |
9427 of being deleted. */ | |
9428 if (w->current_matrix) | |
9429 { | |
9430 BLOCK_INPUT; | |
9431 x_display_and_set_cursor (w, on, w->phys_cursor.hpos, | |
9432 w->phys_cursor.vpos, w->phys_cursor.x, | |
9433 w->phys_cursor.y); | |
9434 UNBLOCK_INPUT; | |
9435 } | |
9436 } | |
9437 | |
9438 | |
9439 | |
9440 | |
9441 /* Icons. */ | |
9442 | |
9443 #if 0 /* MAC_TODO: no icon support yet. */ | |
9444 int | |
9445 x_bitmap_icon (f, icon) | |
9446 struct frame *f; | |
9447 Lisp_Object icon; | |
9448 { | |
9449 HANDLE hicon; | |
9450 | |
9451 if (FRAME_W32_WINDOW (f) == 0) | |
9452 return 1; | |
9453 | |
9454 if (NILP (icon)) | |
9455 hicon = LoadIcon (hinst, EMACS_CLASS); | |
9456 else if (STRINGP (icon)) | |
9457 hicon = LoadImage (NULL, (LPCTSTR) XSTRING (icon)->data, IMAGE_ICON, 0, 0, | |
9458 LR_DEFAULTSIZE | LR_LOADFROMFILE); | |
9459 else if (SYMBOLP (icon)) | |
9460 { | |
9461 LPCTSTR name; | |
9462 | |
9463 if (EQ (icon, intern ("application"))) | |
9464 name = (LPCTSTR) IDI_APPLICATION; | |
9465 else if (EQ (icon, intern ("hand"))) | |
9466 name = (LPCTSTR) IDI_HAND; | |
9467 else if (EQ (icon, intern ("question"))) | |
9468 name = (LPCTSTR) IDI_QUESTION; | |
9469 else if (EQ (icon, intern ("exclamation"))) | |
9470 name = (LPCTSTR) IDI_EXCLAMATION; | |
9471 else if (EQ (icon, intern ("asterisk"))) | |
9472 name = (LPCTSTR) IDI_ASTERISK; | |
9473 else if (EQ (icon, intern ("winlogo"))) | |
9474 name = (LPCTSTR) IDI_WINLOGO; | |
9475 else | |
9476 return 1; | |
9477 | |
9478 hicon = LoadIcon (NULL, name); | |
9479 } | |
9480 else | |
9481 return 1; | |
9482 | |
9483 if (hicon == NULL) | |
9484 return 1; | |
9485 | |
9486 PostMessage (FRAME_W32_WINDOW (f), WM_SETICON, (WPARAM) ICON_BIG, | |
9487 (LPARAM) hicon); | |
9488 | |
9489 return 0; | |
9490 } | |
9491 #endif /* MAC_TODO */ | |
9492 | |
9493 /************************************************************************ | |
9494 Handling X errors | |
9495 ************************************************************************/ | |
9496 | |
9497 /* Display Error Handling functions not used on W32. Listing them here | |
9498 helps diff stay in step when comparing w32term.c with xterm.c. | |
9499 | |
9500 x_error_catcher (display, error) | |
9501 x_catch_errors (dpy) | |
9502 x_catch_errors_unwind (old_val) | |
9503 x_check_errors (dpy, format) | |
9504 x_had_errors_p (dpy) | |
9505 x_clear_errors (dpy) | |
9506 x_uncatch_errors (dpy, count) | |
9507 x_trace_wire () | |
9508 x_connection_signal (signalnum) | |
9509 x_connection_closed (dpy, error_message) | |
9510 x_error_quitter (display, error) | |
9511 x_error_handler (display, error) | |
9512 x_io_error_quitter (display) | |
9513 | |
9514 */ | |
9515 | |
9516 | |
9517 /* Changing the font of the frame. */ | |
9518 | |
9519 /* Give frame F the font named FONTNAME as its default font, and | |
9520 return the full name of that font. FONTNAME may be a wildcard | |
9521 pattern; in that case, we choose some font that fits the pattern. | |
9522 The return value shows which font we chose. */ | |
9523 | |
9524 Lisp_Object | |
9525 x_new_font (f, fontname) | |
9526 struct frame *f; | |
9527 register char *fontname; | |
9528 { | |
9529 struct font_info *fontp | |
9530 = FS_LOAD_FONT (f, 0, fontname, -1); | |
9531 | |
9532 if (!fontp) | |
9533 return Qnil; | |
9534 | |
9535 FRAME_FONT (f) = (XFontStruct *) (fontp->font); | |
9536 FRAME_BASELINE_OFFSET (f) = fontp->baseline_offset; | |
9537 FRAME_FONTSET (f) = -1; | |
9538 | |
9539 /* Compute the scroll bar width in character columns. */ | |
9540 if (f->scroll_bar_pixel_width > 0) | |
9541 { | |
9542 int wid = FONT_WIDTH (FRAME_FONT (f)); | |
9543 f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid; | |
9544 } | |
9545 else | |
9546 { | |
9547 int wid = FONT_WIDTH (FRAME_FONT (f)); | |
9548 f->scroll_bar_cols = (14 + wid - 1) / wid; | |
9549 } | |
9550 | |
9551 /* Now make the frame display the given font. */ | |
9552 if (FRAME_MAC_WINDOW (f) != 0) | |
9553 { | |
9554 frame_update_line_height (f); | |
9555 if (NILP (tip_frame) || XFRAME (tip_frame) != f) | |
9556 x_set_window_size (f, 0, f->width, f->height); | |
9557 } | |
9558 else | |
9559 /* If we are setting a new frame's font for the first time, | |
9560 there are no faces yet, so this font's height is the line height. */ | |
9561 f->output_data.mac->line_height = FONT_HEIGHT (FRAME_FONT (f)); | |
9562 | |
9563 return build_string (fontp->full_name); | |
9564 } | |
9565 | |
9566 /* Give frame F the fontset named FONTSETNAME as its default font, and | |
9567 return the full name of that fontset. FONTSETNAME may be a wildcard | |
9568 pattern; in that case, we choose some fontset that fits the pattern. | |
9569 The return value shows which fontset we chose. */ | |
9570 | |
9571 Lisp_Object | |
9572 x_new_fontset (f, fontsetname) | |
9573 struct frame *f; | |
9574 char *fontsetname; | |
9575 { | |
9576 int fontset = fs_query_fontset (build_string (fontsetname), 0); | |
9577 Lisp_Object result; | |
9578 | |
9579 if (fontset < 0) | |
9580 return Qnil; | |
9581 | |
9582 if (FRAME_FONTSET (f) == fontset) | |
9583 /* This fontset is already set in frame F. There's nothing more | |
9584 to do. */ | |
9585 return fontset_name (fontset); | |
9586 | |
9587 result = x_new_font (f, (XSTRING (fontset_ascii (fontset))->data)); | |
9588 | |
9589 if (!STRINGP (result)) | |
9590 /* Can't load ASCII font. */ | |
9591 return Qnil; | |
9592 | |
9593 /* Since x_new_font doesn't update any fontset information, do it now. */ | |
9594 FRAME_FONTSET(f) = fontset; | |
9595 | |
9596 return build_string (fontsetname); | |
9597 } | |
9598 | |
9599 /* Compute actual fringe widths */ | |
9600 | |
9601 void | |
9602 x_compute_fringe_widths (f, redraw) | |
9603 struct frame *f; | |
9604 int redraw; | |
9605 { | |
9606 int o_left = f->output_data.mac->left_fringe_width; | |
9607 int o_right = f->output_data.mac->right_fringe_width; | |
9608 int o_cols = f->output_data.mac->fringe_cols; | |
9609 | |
9610 Lisp_Object left_fringe = Fassq (Qleft_fringe, f->param_alist); | |
9611 Lisp_Object right_fringe = Fassq (Qright_fringe, f->param_alist); | |
9612 int left_fringe_width, right_fringe_width; | |
9613 | |
9614 if (!NILP (left_fringe)) | |
9615 left_fringe = Fcdr (left_fringe); | |
9616 if (!NILP (right_fringe)) | |
9617 right_fringe = Fcdr (right_fringe); | |
9618 | |
9619 left_fringe_width = ((NILP (left_fringe) || !INTEGERP (left_fringe)) ? 8 : | |
9620 XINT (left_fringe)); | |
9621 right_fringe_width = ((NILP (right_fringe) || !INTEGERP (right_fringe)) ? 8 : | |
9622 XINT (right_fringe)); | |
9623 | |
9624 if (left_fringe_width || right_fringe_width) | |
9625 { | |
9626 int left_wid = left_fringe_width >= 0 ? left_fringe_width : -left_fringe_width; | |
9627 int right_wid = right_fringe_width >= 0 ? right_fringe_width : -right_fringe_width; | |
9628 int conf_wid = left_wid + right_wid; | |
9629 int font_wid = FONT_WIDTH (f->output_data.mac->font); | |
9630 int cols = (left_wid + right_wid + font_wid-1) / font_wid; | |
9631 int real_wid = cols * font_wid; | |
9632 if (left_wid && right_wid) | |
9633 { | |
9634 if (left_fringe_width < 0) | |
9635 { | |
9636 /* Left fringe width is fixed, adjust right fringe if necessary */ | |
9637 f->output_data.mac->left_fringe_width = left_wid; | |
9638 f->output_data.mac->right_fringe_width = real_wid - left_wid; | |
9639 } | |
9640 else if (right_fringe_width < 0) | |
9641 { | |
9642 /* Right fringe width is fixed, adjust left fringe if necessary */ | |
9643 f->output_data.mac->left_fringe_width = real_wid - right_wid; | |
9644 f->output_data.mac->right_fringe_width = right_wid; | |
9645 } | |
9646 else | |
9647 { | |
9648 /* Adjust both fringes with an equal amount. | |
9649 Note that we are doing integer arithmetic here, so don't | |
9650 lose a pixel if the total width is an odd number. */ | |
9651 int fill = real_wid - conf_wid; | |
9652 f->output_data.mac->left_fringe_width = left_wid + fill/2; | |
9653 f->output_data.mac->right_fringe_width = right_wid + fill - fill/2; | |
9654 } | |
9655 } | |
9656 else if (left_fringe_width) | |
9657 { | |
9658 f->output_data.mac->left_fringe_width = real_wid; | |
9659 f->output_data.mac->right_fringe_width = 0; | |
9660 } | |
9661 else | |
9662 { | |
9663 f->output_data.mac->left_fringe_width = 0; | |
9664 f->output_data.mac->right_fringe_width = real_wid; | |
9665 } | |
9666 f->output_data.mac->fringe_cols = cols; | |
9667 f->output_data.mac->fringes_extra = real_wid; | |
9668 } | |
9669 else | |
9670 { | |
9671 f->output_data.mac->left_fringe_width = 0; | |
9672 f->output_data.mac->right_fringe_width = 0; | |
9673 f->output_data.mac->fringe_cols = 0; | |
9674 f->output_data.mac->fringes_extra = 0; | |
9675 } | |
9676 | |
9677 if (redraw && FRAME_VISIBLE_P (f)) | |
9678 if (o_left != f->output_data.mac->left_fringe_width || | |
9679 o_right != f->output_data.mac->right_fringe_width || | |
9680 o_cols != f->output_data.mac->fringe_cols) | |
9681 redraw_frame (f); | |
9682 } | |
9683 | |
9684 /*********************************************************************** | |
9685 TODO: W32 Input Methods | |
9686 ***********************************************************************/ | |
9687 /* Listing missing functions from xterm.c helps diff stay in step. | |
9688 | |
9689 xim_destroy_callback (xim, client_data, call_data) | |
9690 xim_open_dpy (dpyinfo, resource_name) | |
9691 struct xim_inst_t | |
9692 xim_instantiate_callback (display, client_data, call_data) | |
9693 xim_initialize (dpyinfo, resource_name) | |
9694 xim_close_dpy (dpyinfo) | |
9695 | |
9696 */ | |
9697 | |
9698 | |
9699 /* Calculate the absolute position in frame F | |
9700 from its current recorded position values and gravity. */ | |
9701 | |
9702 void | |
9703 x_calc_absolute_position (f) | |
9704 struct frame *f; | |
9705 { | |
9706 Point pt; | |
9707 int flags = f->output_data.mac->size_hint_flags; | |
9708 | |
9709 pt.h = pt.v = 0; | |
9710 | |
9711 /* Find the position of the outside upper-left corner of | |
9712 the inner window, with respect to the outer window. */ | |
9713 if (f->output_data.mac->parent_desc != FRAME_MAC_DISPLAY_INFO (f)->root_window) | |
9714 { | |
9715 GrafPtr savePort; | |
9716 GetPort (&savePort); | |
9717 | |
9718 #if TARGET_API_MAC_CARBON | |
9719 SetPort (GetWindowPort (FRAME_MAC_WINDOW (f))); | |
9720 #else | |
9721 SetPort (FRAME_MAC_WINDOW (f)); | |
9722 #endif | |
9723 | |
9724 #if TARGET_API_MAC_CARBON | |
9725 { | |
9726 Rect r; | |
9727 | |
9728 GetWindowPortBounds (FRAME_MAC_WINDOW (f), &r); | |
9729 SetPt(&pt, r.left, r.top); | |
9730 } | |
9731 #else /* not TARGET_API_MAC_CARBON */ | |
9732 SetPt(&pt, FRAME_MAC_WINDOW (f)->portRect.left, FRAME_MAC_WINDOW (f)->portRect.top); | |
9733 #endif /* not TARGET_API_MAC_CARBON */ | |
9734 LocalToGlobal (&pt); | |
9735 SetPort (savePort); | |
9736 } | |
9737 | |
9738 /* Treat negative positions as relative to the leftmost bottommost | |
9739 position that fits on the screen. */ | |
9740 if (flags & XNegative) | |
9741 f->output_data.mac->left_pos = (FRAME_MAC_DISPLAY_INFO (f)->width | |
9742 - 2 * f->output_data.mac->border_width - pt.h | |
9743 - PIXEL_WIDTH (f) | |
9744 + f->output_data.mac->left_pos); | |
9745 /* NTEMACS_TODO: Subtract menubar height? */ | |
9746 if (flags & YNegative) | |
9747 f->output_data.mac->top_pos = (FRAME_MAC_DISPLAY_INFO (f)->height | |
9748 - 2 * f->output_data.mac->border_width - pt.v | |
9749 - PIXEL_HEIGHT (f) | |
9750 + f->output_data.mac->top_pos); | |
9751 /* The left_pos and top_pos | |
9752 are now relative to the top and left screen edges, | |
9753 so the flags should correspond. */ | |
9754 f->output_data.mac->size_hint_flags &= ~ (XNegative | YNegative); | |
9755 } | |
9756 | |
9757 /* CHANGE_GRAVITY is 1 when calling from Fset_frame_position, | |
9758 to really change the position, and 0 when calling from | |
9759 x_make_frame_visible (in that case, XOFF and YOFF are the current | |
9760 position values). It is -1 when calling from x_set_frame_parameters, | |
9761 which means, do adjust for borders but don't change the gravity. */ | |
9762 | |
9763 void | |
9764 x_set_offset (f, xoff, yoff, change_gravity) | |
9765 struct frame *f; | |
9766 register int xoff, yoff; | |
9767 int change_gravity; | |
9768 { | |
9769 int modified_top, modified_left; | |
9770 | |
9771 if (change_gravity > 0) | |
9772 { | |
9773 f->output_data.mac->top_pos = yoff; | |
9774 f->output_data.mac->left_pos = xoff; | |
9775 f->output_data.mac->size_hint_flags &= ~ (XNegative | YNegative); | |
9776 if (xoff < 0) | |
9777 f->output_data.mac->size_hint_flags |= XNegative; | |
9778 if (yoff < 0) | |
9779 f->output_data.mac->size_hint_flags |= YNegative; | |
9780 f->output_data.mac->win_gravity = NorthWestGravity; | |
9781 } | |
9782 x_calc_absolute_position (f); | |
9783 | |
9784 BLOCK_INPUT; | |
9785 x_wm_set_size_hint (f, (long) 0, 0); | |
9786 | |
9787 modified_left = f->output_data.mac->left_pos; | |
9788 modified_top = f->output_data.mac->top_pos; | |
9789 | |
9790 MoveWindow (f->output_data.mac->mWP, modified_left + 6, | |
9791 modified_top + 42, false); | |
9792 | |
9793 UNBLOCK_INPUT; | |
9794 } | |
9795 | |
9796 /* Call this to change the size of frame F's x-window. | |
9797 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity | |
9798 for this size change and subsequent size changes. | |
9799 Otherwise we leave the window gravity unchanged. */ | |
9800 | |
9801 void | |
9802 x_set_window_size (f, change_gravity, cols, rows) | |
9803 struct frame *f; | |
9804 int change_gravity; | |
9805 int cols, rows; | |
9806 { | |
9807 int pixelwidth, pixelheight; | |
9808 | |
9809 BLOCK_INPUT; | |
9810 | |
9811 check_frame_size (f, &rows, &cols); | |
9812 f->output_data.mac->vertical_scroll_bar_extra | |
9813 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f) | |
9814 ? 0 | |
9815 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.mac->font))); | |
9816 | |
9817 x_compute_fringe_widths (f, 0); | |
9818 | |
9819 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols); | |
9820 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows); | |
9821 | |
9822 f->output_data.mac->win_gravity = NorthWestGravity; | |
9823 x_wm_set_size_hint (f, (long) 0, 0); | |
9824 | |
9825 SizeWindow (FRAME_MAC_WINDOW (f), pixelwidth, pixelheight, 0); | |
9826 | |
9827 /* Now, strictly speaking, we can't be sure that this is accurate, | |
9828 but the window manager will get around to dealing with the size | |
9829 change request eventually, and we'll hear how it went when the | |
9830 ConfigureNotify event gets here. | |
9831 | |
9832 We could just not bother storing any of this information here, | |
9833 and let the ConfigureNotify event set everything up, but that | |
9834 might be kind of confusing to the Lisp code, since size changes | |
9835 wouldn't be reported in the frame parameters until some random | |
9836 point in the future when the ConfigureNotify event arrives. | |
9837 | |
9838 We pass 1 for DELAY since we can't run Lisp code inside of | |
9839 a BLOCK_INPUT. */ | |
9840 change_frame_size (f, rows, cols, 0, 1, 0); | |
9841 PIXEL_WIDTH (f) = pixelwidth; | |
9842 PIXEL_HEIGHT (f) = pixelheight; | |
9843 | |
9844 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to | |
9845 receive in the ConfigureNotify event; if we get what we asked | |
9846 for, then the event won't cause the screen to become garbaged, so | |
9847 we have to make sure to do it here. */ | |
9848 SET_FRAME_GARBAGED (f); | |
9849 | |
9850 XFlush (FRAME_X_DISPLAY (f)); | |
9851 | |
9852 /* If cursor was outside the new size, mark it as off. */ | |
9853 mark_window_cursors_off (XWINDOW (f->root_window)); | |
9854 | |
9855 /* Clear out any recollection of where the mouse highlighting was, | |
9856 since it might be in a place that's outside the new frame size. | |
9857 Actually checking whether it is outside is a pain in the neck, | |
9858 so don't try--just let the highlighting be done afresh with new size. */ | |
9859 cancel_mouse_face (f); | |
9860 | |
9861 UNBLOCK_INPUT; | |
9862 } | |
9863 | |
9864 /* Mouse warping. */ | |
9865 | |
9866 void x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y); | |
9867 | |
9868 void | |
9869 x_set_mouse_position (f, x, y) | |
9870 struct frame *f; | |
9871 int x, y; | |
9872 { | |
9873 int pix_x, pix_y; | |
9874 | |
9875 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->output_data.mac->font) / 2; | |
9876 pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->output_data.mac->line_height / 2; | |
9877 | |
9878 if (pix_x < 0) pix_x = 0; | |
9879 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f); | |
9880 | |
9881 if (pix_y < 0) pix_y = 0; | |
9882 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f); | |
9883 | |
9884 x_set_mouse_pixel_position (f, pix_x, pix_y); | |
9885 } | |
9886 | |
9887 void | |
9888 x_set_mouse_pixel_position (f, pix_x, pix_y) | |
9889 struct frame *f; | |
9890 int pix_x, pix_y; | |
9891 { | |
9892 #if 0 /* MAC_TODO: CursorDeviceMoveTo is non-Carbon */ | |
9893 BLOCK_INPUT; | |
9894 | |
9895 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f), | |
9896 0, 0, 0, 0, pix_x, pix_y); | |
9897 UNBLOCK_INPUT; | |
9898 #endif | |
9899 } | |
9900 | |
9901 | |
9902 /* focus shifting, raising and lowering. */ | |
9903 | |
9904 void | |
9905 x_focus_on_frame (f) | |
9906 struct frame *f; | |
9907 { | |
9908 #if 0 /* This proves to be unpleasant. */ | |
9909 x_raise_frame (f); | |
9910 #endif | |
9911 #if 0 | |
9912 /* I don't think that the ICCCM allows programs to do things like this | |
9913 without the interaction of the window manager. Whatever you end up | |
9914 doing with this code, do it to x_unfocus_frame too. */ | |
9915 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), | |
9916 RevertToPointerRoot, CurrentTime); | |
9917 #endif /* ! 0 */ | |
9918 } | |
9919 | |
9920 void | |
9921 x_unfocus_frame (f) | |
9922 struct frame *f; | |
9923 { | |
9924 } | |
9925 | |
9926 /* Raise frame F. */ | |
9927 void | |
9928 x_raise_frame (f) | |
9929 struct frame *f; | |
9930 { | |
9931 if (f->async_visible) | |
9932 SelectWindow (FRAME_MAC_WINDOW (f)); | |
9933 } | |
9934 | |
9935 /* Lower frame F. */ | |
9936 void | |
9937 x_lower_frame (f) | |
9938 struct frame *f; | |
9939 { | |
9940 if (f->async_visible) | |
9941 SendBehind (FRAME_MAC_WINDOW (f), nil); | |
9942 } | |
9943 | |
9944 static void | |
9945 XTframe_raise_lower (f, raise_flag) | |
9946 FRAME_PTR f; | |
9947 int raise_flag; | |
9948 { | |
9949 if (raise_flag) | |
9950 x_raise_frame (f); | |
9951 else | |
9952 x_lower_frame (f); | |
9953 } | |
9954 | |
9955 /* Change of visibility. */ | |
9956 | |
9957 /* This tries to wait until the frame is really visible. | |
9958 However, if the window manager asks the user where to position | |
9959 the frame, this will return before the user finishes doing that. | |
9960 The frame will not actually be visible at that time, | |
9961 but it will become visible later when the window manager | |
9962 finishes with it. */ | |
9963 | |
9964 void | |
9965 x_make_frame_visible (f) | |
9966 struct frame *f; | |
9967 { | |
9968 Lisp_Object type; | |
9969 int original_top, original_left; | |
9970 | |
9971 BLOCK_INPUT; | |
9972 | |
9973 if (! FRAME_VISIBLE_P (f)) | |
9974 { | |
9975 /* We test FRAME_GARBAGED_P here to make sure we don't | |
9976 call x_set_offset a second time | |
9977 if we get to x_make_frame_visible a second time | |
9978 before the window gets really visible. */ | |
9979 if (! FRAME_ICONIFIED_P (f) | |
9980 && ! f->output_data.mac->asked_for_visible) | |
9981 x_set_offset (f, f->output_data.mac->left_pos, | |
9982 f->output_data.mac->top_pos, 0); | |
9983 | |
9984 f->output_data.mac->asked_for_visible = 1; | |
9985 | |
9986 ShowWindow (FRAME_MAC_WINDOW (f)); | |
9987 } | |
9988 | |
9989 XFlush (FRAME_MAC_DISPLAY (f)); | |
9990 | |
9991 #if 0 /* MAC_TODO */ | |
9992 /* Synchronize to ensure Emacs knows the frame is visible | |
9993 before we do anything else. We do this loop with input not blocked | |
9994 so that incoming events are handled. */ | |
9995 { | |
9996 Lisp_Object frame; | |
9997 int count; | |
9998 | |
9999 /* This must come after we set COUNT. */ | |
10000 UNBLOCK_INPUT; | |
10001 | |
10002 XSETFRAME (frame, f); | |
10003 | |
10004 /* Wait until the frame is visible. Process X events until a | |
10005 MapNotify event has been seen, or until we think we won't get a | |
10006 MapNotify at all.. */ | |
10007 for (count = input_signal_count + 10; | |
10008 input_signal_count < count && !FRAME_VISIBLE_P (f);) | |
10009 { | |
10010 /* Force processing of queued events. */ | |
10011 x_sync (f); | |
10012 | |
10013 /* Machines that do polling rather than SIGIO have been | |
10014 observed to go into a busy-wait here. So we'll fake an | |
10015 alarm signal to let the handler know that there's something | |
10016 to be read. We used to raise a real alarm, but it seems | |
10017 that the handler isn't always enabled here. This is | |
10018 probably a bug. */ | |
10019 if (input_polling_used ()) | |
10020 { | |
10021 /* It could be confusing if a real alarm arrives while | |
10022 processing the fake one. Turn it off and let the | |
10023 handler reset it. */ | |
10024 extern void poll_for_input_1 P_ ((void)); | |
10025 int old_poll_suppress_count = poll_suppress_count; | |
10026 poll_suppress_count = 1; | |
10027 poll_for_input_1 (); | |
10028 poll_suppress_count = old_poll_suppress_count; | |
10029 } | |
10030 | |
10031 /* See if a MapNotify event has been processed. */ | |
10032 FRAME_SAMPLE_VISIBILITY (f); | |
10033 } | |
10034 } | |
10035 #endif /* MAC_TODO */ | |
10036 } | |
10037 | |
10038 /* Change from mapped state to withdrawn state. */ | |
10039 | |
10040 /* Make the frame visible (mapped and not iconified). */ | |
10041 | |
10042 void | |
10043 x_make_frame_invisible (f) | |
10044 struct frame *f; | |
10045 { | |
10046 /* Don't keep the highlight on an invisible frame. */ | |
10047 if (FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame == f) | |
10048 FRAME_MAC_DISPLAY_INFO (f)->x_highlight_frame = 0; | |
10049 | |
10050 BLOCK_INPUT; | |
10051 | |
10052 HideWindow (FRAME_MAC_WINDOW (f)); | |
10053 | |
10054 /* We can't distinguish this from iconification | |
10055 just by the event that we get from the server. | |
10056 So we can't win using the usual strategy of letting | |
10057 FRAME_SAMPLE_VISIBILITY set this. So do it by hand, | |
10058 and synchronize with the server to make sure we agree. */ | |
10059 f->visible = 0; | |
10060 FRAME_ICONIFIED_P (f) = 0; | |
10061 f->async_visible = 0; | |
10062 f->async_iconified = 0; | |
10063 | |
10064 UNBLOCK_INPUT; | |
10065 } | |
10066 | |
10067 /* Change window state from mapped to iconified. */ | |
10068 | |
10069 void | |
10070 x_iconify_frame (f) | |
10071 struct frame *f; | |
10072 { | |
10073 #if 0 /* MAC_TODO: really no iconify on Mac */ | |
10074 int result; | |
10075 Lisp_Object type; | |
10076 | |
10077 /* Don't keep the highlight on an invisible frame. */ | |
10078 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f) | |
10079 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0; | |
10080 | |
10081 if (f->async_iconified) | |
10082 return; | |
10083 | |
10084 BLOCK_INPUT; | |
10085 | |
10086 FRAME_SAMPLE_VISIBILITY (f); | |
10087 | |
10088 type = x_icon_type (f); | |
10089 if (!NILP (type)) | |
10090 x_bitmap_icon (f, type); | |
10091 | |
10092 #ifdef USE_X_TOOLKIT | |
10093 | |
10094 if (! FRAME_VISIBLE_P (f)) | |
10095 { | |
10096 if (! EQ (Vx_no_window_manager, Qt)) | |
10097 x_wm_set_window_state (f, IconicState); | |
10098 /* This was XtPopup, but that did nothing for an iconified frame. */ | |
10099 XtMapWidget (f->output_data.x->widget); | |
10100 /* The server won't give us any event to indicate | |
10101 that an invisible frame was changed to an icon, | |
10102 so we have to record it here. */ | |
10103 f->iconified = 1; | |
10104 f->visible = 1; | |
10105 f->async_iconified = 1; | |
10106 f->async_visible = 0; | |
10107 UNBLOCK_INPUT; | |
10108 return; | |
10109 } | |
10110 | |
10111 result = XIconifyWindow (FRAME_X_DISPLAY (f), | |
10112 XtWindow (f->output_data.x->widget), | |
10113 DefaultScreen (FRAME_X_DISPLAY (f))); | |
10114 UNBLOCK_INPUT; | |
10115 | |
10116 if (!result) | |
10117 error ("Can't notify window manager of iconification"); | |
10118 | |
10119 f->async_iconified = 1; | |
10120 f->async_visible = 0; | |
10121 | |
10122 | |
10123 BLOCK_INPUT; | |
10124 XFlush (FRAME_X_DISPLAY (f)); | |
10125 UNBLOCK_INPUT; | |
10126 #else /* not USE_X_TOOLKIT */ | |
10127 | |
10128 /* Make sure the X server knows where the window should be positioned, | |
10129 in case the user deiconifies with the window manager. */ | |
10130 if (! FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P (f)) | |
10131 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0); | |
10132 | |
10133 /* Since we don't know which revision of X we're running, we'll use both | |
10134 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */ | |
10135 | |
10136 /* X11R4: send a ClientMessage to the window manager using the | |
10137 WM_CHANGE_STATE type. */ | |
10138 { | |
10139 XEvent message; | |
10140 | |
10141 message.xclient.window = FRAME_X_WINDOW (f); | |
10142 message.xclient.type = ClientMessage; | |
10143 message.xclient.message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_change_state; | |
10144 message.xclient.format = 32; | |
10145 message.xclient.data.l[0] = IconicState; | |
10146 | |
10147 if (! XSendEvent (FRAME_X_DISPLAY (f), | |
10148 DefaultRootWindow (FRAME_X_DISPLAY (f)), | |
10149 False, | |
10150 SubstructureRedirectMask | SubstructureNotifyMask, | |
10151 &message)) | |
10152 { | |
10153 UNBLOCK_INPUT_RESIGNAL; | |
10154 error ("Can't notify window manager of iconification"); | |
10155 } | |
10156 } | |
10157 | |
10158 /* X11R3: set the initial_state field of the window manager hints to | |
10159 IconicState. */ | |
10160 x_wm_set_window_state (f, IconicState); | |
10161 | |
10162 if (!FRAME_VISIBLE_P (f)) | |
10163 { | |
10164 /* If the frame was withdrawn, before, we must map it. */ | |
10165 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f)); | |
10166 } | |
10167 | |
10168 f->async_iconified = 1; | |
10169 f->async_visible = 0; | |
10170 | |
10171 XFlush (FRAME_X_DISPLAY (f)); | |
10172 UNBLOCK_INPUT; | |
10173 #endif /* not USE_X_TOOLKIT */ | |
10174 #endif /* MAC_TODO */ | |
10175 } | |
10176 | |
10177 | |
10178 /* Destroy the X window of frame F. */ | |
10179 | |
10180 void | |
10181 x_destroy_window (f) | |
10182 struct frame *f; | |
10183 { | |
10184 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); | |
10185 | |
10186 BLOCK_INPUT; | |
10187 | |
10188 DisposeWindow (FRAME_MAC_WINDOW (f)); | |
10189 | |
10190 free_frame_menubar (f); | |
10191 free_frame_faces (f); | |
10192 | |
10193 xfree (f->output_data.mac); | |
10194 f->output_data.mac = 0; | |
10195 if (f == dpyinfo->x_focus_frame) | |
10196 dpyinfo->x_focus_frame = 0; | |
10197 if (f == dpyinfo->x_focus_event_frame) | |
10198 dpyinfo->x_focus_event_frame = 0; | |
10199 if (f == dpyinfo->x_highlight_frame) | |
10200 dpyinfo->x_highlight_frame = 0; | |
10201 | |
10202 dpyinfo->reference_count--; | |
10203 | |
10204 if (f == dpyinfo->mouse_face_mouse_frame) | |
10205 { | |
10206 dpyinfo->mouse_face_beg_row | |
10207 = dpyinfo->mouse_face_beg_col = -1; | |
10208 dpyinfo->mouse_face_end_row | |
10209 = dpyinfo->mouse_face_end_col = -1; | |
10210 dpyinfo->mouse_face_window = Qnil; | |
10211 dpyinfo->mouse_face_deferred_gc = 0; | |
10212 dpyinfo->mouse_face_mouse_frame = 0; | |
10213 } | |
10214 | |
10215 UNBLOCK_INPUT; | |
10216 } | |
10217 | |
10218 /* Setting window manager hints. */ | |
10219 | |
10220 /* Set the normal size hints for the window manager, for frame F. | |
10221 FLAGS is the flags word to use--or 0 meaning preserve the flags | |
10222 that the window now has. | |
10223 If USER_POSITION is nonzero, we set the USPosition | |
10224 flag (this is useful when FLAGS is 0). */ | |
10225 void | |
10226 x_wm_set_size_hint (f, flags, user_position) | |
10227 struct frame *f; | |
10228 long flags; | |
10229 int user_position; | |
10230 { | |
10231 #if 0 /* MAC_TODO: connect this to the Appearance Manager */ | |
10232 XSizeHints size_hints; | |
10233 | |
10234 #ifdef USE_X_TOOLKIT | |
10235 Arg al[2]; | |
10236 int ac = 0; | |
10237 Dimension widget_width, widget_height; | |
10238 Window window = XtWindow (f->output_data.x->widget); | |
10239 #else /* not USE_X_TOOLKIT */ | |
10240 Window window = FRAME_X_WINDOW (f); | |
10241 #endif /* not USE_X_TOOLKIT */ | |
10242 | |
10243 /* Setting PMaxSize caused various problems. */ | |
10244 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */; | |
10245 | |
10246 size_hints.x = f->output_data.x->left_pos; | |
10247 size_hints.y = f->output_data.x->top_pos; | |
10248 | |
10249 #ifdef USE_X_TOOLKIT | |
10250 XtSetArg (al[ac], XtNwidth, &widget_width); ac++; | |
10251 XtSetArg (al[ac], XtNheight, &widget_height); ac++; | |
10252 XtGetValues (f->output_data.x->widget, al, ac); | |
10253 size_hints.height = widget_height; | |
10254 size_hints.width = widget_width; | |
10255 #else /* not USE_X_TOOLKIT */ | |
10256 size_hints.height = PIXEL_HEIGHT (f); | |
10257 size_hints.width = PIXEL_WIDTH (f); | |
10258 #endif /* not USE_X_TOOLKIT */ | |
10259 | |
10260 size_hints.width_inc = FONT_WIDTH (f->output_data.x->font); | |
10261 size_hints.height_inc = f->output_data.x->line_height; | |
10262 size_hints.max_width | |
10263 = FRAME_X_DISPLAY_INFO (f)->width - CHAR_TO_PIXEL_WIDTH (f, 0); | |
10264 size_hints.max_height | |
10265 = FRAME_X_DISPLAY_INFO (f)->height - CHAR_TO_PIXEL_HEIGHT (f, 0); | |
10266 | |
10267 /* Calculate the base and minimum sizes. | |
10268 | |
10269 (When we use the X toolkit, we don't do it here. | |
10270 Instead we copy the values that the widgets are using, below.) */ | |
10271 #ifndef USE_X_TOOLKIT | |
10272 { | |
10273 int base_width, base_height; | |
10274 int min_rows = 0, min_cols = 0; | |
10275 | |
10276 base_width = CHAR_TO_PIXEL_WIDTH (f, 0); | |
10277 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0); | |
10278 | |
10279 check_frame_size (f, &min_rows, &min_cols); | |
10280 | |
10281 /* The window manager uses the base width hints to calculate the | |
10282 current number of rows and columns in the frame while | |
10283 resizing; min_width and min_height aren't useful for this | |
10284 purpose, since they might not give the dimensions for a | |
10285 zero-row, zero-column frame. | |
10286 | |
10287 We use the base_width and base_height members if we have | |
10288 them; otherwise, we set the min_width and min_height members | |
10289 to the size for a zero x zero frame. */ | |
10290 | |
10291 #ifdef HAVE_X11R4 | |
10292 size_hints.flags |= PBaseSize; | |
10293 size_hints.base_width = base_width; | |
10294 size_hints.base_height = base_height; | |
10295 size_hints.min_width = base_width + min_cols * size_hints.width_inc; | |
10296 size_hints.min_height = base_height + min_rows * size_hints.height_inc; | |
10297 #else | |
10298 size_hints.min_width = base_width; | |
10299 size_hints.min_height = base_height; | |
10300 #endif | |
10301 } | |
10302 | |
10303 /* If we don't need the old flags, we don't need the old hint at all. */ | |
10304 if (flags) | |
10305 { | |
10306 size_hints.flags |= flags; | |
10307 goto no_read; | |
10308 } | |
10309 #endif /* not USE_X_TOOLKIT */ | |
10310 | |
10311 { | |
10312 XSizeHints hints; /* Sometimes I hate X Windows... */ | |
10313 long supplied_return; | |
10314 int value; | |
10315 | |
10316 #ifdef HAVE_X11R4 | |
10317 value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints, | |
10318 &supplied_return); | |
10319 #else | |
10320 value = XGetNormalHints (FRAME_X_DISPLAY (f), window, &hints); | |
10321 #endif | |
10322 | |
10323 #ifdef USE_X_TOOLKIT | |
10324 size_hints.base_height = hints.base_height; | |
10325 size_hints.base_width = hints.base_width; | |
10326 size_hints.min_height = hints.min_height; | |
10327 size_hints.min_width = hints.min_width; | |
10328 #endif | |
10329 | |
10330 if (flags) | |
10331 size_hints.flags |= flags; | |
10332 else | |
10333 { | |
10334 if (value == 0) | |
10335 hints.flags = 0; | |
10336 if (hints.flags & PSize) | |
10337 size_hints.flags |= PSize; | |
10338 if (hints.flags & PPosition) | |
10339 size_hints.flags |= PPosition; | |
10340 if (hints.flags & USPosition) | |
10341 size_hints.flags |= USPosition; | |
10342 if (hints.flags & USSize) | |
10343 size_hints.flags |= USSize; | |
10344 } | |
10345 } | |
10346 | |
10347 #ifndef USE_X_TOOLKIT | |
10348 no_read: | |
10349 #endif | |
10350 | |
10351 #ifdef PWinGravity | |
10352 size_hints.win_gravity = f->output_data.x->win_gravity; | |
10353 size_hints.flags |= PWinGravity; | |
10354 | |
10355 if (user_position) | |
10356 { | |
10357 size_hints.flags &= ~ PPosition; | |
10358 size_hints.flags |= USPosition; | |
10359 } | |
10360 #endif /* PWinGravity */ | |
10361 | |
10362 #ifdef HAVE_X11R4 | |
10363 XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints); | |
10364 #else | |
10365 XSetNormalHints (FRAME_X_DISPLAY (f), window, &size_hints); | |
10366 #endif | |
10367 #endif /* MAC_TODO */ | |
10368 } | |
10369 | |
10370 #if 0 /* MAC_TODO: hide application instead of iconify? */ | |
10371 /* Used for IconicState or NormalState */ | |
10372 | |
10373 void | |
10374 x_wm_set_window_state (f, state) | |
10375 struct frame *f; | |
10376 int state; | |
10377 { | |
10378 #ifdef USE_X_TOOLKIT | |
10379 Arg al[1]; | |
10380 | |
10381 XtSetArg (al[0], XtNinitialState, state); | |
10382 XtSetValues (f->output_data.x->widget, al, 1); | |
10383 #else /* not USE_X_TOOLKIT */ | |
10384 Window window = FRAME_X_WINDOW (f); | |
10385 | |
10386 f->output_data.x->wm_hints.flags |= StateHint; | |
10387 f->output_data.x->wm_hints.initial_state = state; | |
10388 | |
10389 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints); | |
10390 #endif /* not USE_X_TOOLKIT */ | |
10391 } | |
10392 | |
10393 void | |
10394 x_wm_set_icon_pixmap (f, pixmap_id) | |
10395 struct frame *f; | |
10396 int pixmap_id; | |
10397 { | |
10398 Pixmap icon_pixmap; | |
10399 | |
10400 #ifndef USE_X_TOOLKIT | |
10401 Window window = FRAME_X_WINDOW (f); | |
10402 #endif | |
10403 | |
10404 if (pixmap_id > 0) | |
10405 { | |
10406 icon_pixmap = x_bitmap_pixmap (f, pixmap_id); | |
10407 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap; | |
10408 } | |
10409 else | |
10410 { | |
10411 /* It seems there is no way to turn off use of an icon pixmap. | |
10412 The following line does it, only if no icon has yet been created, | |
10413 for some window managers. But with mwm it crashes. | |
10414 Some people say it should clear the IconPixmapHint bit in this case, | |
10415 but that doesn't work, and the X consortium said it isn't the | |
10416 right thing at all. Since there is no way to win, | |
10417 best to explicitly give up. */ | |
10418 #if 0 | |
10419 f->output_data.x->wm_hints.icon_pixmap = None; | |
10420 #else | |
10421 return; | |
10422 #endif | |
10423 } | |
10424 | |
10425 #ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */ | |
10426 | |
10427 { | |
10428 Arg al[1]; | |
10429 XtSetArg (al[0], XtNiconPixmap, icon_pixmap); | |
10430 XtSetValues (f->output_data.x->widget, al, 1); | |
10431 } | |
10432 | |
10433 #else /* not USE_X_TOOLKIT */ | |
10434 | |
10435 f->output_data.x->wm_hints.flags |= IconPixmapHint; | |
10436 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints); | |
10437 | |
10438 #endif /* not USE_X_TOOLKIT */ | |
10439 } | |
10440 | |
10441 #endif /* MAC_TODO */ | |
10442 | |
10443 void | |
10444 x_wm_set_icon_position (f, icon_x, icon_y) | |
10445 struct frame *f; | |
10446 int icon_x, icon_y; | |
10447 { | |
10448 #if 0 /* MAC_TODO: no icons on Mac */ | |
10449 #ifdef USE_X_TOOLKIT | |
10450 Window window = XtWindow (f->output_data.x->widget); | |
10451 #else | |
10452 Window window = FRAME_X_WINDOW (f); | |
10453 #endif | |
10454 | |
10455 f->output_data.x->wm_hints.flags |= IconPositionHint; | |
10456 f->output_data.x->wm_hints.icon_x = icon_x; | |
10457 f->output_data.x->wm_hints.icon_y = icon_y; | |
10458 | |
10459 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints); | |
10460 #endif /* MAC_TODO */ | |
10461 } | |
10462 | |
10463 | |
10464 /*********************************************************************** | |
10465 Fonts | |
10466 ***********************************************************************/ | |
10467 | |
10468 /* Return a pointer to struct font_info of font FONT_IDX of frame F. */ | |
10469 | |
10470 struct font_info * | |
10471 x_get_font_info (f, font_idx) | |
10472 FRAME_PTR f; | |
10473 int font_idx; | |
10474 { | |
10475 return (FRAME_MAC_FONT_TABLE (f) + font_idx); | |
10476 } | |
10477 | |
10478 /* the global font name table */ | |
10479 char **font_name_table = NULL; | |
10480 int font_name_table_size = 0; | |
10481 int font_name_count = 0; | |
10482 | |
10483 /* compare two strings ignoring case */ | |
10484 static int | |
10485 stricmp (const char *s, const char *t) | |
10486 { | |
10487 for ( ; tolower (*s) == tolower (*t); s++, t++) | |
10488 if (*s == '\0') | |
10489 return 0; | |
10490 return tolower (*s) - tolower (*t); | |
10491 } | |
10492 | |
10493 /* compare two strings ignoring case and handling wildcard */ | |
10494 static int | |
10495 wildstrieq (char *s1, char *s2) | |
10496 { | |
10497 if (strcmp (s1, "*") == 0 || strcmp (s2, "*") == 0) | |
10498 return true; | |
10499 | |
10500 return stricmp (s1, s2) == 0; | |
10501 } | |
10502 | |
10503 /* Assume parameter 1 is fully qualified, no wildcards. */ | |
10504 static int | |
10505 mac_font_pattern_match (fontname, pattern) | |
10506 char * fontname; | |
10507 char * pattern; | |
10508 { | |
10509 char *regex = (char *) alloca (strlen (pattern) * 2 + 3); | |
10510 char *font_name_copy = (char *) alloca (strlen (fontname) + 1); | |
10511 char *ptr; | |
10512 | |
10513 /* Copy fontname so we can modify it during comparison. */ | |
10514 strcpy (font_name_copy, fontname); | |
10515 | |
10516 ptr = regex; | |
10517 *ptr++ = '^'; | |
10518 | |
10519 /* Turn pattern into a regexp and do a regexp match. */ | |
10520 for (; *pattern; pattern++) | |
10521 { | |
10522 if (*pattern == '?') | |
10523 *ptr++ = '.'; | |
10524 else if (*pattern == '*') | |
10525 { | |
10526 *ptr++ = '.'; | |
10527 *ptr++ = '*'; | |
10528 } | |
10529 else | |
10530 *ptr++ = *pattern; | |
10531 } | |
10532 *ptr = '$'; | |
10533 *(ptr + 1) = '\0'; | |
10534 | |
10535 return (fast_c_string_match_ignore_case (build_string (regex), | |
10536 font_name_copy) >= 0); | |
10537 } | |
10538 | |
10539 /* Two font specs are considered to match if their foundry, family, | |
10540 weight, slant, and charset match. */ | |
10541 static int | |
10542 mac_font_match (char *mf, char *xf) | |
10543 { | |
10544 char m_foundry[50], m_family[50], m_weight[20], m_slant[2], m_charset[20]; | |
10545 char x_foundry[50], x_family[50], x_weight[20], x_slant[2], x_charset[20]; | |
10546 | |
10547 if (sscanf (mf, "-%49[^-]-%49[^-]-%19[^-]-%1[^-]-%*[^-]--%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%19s", | |
10548 m_foundry, m_family, m_weight, m_slant, m_charset) != 5) | |
10549 return mac_font_pattern_match (mf, xf); | |
10550 | |
10551 if (sscanf (xf, "-%49[^-]-%49[^-]-%19[^-]-%1[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%19s", | |
10552 x_foundry, x_family, x_weight, x_slant, x_charset) != 5) | |
10553 return mac_font_pattern_match (mf, xf); | |
10554 | |
10555 return (wildstrieq (m_foundry, x_foundry) | |
10556 && wildstrieq (m_family, x_family) | |
10557 && wildstrieq (m_weight, x_weight) | |
10558 && wildstrieq (m_slant, x_slant) | |
10559 && wildstrieq (m_charset, x_charset)) | |
10560 || mac_font_pattern_match (mf, xf); | |
10561 } | |
10562 | |
10563 | |
10564 static char * | |
10565 mac_to_x_fontname (char *name, int size, Style style, short scriptcode) | |
10566 { | |
10567 char foundry[32], family[32], cs[32]; | |
10568 char xf[255], *result, *p; | |
10569 | |
10570 if (sscanf (name, "%31[^-]-%31[^-]-%31s", foundry, family, cs) != 3) | |
10571 { | |
10572 strcpy(foundry, "Apple"); | |
10573 strcpy(family, name); | |
10574 | |
10575 switch (scriptcode) | |
10576 { | |
10577 case smTradChinese: | |
10578 strcpy(cs, "big5-0"); | |
10579 break; | |
10580 case smSimpChinese: | |
10581 strcpy(cs, "gb2312.1980-0"); | |
10582 break; | |
10583 case smJapanese: | |
10584 strcpy(cs, "jisx0208.1983-sjis"); | |
10585 break; | |
10586 case -smJapanese: | |
10587 /* Each Apple Japanese font is entered into the font table | |
10588 twice: once as a jisx0208.1983-sjis font and once as a | |
10589 jisx0201.1976-0 font. The latter can be used to display | |
10590 the ascii charset and katakana-jisx0201 charset. A | |
10591 negative script code signals that the name of this latter | |
10592 font is being built. */ | |
10593 strcpy(cs, "jisx0201.1976-0"); | |
10594 break; | |
10595 case smKorean: | |
10596 strcpy(cs, "ksc5601.1989-0"); | |
10597 break; | |
10598 default: | |
10599 strcpy(cs, "mac-roman"); | |
10600 break; | |
10601 } | |
10602 } | |
10603 | |
10604 sprintf(xf, "-%s-%s-%s-%c-normal--%d-%d-75-75-m-%d-%s", | |
10605 foundry, family, style & bold ? "bold" : "medium", | |
10606 style & italic ? 'i' : 'r', size, size * 10, size * 10, cs); | |
10607 | |
10608 result = (char *) xmalloc (strlen (xf) + 1); | |
10609 strcpy (result, xf); | |
10610 for (p = result; *p; p++) | |
10611 *p = tolower(*p); | |
10612 return result; | |
10613 } | |
10614 | |
10615 | |
10616 /* Convert an X font spec to the corresponding mac font name, which | |
10617 can then be passed to GetFNum after conversion to a Pascal string. | |
10618 For ordinary Mac fonts, this should just be their names, like | |
10619 "monaco", "Taipei", etc. Fonts converted from the GNU intlfonts | |
10620 collection contain their charset designation in their names, like | |
10621 "ETL-Fixed-iso8859-1", "ETL-Fixed-koi8-r", etc. Both types of font | |
10622 names are handled accordingly. */ | |
10623 static void | |
10624 x_font_name_to_mac_font_name (char *xf, char *mf) | |
10625 { | |
10626 char foundry[32], family[32], weight[20], slant[2], cs[32]; | |
10627 | |
10628 strcpy (mf, ""); | |
10629 | |
10630 if (sscanf (xf, "-%31[^-]-%31[^-]-%19[^-]-%1[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%31s", | |
10631 foundry, family, weight, slant, cs) != 5 && | |
10632 sscanf (xf, "-%31[^-]-%31[^-]-%19[^-]-%1[^-]-%*[^-]--%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%31s", | |
10633 foundry, family, weight, slant, cs) != 5) | |
10634 return; | |
10635 | |
10636 if (strcmp (cs, "big5-0") == 0 || strcmp (cs, "gb2312.1980-0") == 0 | |
10637 || strcmp (cs, "jisx0208.1983-sjis") == 0 | |
10638 || strcmp (cs, "jisx0201.1976-0") == 0 | |
10639 || strcmp (cs, "ksc5601.1989-0") == 0 || strcmp (cs, "mac-roman") == 0) | |
10640 strcpy(mf, family); | |
10641 else | |
10642 sprintf(mf, "%s-%s-%s", foundry, family, cs); | |
10643 } | |
10644 | |
10645 | |
10646 /* Sets up the table font_name_table to contain the list of all | |
10647 monospace fonts in the system the first time the table is used so | |
10648 that the Resource Manager need not be accessed every time this | |
10649 information is needed. */ | |
10650 | |
10651 static void | |
10652 init_font_name_table () | |
10653 { | |
10654 #if TARGET_API_MAC_CARBON | |
10655 SInt32 sv; | |
10656 | |
10657 if (Gestalt (gestaltSystemVersion, &sv) == noErr && sv >= 0x1000) | |
10658 { | |
10659 FMFontFamilyIterator ffi; | |
10660 FMFontFamilyInstanceIterator ffii; | |
10661 FMFontFamily ff; | |
10662 | |
10663 /* Create a dummy instance iterator here to avoid creating and | |
10664 destroying it in the loop. */ | |
10665 if (FMCreateFontFamilyInstanceIterator (0, &ffii) != noErr) | |
10666 return; | |
10667 /* Create an iterator to enumerate the font families. */ | |
10668 if (FMCreateFontFamilyIterator (NULL, NULL, kFMDefaultOptions, &ffi) | |
10669 != noErr) | |
10670 { | |
10671 FMDisposeFontFamilyInstanceIterator (&ffii); | |
10672 return; | |
10673 } | |
10674 | |
10675 while (FMGetNextFontFamily (&ffi, &ff) == noErr) | |
10676 { | |
10677 Str255 name; | |
10678 FMFont font; | |
10679 FMFontStyle style; | |
10680 FMFontSize size; | |
10681 SInt16 sc; | |
10682 | |
10683 if (FMGetFontFamilyName (ff, name) != noErr) | |
10684 break; | |
10685 p2cstr (name); | |
10686 | |
10687 sc = FontToScript (ff); | |
10688 | |
10689 /* Point the instance iterator at the current font family. */ | |
10690 if (FMResetFontFamilyInstanceIterator(ff, &ffii) != noErr) | |
10691 break; | |
10692 | |
10693 while (FMGetNextFontFamilyInstance (&ffii, &font, &style, &size) | |
10694 == noErr) | |
10695 { | |
10696 if (font_name_table_size == 0) | |
10697 { | |
10698 font_name_table_size = 16; | |
10699 font_name_table = (char **) | |
10700 xmalloc (font_name_table_size * sizeof (char *)); | |
10701 } | |
10702 else if (font_name_count + 1 >= font_name_table_size) | |
10703 { | |
10704 font_name_table_size += 16; | |
10705 font_name_table = (char **) | |
10706 xrealloc (font_name_table, | |
10707 font_name_table_size * sizeof (char *)); | |
10708 } | |
10709 font_name_table[font_name_count++] | |
10710 = mac_to_x_fontname (name, size, style, sc); | |
10711 } | |
10712 } | |
10713 | |
10714 /* Dispose of the iterators. */ | |
10715 FMDisposeFontFamilyIterator (&ffi); | |
10716 FMDisposeFontFamilyInstanceIterator (&ffii); | |
10717 } | |
10718 else | |
10719 { | |
10720 #endif /* TARGET_API_MAC_CARBON */ | |
10721 GrafPtr port; | |
10722 SInt16 fontnum, old_fontnum; | |
10723 int num_mac_fonts = CountResources('FOND'); | |
10724 int i, j; | |
10725 Handle font_handle, font_handle_2; | |
10726 short id, scriptcode; | |
10727 ResType type; | |
10728 Str32 name; | |
10729 struct FontAssoc *fat; | |
10730 struct AsscEntry *assc_entry; | |
10731 | |
10732 GetPort (&port); /* save the current font number used */ | |
10733 #if TARGET_API_MAC_CARBON | |
10734 old_fontnum = GetPortTextFont (port); | |
10735 #else | |
10736 old_fontnum = port->txFont; | |
10737 #endif | |
10738 | |
10739 for (i = 1; i <= num_mac_fonts; i++) /* get all available fonts */ | |
10740 { | |
10741 font_handle = GetIndResource ('FOND', i); | |
10742 if (!font_handle) | |
10743 continue; | |
10744 | |
10745 GetResInfo (font_handle, &id, &type, name); | |
10746 GetFNum (name, &fontnum); | |
10747 p2cstr (name); | |
10748 if (fontnum == 0) | |
10749 continue; | |
10750 | |
10751 TextFont (fontnum); | |
10752 scriptcode = FontToScript (fontnum); | |
10753 do | |
10754 { | |
10755 HLock (font_handle); | |
10756 | |
10757 if (GetResourceSizeOnDisk (font_handle) | |
10758 >= sizeof (struct FamRec)) | |
10759 { | |
10760 fat = (struct FontAssoc *) (*font_handle | |
10761 + sizeof (struct FamRec)); | |
10762 assc_entry | |
10763 = (struct AsscEntry *) (*font_handle | |
10764 + sizeof (struct FamRec) | |
10765 + sizeof (struct FontAssoc)); | |
10766 | |
10767 for (j = 0; j <= fat->numAssoc; j++, assc_entry++) | |
10768 { | |
10769 if (font_name_table_size == 0) | |
10770 { | |
10771 font_name_table_size = 16; | |
10772 font_name_table = (char **) | |
10773 xmalloc (font_name_table_size * sizeof (char *)); | |
10774 } | |
10775 else if (font_name_count >= font_name_table_size) | |
10776 { | |
10777 font_name_table_size += 16; | |
10778 font_name_table = (char **) | |
10779 xrealloc (font_name_table, | |
10780 font_name_table_size * sizeof (char *)); | |
10781 } | |
10782 font_name_table[font_name_count++] | |
10783 = mac_to_x_fontname (name, | |
10784 assc_entry->fontSize, | |
10785 assc_entry->fontStyle, | |
10786 scriptcode); | |
10787 /* Both jisx0208.1983-sjis and | |
10788 jisx0201.1976-sjis parts are contained in | |
10789 Apple Japanese (SJIS) font. */ | |
10790 if (smJapanese == scriptcode) | |
10791 { | |
10792 font_name_table[font_name_count++] | |
10793 = mac_to_x_fontname (name, | |
10794 assc_entry->fontSize, | |
10795 assc_entry->fontStyle, | |
10796 smRoman); | |
10797 } | |
10798 } | |
10799 } | |
10800 | |
10801 HUnlock (font_handle); | |
10802 font_handle_2 = GetNextFOND (font_handle); | |
10803 ReleaseResource (font_handle); | |
10804 font_handle = font_handle_2; | |
10805 } | |
10806 while (ResError () == noErr && font_handle); | |
10807 } | |
10808 | |
10809 TextFont (old_fontnum); | |
10810 #if TARGET_API_MAC_CARBON | |
10811 } | |
10812 #endif /* TARGET_API_MAC_CARBON */ | |
10813 } | |
10814 | |
10815 | |
10816 /* Return a list of at most MAXNAMES font specs matching the one in | |
10817 PATTERN. Note that each '*' in the PATTERN matches exactly one | |
10818 field of the font spec, unlike X in which an '*' in a font spec can | |
10819 match a number of fields. The result is in the Mac implementation | |
10820 all fonts must be specified by a font spec with all 13 fields | |
10821 (although many of these can be "*'s"). */ | |
10822 | |
10823 Lisp_Object | |
10824 x_list_fonts (struct frame *f, | |
10825 Lisp_Object pattern, | |
10826 int size, | |
10827 int maxnames) | |
10828 { | |
10829 char *ptnstr; | |
10830 Lisp_Object newlist = Qnil; | |
10831 int n_fonts = 0; | |
10832 int i; | |
10833 struct gcpro gcpro1, gcpro2; | |
10834 | |
10835 if (font_name_table == NULL) /* Initialize when first used. */ | |
10836 init_font_name_table (); | |
10837 | |
10838 ptnstr = XSTRING (pattern)->data; | |
10839 | |
10840 GCPRO2 (pattern, newlist); | |
10841 | |
10842 /* Scan and matching bitmap fonts. */ | |
10843 for (i = 0; i < font_name_count; i++) | |
10844 { | |
10845 if (mac_font_pattern_match (font_name_table[i], ptnstr)) | |
10846 { | |
10847 newlist = Fcons (build_string (font_name_table[i]), newlist); | |
10848 | |
10849 n_fonts++; | |
10850 if (n_fonts >= maxnames) | |
10851 break; | |
10852 } | |
10853 } | |
10854 | |
10855 /* MAC_TODO: add code for matching outline fonts here */ | |
10856 | |
10857 UNGCPRO; | |
10858 | |
10859 return newlist; | |
10860 } | |
10861 | |
10862 | |
10863 #if GLYPH_DEBUG | |
10864 | |
10865 /* Check that FONT is valid on frame F. It is if it can be found in F's | |
10866 font table. */ | |
10867 | |
10868 static void | |
10869 x_check_font (f, font) | |
10870 struct frame *f; | |
10871 XFontStruct *font; | |
10872 { | |
10873 int i; | |
10874 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f); | |
10875 | |
10876 xassert (font != NULL); | |
10877 | |
10878 for (i = 0; i < dpyinfo->n_fonts; i++) | |
10879 if (dpyinfo->font_table[i].name | |
10880 && font == dpyinfo->font_table[i].font) | |
10881 break; | |
10882 | |
10883 xassert (i < dpyinfo->n_fonts); | |
10884 } | |
10885 | |
10886 #endif /* GLYPH_DEBUG != 0 */ | |
10887 | |
10888 /* Set *W to the minimum width, *H to the minimum font height of FONT. | |
10889 Note: There are (broken) X fonts out there with invalid XFontStruct | |
10890 min_bounds contents. For example, handa@etl.go.jp reports that | |
10891 "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts | |
10892 have font->min_bounds.width == 0. */ | |
10893 | |
10894 static INLINE void | |
10895 x_font_min_bounds (font, w, h) | |
10896 MacFontStruct *font; | |
10897 int *w, *h; | |
10898 { | |
10899 /* | |
10900 * TODO: Windows does not appear to offer min bound, only | |
10901 * average and maximum width, and maximum height. | |
10902 */ | |
10903 *h = FONT_HEIGHT (font); | |
10904 *w = FONT_WIDTH (font); | |
10905 } | |
10906 | |
10907 | |
10908 /* Compute the smallest character width and smallest font height over | |
10909 all fonts available on frame F. Set the members smallest_char_width | |
10910 and smallest_font_height in F's x_display_info structure to | |
10911 the values computed. Value is non-zero if smallest_font_height or | |
10912 smallest_char_width become smaller than they were before. */ | |
10913 | |
10914 int | |
10915 x_compute_min_glyph_bounds (f) | |
10916 struct frame *f; | |
10917 { | |
10918 int i; | |
10919 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); | |
10920 MacFontStruct *font; | |
10921 int old_width = dpyinfo->smallest_char_width; | |
10922 int old_height = dpyinfo->smallest_font_height; | |
10923 | |
10924 dpyinfo->smallest_font_height = 100000; | |
10925 dpyinfo->smallest_char_width = 100000; | |
10926 | |
10927 for (i = 0; i < dpyinfo->n_fonts; ++i) | |
10928 if (dpyinfo->font_table[i].name) | |
10929 { | |
10930 struct font_info *fontp = dpyinfo->font_table + i; | |
10931 int w, h; | |
10932 | |
10933 font = (MacFontStruct *) fontp->font; | |
10934 xassert (font != (MacFontStruct *) ~0); | |
10935 x_font_min_bounds (font, &w, &h); | |
10936 | |
10937 dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h); | |
10938 dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w); | |
10939 } | |
10940 | |
10941 xassert (dpyinfo->smallest_char_width > 0 | |
10942 && dpyinfo->smallest_font_height > 0); | |
10943 | |
10944 return (dpyinfo->n_fonts == 1 | |
10945 || dpyinfo->smallest_char_width < old_width | |
10946 || dpyinfo->smallest_font_height < old_height); | |
10947 } | |
10948 | |
10949 | |
10950 /* Determine whether given string is a fully-specified XLFD: all 14 | |
10951 fields are present, none is '*'. */ | |
10952 | |
10953 static int | |
10954 is_fully_specified_xlfd (char *p) | |
10955 { | |
10956 int i; | |
10957 char *q; | |
10958 | |
10959 if (*p != '-') | |
10960 return 0; | |
10961 | |
10962 for (i = 0; i < 13; i++) | |
10963 { | |
10964 q = strchr (p + 1, '-'); | |
10965 if (q == NULL) | |
10966 return 0; | |
10967 if (q - p == 2 && *(p + 1) == '*') | |
10968 return 0; | |
10969 p = q; | |
10970 } | |
10971 | |
10972 if (strchr (p + 1, '-') != NULL) | |
10973 return 0; | |
10974 | |
10975 if (*(p + 1) == '*' && *(p + 2) == '\0') | |
10976 return 0; | |
10977 | |
10978 return 1; | |
10979 } | |
10980 | |
10981 | |
10982 const int kDefaultFontSize = 9; | |
10983 | |
10984 | |
10985 /* XLoadQueryFont creates and returns an internal representation for a | |
10986 font in a MacFontStruct struct. There is really no concept | |
10987 corresponding to "loading" a font on the Mac. But we check its | |
10988 existence and find the font number and all other information for it | |
10989 and store them in the returned MacFontStruct. */ | |
10990 | |
10991 static MacFontStruct * | |
10992 XLoadQueryFont (Display *dpy, char *fontname) | |
10993 { | |
10994 int i, size, is_two_byte_font, char_width; | |
10995 char *name; | |
10996 GrafPtr port; | |
10997 SInt16 old_fontnum, old_fontsize; | |
10998 Style old_fontface; | |
10999 Str32 mfontname; | |
11000 SInt16 fontnum; | |
11001 Style fontface = normal; | |
11002 MacFontStruct *font; | |
11003 FontInfo the_fontinfo; | |
11004 char s_weight[7], c_slant; | |
11005 | |
11006 if (is_fully_specified_xlfd (fontname)) | |
11007 name = fontname; | |
11008 else | |
11009 { | |
11010 for (i = 0; i < font_name_count; i++) | |
11011 if (mac_font_pattern_match (font_name_table[i], fontname)) | |
11012 break; | |
11013 | |
11014 if (i >= font_name_count) | |
11015 return NULL; | |
11016 | |
11017 name = font_name_table[i]; | |
11018 } | |
11019 | |
11020 GetPort (&port); /* save the current font number used */ | |
11021 #if TARGET_API_MAC_CARBON | |
11022 old_fontnum = GetPortTextFont (port); | |
11023 old_fontsize = GetPortTextSize (port); | |
11024 old_fontface = GetPortTextFace (port); | |
11025 #else | |
11026 old_fontnum = port->txFont; | |
11027 old_fontsize = port->txSize; | |
11028 old_fontface = port->txFace; | |
11029 #endif | |
11030 | |
11031 if (sscanf (name, "-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]--%d-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%*s", &size) != 1) | |
11032 size = kDefaultFontSize; | |
11033 | |
11034 if (sscanf (name, "-%*[^-]-%*[^-]-%6[^-]-%*c-%*[^-]--%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%*s", s_weight) == 1) | |
11035 if (strcmp (s_weight, "bold") == 0) | |
11036 fontface |= bold; | |
11037 | |
11038 if (sscanf (name, "-%*[^-]-%*[^-]-%*[^-]-%c-%*[^-]--%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%*s", &c_slant) == 1) | |
11039 if (c_slant == 'i') | |
11040 fontface |= italic; | |
11041 | |
11042 x_font_name_to_mac_font_name (name, mfontname); | |
11043 c2pstr (mfontname); | |
11044 GetFNum (mfontname, &fontnum); | |
11045 if (fontnum == 0) | |
11046 return NULL; | |
11047 | |
11048 font = (MacFontStruct *) xmalloc (sizeof (struct MacFontStruct)); | |
11049 | |
11050 font->fontname = (char *) xmalloc (strlen (name) + 1); | |
11051 bcopy (name, font->fontname, strlen (name) + 1); | |
11052 | |
11053 font->mac_fontnum = fontnum; | |
11054 font->mac_fontsize = size; | |
11055 font->mac_fontface = fontface; | |
11056 font->mac_scriptcode = FontToScript (fontnum); | |
11057 | |
11058 /* Apple Japanese (SJIS) font is listed as both | |
11059 "*-jisx0208.1983-sjis" (Japanese script) and "*-jisx0201.1976-0" | |
11060 (Roman script) in init_font_name_table (). The latter should be | |
11061 treated as a one-byte font. */ | |
11062 { | |
11063 char cs[32]; | |
11064 | |
11065 if (sscanf (name, | |
11066 "-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]--%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*c-%*[^-]-%31s", | |
11067 cs) == 1 | |
11068 && 0 == strcmp (cs, "mac-roman")) | |
11069 font->mac_scriptcode = smRoman; | |
11070 } | |
11071 | |
11072 is_two_byte_font = font->mac_scriptcode == smJapanese || | |
11073 font->mac_scriptcode == smTradChinese || | |
11074 font->mac_scriptcode == smSimpChinese || | |
11075 font->mac_scriptcode == smKorean; | |
11076 | |
11077 TextFont (fontnum); | |
11078 TextSize (size); | |
11079 TextFace (fontface); | |
11080 | |
11081 GetFontInfo (&the_fontinfo); | |
11082 | |
11083 font->ascent = the_fontinfo.ascent; | |
11084 font->descent = the_fontinfo.descent; | |
11085 | |
11086 font->min_byte1 = 0; | |
11087 if (is_two_byte_font) | |
11088 font->max_byte1 = 1; | |
11089 else | |
11090 font->max_byte1 = 0; | |
11091 font->min_char_or_byte2 = 0x20; | |
11092 font->max_char_or_byte2 = 0xff; | |
11093 | |
11094 if (is_two_byte_font) | |
11095 { | |
11096 /* Use the width of an "ideographic space" of that font because | |
11097 the_fontinfo.widMax returns the wrong width for some fonts. */ | |
11098 switch (font->mac_scriptcode) | |
11099 { | |
11100 case smJapanese: | |
11101 char_width = StringWidth("\p\x81\x40"); | |
11102 break; | |
11103 case smTradChinese: | |
11104 char_width = StringWidth("\p\xa1\x40"); | |
11105 break; | |
11106 case smSimpChinese: | |
11107 char_width = StringWidth("\p\xa1\xa1"); | |
11108 break; | |
11109 case smKorean: | |
11110 char_width = StringWidth("\p\xa1\xa1"); | |
11111 break; | |
11112 } | |
11113 } | |
11114 else | |
11115 /* Do this instead of use the_fontinfo.widMax, which incorrectly | |
11116 returns 15 for 12-point Monaco! */ | |
11117 char_width = CharWidth ('m'); | |
11118 | |
11119 font->max_bounds.rbearing = char_width; | |
11120 font->max_bounds.lbearing = 0; | |
11121 font->max_bounds.width = char_width; | |
11122 font->max_bounds.ascent = the_fontinfo.ascent; | |
11123 font->max_bounds.descent = the_fontinfo.descent; | |
11124 | |
11125 font->min_bounds = font->max_bounds; | |
11126 | |
11127 if (is_two_byte_font || CharWidth ('m') == CharWidth ('i')) | |
11128 font->per_char = NULL; | |
11129 else | |
11130 { | |
11131 font->per_char = (XCharStruct *) | |
11132 xmalloc (sizeof (XCharStruct) * (0xff - 0x20 + 1)); | |
11133 { | |
11134 int c; | |
11135 | |
11136 for (c = 0x20; c <= 0xff; c++) | |
11137 { | |
11138 font->per_char[c - 0x20] = font->max_bounds; | |
11139 font->per_char[c - 0x20].width = CharWidth (c); | |
11140 } | |
11141 } | |
11142 } | |
11143 | |
11144 TextFont (old_fontnum); /* restore previous font number, size and face */ | |
11145 TextSize (old_fontsize); | |
11146 TextFace (old_fontface); | |
11147 | |
11148 return font; | |
11149 } | |
11150 | |
11151 | |
11152 /* Load font named FONTNAME of the size SIZE for frame F, and return a | |
11153 pointer to the structure font_info while allocating it dynamically. | |
11154 If SIZE is 0, load any size of font. | |
11155 If loading is failed, return NULL. */ | |
11156 | |
11157 struct font_info * | |
11158 x_load_font (f, fontname, size) | |
11159 struct frame *f; | |
11160 register char *fontname; | |
11161 int size; | |
11162 { | |
11163 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); | |
11164 Lisp_Object font_names; | |
11165 | |
11166 /* Get a list of all the fonts that match this name. Once we | |
11167 have a list of matching fonts, we compare them against the fonts | |
11168 we already have by comparing names. */ | |
11169 font_names = x_list_fonts (f, build_string (fontname), size, 1); | |
11170 | |
11171 if (!NILP (font_names)) | |
11172 { | |
11173 Lisp_Object tail; | |
11174 int i; | |
11175 | |
11176 for (i = 0; i < dpyinfo->n_fonts; i++) | |
11177 for (tail = font_names; CONSP (tail); tail = XCDR (tail)) | |
11178 if (dpyinfo->font_table[i].name | |
11179 && (!strcmp (dpyinfo->font_table[i].name, | |
11180 XSTRING (XCAR (tail))->data) | |
11181 || !strcmp (dpyinfo->font_table[i].full_name, | |
11182 XSTRING (XCAR (tail))->data))) | |
11183 return (dpyinfo->font_table + i); | |
11184 } | |
11185 | |
11186 /* Load the font and add it to the table. */ | |
11187 { | |
11188 char *full_name; | |
11189 struct MacFontStruct *font; | |
11190 struct font_info *fontp; | |
11191 unsigned long value; | |
11192 int i; | |
11193 | |
11194 /* If we have found fonts by x_list_font, load one of them. If | |
11195 not, we still try to load a font by the name given as FONTNAME | |
11196 because XListFonts (called in x_list_font) of some X server has | |
11197 a bug of not finding a font even if the font surely exists and | |
11198 is loadable by XLoadQueryFont. */ | |
11199 if (size > 0 && !NILP (font_names)) | |
11200 fontname = (char *) XSTRING (XCAR (font_names))->data; | |
11201 | |
11202 font = (MacFontStruct *) XLoadQueryFont (FRAME_MAC_DISPLAY (f), fontname); | |
11203 if (!font) | |
11204 return NULL; | |
11205 | |
11206 /* Find a free slot in the font table. */ | |
11207 for (i = 0; i < dpyinfo->n_fonts; ++i) | |
11208 if (dpyinfo->font_table[i].name == NULL) | |
11209 break; | |
11210 | |
11211 /* If no free slot found, maybe enlarge the font table. */ | |
11212 if (i == dpyinfo->n_fonts | |
11213 && dpyinfo->n_fonts == dpyinfo->font_table_size) | |
11214 { | |
11215 int sz; | |
11216 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size); | |
11217 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table; | |
11218 dpyinfo->font_table | |
11219 = (struct font_info *) xrealloc (dpyinfo->font_table, sz); | |
11220 } | |
11221 | |
11222 fontp = dpyinfo->font_table + i; | |
11223 if (i == dpyinfo->n_fonts) | |
11224 ++dpyinfo->n_fonts; | |
11225 | |
11226 /* Now fill in the slots of *FONTP. */ | |
11227 BLOCK_INPUT; | |
11228 fontp->font = font; | |
11229 fontp->font_idx = i; | |
11230 fontp->name = (char *) xmalloc (strlen (font->fontname) + 1); | |
11231 bcopy (font->fontname, fontp->name, strlen (font->fontname) + 1); | |
11232 | |
11233 fontp->full_name = fontp->name; | |
11234 | |
11235 fontp->size = font->max_bounds.width; | |
11236 fontp->height = FONT_HEIGHT (font); | |
11237 { | |
11238 /* For some font, ascent and descent in max_bounds field is | |
11239 larger than the above value. */ | |
11240 int max_height = font->max_bounds.ascent + font->max_bounds.descent; | |
11241 if (max_height > fontp->height) | |
11242 fontp->height = max_height; | |
11243 } | |
11244 | |
11245 /* The slot `encoding' specifies how to map a character | |
11246 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to | |
11247 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or | |
11248 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF, | |
11249 2:0xA020..0xFF7F). For the moment, we don't know which charset | |
11250 uses this font. So, we set information in fontp->encoding[1] | |
11251 which is never used by any charset. If mapping can't be | |
11252 decided, set FONT_ENCODING_NOT_DECIDED. */ | |
11253 if (font->mac_scriptcode == smJapanese) | |
11254 fontp->encoding[1] = 4; | |
11255 else | |
11256 { | |
11257 fontp->encoding[1] | |
11258 = (font->max_byte1 == 0 | |
11259 /* 1-byte font */ | |
11260 ? (font->min_char_or_byte2 < 0x80 | |
11261 ? (font->max_char_or_byte2 < 0x80 | |
11262 ? 0 /* 0x20..0x7F */ | |
11263 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */ | |
11264 : 1) /* 0xA0..0xFF */ | |
11265 /* 2-byte font */ | |
11266 : (font->min_byte1 < 0x80 | |
11267 ? (font->max_byte1 < 0x80 | |
11268 ? (font->min_char_or_byte2 < 0x80 | |
11269 ? (font->max_char_or_byte2 < 0x80 | |
11270 ? 0 /* 0x2020..0x7F7F */ | |
11271 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */ | |
11272 : 3) /* 0x20A0..0x7FFF */ | |
11273 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */ | |
11274 : (font->min_char_or_byte2 < 0x80 | |
11275 ? (font->max_char_or_byte2 < 0x80 | |
11276 ? 2 /* 0xA020..0xFF7F */ | |
11277 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */ | |
11278 : 1))); /* 0xA0A0..0xFFFF */ | |
11279 } | |
11280 | |
11281 #if 0 /* MAC_TODO: fill these out with more reasonably values */ | |
11282 fontp->baseline_offset | |
11283 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value) | |
11284 ? (long) value : 0); | |
11285 fontp->relative_compose | |
11286 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value) | |
11287 ? (long) value : 0); | |
11288 fontp->default_ascent | |
11289 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value) | |
11290 ? (long) value : 0); | |
11291 #else | |
11292 fontp->baseline_offset = 0; | |
11293 fontp->relative_compose = 0; | |
11294 fontp->default_ascent = 0; | |
11295 #endif | |
11296 | |
11297 /* Set global flag fonts_changed_p to non-zero if the font loaded | |
11298 has a character with a smaller width than any other character | |
11299 before, or if the font loaded has a smalle>r height than any | |
11300 other font loaded before. If this happens, it will make a | |
11301 glyph matrix reallocation necessary. */ | |
11302 fonts_changed_p = x_compute_min_glyph_bounds (f); | |
11303 UNBLOCK_INPUT; | |
11304 return fontp; | |
11305 } | |
11306 } | |
11307 | |
11308 | |
11309 /* Return a pointer to struct font_info of a font named FONTNAME for | |
11310 frame F. If no such font is loaded, return NULL. */ | |
11311 | |
11312 struct font_info * | |
11313 x_query_font (f, fontname) | |
11314 struct frame *f; | |
11315 register char *fontname; | |
11316 { | |
11317 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); | |
11318 int i; | |
11319 | |
11320 for (i = 0; i < dpyinfo->n_fonts; i++) | |
11321 if (dpyinfo->font_table[i].name | |
11322 && (!strcmp (dpyinfo->font_table[i].name, fontname) | |
11323 || !strcmp (dpyinfo->font_table[i].full_name, fontname))) | |
11324 return (dpyinfo->font_table + i); | |
11325 return NULL; | |
11326 } | |
11327 | |
11328 | |
11329 /* Find a CCL program for a font specified by FONTP, and set the member | |
11330 `encoder' of the structure. */ | |
11331 | |
11332 void | |
11333 x_find_ccl_program (fontp) | |
11334 struct font_info *fontp; | |
11335 { | |
11336 Lisp_Object list, elt; | |
11337 | |
11338 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list)) | |
11339 { | |
11340 elt = XCAR (list); | |
11341 if (CONSP (elt) | |
11342 && STRINGP (XCAR (elt)) | |
11343 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name) | |
11344 >= 0)) | |
11345 break; | |
11346 } | |
11347 if (! NILP (list)) | |
11348 { | |
11349 struct ccl_program *ccl | |
11350 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program)); | |
11351 | |
11352 if (setup_ccl_program (ccl, XCDR (elt)) < 0) | |
11353 xfree (ccl); | |
11354 else | |
11355 fontp->font_encoder = ccl; | |
11356 } | |
11357 } | |
11358 | |
11359 | |
11360 | |
11361 /*********************************************************************** | |
11362 Initialization | |
11363 ***********************************************************************/ | |
11364 | |
11365 #ifdef USE_X_TOOLKIT | |
11366 static XrmOptionDescRec emacs_options[] = { | |
11367 {"-geometry", ".geometry", XrmoptionSepArg, NULL}, | |
11368 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"}, | |
11369 | |
11370 {"-internal-border-width", "*EmacsScreen.internalBorderWidth", | |
11371 XrmoptionSepArg, NULL}, | |
11372 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL}, | |
11373 | |
11374 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL}, | |
11375 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL}, | |
11376 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL}, | |
11377 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL}, | |
11378 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL}, | |
11379 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL}, | |
11380 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL} | |
11381 }; | |
11382 #endif /* USE_X_TOOLKIT */ | |
11383 | |
11384 static int x_initialized; | |
11385 | |
11386 #ifdef MULTI_KBOARD | |
11387 /* Test whether two display-name strings agree up to the dot that separates | |
11388 the screen number from the server number. */ | |
11389 static int | |
11390 same_x_server (name1, name2) | |
11391 char *name1, *name2; | |
11392 { | |
11393 int seen_colon = 0; | |
11394 unsigned char *system_name = XSTRING (Vsystem_name)->data; | |
11395 int system_name_length = strlen (system_name); | |
11396 int length_until_period = 0; | |
11397 | |
11398 while (system_name[length_until_period] != 0 | |
11399 && system_name[length_until_period] != '.') | |
11400 length_until_period++; | |
11401 | |
11402 /* Treat `unix' like an empty host name. */ | |
11403 if (! strncmp (name1, "unix:", 5)) | |
11404 name1 += 4; | |
11405 if (! strncmp (name2, "unix:", 5)) | |
11406 name2 += 4; | |
11407 /* Treat this host's name like an empty host name. */ | |
11408 if (! strncmp (name1, system_name, system_name_length) | |
11409 && name1[system_name_length] == ':') | |
11410 name1 += system_name_length; | |
11411 if (! strncmp (name2, system_name, system_name_length) | |
11412 && name2[system_name_length] == ':') | |
11413 name2 += system_name_length; | |
11414 /* Treat this host's domainless name like an empty host name. */ | |
11415 if (! strncmp (name1, system_name, length_until_period) | |
11416 && name1[length_until_period] == ':') | |
11417 name1 += length_until_period; | |
11418 if (! strncmp (name2, system_name, length_until_period) | |
11419 && name2[length_until_period] == ':') | |
11420 name2 += length_until_period; | |
11421 | |
11422 for (; *name1 != '\0' && *name1 == *name2; name1++, name2++) | |
11423 { | |
11424 if (*name1 == ':') | |
11425 seen_colon++; | |
11426 if (seen_colon && *name1 == '.') | |
11427 return 1; | |
11428 } | |
11429 return (seen_colon | |
11430 && (*name1 == '.' || *name1 == '\0') | |
11431 && (*name2 == '.' || *name2 == '\0')); | |
11432 } | |
11433 #endif | |
11434 | |
11435 | |
11436 /* The Mac Event loop code */ | |
11437 | |
11438 #ifndef MAC_OSX | |
11439 #include <Events.h> | |
11440 #include <Quickdraw.h> | |
11441 #include <Balloons.h> | |
11442 #include <Devices.h> | |
11443 #include <Fonts.h> | |
11444 #include <Gestalt.h> | |
11445 #include <Menus.h> | |
11446 #include <Processes.h> | |
11447 #include <Sound.h> | |
11448 #include <ToolUtils.h> | |
11449 #include <TextUtils.h> | |
11450 #include <Dialogs.h> | |
11451 #include <Script.h> | |
11452 #include <Types.h> | |
11453 #include <TextEncodingConverter.h> | |
11454 #include <Resources.h> | |
11455 | |
11456 #if __MWERKS__ | |
11457 #include <unix.h> | |
11458 #endif | |
11459 #endif /* ! MAC_OSX */ | |
11460 | |
11461 #define M_APPLE 128 | |
11462 #define I_ABOUT 1 | |
11463 | |
11464 #define WINDOW_RESOURCE 128 | |
11465 #define TERM_WINDOW_RESOURCE 129 | |
11466 | |
11467 #define DEFAULT_NUM_COLS 80 | |
11468 | |
11469 #define MIN_DOC_SIZE 64 | |
11470 #define MAX_DOC_SIZE 32767 | |
11471 | |
11472 /* sleep time for WaitNextEvent */ | |
11473 #define WNE_SLEEP_AT_SUSPEND 10 | |
11474 #define WNE_SLEEP_AT_RESUME 1 | |
11475 | |
11476 /* true when cannot handle any Mac OS events */ | |
11477 static int handling_window_update = 0; | |
11478 | |
11479 /* the flag appl_is_suspended is used both for determining the sleep | |
11480 time to be passed to WaitNextEvent and whether the cursor should be | |
11481 drawn when updating the display. The cursor is turned off when | |
11482 Emacs is suspended. Redrawing it is unnecessary and what needs to | |
11483 be done depends on whether the cursor lies inside or outside the | |
11484 redraw region. So we might as well skip drawing it when Emacs is | |
11485 suspended. */ | |
11486 static Boolean app_is_suspended = false; | |
11487 static long app_sleep_time = WNE_SLEEP_AT_RESUME; | |
11488 | |
11489 #define EXTRA_STACK_ALLOC (256 * 1024) | |
11490 | |
11491 #define ARGV_STRING_LIST_ID 129 | |
11492 #define ABOUT_ALERT_ID 128 | |
11493 #define RAM_TOO_LARGE_ALERT_ID 129 | |
11494 | |
11495 Boolean terminate_flag = false; | |
11496 | |
11497 /* true if using command key as meta key */ | |
11498 Lisp_Object Vmac_command_key_is_meta; | |
11499 | |
11500 /* convert input from Mac keyboard (assumed to be in Mac Roman coding) | |
11501 to this text encoding */ | |
11502 int mac_keyboard_text_encoding; | |
11503 int current_mac_keyboard_text_encoding = kTextEncodingMacRoman; | |
11504 | |
11505 /* Set in term/mac-win.el to indicate that event loop can now generate | |
11506 drag and drop events. */ | |
11507 Lisp_Object Qmac_ready_for_drag_n_drop; | |
11508 | |
11509 Lisp_Object drag_and_drop_file_list; | |
11510 | |
11511 Point saved_menu_event_location; | |
11512 | |
11513 /* Apple Events */ | |
11514 static void init_required_apple_events(void); | |
11515 static pascal OSErr | |
11516 do_ae_open_application(const AppleEvent *, AppleEvent *, long); | |
11517 static pascal OSErr | |
11518 do_ae_print_documents(const AppleEvent *, AppleEvent *, long); | |
11519 static pascal OSErr do_ae_open_documents(AppleEvent *, AppleEvent *, long); | |
11520 static pascal OSErr do_ae_quit_application(AppleEvent *, AppleEvent *, long); | |
11521 | |
11522 extern void init_emacs_passwd_dir (); | |
11523 extern int emacs_main (int, char **, char **); | |
11524 extern void check_alarm (); | |
11525 | |
11526 extern void initialize_applescript(); | |
11527 extern void terminate_applescript(); | |
11528 | |
11529 | |
11530 static void | |
11531 do_get_menus (void) | |
11532 { | |
11533 Handle menubar_handle; | |
11534 MenuHandle menu_handle; | |
11535 | |
11536 menubar_handle = GetNewMBar (128); | |
11537 if(menubar_handle == NULL) | |
11538 abort (); | |
11539 SetMenuBar (menubar_handle); | |
11540 DrawMenuBar (); | |
11541 | |
11542 menu_handle = GetMenuHandle (M_APPLE); | |
11543 if(menu_handle != NULL) | |
11544 AppendResMenu (menu_handle,'DRVR'); | |
11545 else | |
11546 abort (); | |
11547 } | |
11548 | |
11549 | |
11550 static void | |
11551 do_init_managers (void) | |
11552 { | |
11553 #if !TARGET_API_MAC_CARBON | |
11554 InitGraf (&qd.thePort); | |
11555 InitFonts (); | |
11556 FlushEvents (everyEvent, 0); | |
11557 InitWindows (); | |
11558 InitMenus (); | |
11559 TEInit (); | |
11560 InitDialogs (NULL); | |
11561 #endif /* !TARGET_API_MAC_CARBON */ | |
11562 InitCursor (); | |
11563 | |
11564 #if !TARGET_API_MAC_CARBON | |
11565 /* set up some extra stack space for use by emacs */ | |
11566 SetApplLimit ((Ptr) ((long) GetApplLimit () - EXTRA_STACK_ALLOC)); | |
11567 | |
11568 /* MaxApplZone must be called for AppleScript to execute more | |
11569 complicated scripts */ | |
11570 MaxApplZone (); | |
11571 MoreMasters (); | |
11572 #endif /* !TARGET_API_MAC_CARBON */ | |
11573 } | |
11574 | |
11575 static void | |
11576 do_check_ram_size (void) | |
11577 { | |
11578 SInt32 physical_ram_size, logical_ram_size; | |
11579 | |
11580 if (Gestalt (gestaltPhysicalRAMSize, &physical_ram_size) != noErr | |
11581 || Gestalt (gestaltLogicalRAMSize, &logical_ram_size) != noErr | |
11582 || physical_ram_size > 256 * 1024 * 1024 | |
11583 || logical_ram_size > 256 * 1024 * 1024) | |
11584 { | |
11585 StopAlert (RAM_TOO_LARGE_ALERT_ID, NULL); | |
11586 exit (1); | |
11587 } | |
11588 } | |
11589 | |
11590 static void | |
11591 do_window_update (WindowPtr win) | |
11592 { | |
11593 struct mac_output *mwp = (mac_output *) GetWRefCon (win); | |
11594 struct frame *f = mwp->mFP; | |
11595 | |
11596 if (f) | |
11597 { | |
11598 if (f->async_visible == 0) | |
11599 { | |
11600 f->async_visible = 1; | |
11601 f->async_iconified = 0; | |
11602 SET_FRAME_GARBAGED (f); | |
11603 | |
11604 /* An update event is equivalent to MapNotify on X, so report | |
11605 visibility changes properly. */ | |
11606 if (! NILP(Vframe_list) && ! NILP (XCDR (Vframe_list))) | |
11607 /* Force a redisplay sooner or later to update the | |
11608 frame titles in case this is the second frame. */ | |
11609 record_asynch_buffer_change (); | |
11610 } | |
11611 else | |
11612 { | |
11613 BeginUpdate (win); | |
11614 handling_window_update = 1; | |
11615 | |
11616 expose_frame (f, 0, 0, 0, 0); | |
11617 | |
11618 handling_window_update = 0; | |
11619 EndUpdate (win); | |
11620 } | |
11621 } | |
11622 } | |
11623 | |
11624 static int | |
11625 is_emacs_window (WindowPtr win) | |
11626 { | |
11627 Lisp_Object tail, frame; | |
11628 | |
11629 if (!win) | |
11630 return 0; | |
11631 | |
11632 FOR_EACH_FRAME (tail, frame) | |
11633 if (FRAME_MAC_P (XFRAME (frame))) | |
11634 if (FRAME_MAC_WINDOW (XFRAME (frame)) == win) | |
11635 return 1; | |
11636 | |
11637 return 0; | |
11638 } | |
11639 | |
11640 static void | |
11641 do_window_activate (WindowPtr win) | |
11642 { | |
11643 mac_output *mwp; | |
11644 struct frame *f; | |
11645 | |
11646 if (is_emacs_window (win)) | |
11647 { | |
11648 mwp = (mac_output *) GetWRefCon (win); | |
11649 f = mwp->mFP; | |
11650 | |
11651 if (f) | |
11652 { | |
11653 x_new_focus_frame (FRAME_MAC_DISPLAY_INFO (f), f); | |
11654 activate_scroll_bars (f); | |
11655 } | |
11656 } | |
11657 } | |
11658 | |
11659 static void | |
11660 do_window_deactivate (WindowPtr win) | |
11661 { | |
11662 mac_output *mwp; | |
11663 struct frame *f; | |
11664 | |
11665 if (is_emacs_window (win)) | |
11666 { | |
11667 mwp = (mac_output *) GetWRefCon (win); | |
11668 f = mwp->mFP; | |
11669 | |
11670 if (f == FRAME_MAC_DISPLAY_INFO (f)->x_focus_frame) | |
11671 { | |
11672 x_new_focus_frame (FRAME_MAC_DISPLAY_INFO (f), 0); | |
11673 deactivate_scroll_bars (f); | |
11674 } | |
11675 } | |
11676 } | |
11677 | |
11678 static void | |
11679 do_app_resume () | |
11680 { | |
11681 WindowPtr wp; | |
11682 mac_output *mwp; | |
11683 struct frame *f; | |
11684 | |
11685 wp = FrontWindow(); | |
11686 if (is_emacs_window (wp)) | |
11687 { | |
11688 mwp = (mac_output *) GetWRefCon (wp); | |
11689 f = mwp->mFP; | |
11690 | |
11691 if (f) | |
11692 { | |
11693 x_new_focus_frame (FRAME_MAC_DISPLAY_INFO (f), f); | |
11694 activate_scroll_bars (f); | |
11695 } | |
11696 } | |
11697 | |
11698 app_is_suspended = false; | |
11699 app_sleep_time = WNE_SLEEP_AT_RESUME; | |
11700 } | |
11701 | |
11702 static void | |
11703 do_app_suspend () | |
11704 { | |
11705 WindowPtr wp; | |
11706 mac_output *mwp; | |
11707 struct frame *f; | |
11708 | |
11709 wp = FrontWindow(); | |
11710 if (is_emacs_window (wp)) | |
11711 { | |
11712 mwp = (mac_output *) GetWRefCon (wp); | |
11713 f = mwp->mFP; | |
11714 | |
11715 if (f == FRAME_MAC_DISPLAY_INFO (f)->x_focus_frame) | |
11716 { | |
11717 x_new_focus_frame (FRAME_MAC_DISPLAY_INFO (f), 0); | |
11718 deactivate_scroll_bars (f); | |
11719 } | |
11720 } | |
11721 | |
11722 app_is_suspended = true; | |
11723 app_sleep_time = WNE_SLEEP_AT_SUSPEND; | |
11724 } | |
11725 | |
11726 | |
11727 static void | |
11728 do_mouse_moved (Point mouse_pos) | |
11729 { | |
11730 WindowPtr wp = FrontWindow (); | |
11731 struct frame *f = ((mac_output *) GetWRefCon (wp))->mFP; | |
11732 | |
11733 #if TARGET_API_MAC_CARBON | |
11734 SetPort (GetWindowPort (wp)); | |
11735 #else | |
11736 SetPort (wp); | |
11737 #endif | |
11738 | |
11739 GlobalToLocal (&mouse_pos); | |
11740 | |
11741 note_mouse_movement (f, &mouse_pos); | |
11742 } | |
11743 | |
11744 | |
11745 static void | |
11746 do_os_event (EventRecord *erp) | |
11747 { | |
11748 switch((erp->message >> 24) & 0x000000FF) | |
11749 { | |
11750 case suspendResumeMessage: | |
11751 if((erp->message & resumeFlag) == 1) | |
11752 do_app_resume (); | |
11753 else | |
11754 do_app_suspend (); | |
11755 break; | |
11756 | |
11757 case mouseMovedMessage: | |
11758 do_mouse_moved (erp->where); | |
11759 break; | |
11760 } | |
11761 } | |
11762 | |
11763 static void | |
11764 do_events (EventRecord *erp) | |
11765 { | |
11766 switch (erp->what) | |
11767 { | |
11768 case updateEvt: | |
11769 do_window_update ((WindowPtr) erp->message); | |
11770 break; | |
11771 | |
11772 case osEvt: | |
11773 do_os_event (erp); | |
11774 break; | |
11775 | |
11776 case activateEvt: | |
11777 if ((erp->modifiers & activeFlag) != 0) | |
11778 do_window_activate ((WindowPtr) erp->message); | |
11779 else | |
11780 do_window_deactivate ((WindowPtr) erp->message); | |
11781 break; | |
11782 } | |
11783 } | |
11784 | |
11785 static void | |
11786 do_apple_menu (SInt16 menu_item) | |
11787 { | |
11788 #if !TARGET_API_MAC_CARBON | |
11789 Str255 item_name; | |
11790 SInt16 da_driver_refnum; | |
11791 | |
11792 if (menu_item == I_ABOUT) | |
11793 NoteAlert (ABOUT_ALERT_ID, NULL); | |
11794 else | |
11795 { | |
11796 GetMenuItemText (GetMenuHandle (M_APPLE), menu_item, item_name); | |
11797 da_driver_refnum = OpenDeskAcc (item_name); | |
11798 } | |
11799 #endif /* !TARGET_API_MAC_CARBON */ | |
11800 } | |
11801 | |
11802 void | |
11803 do_menu_choice (SInt32 menu_choice) | |
11804 { | |
11805 SInt16 menu_id, menu_item; | |
11806 | |
11807 menu_id = HiWord (menu_choice); | |
11808 menu_item = LoWord (menu_choice); | |
11809 | |
11810 if (menu_id == 0) | |
11811 return; | |
11812 | |
11813 switch (menu_id) | |
11814 { | |
11815 case M_APPLE: | |
11816 do_apple_menu (menu_item); | |
11817 break; | |
11818 | |
11819 default: | |
11820 { | |
11821 WindowPtr wp = FrontWindow (); | |
11822 struct frame *f = ((mac_output *) GetWRefCon (wp))->mFP; | |
11823 MenuHandle menu = GetMenuHandle (menu_id); | |
11824 if (menu) | |
11825 { | |
11826 UInt32 refcon; | |
11827 | |
11828 GetMenuItemRefCon (menu, menu_item, &refcon); | |
11829 menubar_selection_callback (f, refcon); | |
11830 } | |
11831 } | |
11832 } | |
11833 | |
11834 HiliteMenu (0); | |
11835 } | |
11836 | |
11837 | |
11838 /* Handle drags in size box. Based on code contributed by Ben | |
11839 Mesander and IM - Window Manager A. */ | |
11840 | |
11841 static void | |
11842 do_grow_window (WindowPtr w, EventRecord *e) | |
11843 { | |
11844 long grow_size; | |
11845 Rect limit_rect; | |
11846 int rows, columns; | |
11847 mac_output *mwp = (mac_output *) GetWRefCon (w); | |
11848 struct frame *f = mwp->mFP; | |
11849 | |
11850 SetRect(&limit_rect, MIN_DOC_SIZE, MIN_DOC_SIZE, MAX_DOC_SIZE, MAX_DOC_SIZE); | |
11851 | |
11852 grow_size = GrowWindow (w, e->where, &limit_rect); | |
11853 | |
11854 /* see if it really changed size */ | |
11855 if (grow_size != 0) | |
11856 { | |
11857 rows = PIXEL_TO_CHAR_HEIGHT (f, HiWord (grow_size)); | |
11858 columns = PIXEL_TO_CHAR_WIDTH (f, LoWord (grow_size)); | |
11859 | |
11860 x_set_window_size (f, 0, columns, rows); | |
11861 } | |
11862 } | |
11863 | |
11864 | |
11865 /* Handle clicks in zoom box. Calculation of "standard state" based | |
11866 on code in IM - Window Manager A and code contributed by Ben | |
11867 Mesander. The standard state of an Emacs window is 80-characters | |
11868 wide (DEFAULT_NUM_COLS) and as tall as will fit on the screen. */ | |
11869 | |
11870 static void | |
11871 do_zoom_window (WindowPtr w, int zoom_in_or_out) | |
11872 { | |
11873 GrafPtr save_port; | |
11874 Rect zoom_rect, port_rect; | |
11875 Point top_left; | |
11876 int w_title_height, columns, rows, width, height, dummy, x, y; | |
11877 mac_output *mwp = (mac_output *) GetWRefCon (w); | |
11878 struct frame *f = mwp->mFP; | |
11879 | |
11880 GetPort (&save_port); | |
11881 | |
11882 #if TARGET_API_MAC_CARBON | |
11883 SetPort (GetWindowPort (w)); | |
11884 #else | |
11885 SetPort (w); | |
11886 #endif | |
11887 | |
11888 /* Clear window to avoid flicker. */ | |
11889 #if TARGET_API_MAC_CARBON | |
11890 { | |
11891 Rect r; | |
11892 BitMap bm; | |
11893 | |
11894 GetWindowPortBounds (w, &r); | |
11895 EraseRect (&r); | |
11896 | |
11897 if (zoom_in_or_out == inZoomOut) | |
11898 { | |
11899 /* calculate height of window's title bar (hard card it for now). */ | |
11900 w_title_height = 20 + GetMBarHeight (); | |
11901 | |
11902 /* get maximum height of window into zoom_rect.bottom - | |
11903 zoom_rect.top */ | |
11904 GetQDGlobalsScreenBits (&bm); | |
11905 zoom_rect = bm.bounds; | |
11906 zoom_rect.top += w_title_height; | |
11907 InsetRect (&zoom_rect, 8, 4); /* not too tight */ | |
11908 | |
11909 zoom_rect.right = zoom_rect.left | |
11910 + CHAR_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS); | |
11911 | |
11912 SetWindowStandardState (w, &zoom_rect); | |
11913 } | |
11914 } | |
11915 #else /* not TARGET_API_MAC_CARBON */ | |
11916 EraseRect (&(w->portRect)); | |
11917 if (zoom_in_or_out == inZoomOut) | |
11918 { | |
11919 SetPt (&top_left, w->portRect.left, w->portRect.top); | |
11920 LocalToGlobal (&top_left); | |
11921 | |
11922 /* calculate height of window's title bar */ | |
11923 w_title_height = top_left.v - 1 | |
11924 - (**((WindowPeek) w)->strucRgn).rgnBBox.top + GetMBarHeight (); | |
11925 | |
11926 /* get maximum height of window into zoom_rect.bottom - zoom_rect.top */ | |
11927 zoom_rect = qd.screenBits.bounds; | |
11928 zoom_rect.top += w_title_height; | |
11929 InsetRect (&zoom_rect, 8, 4); /* not too tight */ | |
11930 | |
11931 zoom_rect.right = zoom_rect.left | |
11932 + CHAR_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS); | |
11933 | |
11934 (**((WStateDataHandle) ((WindowPeek) w)->dataHandle)).stdState | |
11935 = zoom_rect; | |
11936 } | |
11937 #endif /* not TARGET_API_MAC_CARBON */ | |
11938 | |
11939 ZoomWindow (w, zoom_in_or_out, w == FrontWindow ()); | |
11940 | |
11941 /* retrieve window size and update application values */ | |
11942 #if TARGET_API_MAC_CARBON | |
11943 GetWindowPortBounds (w, &port_rect); | |
11944 #else | |
11945 port_rect = w->portRect; | |
11946 #endif | |
11947 rows = PIXEL_TO_CHAR_HEIGHT (f, port_rect.bottom - port_rect.top); | |
11948 columns = PIXEL_TO_CHAR_WIDTH (f, port_rect.right - port_rect.left); | |
11949 x_set_window_size (mwp->mFP, 0, columns, rows); | |
11950 | |
11951 SetPort (save_port); | |
11952 } | |
11953 | |
11954 | |
11955 /* Intialize AppleEvent dispatcher table for the required events. */ | |
11956 void | |
11957 init_required_apple_events () | |
11958 { | |
11959 OSErr err; | |
11960 long result; | |
11961 | |
11962 /* Make sure we have apple events before starting. */ | |
11963 err = Gestalt (gestaltAppleEventsAttr, &result); | |
11964 if (err != noErr) | |
11965 abort (); | |
11966 | |
11967 if (!(result & (1 << gestaltAppleEventsPresent))) | |
11968 abort (); | |
11969 | |
11970 #if TARGET_API_MAC_CARBON | |
11971 err = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, | |
11972 NewAEEventHandlerUPP | |
11973 ((AEEventHandlerProcPtr) do_ae_open_application), | |
11974 0L, false); | |
11975 #else | |
11976 err = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, | |
11977 NewAEEventHandlerProc | |
11978 ((AEEventHandlerProcPtr) do_ae_open_application), | |
11979 0L, false); | |
11980 #endif | |
11981 if (err != noErr) | |
11982 abort (); | |
11983 | |
11984 #if TARGET_API_MAC_CARBON | |
11985 err = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, | |
11986 NewAEEventHandlerUPP | |
11987 ((AEEventHandlerProcPtr) do_ae_open_documents), | |
11988 0L, false); | |
11989 #else | |
11990 err = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, | |
11991 NewAEEventHandlerProc | |
11992 ((AEEventHandlerProcPtr) do_ae_open_documents), | |
11993 0L, false); | |
11994 #endif | |
11995 if (err != noErr) | |
11996 abort (); | |
11997 | |
11998 #if TARGET_API_MAC_CARBON | |
11999 err = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments, | |
12000 NewAEEventHandlerUPP | |
12001 ((AEEventHandlerProcPtr) do_ae_print_documents), | |
12002 0L, false); | |
12003 #else | |
12004 err = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments, | |
12005 NewAEEventHandlerProc | |
12006 ((AEEventHandlerProcPtr) do_ae_print_documents), | |
12007 0L, false); | |
12008 #endif | |
12009 if (err != noErr) | |
12010 abort (); | |
12011 | |
12012 #if TARGET_API_MAC_CARBON | |
12013 err = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, | |
12014 NewAEEventHandlerUPP | |
12015 ((AEEventHandlerProcPtr) do_ae_quit_application), | |
12016 0L, false); | |
12017 #else | |
12018 err = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, | |
12019 NewAEEventHandlerProc | |
12020 ((AEEventHandlerProcPtr) do_ae_quit_application), | |
12021 0L, false); | |
12022 #endif | |
12023 if (err != noErr) | |
12024 abort (); | |
12025 } | |
12026 | |
12027 | |
12028 /* Open Application Apple Event */ | |
12029 static pascal OSErr | |
12030 do_ae_open_application(const AppleEvent *pae, AppleEvent *preply, long prefcon) | |
12031 { | |
12032 return noErr; | |
12033 } | |
12034 | |
12035 | |
12036 /* Defined in mac.c. */ | |
12037 extern int | |
12038 path_from_vol_dir_name (char *, int, short, long, char *); | |
12039 | |
12040 | |
12041 /* Called when we receive an AppleEvent with an ID of | |
12042 "kAEOpenDocuments". This routine gets the direct parameter, | |
12043 extracts the FSSpecs in it, and puts their names on a list. */ | |
12044 static pascal OSErr | |
12045 do_ae_open_documents(AppleEvent *message, AppleEvent *reply, long refcon) | |
12046 { | |
12047 OSErr err, err2; | |
12048 AEDesc the_desc; | |
12049 AEKeyword keyword; | |
12050 DescType actual_type; | |
12051 Size actual_size; | |
12052 | |
12053 err = AEGetParamDesc (message, keyDirectObject, typeAEList, &the_desc); | |
12054 if (err != noErr) | |
12055 goto descriptor_error_exit; | |
12056 | |
12057 /* Check to see that we got all of the required parameters from the | |
12058 event descriptor. For an 'odoc' event this should just be the | |
12059 file list. */ | |
12060 err = AEGetAttributePtr(message, keyMissedKeywordAttr, typeWildCard, | |
12061 &actual_type, (Ptr) &keyword, | |
12062 sizeof (keyword), &actual_size); | |
12063 /* No error means that we found some unused parameters. | |
12064 errAEDescNotFound means that there are no more parameters. If we | |
12065 get an error code other than that, flag it. */ | |
12066 if ((err == noErr) || (err != errAEDescNotFound)) | |
12067 { | |
12068 err = errAEEventNotHandled; | |
12069 goto error_exit; | |
12070 } | |
12071 err = noErr; | |
12072 | |
12073 /* Got all the parameters we need. Now, go through the direct | |
12074 object list and parse it up. */ | |
12075 { | |
12076 long num_files_to_open; | |
12077 | |
12078 err = AECountItems (&the_desc, &num_files_to_open); | |
12079 if (err == noErr) | |
12080 { | |
12081 int i; | |
12082 | |
12083 /* AE file list is one based so just use that for indexing here. */ | |
12084 for (i = 1; (err == noErr) && (i <= num_files_to_open); i++) { | |
12085 FSSpec fs; | |
12086 Str255 path_name, unix_path_name; | |
12087 | |
12088 err = AEGetNthPtr(&the_desc, i, typeFSS, &keyword, &actual_type, | |
12089 (Ptr) &fs, sizeof (fs), &actual_size); | |
12090 if (err != noErr) break; | |
12091 | |
12092 if (path_from_vol_dir_name (path_name, 255, fs.vRefNum, fs.parID, | |
12093 fs.name) && | |
12094 mac_to_posix_pathname (path_name, unix_path_name, 255)) | |
12095 drag_and_drop_file_list = Fcons (build_string (unix_path_name), | |
12096 drag_and_drop_file_list); | |
12097 } | |
12098 } | |
12099 } | |
12100 | |
12101 error_exit: | |
12102 /* Nuke the coerced file list in any case */ | |
12103 err2 = AEDisposeDesc(&the_desc); | |
12104 | |
12105 descriptor_error_exit: | |
12106 /* InvalRect(&(gFrontMacWindowP->mWP->portRect)); */ | |
12107 return err; | |
12108 } | |
12109 | |
12110 | |
12111 /* Print Document Apple Event */ | |
12112 static pascal OSErr | |
12113 do_ae_print_documents (const AppleEvent *pAE, AppleEvent *reply, long refcon) | |
12114 { | |
12115 return errAEEventNotHandled; | |
12116 } | |
12117 | |
12118 | |
12119 static pascal OSErr | |
12120 do_ae_quit_application (AppleEvent* message, AppleEvent *reply, long refcon) | |
12121 { | |
12122 /* FixMe: Do we need an unwind-protect or something here? And what | |
12123 do we do about unsaved files. Currently just forces quit rather | |
12124 than doing recursive callback to get user input. */ | |
12125 | |
12126 terminate_flag = true; | |
12127 | |
12128 /* Fkill_emacs doesn't return. We have to return. (TI) */ | |
12129 return noErr; | |
12130 } | |
12131 | |
12132 | |
12133 #if __profile__ | |
12134 void | |
12135 profiler_exit_proc () | |
12136 { | |
12137 ProfilerDump ("\pEmacs.prof"); | |
12138 ProfilerTerm (); | |
12139 } | |
12140 #endif | |
12141 | |
12142 /* These few functions implement Emacs as a normal Mac application | |
12143 (almost): set up the heap and the Toolbox, handle necessary | |
12144 system events plus a few simple menu events. They also set up | |
12145 Emacs's access to functions defined in the rest of this file. | |
12146 Emacs uses function hooks to perform all its terminal I/O. A | |
12147 complete list of these functions appear in termhooks.h. For what | |
12148 they do, read the comments there and see also w32term.c and | |
12149 xterm.c. What's noticeably missing here is the event loop, which | |
12150 is normally present in most Mac application. After performing the | |
12151 necessary Mac initializations, main passes off control to | |
12152 emacs_main (corresponding to main in emacs.c). Emacs_main calls | |
12153 mac_read_socket (defined further below) to read input. This is | |
12154 where WaitNextEvent is called to process Mac events. This is also | |
12155 where check_alarm in sysdep.c is called to simulate alarm signals. | |
12156 This makes the cursor jump back to its correct position after | |
12157 briefly jumping to that of the matching parenthesis, print useful | |
12158 hints and prompts in the minibuffer after the user stops typing for | |
12159 a wait, etc. */ | |
12160 | |
12161 #if !TARGET_API_MAC_CARBON | |
12162 #undef main | |
12163 int | |
12164 main (void) | |
12165 { | |
12166 #if __profile__ /* is the profiler on? */ | |
12167 if (ProfilerInit(collectDetailed, bestTimeBase, 5000, 200)) | |
12168 exit(1); | |
12169 #endif | |
12170 | |
12171 #if __MWERKS__ | |
12172 /* set creator and type for files created by MSL */ | |
12173 _fcreator = 'EMAx'; | |
12174 _ftype = 'TEXT'; | |
12175 #endif | |
12176 | |
12177 do_init_managers (); | |
12178 | |
12179 do_get_menus (); | |
12180 | |
12181 do_check_ram_size (); | |
12182 | |
12183 init_emacs_passwd_dir (); | |
12184 | |
12185 init_environ (); | |
12186 | |
12187 initialize_applescript (); | |
12188 | |
12189 init_required_apple_events (); | |
12190 | |
12191 { | |
12192 char **argv; | |
12193 int argc = 0; | |
12194 | |
12195 /* set up argv array from STR# resource */ | |
12196 get_string_list (&argv, ARGV_STRING_LIST_ID); | |
12197 while (argv[argc]) | |
12198 argc++; | |
12199 | |
12200 /* free up AppleScript resources on exit */ | |
12201 atexit (terminate_applescript); | |
12202 | |
12203 #if __profile__ /* is the profiler on? */ | |
12204 atexit (profiler_exit_proc); | |
12205 #endif | |
12206 | |
12207 /* 3rd param "envp" never used in emacs_main */ | |
12208 (void) emacs_main (argc, argv, 0); | |
12209 } | |
12210 | |
12211 /* Never reached - real exit in Fkill_emacs */ | |
12212 return 0; | |
12213 } | |
12214 #endif | |
12215 | |
12216 /* Table for translating Mac keycode to X keysym values. Contributed | |
12217 by Sudhir Shenoy. */ | |
12218 static unsigned char keycode_to_xkeysym_table[] = { | |
12219 /* 0x00 - 0x3f */ | |
12220 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
12221 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
12222 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
12223 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
12224 /* 0x40 */ | |
12225 0, '\xae' /* kp. */, 0, '\xaa' /* kp* */, | |
12226 0, '\xab' /* kp+ */, 0, '\x7f' /* kp_clr */, | |
12227 0, 0, 0, '\xaf' /* kp/ */, | |
12228 '\x8d' /* kp_ent */, 0, '\xad' /* kp- */, 0, | |
12229 /* 0x50 */ | |
12230 0, '\xbd' /* kp= */, '\xb0' /* kp0 */, '\xb1' /* kp1 */, | |
12231 '\xb2' /* kp2 */, '\xb3' /* kp3 */, '\xb4' /* kp4 */, '\xb5' /* kp5 */, | |
12232 '\xb6' /* kp6 */, '\xb7' /* kp7 */, 0, '\xb8' /* kp8 */, | |
12233 '\xb9' /* kp9 */, 0, 0, 0, | |
12234 /* 0x60 */ | |
12235 '\xc2' /* F5 */, '\xc3' /* F6 */, '\xc4' /* F7 */, '\xc0' /* F3 */, | |
12236 '\xc5' /* F8 */, '\xc6' /* F9 */, 0, '\xc8' /* F11 */, | |
12237 0, '\xca' /* F13 */, 0, '\xcb' /* F14 */, | |
12238 0, '\xc7' /* F10 */, 0, '\xc9' /* F12 */, | |
12239 /* 0x70 */ | |
12240 0, '\xcc' /* F15 */, '\x9e' /* ins */, '\x95' /* home */, | |
12241 '\x9a' /* pgup */, '\x9f' /* del */, '\xc1' /* F4 */, '\x9c' /* end */, | |
12242 '\xbf' /* F2 */, '\x9b' /* pgdown */, '\xbe' /* F1 */, '\x51' /* left */, | |
12243 '\x53' /* right */, '\x54' /* down */, '\x52' /* up */, 0 | |
12244 }; | |
12245 | |
12246 static int | |
12247 keycode_to_xkeysym (int keyCode, int *xKeySym) | |
12248 { | |
12249 *xKeySym = keycode_to_xkeysym_table [keyCode & 0x7f]; | |
12250 return *xKeySym != 0; | |
12251 } | |
12252 | |
12253 /* Emacs calls this whenever it wants to read an input event from the | |
12254 user. */ | |
12255 int | |
12256 XTread_socket (int sd, struct input_event *bufp, int numchars, int expected) | |
12257 { | |
12258 int count = 0; | |
12259 EventRecord er; | |
12260 int the_modifiers; | |
12261 EventMask event_mask; | |
12262 | |
12263 #if 0 | |
12264 if (interrupt_input_blocked) | |
12265 { | |
12266 interrupt_input_pending = 1; | |
12267 return -1; | |
12268 } | |
12269 #endif | |
12270 | |
12271 interrupt_input_pending = 0; | |
12272 BLOCK_INPUT; | |
12273 | |
12274 /* So people can tell when we have read the available input. */ | |
12275 input_signal_count++; | |
12276 | |
12277 if (numchars <= 0) | |
12278 abort (); | |
12279 | |
12280 /* Don't poll for events to process (specifically updateEvt) if | |
12281 window update currently already in progress. A call to redisplay | |
12282 (in do_window_update) can be preempted by another call to | |
12283 redisplay, causing blank regions to be left on the screen and the | |
12284 cursor to be left at strange places. */ | |
12285 if (handling_window_update) | |
12286 { | |
12287 UNBLOCK_INPUT; | |
12288 return 0; | |
12289 } | |
12290 | |
12291 if (terminate_flag) | |
12292 Fkill_emacs (make_number (1)); | |
12293 | |
12294 /* It is necessary to set this (additional) argument slot of an | |
12295 event to nil because keyboard.c protects incompletely processed | |
12296 event from being garbage collected by placing them in the | |
12297 kbd_buffer_gcpro vector. */ | |
12298 bufp->arg = Qnil; | |
12299 | |
12300 event_mask = everyEvent; | |
12301 if (NILP (Fboundp (Qmac_ready_for_drag_n_drop))) | |
12302 event_mask -= highLevelEventMask; | |
12303 | |
12304 while (WaitNextEvent (event_mask, &er, 0L, NULL) && numchars > 0) | |
12305 switch (er.what) | |
12306 { | |
12307 case mouseDown: | |
12308 case mouseUp: | |
12309 { | |
12310 WindowPtr window_ptr = FrontWindow (); | |
12311 SInt16 part_code; | |
12312 | |
12313 if (mouse_tracking_in_progress == mouse_tracking_scroll_bar | |
12314 && er.what == mouseUp) | |
12315 { | |
12316 struct mac_output *mwp = (mac_output *) GetWRefCon (window_ptr); | |
12317 Point mouse_loc = er.where; | |
12318 | |
12319 /* Convert to local coordinates of new window. */ | |
12320 #if TARGET_API_MAC_CARBON | |
12321 SetPort (GetWindowPort (window_ptr)); | |
12322 #else | |
12323 SetPort (window_ptr); | |
12324 #endif | |
12325 | |
12326 GlobalToLocal (&mouse_loc); | |
12327 | |
12328 bufp->code = 0; /* only one mouse button */ | |
12329 bufp->kind = scroll_bar_click; | |
12330 bufp->frame_or_window = tracked_scroll_bar->window; | |
12331 bufp->part = scroll_bar_handle; | |
12332 bufp->modifiers = up_modifier; | |
12333 bufp->timestamp = er.when * (1000 / 60); | |
12334 /* ticks to milliseconds */ | |
12335 | |
12336 XSETINT (bufp->x, tracked_scroll_bar->left + 2); | |
12337 XSETINT (bufp->y, mouse_loc.v - 24); | |
12338 tracked_scroll_bar->dragging = Qnil; | |
12339 mouse_tracking_in_progress = mouse_tracking_none; | |
12340 tracked_scroll_bar = NULL; | |
12341 count++; | |
12342 bufp++; | |
12343 numchars--; | |
12344 break; | |
12345 } | |
12346 | |
12347 part_code = FindWindow (er.where, &window_ptr); | |
12348 | |
12349 switch (part_code) | |
12350 { | |
12351 case inMenuBar: | |
12352 { | |
12353 struct frame *f = ((mac_output *) | |
12354 GetWRefCon (FrontWindow ()))->mFP; | |
12355 saved_menu_event_location = er.where; | |
12356 bufp->kind = menu_bar_activate_event; | |
12357 XSETFRAME (bufp->frame_or_window, f); | |
12358 count++; | |
12359 bufp++; | |
12360 numchars--; | |
12361 } | |
12362 break; | |
12363 | |
12364 case inContent: | |
12365 if (window_ptr != FrontWindow ()) | |
12366 SelectWindow (window_ptr); | |
12367 else | |
12368 { | |
12369 SInt16 control_part_code; | |
12370 ControlHandle ch; | |
12371 struct mac_output *mwp = (mac_output *) | |
12372 GetWRefCon (window_ptr); | |
12373 Point mouse_loc = er.where; | |
12374 | |
12375 /* convert to local coordinates of new window */ | |
12376 #if TARGET_API_MAC_CARBON | |
12377 SetPort (GetWindowPort (window_ptr)); | |
12378 #else | |
12379 SetPort (window_ptr); | |
12380 #endif | |
12381 | |
12382 GlobalToLocal (&mouse_loc); | |
12383 #if TARGET_API_MAC_CARBON | |
12384 ch = FindControlUnderMouse (mouse_loc, window_ptr, | |
12385 &control_part_code); | |
12386 #else | |
12387 control_part_code = FindControl (mouse_loc, window_ptr, &ch); | |
12388 #endif | |
12389 bufp->code = 0; /* only one mouse button */ | |
12390 XSETINT (bufp->x, mouse_loc.h); | |
12391 XSETINT (bufp->y, mouse_loc.v); | |
12392 bufp->timestamp = er.when * (1000 / 60); | |
12393 /* ticks to milliseconds */ | |
12394 | |
12395 #if TARGET_API_MAC_CARBON | |
12396 if (ch != 0) | |
12397 #else | |
12398 if (control_part_code != 0) | |
12399 #endif | |
12400 { | |
12401 struct scroll_bar *bar = (struct scroll_bar *) | |
12402 GetControlReference (ch); | |
12403 x_scroll_bar_handle_click (bar, control_part_code, &er, | |
12404 bufp); | |
12405 if (er.what == mouseDown | |
12406 && control_part_code == kControlIndicatorPart) | |
12407 { | |
12408 mouse_tracking_in_progress | |
12409 = mouse_tracking_scroll_bar; | |
12410 tracked_scroll_bar = bar; | |
12411 } | |
12412 else | |
12413 { | |
12414 mouse_tracking_in_progress = mouse_tracking_none; | |
12415 tracked_scroll_bar = NULL; | |
12416 } | |
12417 } | |
12418 else | |
12419 { | |
12420 bufp->kind = mouse_click; | |
12421 XSETFRAME (bufp->frame_or_window, mwp->mFP); | |
12422 if (er.what == mouseDown) | |
12423 mouse_tracking_in_progress | |
12424 = mouse_tracking_mouse_movement; | |
12425 else | |
12426 mouse_tracking_in_progress = mouse_tracking_none; | |
12427 } | |
12428 | |
12429 switch (er.what) | |
12430 { | |
12431 case mouseDown: | |
12432 bufp->modifiers = down_modifier; | |
12433 break; | |
12434 case mouseUp: | |
12435 bufp->modifiers = up_modifier; | |
12436 break; | |
12437 } | |
12438 | |
12439 count++; | |
12440 bufp++; | |
12441 numchars--; | |
12442 } | |
12443 break; | |
12444 | |
12445 case inDrag: | |
12446 #if TARGET_API_MAC_CARBON | |
12447 { | |
12448 BitMap bm; | |
12449 | |
12450 GetQDGlobalsScreenBits (&bm); | |
12451 DragWindow (window_ptr, er.where, &bm.bounds); | |
12452 } | |
12453 #else /* not TARGET_API_MAC_CARBON */ | |
12454 DragWindow (window_ptr, er.where, &qd.screenBits.bounds); | |
12455 #endif /* not TARGET_API_MAC_CARBON */ | |
12456 break; | |
12457 | |
12458 case inGoAway: | |
12459 if (TrackGoAway (window_ptr, er.where)) | |
12460 { | |
12461 bufp->kind = delete_window_event; | |
12462 XSETFRAME (bufp->frame_or_window, | |
12463 ((mac_output *) GetWRefCon (window_ptr))->mFP); | |
12464 count++; | |
12465 bufp++; | |
12466 numchars--; | |
12467 } | |
12468 break; | |
12469 | |
12470 /* window resize handling added --ben */ | |
12471 case inGrow: | |
12472 do_grow_window(window_ptr, &er); | |
12473 break; | |
12474 | |
12475 /* window zoom handling added --ben */ | |
12476 case inZoomIn: | |
12477 case inZoomOut: | |
12478 if (TrackBox (window_ptr, er.where, part_code)) | |
12479 do_zoom_window (window_ptr, part_code); | |
12480 break; | |
12481 | |
12482 default: | |
12483 break; | |
12484 } | |
12485 } | |
12486 break; | |
12487 | |
12488 case updateEvt: | |
12489 case osEvt: | |
12490 case activateEvt: | |
12491 do_events (&er); | |
12492 break; | |
12493 | |
12494 case keyDown: | |
12495 case autoKey: | |
12496 { | |
12497 int keycode = (er.message & keyCodeMask) >> 8; | |
12498 int xkeysym; | |
12499 | |
12500 ObscureCursor (); | |
12501 | |
12502 if (keycode == 0x33) /* delete key (charCode translated to 0x8) */ | |
12503 { | |
12504 bufp->code = 0x7f; | |
12505 bufp->kind = ascii_keystroke; | |
12506 } | |
12507 else if (keycode_to_xkeysym (keycode, &xkeysym)) | |
12508 { | |
12509 bufp->code = 0xff00 | xkeysym; | |
12510 bufp->kind = non_ascii_keystroke; | |
12511 } | |
12512 else | |
12513 { | |
12514 if (er.modifiers | |
12515 & (NILP (Vmac_command_key_is_meta) ? optionKey : cmdKey)) | |
12516 { | |
12517 /* This code comes from Keyboard Resource, Appendix | |
12518 C of IM - Text. This is necessary since shift is | |
12519 ignored in KCHR table translation when option or | |
12520 command is pressed. */ | |
12521 int new_modifiers = er.modifiers & 0xf600; | |
12522 /* mask off option and command */ | |
12523 int new_keycode = keycode | new_modifiers; | |
12524 Ptr kchr_ptr = (Ptr) GetScriptManagerVariable (smKCHRCache); | |
12525 unsigned long some_state = 0; | |
12526 bufp->code = KeyTranslate (kchr_ptr, new_keycode, | |
12527 &some_state) & 0xff; | |
12528 } | |
12529 else | |
12530 bufp->code = er.message & charCodeMask; | |
12531 bufp->kind = ascii_keystroke; | |
12532 } | |
12533 } | |
12534 | |
12535 /* If variable mac-convert-keyboard-input-to-latin-1 is non-nil, | |
12536 convert non-ASCII characters typed at the Mac keyboard | |
12537 (presumed to be in the Mac Roman encoding) to iso-latin-1 | |
12538 encoding before they are passed to Emacs. This enables the | |
12539 Mac keyboard to be used to enter non-ASCII iso-latin-1 | |
12540 characters directly. */ | |
12541 if (mac_keyboard_text_encoding != kTextEncodingMacRoman | |
12542 && bufp->kind == ascii_keystroke && bufp->code >= 128) | |
12543 { | |
12544 static TECObjectRef converter = NULL; | |
12545 OSStatus the_err = noErr; | |
12546 OSStatus convert_status = noErr; | |
12547 | |
12548 if (converter == NULL) | |
12549 { | |
12550 the_err = TECCreateConverter (&converter, | |
12551 kTextEncodingMacRoman, | |
12552 mac_keyboard_text_encoding); | |
12553 current_mac_keyboard_text_encoding | |
12554 = mac_keyboard_text_encoding; | |
12555 } | |
12556 else if (mac_keyboard_text_encoding | |
12557 != current_mac_keyboard_text_encoding) | |
12558 { | |
12559 /* Free the converter for the current encoding before | |
12560 creating a new one. */ | |
12561 TECDisposeConverter (converter); | |
12562 the_err = TECCreateConverter (&converter, | |
12563 kTextEncodingMacRoman, | |
12564 mac_keyboard_text_encoding); | |
12565 current_mac_keyboard_text_encoding | |
12566 = mac_keyboard_text_encoding; | |
12567 } | |
12568 | |
12569 if (the_err == noErr) | |
12570 { | |
12571 unsigned char ch = bufp->code; | |
12572 ByteCount actual_input_length, actual_output_length; | |
12573 unsigned char outch; | |
12574 | |
12575 convert_status = TECConvertText (converter, &ch, 1, | |
12576 &actual_input_length, | |
12577 &outch, 1, | |
12578 &actual_output_length); | |
12579 if (convert_status == noErr | |
12580 && actual_input_length == 1 | |
12581 && actual_output_length == 1) | |
12582 bufp->code = outch; | |
12583 } | |
12584 } | |
12585 | |
12586 the_modifiers = 0; | |
12587 if (er.modifiers & shiftKey) | |
12588 the_modifiers |= shift_modifier; | |
12589 if (er.modifiers & controlKey) | |
12590 the_modifiers |= ctrl_modifier; | |
12591 /* use option or command key as meta depending on value of | |
12592 mac-command-key-is-meta */ | |
12593 if (er.modifiers | |
12594 & (NILP (Vmac_command_key_is_meta) ? optionKey : cmdKey)) | |
12595 the_modifiers |= meta_modifier; | |
12596 bufp->modifiers = the_modifiers; | |
12597 | |
12598 { | |
12599 mac_output *mwp = (mac_output *) GetWRefCon (FrontWindow ()); | |
12600 XSETFRAME (bufp->frame_or_window, mwp->mFP); | |
12601 } | |
12602 | |
12603 bufp->timestamp = er.when * (1000 / 60); /* ticks to milliseconds */ | |
12604 | |
12605 count++; | |
12606 bufp++; | |
12607 numchars--; | |
12608 break; | |
12609 | |
12610 case kHighLevelEvent: | |
12611 drag_and_drop_file_list = Qnil; | |
12612 | |
12613 AEProcessAppleEvent(&er); | |
12614 | |
12615 /* Build a drag_n_drop type event as is done in | |
12616 constuct_drag_n_drop in w32term.c. */ | |
12617 if (!NILP (drag_and_drop_file_list)) | |
12618 { | |
12619 struct frame *f; | |
12620 WindowPtr wp; | |
12621 Lisp_Object frame; | |
12622 | |
12623 wp = FrontWindow (); | |
12624 if (!wp) | |
12625 f = NULL; | |
12626 else | |
12627 f = ((mac_output *) GetWRefCon (wp))->mFP; | |
12628 | |
12629 bufp->kind = drag_n_drop; | |
12630 bufp->code = 0; | |
12631 bufp->timestamp = er.when * (1000 / 60); | |
12632 /* ticks to milliseconds */ | |
12633 bufp->modifiers = 0; | |
12634 | |
12635 XSETINT (bufp->x, 0); | |
12636 XSETINT (bufp->y, 0); | |
12637 | |
12638 XSETFRAME (frame, f); | |
12639 bufp->frame_or_window = Fcons (frame, drag_and_drop_file_list); | |
12640 | |
12641 /* Regardless of whether Emacs was suspended or in the | |
12642 foreground, ask it to redraw its entire screen. | |
12643 Otherwise parts of the screen can be left in an | |
12644 inconsistent state. */ | |
12645 if (wp) | |
12646 #if TARGET_API_MAC_CARBON | |
12647 { | |
12648 Rect r; | |
12649 | |
12650 GetWindowPortBounds (wp, &r); | |
12651 InvalWindowRect (wp, &r); | |
12652 } | |
12653 #else /* not TARGET_API_MAC_CARBON */ | |
12654 InvalRect (&(wp->portRect)); | |
12655 #endif /* not TARGET_API_MAC_CARBON */ | |
12656 | |
12657 count++; | |
12658 bufp++; | |
12659 numchars--; | |
12660 } | |
12661 | |
12662 default: | |
12663 break; | |
12664 } | |
12665 | |
12666 /* If the focus was just given to an autoraising frame, | |
12667 raise it now. */ | |
12668 /* ??? This ought to be able to handle more than one such frame. */ | |
12669 if (pending_autoraise_frame) | |
12670 { | |
12671 x_raise_frame (pending_autoraise_frame); | |
12672 pending_autoraise_frame = 0; | |
12673 } | |
12674 | |
12675 #if !TARGET_API_MAC_CARBON | |
12676 check_alarm (); /* simulate the handling of a SIGALRM */ | |
12677 #endif | |
12678 | |
12679 { | |
12680 static Point old_mouse_pos = { -1, -1 }; | |
12681 | |
12682 if (app_is_suspended) | |
12683 { | |
12684 old_mouse_pos.h = -1; | |
12685 old_mouse_pos.v = -1; | |
12686 } | |
12687 else | |
12688 { | |
12689 Point mouse_pos; | |
12690 WindowPtr wp; | |
12691 struct frame *f; | |
12692 Lisp_Object bar; | |
12693 struct scroll_bar *sb; | |
12694 | |
12695 wp = FrontWindow (); | |
12696 if (is_emacs_window (wp)) | |
12697 { | |
12698 f = ((mac_output *) GetWRefCon (wp))->mFP; | |
12699 | |
12700 #if TARGET_API_MAC_CARBON | |
12701 SetPort (GetWindowPort (wp)); | |
12702 #else | |
12703 SetPort (wp); | |
12704 #endif | |
12705 | |
12706 GetMouse (&mouse_pos); | |
12707 | |
12708 if (!EqualPt (mouse_pos, old_mouse_pos)) | |
12709 { | |
12710 if (mouse_tracking_in_progress == mouse_tracking_scroll_bar | |
12711 && tracked_scroll_bar) | |
12712 x_scroll_bar_note_movement (tracked_scroll_bar, | |
12713 mouse_pos.v | |
12714 - XINT (tracked_scroll_bar->top), | |
12715 TickCount() * (1000 / 60)); | |
12716 else | |
12717 note_mouse_movement (f, &mouse_pos); | |
12718 | |
12719 old_mouse_pos = mouse_pos; | |
12720 } | |
12721 } | |
12722 } | |
12723 } | |
12724 | |
12725 UNBLOCK_INPUT; | |
12726 | |
12727 return count; | |
12728 } | |
12729 | |
12730 | |
12731 /* Need to override CodeWarrior's input function so no conversion is | |
12732 done on newlines Otherwise compiled functions in .elc files will be | |
12733 read incorrectly. Defined in ...:MSL C:MSL | |
12734 Common:Source:buffer_io.c. */ | |
12735 #ifdef __MWERKS__ | |
12736 void | |
12737 __convert_to_newlines (unsigned char * p, size_t * n) | |
12738 { | |
12739 #pragma unused(p,n) | |
12740 } | |
12741 | |
12742 void | |
12743 __convert_from_newlines (unsigned char * p, size_t * n) | |
12744 { | |
12745 #pragma unused(p,n) | |
12746 } | |
12747 #endif | |
12748 | |
12749 | |
12750 /* Initialize the struct pointed to by MW to represent a new COLS x | |
12751 ROWS Macintosh window, using font with name FONTNAME and size | |
12752 FONTSIZE. */ | |
12753 void | |
12754 NewMacWindow (FRAME_PTR fp) | |
12755 { | |
12756 mac_output *mwp; | |
12757 #if TARGET_API_MAC_CARBON | |
12758 static int making_terminal_window = 0; | |
12759 #else | |
12760 static int making_terminal_window = 1; | |
12761 #endif | |
12762 | |
12763 mwp = fp->output_data.mac; | |
12764 | |
12765 if (making_terminal_window) | |
12766 { | |
12767 if (!(mwp->mWP = GetNewCWindow (TERM_WINDOW_RESOURCE, NULL, | |
12768 (WindowPtr) -1))) | |
12769 abort (); | |
12770 making_terminal_window = 0; | |
12771 } | |
12772 else | |
12773 if (!(mwp->mWP = GetNewCWindow (WINDOW_RESOURCE, NULL, (WindowPtr) -1))) | |
12774 abort (); | |
12775 | |
12776 | |
12777 SetWRefCon (mwp->mWP, (long) mwp); | |
12778 /* so that update events can find this mac_output struct */ | |
12779 mwp->mFP = fp; /* point back to emacs frame */ | |
12780 | |
12781 #if TARGET_API_MAC_CARBON | |
12782 SetPort (GetWindowPort (mwp->mWP)); | |
12783 #else | |
12784 SetPort (mwp->mWP); | |
12785 #endif | |
12786 | |
12787 mwp->fontset = -1; | |
12788 | |
12789 SizeWindow (mwp->mWP, mwp->pixel_width, mwp->pixel_height, false); | |
12790 ShowWindow (mwp->mWP); | |
12791 | |
12792 } | |
12793 | |
12794 | |
12795 void make_mac_frame (struct frame *f) | |
12796 { | |
12797 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1; | |
12798 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_right; | |
12799 | |
12800 NewMacWindow(f); | |
12801 FRAME_BACKGROUND_PIXEL (f) = 0xffffff; | |
12802 FRAME_FOREGROUND_PIXEL (f) = 0; | |
12803 | |
12804 f->output_data.mac->cursor_pixel = 0; | |
12805 f->output_data.mac->border_pixel = 0x00ff00; | |
12806 f->output_data.mac->mouse_pixel = 0xff00ff; | |
12807 f->output_data.mac->cursor_foreground_pixel = 0x0000ff; | |
12808 | |
12809 f->output_data.mac->desired_cursor = FILLED_BOX_CURSOR; | |
12810 | |
12811 f->output_data.mac->fontset = -1; | |
12812 f->output_data.mac->scroll_bar_foreground_pixel = -1; | |
12813 f->output_data.mac->scroll_bar_background_pixel = -1; | |
12814 f->output_data.mac->left_pos = 4; | |
12815 f->output_data.mac->top_pos = 4; | |
12816 f->output_data.mac->border_width = 0; | |
12817 f->output_data.mac->explicit_parent = 0; | |
12818 | |
12819 f->output_data.mac->internal_border_width = 0; | |
12820 | |
12821 f->output_method = output_mac; | |
12822 | |
12823 f->auto_raise = 1; | |
12824 f->auto_lower = 1; | |
12825 | |
12826 f->new_width = 0; | |
12827 f->new_height = 0; | |
12828 } | |
12829 | |
12830 void make_mac_terminal_frame (struct frame *f) | |
12831 { | |
12832 Lisp_Object frame; | |
12833 | |
12834 XSETFRAME (frame, f); | |
12835 | |
12836 f->output_method = output_mac; | |
12837 f->output_data.mac = (struct mac_output *) | |
12838 xmalloc (sizeof (struct mac_output)); | |
12839 bzero (f->output_data.mac, sizeof (struct mac_output)); | |
12840 f->output_data.mac->fontset = -1; | |
12841 f->output_data.mac->scroll_bar_foreground_pixel = -1; | |
12842 f->output_data.mac->scroll_bar_background_pixel = -1; | |
12843 | |
12844 XSETFRAME (FRAME_KBOARD (f)->Vdefault_minibuffer_frame, f); | |
12845 | |
12846 f->width = 96; | |
12847 f->height = 4; | |
12848 | |
12849 make_mac_frame (f); | |
12850 | |
12851 x_make_gc (f); | |
12852 | |
12853 /* Need to be initialized for unshow_buffer in window.c. */ | |
12854 selected_window = f->selected_window; | |
12855 | |
12856 Fmodify_frame_parameters (frame, | |
12857 Fcons (Fcons (Qfont, | |
12858 build_string ("-*-monaco-medium-r-*--*-90-*-*-*-*-mac-roman")), Qnil)); | |
12859 Fmodify_frame_parameters (frame, | |
12860 Fcons (Fcons (Qforeground_color, | |
12861 build_string ("black")), Qnil)); | |
12862 Fmodify_frame_parameters (frame, | |
12863 Fcons (Fcons (Qbackground_color, | |
12864 build_string ("white")), Qnil)); | |
12865 } | |
12866 | |
12867 | |
12868 /*********************************************************************** | |
12869 Initialization | |
12870 ***********************************************************************/ | |
12871 | |
12872 #ifdef USE_X_TOOLKIT | |
12873 static XrmOptionDescRec emacs_options[] = { | |
12874 {"-geometry", ".geometry", XrmoptionSepArg, NULL}, | |
12875 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"}, | |
12876 | |
12877 {"-internal-border-width", "*EmacsScreen.internalBorderWidth", | |
12878 XrmoptionSepArg, NULL}, | |
12879 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL}, | |
12880 | |
12881 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL}, | |
12882 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL}, | |
12883 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL}, | |
12884 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL}, | |
12885 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL}, | |
12886 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL}, | |
12887 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL} | |
12888 }; | |
12889 #endif /* USE_X_TOOLKIT */ | |
12890 | |
12891 #ifdef MULTI_KBOARD | |
12892 /* Test whether two display-name strings agree up to the dot that separates | |
12893 the screen number from the server number. */ | |
12894 static int | |
12895 same_x_server (name1, name2) | |
12896 char *name1, *name2; | |
12897 { | |
12898 int seen_colon = 0; | |
12899 unsigned char *system_name = XSTRING (Vsystem_name)->data; | |
12900 int system_name_length = strlen (system_name); | |
12901 int length_until_period = 0; | |
12902 | |
12903 while (system_name[length_until_period] != 0 | |
12904 && system_name[length_until_period] != '.') | |
12905 length_until_period++; | |
12906 | |
12907 /* Treat `unix' like an empty host name. */ | |
12908 if (! strncmp (name1, "unix:", 5)) | |
12909 name1 += 4; | |
12910 if (! strncmp (name2, "unix:", 5)) | |
12911 name2 += 4; | |
12912 /* Treat this host's name like an empty host name. */ | |
12913 if (! strncmp (name1, system_name, system_name_length) | |
12914 && name1[system_name_length] == ':') | |
12915 name1 += system_name_length; | |
12916 if (! strncmp (name2, system_name, system_name_length) | |
12917 && name2[system_name_length] == ':') | |
12918 name2 += system_name_length; | |
12919 /* Treat this host's domainless name like an empty host name. */ | |
12920 if (! strncmp (name1, system_name, length_until_period) | |
12921 && name1[length_until_period] == ':') | |
12922 name1 += length_until_period; | |
12923 if (! strncmp (name2, system_name, length_until_period) | |
12924 && name2[length_until_period] == ':') | |
12925 name2 += length_until_period; | |
12926 | |
12927 for (; *name1 != '\0' && *name1 == *name2; name1++, name2++) | |
12928 { | |
12929 if (*name1 == ':') | |
12930 seen_colon++; | |
12931 if (seen_colon && *name1 == '.') | |
12932 return 1; | |
12933 } | |
12934 return (seen_colon | |
12935 && (*name1 == '.' || *name1 == '\0') | |
12936 && (*name2 == '.' || *name2 == '\0')); | |
12937 } | |
12938 #endif | |
12939 | |
12940 int mac_initialized = 0; | |
12941 | |
12942 void | |
12943 mac_initialize_display_info () | |
12944 { | |
12945 struct mac_display_info *dpyinfo = &one_mac_display_info; | |
12946 GDHandle main_device_handle; | |
12947 | |
12948 bzero (dpyinfo, sizeof (*dpyinfo)); | |
12949 | |
12950 /* Put it on x_display_name_list. */ | |
12951 x_display_name_list = Fcons (Fcons (build_string ("Mac"), Qnil), | |
12952 x_display_name_list); | |
12953 dpyinfo->name_list_element = XCAR (x_display_name_list); | |
12954 | |
12955 #if 0 | |
12956 dpyinfo->mac_id_name | |
12957 = (char *) xmalloc (XSTRING (Vinvocation_name)->size | |
12958 + XSTRING (Vsystem_name)->size | |
12959 + 2); | |
12960 sprintf (dpyinfo->mac_id_name, "%s@%s", | |
12961 XSTRING (Vinvocation_name)->data, XSTRING (Vsystem_name)->data); | |
12962 #else | |
12963 dpyinfo->mac_id_name = (char *) xmalloc (strlen ("Mac Display") + 1); | |
12964 strcpy (dpyinfo->mac_id_name, "Mac Display"); | |
12965 #endif | |
12966 | |
12967 main_device_handle = LMGetMainDevice(); | |
12968 | |
12969 dpyinfo->reference_count = 0; | |
12970 dpyinfo->resx = 75.0; | |
12971 dpyinfo->resy = 75.0; | |
12972 dpyinfo->n_planes = 1; | |
12973 dpyinfo->n_cbits = 16; | |
12974 dpyinfo->height = (**main_device_handle).gdRect.bottom; | |
12975 dpyinfo->width = (**main_device_handle).gdRect.right; | |
12976 dpyinfo->grabbed = 0; | |
12977 dpyinfo->root_window = NULL; | |
12978 | |
12979 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1; | |
12980 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1; | |
12981 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID; | |
12982 dpyinfo->mouse_face_window = Qnil; | |
12983 } | |
12984 | |
12985 struct mac_display_info * | |
12986 mac_term_init (display_name, xrm_option, resource_name) | |
12987 Lisp_Object display_name; | |
12988 char *xrm_option; | |
12989 char *resource_name; | |
12990 { | |
12991 struct mac_display_info *dpyinfo; | |
12992 GDHandle main_device_handle; | |
12993 | |
12994 if (!mac_initialized) | |
12995 { | |
12996 mac_initialize (); | |
12997 mac_initialized = 1; | |
12998 } | |
12999 | |
13000 mac_initialize_display_info (display_name); | |
13001 | |
13002 dpyinfo = &one_mac_display_info; | |
13003 | |
13004 main_device_handle = LMGetMainDevice(); | |
13005 | |
13006 dpyinfo->height = (**main_device_handle).gdRect.bottom; | |
13007 dpyinfo->width = (**main_device_handle).gdRect.right; | |
13008 | |
13009 return dpyinfo; | |
13010 } | |
13011 | |
13012 /* Set up use of X before we make the first connection. */ | |
13013 | |
13014 static struct redisplay_interface x_redisplay_interface = | |
13015 { | |
13016 x_produce_glyphs, | |
13017 x_write_glyphs, | |
13018 x_insert_glyphs, | |
13019 x_clear_end_of_line, | |
13020 x_scroll_run, | |
13021 x_after_update_window_line, | |
13022 x_update_window_begin, | |
13023 x_update_window_end, | |
13024 XTcursor_to, | |
13025 x_flush, | |
13026 x_clear_mouse_face, | |
13027 x_get_glyph_overhangs, | |
13028 x_fix_overlapping_area | |
13029 }; | |
13030 | |
13031 void | |
13032 mac_initialize () | |
13033 { | |
13034 rif = &x_redisplay_interface; | |
13035 | |
13036 clear_frame_hook = x_clear_frame; | |
13037 ins_del_lines_hook = x_ins_del_lines; | |
13038 delete_glyphs_hook = x_delete_glyphs; | |
13039 ring_bell_hook = XTring_bell; | |
13040 reset_terminal_modes_hook = XTreset_terminal_modes; | |
13041 set_terminal_modes_hook = XTset_terminal_modes; | |
13042 update_begin_hook = x_update_begin; | |
13043 update_end_hook = x_update_end; | |
13044 set_terminal_window_hook = XTset_terminal_window; | |
13045 read_socket_hook = XTread_socket; | |
13046 frame_up_to_date_hook = XTframe_up_to_date; | |
13047 mouse_position_hook = XTmouse_position; | |
13048 frame_rehighlight_hook = XTframe_rehighlight; | |
13049 frame_raise_lower_hook = XTframe_raise_lower; | |
13050 | |
13051 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar; | |
13052 condemn_scroll_bars_hook = XTcondemn_scroll_bars; | |
13053 redeem_scroll_bar_hook = XTredeem_scroll_bar; | |
13054 judge_scroll_bars_hook = XTjudge_scroll_bars; | |
13055 | |
13056 estimate_mode_line_height_hook = x_estimate_mode_line_height; | |
13057 | |
13058 scroll_region_ok = 1; /* we'll scroll partial frames */ | |
13059 char_ins_del_ok = 1; | |
13060 line_ins_del_ok = 1; /* we'll just blt 'em */ | |
13061 fast_clear_end_of_line = 1; /* X does this well */ | |
13062 memory_below_frame = 0; /* we don't remember what scrolls | |
13063 off the bottom */ | |
13064 baud_rate = 19200; | |
13065 | |
13066 x_noop_count = 0; | |
13067 last_tool_bar_item = -1; | |
13068 any_help_event_p = 0; | |
13069 | |
13070 /* Try to use interrupt input; if we can't, then start polling. */ | |
13071 Fset_input_mode (Qt, Qnil, Qt, Qnil); | |
13072 | |
13073 #ifdef USE_X_TOOLKIT | |
13074 XtToolkitInitialize (); | |
13075 Xt_app_con = XtCreateApplicationContext (); | |
13076 XtAppSetFallbackResources (Xt_app_con, Xt_default_resources); | |
13077 | |
13078 /* Install an asynchronous timer that processes Xt timeout events | |
13079 every 0.1s. This is necessary because some widget sets use | |
13080 timeouts internally, for example the LessTif menu bar, or the | |
13081 Xaw3d scroll bar. When Xt timouts aren't processed, these | |
13082 widgets don't behave normally. */ | |
13083 { | |
13084 EMACS_TIME interval; | |
13085 EMACS_SET_SECS_USECS (interval, 0, 100000); | |
13086 start_atimer (ATIMER_CONTINUOUS, interval, x_process_timeouts, 0); | |
13087 } | |
13088 #endif | |
13089 | |
13090 #if USE_TOOLKIT_SCROLL_BARS | |
13091 xaw3d_arrow_scroll = False; | |
13092 xaw3d_pick_top = True; | |
13093 #endif | |
13094 | |
13095 #if 0 | |
13096 /* Note that there is no real way portable across R3/R4 to get the | |
13097 original error handler. */ | |
13098 XSetErrorHandler (x_error_handler); | |
13099 XSetIOErrorHandler (x_io_error_quitter); | |
13100 | |
13101 /* Disable Window Change signals; they are handled by X events. */ | |
13102 #ifdef SIGWINCH | |
13103 signal (SIGWINCH, SIG_DFL); | |
13104 #endif /* ! defined (SIGWINCH) */ | |
13105 | |
13106 signal (SIGPIPE, x_connection_signal); | |
13107 #endif | |
13108 | |
13109 mac_initialize_display_info (); | |
13110 } | |
13111 | |
13112 | |
13113 void | |
13114 syms_of_macterm () | |
13115 { | |
13116 #if 0 | |
13117 staticpro (&x_error_message_string); | |
13118 x_error_message_string = Qnil; | |
13119 #endif | |
13120 | |
13121 staticpro (&x_display_name_list); | |
13122 x_display_name_list = Qnil; | |
13123 | |
13124 staticpro (&last_mouse_scroll_bar); | |
13125 last_mouse_scroll_bar = Qnil; | |
13126 | |
13127 staticpro (&Qvendor_specific_keysyms); | |
13128 Qvendor_specific_keysyms = intern ("vendor-specific-keysyms"); | |
13129 | |
13130 staticpro (&last_mouse_press_frame); | |
13131 last_mouse_press_frame = Qnil; | |
13132 | |
13133 Qmac_ready_for_drag_n_drop = intern ("mac-ready-for-drag-n-drop"); | |
13134 staticpro (&Qmac_ready_for_drag_n_drop); | |
13135 | |
13136 help_echo = Qnil; | |
13137 staticpro (&help_echo); | |
13138 help_echo_object = Qnil; | |
13139 staticpro (&help_echo_object); | |
13140 help_echo_window = Qnil; | |
13141 staticpro (&help_echo_window); | |
13142 previous_help_echo = Qnil; | |
13143 staticpro (&previous_help_echo); | |
13144 help_echo_pos = -1; | |
13145 | |
13146 DEFVAR_BOOL ("x-autoselect-window", &x_autoselect_window_p, | |
13147 doc: /* *Non-nil means autoselect window with mouse pointer. */); | |
13148 x_autoselect_window_p = 0; | |
13149 | |
13150 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p, | |
13151 doc: /* *Non-nil means draw block cursor as wide as the glyph under it. | |
13152 For example, if a block cursor is over a tab, it will be drawn as | |
13153 wide as that tab on the display. */); | |
13154 x_stretch_cursor_p = 0; | |
13155 | |
13156 #if 0 /* TODO: Setting underline position from font properties. */ | |
13157 DEFVAR_BOOL ("x-use-underline-position-properties", | |
13158 &x_use_underline_position_properties, | |
13159 doc: /* *Non-nil means make use of UNDERLINE_POSITION font properties. | |
13160 nil means ignore them. If you encounter fonts with bogus | |
13161 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior | |
13162 to 4.1, set this to nil. */); | |
13163 x_use_underline_position_properties = 1; | |
13164 #endif | |
13165 | |
13166 DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars, | |
13167 doc: /* If not nil, Emacs uses toolkit scroll bars. */); | |
13168 Vx_toolkit_scroll_bars = Qt; | |
13169 | |
13170 staticpro (&last_mouse_motion_frame); | |
13171 last_mouse_motion_frame = Qnil; | |
13172 | |
13173 DEFVAR_LISP ("mac-command-key-is-meta", &Vmac_command_key_is_meta, | |
13174 doc: /* Non-nil means that the command key is used as the Emacs meta key. | |
13175 Otherwise the option key is used. */); | |
13176 Vmac_command_key_is_meta = Qt; | |
13177 | |
13178 DEFVAR_INT ("mac-keyboard-text-encoding", &mac_keyboard_text_encoding, | |
13179 doc: /* One of the Text Encoding Base constant values defined in the | |
13180 Basic Text Constants section of Inside Macintosh - Text Encoding | |
13181 Conversion Manager. Its value determines the encoding characters | |
13182 typed at the Mac keyboard (presumed to be in the MacRoman encoding) | |
13183 will convert into. E.g., if it is set to kTextEncodingMacRoman (0), | |
13184 its default value, no conversion takes place. If it is set to | |
13185 kTextEncodingISOLatin1 (0x201) or kTextEncodingISOLatin2 (0x202), | |
13186 characters typed on Mac keyboard are first converted into the | |
13187 ISO Latin-1 or ISO Latin-2 encoding, respectively before being | |
13188 passed to Emacs. Together with Emacs's set-keyboard-coding-system | |
13189 command, this enables the Mac keyboard to be used to enter non-ASCII | |
13190 characters directly. */); | |
13191 mac_keyboard_text_encoding = kTextEncodingMacRoman; | |
13192 } |