1 /* NeXT/Open/GNUstep / MacOSX communication module.
2 Copyright (C) 1989, 1993, 1994, 2005, 2006, 2008, 2009, 2010
3 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
21 Originally by Carl Edman
22 Updated by Christian Limpach (chris@nice.ch)
23 OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
24 MacOSX/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
25 GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
28 /* This should be the first include, as it may set up #defines affecting
29 interpretation of even the system includes. */
33 #include <sys/types.h>
40 #include "blockinput.h"
41 #include "sysselect.h"
44 #include "character.h"
46 #include "composite.h"
49 #include "termhooks.h"
60 int term_trace_num = 0;
61 #define NSTRACE(x) fprintf (stderr, "%s:%d: [%d] " #x "\n", \
62 __FILE__, __LINE__, ++term_trace_num)
68 /* ==========================================================================
72 ========================================================================== */
74 /* Convert a symbol indexed with an NSxxx value to a value as defined
75 in keyboard.c (lispy_function_key). I hope this is a correct way
77 static unsigned convert_ns_to_X_keysym[] =
79 NSHomeFunctionKey, 0x50,
80 NSLeftArrowFunctionKey, 0x51,
81 NSUpArrowFunctionKey, 0x52,
82 NSRightArrowFunctionKey, 0x53,
83 NSDownArrowFunctionKey, 0x54,
84 NSPageUpFunctionKey, 0x55,
85 NSPageDownFunctionKey, 0x56,
86 NSEndFunctionKey, 0x57,
87 NSBeginFunctionKey, 0x58,
88 NSSelectFunctionKey, 0x60,
89 NSPrintFunctionKey, 0x61,
90 NSExecuteFunctionKey, 0x62,
91 NSInsertFunctionKey, 0x63,
92 NSUndoFunctionKey, 0x65,
93 NSRedoFunctionKey, 0x66,
94 NSMenuFunctionKey, 0x67,
95 NSFindFunctionKey, 0x68,
96 NSHelpFunctionKey, 0x6A,
97 NSBreakFunctionKey, 0x6B,
99 NSF1FunctionKey, 0xBE,
100 NSF2FunctionKey, 0xBF,
101 NSF3FunctionKey, 0xC0,
102 NSF4FunctionKey, 0xC1,
103 NSF5FunctionKey, 0xC2,
104 NSF6FunctionKey, 0xC3,
105 NSF7FunctionKey, 0xC4,
106 NSF8FunctionKey, 0xC5,
107 NSF9FunctionKey, 0xC6,
108 NSF10FunctionKey, 0xC7,
109 NSF11FunctionKey, 0xC8,
110 NSF12FunctionKey, 0xC9,
111 NSF13FunctionKey, 0xCA,
112 NSF14FunctionKey, 0xCB,
113 NSF15FunctionKey, 0xCC,
114 NSF16FunctionKey, 0xCD,
115 NSF17FunctionKey, 0xCE,
116 NSF18FunctionKey, 0xCF,
117 NSF19FunctionKey, 0xD0,
118 NSF20FunctionKey, 0xD1,
119 NSF21FunctionKey, 0xD2,
120 NSF22FunctionKey, 0xD3,
121 NSF23FunctionKey, 0xD4,
122 NSF24FunctionKey, 0xD5,
124 NSBackspaceCharacter, 0x08, /* 8: Not on some KBs. */
125 NSDeleteCharacter, 0xFF, /* 127: Big 'delete' key upper right. */
126 NSDeleteFunctionKey, 0x9F, /* 63272: Del forw key off main array. */
128 NSTabCharacter, 0x09,
129 0x19, 0x09, /* left tab->regular since pass shift */
130 NSCarriageReturnCharacter, 0x0D,
131 NSNewlineCharacter, 0x0D,
132 NSEnterCharacter, 0x8D,
134 0x1B, 0x1B /* escape */
138 /* Lisp communications */
139 Lisp_Object ns_input_file, ns_input_font, ns_input_fontsize, ns_input_line;
140 Lisp_Object ns_input_color, ns_input_text, ns_working_text;
141 Lisp_Object ns_input_spi_name, ns_input_spi_arg;
142 Lisp_Object Vx_toolkit_scroll_bars;
143 static Lisp_Object Qmodifier_value;
144 Lisp_Object Qalt, Qcontrol, Qhyper, Qmeta, Qsuper, Qnone;
145 extern Lisp_Object Qcursor_color, Qcursor_type, Qns;
147 /* Specifies which emacs modifier should be generated when NS receives
148 the Alternate modifer. May be Qnone or any of the modifier lisp symbols. */
149 Lisp_Object ns_alternate_modifier;
151 /* Specifies which emacs modifier should be generated when NS receives
152 the Command modifer. May be any of the modifier lisp symbols. */
153 Lisp_Object ns_command_modifier;
155 /* Specifies which emacs modifier should be generated when NS receives
156 the Control modifer. May be any of the modifier lisp symbols. */
157 Lisp_Object ns_control_modifier;
159 /* Specifies which emacs modifier should be generated when NS receives
160 the Function modifer (laptops). May be any of the modifier lisp symbols. */
161 Lisp_Object ns_function_modifier;
163 /* Control via default 'GSFontAntiAlias' on OS X and GNUstep. */
164 Lisp_Object ns_antialias_text;
166 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
167 the maximum font size to NOT antialias. On GNUstep there is currently
168 no way to control this behavior. */
169 float ns_antialias_threshold;
171 /* Used to pick up AppleHighlightColor on OS X */
172 NSString *ns_selection_color;
174 /* Confirm on exit. */
175 Lisp_Object ns_confirm_quit;
177 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
178 NSString *ns_app_name = @"Emacs"; /* default changed later */
180 /* Display variables */
181 struct ns_display_info *x_display_list; /* Chain of existing displays */
182 Lisp_Object ns_display_name_list;
183 long context_menu_value = 0;
186 NSPoint last_mouse_motion_position;
187 static NSRect last_mouse_glyph;
188 static unsigned long last_mouse_movement_time = 0;
189 static Lisp_Object last_mouse_motion_frame;
190 static EmacsScroller *last_mouse_scroll_bar = nil;
191 static struct frame *ns_updating_frame;
192 static NSView *focus_view = NULL;
193 static int ns_window_num =0;
195 static BOOL gsaved = NO;
196 BOOL ns_in_resize = NO;
197 static BOOL ns_fake_keydown = NO;
198 int ns_tmp_flags; /* FIXME */
199 struct nsfont_info *ns_tmp_font; /* FIXME */
200 /*static int debug_lock = 0; */
203 static BOOL send_appdefined = YES;
204 static NSEvent *last_appdefined_event = 0;
205 static NSTimer *timed_entry = 0;
206 static NSTimer *fd_entry = nil;
207 static NSTimer *scroll_repeat_entry = nil;
208 static fd_set select_readfds, t_readfds;
209 static struct timeval select_timeout;
210 static int select_nfds;
211 static NSAutoreleasePool *outerpool;
212 static struct input_event *emacs_event = NULL;
213 static struct input_event *q_event_ptr = NULL;
214 static int n_emacs_events_pending = 0;
215 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
216 *ns_pending_service_args;
217 static BOOL inNsSelect = 0;
219 /* Convert modifiers in a NeXTSTEP event to emacs style modifiers. */
220 #define NS_FUNCTION_KEY_MASK 0x800000
221 #define EV_MODIFIERS(e) \
222 ((([e modifierFlags] & NSHelpKeyMask) ? \
223 hyper_modifier : 0) \
224 | (([e modifierFlags] & NSAlternateKeyMask) ? \
225 parse_solitary_modifier (ns_alternate_modifier) : 0) \
226 | (([e modifierFlags] & NSShiftKeyMask) ? \
227 shift_modifier : 0) \
228 | (([e modifierFlags] & NSControlKeyMask) ? \
229 parse_solitary_modifier (ns_control_modifier) : 0) \
230 | (([e modifierFlags] & NS_FUNCTION_KEY_MASK) ? \
231 parse_solitary_modifier (ns_function_modifier) : 0) \
232 | (([e modifierFlags] & NSCommandKeyMask) ? \
233 parse_solitary_modifier (ns_command_modifier):0))
235 #define EV_UDMODIFIERS(e) \
236 ((([e type] == NSLeftMouseDown) ? down_modifier : 0) \
237 | (([e type] == NSRightMouseDown) ? down_modifier : 0) \
238 | (([e type] == NSOtherMouseDown) ? down_modifier : 0) \
239 | (([e type] == NSLeftMouseDragged) ? down_modifier : 0) \
240 | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
241 | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
242 | (([e type] == NSLeftMouseUp) ? up_modifier : 0) \
243 | (([e type] == NSRightMouseUp) ? up_modifier : 0) \
244 | (([e type] == NSOtherMouseUp) ? up_modifier : 0))
246 #define EV_BUTTON(e) \
247 ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 : \
248 (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
249 [e buttonNumber] - 1)
251 /* Convert the time field to a timestamp in milliseconds. */
252 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
254 /* This is a piece of code which is common to all the event handling
255 methods. Maybe it should even be a function. */
256 #define EV_TRAILER(e) \
258 XSETFRAME (emacs_event->frame_or_window, emacsframe); \
259 if (e) emacs_event->timestamp = EV_TIMESTAMP (e); \
260 n_emacs_events_pending++; \
261 kbd_buffer_store_event_hold (emacs_event, q_event_ptr); \
262 EVENT_INIT (*emacs_event); \
263 ns_send_appdefined (-1); \
266 void x_set_cursor_type (struct frame *, Lisp_Object, Lisp_Object);
268 /* TODO: get rid of need for these forward declarations */
269 static void ns_condemn_scroll_bars (struct frame *f);
270 static void ns_judge_scroll_bars (struct frame *f);
271 void x_set_frame_alpha (struct frame *f);
273 /* unused variables needed for compatibility reasons */
274 int x_use_underline_position_properties, x_underline_at_descent_line;
275 /* FIXME: figure out what to do with underline_minimum_offset. */
278 /* ==========================================================================
282 ========================================================================== */
286 append2 (Lisp_Object list, Lisp_Object item)
287 /* --------------------------------------------------------------------------
288 Utility to append to a list
289 -------------------------------------------------------------------------- */
291 Lisp_Object array[2];
293 array[1] = Fcons (item, Qnil);
294 return Fnconc (2, &array[0]);
300 /* --------------------------------------------------------------------------
301 Used to allow emacs to find its resources under Emacs.app
302 Called from emacs.c at startup.
303 -------------------------------------------------------------------------- */
305 NSBundle *bundle = [NSBundle mainBundle];
306 NSString *binDir = [bundle bundlePath], *resourceDir = [bundle resourcePath];
307 NSString *resourcePath, *resourcePaths;
309 BOOL onWindows = NO; /* how do I determine this? */
310 NSString *pathSeparator = onWindows ? @";" : @":";
311 NSFileManager *fileManager = [NSFileManager defaultManager];
313 /*NSLog (@"ns_init_paths: '%@'\n%@\n", [[NSBundle mainBundle] bundlePath], [[NSBundle mainBundle] resourcePath]); */
315 /* get bindir from base */
316 range = [resourceDir rangeOfString: @"Contents"];
317 if (range.location != NSNotFound)
319 binDir = [binDir stringByAppendingPathComponent: @"Contents"];
321 binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
325 /* the following based on Andrew Choi's init_mac_osx_environment () */
326 if (!getenv ("EMACSLOADPATH"))
328 NSArray *paths = [resourceDir stringsByAppendingPaths:
329 [NSArray arrayWithObjects:
330 @"site-lisp", @"lisp", @"leim", nil]];
331 NSEnumerator *pathEnum = [paths objectEnumerator];
333 while (resourcePath = [pathEnum nextObject])
335 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
338 if ([resourcePaths length] > 0)
340 = [resourcePaths stringByAppendingString: pathSeparator];
342 = [resourcePaths stringByAppendingString: resourcePath];
345 if ([resourcePaths length] > 0)
346 setenv ("EMACSLOADPATH", [resourcePaths UTF8String], 1);
347 /*NSLog (@"loadPath: '%@'\n", resourcePaths); */
350 if (!getenv ("EMACSPATH"))
352 NSArray *paths = [binDir stringsByAppendingPaths:
353 [NSArray arrayWithObjects: @"bin",
355 NSEnumerator *pathEnum = [paths objectEnumerator];
357 while (resourcePath = [pathEnum nextObject])
359 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
362 if ([resourcePaths length] > 0)
364 = [resourcePaths stringByAppendingString: pathSeparator];
366 = [resourcePaths stringByAppendingString: resourcePath];
369 if ([resourcePaths length] > 0)
370 setenv ("EMACSPATH", [resourcePaths UTF8String], 1);
373 resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
374 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
378 if (!getenv ("EMACSDATA"))
379 setenv ("EMACSDATA", [resourcePath UTF8String], 1);
380 if (!getenv ("EMACSDOC"))
381 setenv ("EMACSDOC", [resourcePath UTF8String], 1);
385 if (!getenv ("INFOPATH"))
387 resourcePath = [resourceDir stringByAppendingPathComponent: @"info"];
388 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
390 setenv ("INFOPATH", [[resourcePath stringByAppendingString: @":"]
392 /* Note, extra colon needed to cause merge w/later user additions. */
398 timeval_subtract (struct timeval *result, struct timeval x, struct timeval y)
399 /* --------------------------------------------------------------------------
400 Subtract the `struct timeval' values X and Y, storing the result in RESULT.
401 Return 1 if the difference is negative, otherwise 0.
402 -------------------------------------------------------------------------- */
404 /* Perform the carry for the later subtraction by updating y.
405 This is safer because on some systems
406 the tv_sec member is unsigned. */
407 if (x.tv_usec < y.tv_usec)
409 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
410 y.tv_usec -= 1000000 * nsec;
413 if (x.tv_usec - y.tv_usec > 1000000)
415 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
416 y.tv_usec += 1000000 * nsec;
420 /* Compute the time remaining to wait. tv_usec is certainly positive. */
421 result->tv_sec = x.tv_sec - y.tv_sec;
422 result->tv_usec = x.tv_usec - y.tv_usec;
424 /* Return indication of whether the result should be considered negative. */
425 return x.tv_sec < y.tv_sec;
429 ns_timeout (int usecs)
430 /* --------------------------------------------------------------------------
431 Blocking timer utility used by ns_ring_bell
432 -------------------------------------------------------------------------- */
434 struct timeval wakeup;
436 EMACS_GET_TIME (wakeup);
438 /* Compute time to wait until, propagating carry from usecs. */
439 wakeup.tv_usec += usecs;
440 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
441 wakeup.tv_usec %= 1000000;
443 /* Keep waiting until past the time wakeup. */
446 struct timeval timeout;
448 EMACS_GET_TIME (timeout);
450 /* In effect, timeout = wakeup - timeout.
451 Break if result would be negative. */
452 if (timeval_subtract (&timeout, wakeup, timeout))
455 /* Try to wait that long--but we might wake up sooner. */
456 select (0, NULL, NULL, NULL, &timeout);
462 ns_release_object (void *obj)
463 /* --------------------------------------------------------------------------
464 Release an object (callable from C)
465 -------------------------------------------------------------------------- */
472 ns_retain_object (void *obj)
473 /* --------------------------------------------------------------------------
474 Retain an object (callable from C)
475 -------------------------------------------------------------------------- */
482 ns_alloc_autorelease_pool ()
483 /* --------------------------------------------------------------------------
484 Allocate a pool for temporary objects (callable from C)
485 -------------------------------------------------------------------------- */
487 return [[NSAutoreleasePool alloc] init];
492 ns_release_autorelease_pool (void *pool)
493 /* --------------------------------------------------------------------------
494 Free a pool and temporary objects it refers to (callable from C)
495 -------------------------------------------------------------------------- */
497 ns_release_object (pool);
502 /* ==========================================================================
504 Focus (clipping) and screen update
506 ========================================================================== */
509 ns_resize_handle_rect (NSWindow *window)
511 NSRect r = [window frame];
512 r.origin.x = r.size.width - RESIZE_HANDLE_SIZE;
514 r.size.width = r.size.height = RESIZE_HANDLE_SIZE;
520 ns_update_begin (struct frame *f)
521 /* --------------------------------------------------------------------------
522 Prepare for a grouped sequence of drawing calls
523 external (RIF) call; whole frame, called before update_window_begin
524 -------------------------------------------------------------------------- */
526 NSView *view = FRAME_NS_VIEW (f);
527 NSTRACE (ns_update_begin);
529 ns_updating_frame = f;
532 #ifdef NS_IMPL_GNUSTEP
533 uRect = NSMakeRect (0, 0, 0, 0);
539 ns_update_window_begin (struct window *w)
540 /* --------------------------------------------------------------------------
541 Prepare for a grouped sequence of drawing calls
542 external (RIF) call; for one window, called after update_begin
543 -------------------------------------------------------------------------- */
545 struct frame *f = XFRAME (WINDOW_FRAME (w));
546 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
547 NSTRACE (ns_update_window_begin);
550 set_output_cursor (&w->cursor);
554 if (f == dpyinfo->mouse_face_mouse_frame)
556 /* Don't do highlighting for mouse motion during the update. */
557 dpyinfo->mouse_face_defer = 1;
559 /* If the frame needs to be redrawn,
560 simply forget about any prior mouse highlighting. */
561 if (FRAME_GARBAGED_P (f))
562 dpyinfo->mouse_face_window = Qnil;
564 /* (further code for mouse faces ifdef'd out in other terms elided) */
572 ns_update_window_end (struct window *w, int cursor_on_p,
573 int mouse_face_overwritten_p)
574 /* --------------------------------------------------------------------------
575 Finished a grouped sequence of drawing calls
576 external (RIF) call; for one window called before update_end
577 -------------------------------------------------------------------------- */
579 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (XFRAME (w->frame));
581 /* note: this fn is nearly identical in all terms */
582 if (!w->pseudo_window_p)
587 display_and_set_cursor (w, 1,
588 output_cursor.hpos, output_cursor.vpos,
589 output_cursor.x, output_cursor.y);
591 if (draw_window_fringes (w, 1))
592 x_draw_vertical_border (w);
597 /* If a row with mouse-face was overwritten, arrange for
598 frame_up_to_date to redisplay the mouse highlight. */
599 if (mouse_face_overwritten_p)
601 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
602 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
603 dpyinfo->mouse_face_window = Qnil;
606 updated_window = NULL;
607 NSTRACE (update_window_end);
612 ns_update_end (struct frame *f)
613 /* --------------------------------------------------------------------------
614 Finished a grouped sequence of drawing calls
615 external (RIF) call; for whole frame, called after update_window_end
616 -------------------------------------------------------------------------- */
618 NSView *view = FRAME_NS_VIEW (f);
620 /* if (f == FRAME_NS_DISPLAY_INFO (f)->mouse_face_mouse_frame) */
621 FRAME_NS_DISPLAY_INFO (f)->mouse_face_defer = 0;
625 #ifdef NS_IMPL_GNUSTEP
626 /* trigger flush only in the rectangle we tracked as being drawn */
627 [view unlockFocusNeedsFlush: NO];
628 /*fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", uRect.origin.x, uRect.origin.y, uRect.size.width, uRect.size.height); */
629 [view lockFocusInRect: uRect];
633 [[view window] flushWindow];
636 ns_updating_frame = NULL;
637 NSTRACE (ns_update_end);
642 ns_flush (struct frame *f)
643 /* --------------------------------------------------------------------------
645 NS impl is no-op since currently we flush in ns_update_end and elsewhere
646 -------------------------------------------------------------------------- */
653 ns_focus (struct frame *f, NSRect *r, int n)
654 /* --------------------------------------------------------------------------
655 Internal: Focus on given frame. During small local updates this is used to
656 draw, however during large updates, ns_update_begin and ns_update_end are
657 called to wrap the whole thing, in which case these calls are stubbed out.
658 Except, on GNUstep, we accumulate the rectangle being drawn into, because
659 the back end won't do this automatically, and will just end up flushing
661 -------------------------------------------------------------------------- */
663 // NSTRACE (ns_focus);
664 #ifdef NS_IMPL_GNUSTEP
667 u = NSUnionRect (r[0], r[1]);
672 fprintf (stderr, "focus: %d", c++);
673 if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
674 fprintf (stderr, "\n"); */
676 if (f != ns_updating_frame)
678 NSView *view = FRAME_NS_VIEW (f);
679 if (view != focus_view)
681 if (focus_view != NULL)
683 [focus_view unlockFocus];
684 [[focus_view window] flushWindow];
689 #ifdef NS_IMPL_GNUSTEP
690 r ? [view lockFocusInRect: u] : [view lockFocus];
695 /*if (view) debug_lock++; */
697 #ifdef NS_IMPL_GNUSTEP
700 /* more than one rect being drawn into */
703 [view unlockFocus]; /* add prev rect to redraw list */
704 [view lockFocusInRect: u]; /* focus for draw in new rect */
709 #ifdef NS_IMPL_GNUSTEP
712 /* in batch mode, but in GNUstep must still track rectangles explicitly */
713 uRect = (r ? NSUnionRect (uRect, u) : [FRAME_NS_VIEW (f) visibleRect]);
720 [[NSGraphicsContext currentContext] saveGraphicsState];
722 NSRectClipList (r, 2);
731 ns_unfocus (struct frame *f)
732 /* --------------------------------------------------------------------------
733 Internal: Remove focus on given frame
734 -------------------------------------------------------------------------- */
736 // NSTRACE (ns_unfocus);
740 [[NSGraphicsContext currentContext] restoreGraphicsState];
744 if (f != ns_updating_frame)
746 if (focus_view != NULL)
748 [focus_view unlockFocus];
749 [[focus_view window] flushWindow];
758 ns_clip_to_row (struct window *w, struct glyph_row *row, int area, BOOL gc)
759 /* --------------------------------------------------------------------------
760 Internal (but parallels other terms): Focus drawing on given row
761 -------------------------------------------------------------------------- */
763 struct frame *f = XFRAME (WINDOW_FRAME (w));
765 int window_x, window_y, window_width;
767 window_box (w, area, &window_x, &window_y, &window_width, 0);
769 clip_rect.origin.x = window_x - FRAME_INTERNAL_BORDER_WIDTH (f);
770 clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
771 clip_rect.origin.y = max (clip_rect.origin.y, window_y);
772 clip_rect.size.width = window_width + 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
773 clip_rect.size.height = row->visible_height;
775 /* allow a full-height row at the top when requested
776 (used to draw fringe all the way through internal border area) */
777 if (gc && clip_rect.origin.y < 5)
779 clip_rect.origin.y -= FRAME_INTERNAL_BORDER_WIDTH (f);
780 clip_rect.size.height += FRAME_INTERNAL_BORDER_WIDTH (f);
783 /* likewise at bottom */
785 FRAME_PIXEL_HEIGHT (f) - (clip_rect.origin.y + clip_rect.size.height) < 5)
786 clip_rect.size.height += FRAME_INTERNAL_BORDER_WIDTH (f);
788 ns_focus (f, &clip_rect, 1);
794 /* --------------------------------------------------------------------------
796 -------------------------------------------------------------------------- */
798 NSTRACE (ns_ring_bell);
801 NSAutoreleasePool *pool;
802 struct frame *frame = SELECTED_FRAME ();
806 pool = [[NSAutoreleasePool alloc] init];
808 view = FRAME_NS_VIEW (frame);
812 NSPoint dim = NSMakePoint (128, 128);
815 r.origin.x += (r.size.width - dim.x) / 2;
816 r.origin.y += (r.size.height - dim.y) / 2;
817 r.size.width = dim.x;
818 r.size.height = dim.y;
819 surr = NSInsetRect (r, -2, -2);
820 ns_focus (frame, &surr, 1);
821 [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
822 [ns_lookup_indexed_color (NS_FACE_FOREGROUND
823 (FRAME_DEFAULT_FACE (frame)), frame) set];
825 [[view window] flushWindow];
827 [[view window] restoreCachedImage];
828 [[view window] flushWindow];
842 ns_reset_terminal_modes (struct terminal *terminal)
843 /* Externally called as hook */
845 NSTRACE (ns_reset_terminal_modes);
850 ns_set_terminal_modes (struct terminal *terminal)
851 /* Externally called as hook */
853 NSTRACE (ns_set_terminal_modes);
858 /* ==========================================================================
860 Frame / window manager related functions
862 ========================================================================== */
866 ns_raise_frame (struct frame *f)
867 /* --------------------------------------------------------------------------
868 Bring window to foreground and make it active
869 -------------------------------------------------------------------------- */
871 NSView *view = FRAME_NS_VIEW (f);
874 FRAME_SAMPLE_VISIBILITY (f);
875 if (FRAME_VISIBLE_P (f))
877 [[view window] makeKeyAndOrderFront: NSApp];
884 ns_lower_frame (struct frame *f)
885 /* --------------------------------------------------------------------------
887 -------------------------------------------------------------------------- */
889 NSView *view = FRAME_NS_VIEW (f);
892 [[view window] orderBack: NSApp];
898 ns_frame_raise_lower (struct frame *f, int raise)
899 /* --------------------------------------------------------------------------
901 -------------------------------------------------------------------------- */
903 NSTRACE (ns_frame_raise_lower);
913 ns_frame_rehighlight (struct frame *frame)
914 /* --------------------------------------------------------------------------
915 External (hook): called on things like window switching within frame
916 -------------------------------------------------------------------------- */
918 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
919 struct frame *old_highlight = dpyinfo->x_highlight_frame;
921 NSTRACE (ns_frame_rehighlight);
922 if (dpyinfo->x_focus_frame)
924 dpyinfo->x_highlight_frame
925 = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
926 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
927 : dpyinfo->x_focus_frame);
928 if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
930 FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
931 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
935 dpyinfo->x_highlight_frame = 0;
937 if (dpyinfo->x_highlight_frame &&
938 dpyinfo->x_highlight_frame != old_highlight)
942 x_update_cursor (old_highlight, 1);
943 x_set_frame_alpha (old_highlight);
945 if (dpyinfo->x_highlight_frame)
947 x_update_cursor (dpyinfo->x_highlight_frame, 1);
948 x_set_frame_alpha (dpyinfo->x_highlight_frame);
955 x_make_frame_visible (struct frame *f)
956 /* --------------------------------------------------------------------------
957 External: Show the window (X11 semantics)
958 -------------------------------------------------------------------------- */
960 NSTRACE (x_make_frame_visible);
961 /* XXX: at some points in past this was not needed, as the only place that
962 called this (frame.c:Fraise_frame ()) also called raise_lower;
963 if this ends up the case again, comment this out again. */
964 if (!FRAME_VISIBLE_P (f))
966 f->async_visible = 1;
973 x_make_frame_invisible (struct frame *f)
974 /* --------------------------------------------------------------------------
975 External: Hide the window (X11 semantics)
976 -------------------------------------------------------------------------- */
978 NSView * view = FRAME_NS_VIEW (f);
979 NSTRACE (x_make_frame_invisible);
981 [[view window] orderOut: NSApp];
982 f->async_visible = 0;
983 f->async_iconified = 0;
988 x_iconify_frame (struct frame *f)
989 /* --------------------------------------------------------------------------
990 External: Iconify window
991 -------------------------------------------------------------------------- */
993 NSView * view = FRAME_NS_VIEW (f);
994 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
995 NSTRACE (x_iconify_frame);
998 if (dpyinfo->x_highlight_frame == f)
999 dpyinfo->x_highlight_frame = 0;
1001 if ([[view window] windowNumber] <= 0)
1003 /* the window is still deferred. Make it very small, bring it
1004 on screen and order it out. */
1005 NSRect s = { { 100, 100}, {0, 0} };
1007 t = [[view window] frame];
1008 [[view window] setFrame: s display: NO];
1009 [[view window] orderBack: NSApp];
1010 [[view window] orderOut: NSApp];
1011 [[view window] setFrame: t display: NO];
1013 [[view window] miniaturize: NSApp];
1018 x_destroy_window (struct frame *f)
1019 /* --------------------------------------------------------------------------
1020 External: Delete the window
1021 -------------------------------------------------------------------------- */
1023 NSView *view = FRAME_NS_VIEW (f);
1024 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1025 NSTRACE (x_destroy_window);
1028 [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1032 free_frame_menubar (f);
1034 if (FRAME_FACE_CACHE (f))
1035 free_frame_faces (f);
1037 if (f == dpyinfo->x_focus_frame)
1038 dpyinfo->x_focus_frame = 0;
1039 if (f == dpyinfo->x_highlight_frame)
1040 dpyinfo->x_highlight_frame = 0;
1041 if (f == dpyinfo->mouse_face_mouse_frame)
1043 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
1044 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
1045 dpyinfo->mouse_face_window = Qnil;
1046 dpyinfo->mouse_face_deferred_gc = 0;
1047 dpyinfo->mouse_face_mouse_frame = 0;
1050 xfree (f->output_data.ns);
1052 [[view window] close];
1061 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1062 /* --------------------------------------------------------------------------
1063 External: Position the window
1064 -------------------------------------------------------------------------- */
1067 NSView *view = FRAME_NS_VIEW (f);
1069 NSTRACE (x_set_offset);
1075 #ifdef NS_IMPL_GNUSTEP
1077 f->left_pos = 100; /* don't overlap menu */
1080 if (view != nil && (screen = [[view window] screen]))
1081 [[view window] setFrameTopLeftPoint:
1082 NSMakePoint (SCREENMAXBOUND (f->left_pos),
1083 SCREENMAXBOUND ([screen frame].size.height
1084 - NS_TOP_POS (f)))];
1090 x_set_window_size (struct frame *f, int change_grav, int cols, int rows)
1091 /* --------------------------------------------------------------------------
1092 Adjust window pixel size based on given character grid size
1093 Impl is a bit more complex than other terms, need to do some
1094 internal clipping and also pay attention to screen constraints.
1095 -------------------------------------------------------------------------- */
1097 EmacsView *view = FRAME_NS_VIEW (f);
1098 EmacsToolbar *toolbar = [view toolbar];
1099 NSWindow *window = [view window];
1100 NSScreen *screen = [window screen];
1101 NSRect wr = [window frame];
1102 int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1103 int pixelwidth, pixelheight;
1104 static int oldRows, oldCols, oldFontWidth, oldFontHeight;
1106 static struct frame *oldF;
1108 NSTRACE (x_set_window_size);
1112 && rows == oldRows && cols == oldCols
1113 && oldFontWidth == FRAME_COLUMN_WIDTH (f)
1114 && oldFontHeight == FRAME_LINE_HEIGHT (f)
1118 /*fprintf (stderr, "\tsetWindowSize: %d x %d, font size %d x %d\n", cols, rows, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f)); */
1122 check_frame_size (f, &rows, &cols);
1126 oldFontWidth = FRAME_COLUMN_WIDTH (f);
1127 oldFontHeight = FRAME_LINE_HEIGHT (f);
1130 f->scroll_bar_actual_width = NS_SCROLL_BAR_WIDTH (f);
1131 compute_fringe_widths (f, 0);
1133 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, cols);
1134 pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1136 /* If we have a toolbar, take its height into account. */
1138 /* NOTE: previously this would generate wrong result if toolbar not
1139 yet displayed and fixing toolbar_height=32 helped, but
1140 now (200903) seems no longer needed */
1141 FRAME_TOOLBAR_HEIGHT (f) =
1142 NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1143 - FRAME_NS_TITLEBAR_HEIGHT (f);
1145 FRAME_TOOLBAR_HEIGHT (f) = 0;
1147 wr.size.width = pixelwidth + f->border_width;
1148 wr.size.height = pixelheight + FRAME_NS_TITLEBAR_HEIGHT (f)
1149 + FRAME_TOOLBAR_HEIGHT (f);
1151 /* constrain to screen if we can */
1154 NSSize sz = [screen visibleFrame].size;
1155 NSSize ez = { wr.size.width - sz.width, wr.size.height - sz.height };
1158 int cr = ez.width / FRAME_COLUMN_WIDTH (f) + 1;
1161 wr.size.width -= cr * FRAME_COLUMN_WIDTH (f);
1162 pixelwidth -= cr * FRAME_COLUMN_WIDTH (f);
1166 int rr = ez.height / FRAME_LINE_HEIGHT (f) + 1;
1169 wr.size.height -= rr * FRAME_LINE_HEIGHT (f);
1170 pixelheight -= rr * FRAME_LINE_HEIGHT (f);
1172 wr.origin.x = f->left_pos;
1173 wr.origin.y = [screen frame].size.height - NS_TOP_POS (f)
1177 [view setRows: rows andColumns: cols];
1178 [window setFrame: wr display: YES];
1180 /*fprintf (stderr, "\tx_set_window_size %d, %d\t%d, %d\n", cols, rows, pixelwidth, pixelheight); */
1182 /* This is a trick to compensate for Emacs' managing the scrollbar area
1183 as a fixed number of standard character columns. Instead of leaving
1184 blank space for the extra, we chopped it off above. Now for
1185 left-hand scrollbars, we shift all rendering to the left by the
1186 difference between the real width and Emacs' imagined one. For
1187 right-hand bars, don't worry about it since the extra is never used.
1188 (Obviously doesn't work for vertically split windows tho..) */
1189 NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1190 ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1191 - NS_SCROLL_BAR_WIDTH (f), 0)
1192 : NSMakePoint (0, 0);
1193 [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1194 [view setBoundsOrigin: origin];
1196 change_frame_size (f, rows, cols, 0, 1, 0); /* pretend, delay, safe */
1197 FRAME_PIXEL_WIDTH (f) = pixelwidth;
1198 FRAME_PIXEL_HEIGHT (f) = pixelheight;
1199 /* SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1201 mark_window_cursors_off (XWINDOW (f->root_window));
1202 cancel_mouse_face (f);
1209 /* ==========================================================================
1213 ========================================================================== */
1217 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1219 struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1220 if (idx < 1 || idx >= color_table->avail)
1222 return color_table->colors[idx];
1227 ns_index_color (NSColor *color, struct frame *f)
1229 struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1233 if (!color_table->colors)
1235 color_table->size = NS_COLOR_CAPACITY;
1236 color_table->avail = 1; /* skip idx=0 as marker */
1238 = (NSColor **)xmalloc (color_table->size * sizeof (NSColor *));
1239 color_table->colors[0] = nil;
1240 color_table->empty_indices = [[NSMutableSet alloc] init];
1243 /* do we already have this color ? */
1246 for (i = 1; i < color_table->avail; i++)
1248 if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1250 [color_table->colors[i] retain];
1256 if ([color_table->empty_indices count] > 0)
1258 index = [color_table->empty_indices anyObject];
1259 [color_table->empty_indices removeObject: index];
1260 idx = [index unsignedIntValue];
1264 if (color_table->avail == color_table->size)
1266 color_table->size += NS_COLOR_CAPACITY;
1268 = (NSColor **)xrealloc (color_table->colors,
1269 color_table->size * sizeof (NSColor *));
1271 idx = color_table->avail++;
1274 color_table->colors[idx] = color;
1276 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1282 ns_free_indexed_color (unsigned long idx, struct frame *f)
1284 struct ns_color_table *color_table;
1291 color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1293 if (idx <= 0 || idx >= color_table->size) {
1294 message1("ns_free_indexed_color: Color index out of range.\n");
1298 index = [NSNumber numberWithUnsignedInt: idx];
1299 if ([color_table->empty_indices containsObject: index]) {
1300 message1("ns_free_indexed_color: attempt to free already freed color.\n");
1304 color = color_table->colors[idx];
1306 color_table->colors[idx] = nil;
1307 [color_table->empty_indices addObject: [NSNumber numberWithUnsignedInt: idx]];
1308 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1313 ns_get_color (const char *name, NSColor **col)
1314 /* --------------------------------------------------------------------------
1316 -------------------------------------------------------------------------- */
1317 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1318 X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1319 See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1322 static char hex[20];
1324 float r = -1.0, g, b;
1325 NSString *nsname = [NSString stringWithUTF8String: name];
1327 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1330 if ([nsname isEqualToString: @"ns_selection_color"])
1332 nsname = ns_selection_color;
1333 name = [ns_selection_color UTF8String];
1336 /* First, check for some sort of numeric specification. */
1339 if (name[0] == '0' || name[0] == '1' || name[0] == '.') /* RGB decimal */
1341 NSScanner *scanner = [NSScanner scannerWithString: nsname];
1342 [scanner scanFloat: &r];
1343 [scanner scanFloat: &g];
1344 [scanner scanFloat: &b];
1346 else if (!strncmp(name, "rgb:", 4)) /* A newer X11 format -- rgb:r/g/b */
1348 strncpy (hex, name + 4, 19);
1350 scaling = (strlen(hex) - 2) / 3;
1352 else if (name[0] == '#') /* An old X11 format; convert to newer */
1354 int len = (strlen(name) - 1);
1355 int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1357 scaling = strlen(name+start) / 3;
1358 for (i=0; i<3; i++) {
1359 strncpy(hex + i * (scaling + 1), name + start + i * scaling, scaling);
1360 hex[(i+1) * (scaling + 1) - 1] = '/';
1362 hex[3 * (scaling + 1) - 1] = '\0';
1368 float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1369 if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1379 *col = [NSColor colorWithCalibratedRed: r green: g blue: b alpha: 1.0];
1384 /* Otherwise, color is expected to be from a list */
1386 NSEnumerator *lenum, *cenum;
1390 #ifdef NS_IMPL_GNUSTEP
1391 /* XXX: who is wrong, the requestor or the implementation? */
1392 if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1394 nsname = @"highlightColor";
1397 lenum = [[NSColorList availableColorLists] objectEnumerator];
1398 while ( (clist = [lenum nextObject]) && new == nil)
1400 cenum = [[clist allKeys] objectEnumerator];
1401 while ( (name = [cenum nextObject]) && new == nil )
1403 if ([name compare: nsname
1404 options: NSCaseInsensitiveSearch] == NSOrderedSame )
1405 new = [clist colorWithKey: name];
1411 *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1418 ns_get_color_default (const char *name, NSColor *dflt)
1419 /* --------------------------------------------------------------------------
1420 Parse a color or use a default value
1421 -------------------------------------------------------------------------- */
1425 if (ns_get_color (name, &col))
1433 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1434 /* --------------------------------------------------------------------------
1435 Convert a Lisp string object to a NS color
1436 -------------------------------------------------------------------------- */
1438 NSTRACE (ns_lisp_to_color);
1439 if (STRINGP (color))
1440 return ns_get_color (SDATA (color), col);
1441 else if (SYMBOLP (color))
1442 return ns_get_color (SDATA (SYMBOL_NAME (color)), col);
1448 ns_color_to_lisp (NSColor *col)
1449 /* --------------------------------------------------------------------------
1450 Convert a color to a lisp string with the RGB equivalent
1451 -------------------------------------------------------------------------- */
1453 CGFloat red, green, blue, alpha, gray;
1456 NSTRACE (ns_color_to_lisp);
1459 if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1461 if ((str =[[col colorNameComponent] UTF8String]))
1464 return build_string ((char *)str);
1467 [[col colorUsingColorSpaceName: NSCalibratedRGBColorSpace]
1468 getRed: &red green: &green blue: &blue alpha: &alpha];
1469 if (red ==green && red ==blue)
1471 [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1472 getWhite: &gray alpha: &alpha];
1473 snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1474 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1476 return build_string (buf);
1479 snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1480 lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1483 return build_string (buf);
1488 ns_query_color(void *col, XColor *color_def, int setPixel)
1489 /* --------------------------------------------------------------------------
1490 Get ARGB values out of NSColor col and put them into color_def.
1491 If setPixel, set the pixel to a concatenated version.
1492 and set color_def pixel to the resulting index.
1493 -------------------------------------------------------------------------- */
1497 [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1498 color_def->red = r * 65535;
1499 color_def->green = g * 65535;
1500 color_def->blue = b * 65535;
1502 if (setPixel == YES)
1504 = ARGB_TO_ULONG((int)(a*255),
1505 (int)(r*255), (int)(g*255), (int)(b*255));
1510 ns_defined_color (struct frame *f, char *name, XColor *color_def, int alloc,
1512 /* --------------------------------------------------------------------------
1513 Return 1 if named color found, and set color_def rgb accordingly.
1514 If makeIndex and alloc are nonzero put the color in the color_table,
1515 and set color_def pixel to the resulting index.
1516 If makeIndex is zero, set color_def pixel to ARGB.
1517 Return 0 if not found
1518 -------------------------------------------------------------------------- */
1521 NSTRACE (ns_defined_color);
1524 if (ns_get_color (name, &col) != 0) /* Color not found */
1529 if (makeIndex && alloc)
1530 color_def->pixel = ns_index_color (col, f);
1531 ns_query_color (col, color_def, !makeIndex);
1538 ns_get_rgb_color (struct frame *f, float r, float g, float b, float a)
1539 /* --------------------------------------------------------------------------
1540 return an autoreleased RGB color
1541 -------------------------------------------------------------------------- */
1543 /*static int c = 1; fprintf (stderr, "color request %d\n", c++); */
1544 if (r < 0.0) r = 0.0;
1545 else if (r > 1.0) r = 1.0;
1546 if (g < 0.0) g = 0.0;
1547 else if (g > 1.0) g = 1.0;
1548 if (b < 0.0) b = 0.0;
1549 else if (b > 1.0) b = 1.0;
1550 if (a < 0.0) a = 0.0;
1551 else if (a > 1.0) a = 1.0;
1552 return (unsigned long) ns_index_color(
1553 [NSColor colorWithCalibratedRed: r green: g blue: b alpha: a], f);
1558 x_set_frame_alpha (struct frame *f)
1559 /* --------------------------------------------------------------------------
1560 change the entire-frame transparency
1561 -------------------------------------------------------------------------- */
1563 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1564 EmacsView *view = FRAME_NS_VIEW (f);
1566 double alpha_min = 1.0;
1568 if (dpyinfo->x_highlight_frame == f)
1569 alpha = f->alpha[0];
1571 alpha = f->alpha[1];
1573 if (FLOATP (Vframe_alpha_lower_limit))
1574 alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1575 else if (INTEGERP (Vframe_alpha_lower_limit))
1576 alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1580 else if (1.0 < alpha)
1582 else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1585 #ifdef NS_IMPL_COCOA
1586 [[view window] setAlphaValue: alpha];
1591 /* ==========================================================================
1595 ========================================================================== */
1599 x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1600 /* --------------------------------------------------------------------------
1601 Programmatically reposition mouse pointer in pixel coordinates
1602 -------------------------------------------------------------------------- */
1604 NSTRACE (x_set_mouse_pixel_position);
1607 /* FIXME: this does not work, and what about GNUstep? */
1608 #ifdef NS_IMPL_COCOA
1609 [FRAME_NS_VIEW (f) lockFocus];
1610 PSsetmouse ((float)pix_x, (float)pix_y);
1611 [FRAME_NS_VIEW (f) unlockFocus];
1618 x_set_mouse_position (struct frame *f, int h, int v)
1619 /* --------------------------------------------------------------------------
1620 Programmatically reposition mouse pointer in character coordinates
1621 -------------------------------------------------------------------------- */
1625 pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
1626 pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
1628 if (pix_x < 0) pix_x = 0;
1629 if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1631 if (pix_y < 0) pix_y = 0;
1632 if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1634 x_set_mouse_pixel_position (f, pix_x, pix_y);
1639 note_mouse_movement (struct frame *frame, float x, float y)
1640 /* ------------------------------------------------------------------------
1641 Called by EmacsView on mouseMovement events. Passes on
1642 to emacs mainstream code if we moved off of a rect of interest
1643 known as last_mouse_glyph.
1644 ------------------------------------------------------------------------ */
1646 // NSTRACE (note_mouse_movement);
1648 XSETFRAME (last_mouse_motion_frame, frame);
1650 /* Note, this doesn't get called for enter/leave, since we don't have a
1651 position. Those are taken care of in the corresponding NSView methods. */
1653 /* has movement gone beyond last rect we were tracking? */
1654 if (x < last_mouse_glyph.origin.x ||
1655 x >= (last_mouse_glyph.origin.x + last_mouse_glyph.size.width) ||
1656 y < last_mouse_glyph.origin.y ||
1657 y >= (last_mouse_glyph.origin.y + last_mouse_glyph.size.height))
1659 ns_update_begin(frame);
1660 frame->mouse_moved = 1;
1661 note_mouse_highlight (frame, x, y);
1662 remember_mouse_glyph (frame, x, y, &last_mouse_glyph);
1663 ns_update_end(frame);
1672 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1673 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1674 unsigned long *time)
1675 /* --------------------------------------------------------------------------
1676 External (hook): inform emacs about mouse position and hit parts.
1677 If a scrollbar is being dragged, set bar_window, part, x, y, time.
1678 x & y should be position in the scrollbar (the whole bar, not the handle)
1679 and length of scrollbar respectively
1680 -------------------------------------------------------------------------- */
1685 Lisp_Object frame, tail;
1687 struct ns_display_info *dpyinfo;
1689 NSTRACE (ns_mouse_position);
1693 fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1697 dpyinfo = FRAME_NS_DISPLAY_INFO (*fp);
1701 if (last_mouse_scroll_bar != nil && insist == 0)
1703 /* TODO: we do not use this path at the moment because drag events will
1704 go directly to the EmacsScroller. Leaving code in for now. */
1705 [last_mouse_scroll_bar getMouseMotionPart: (int *)part window: bar_window
1707 if (time) *time = last_mouse_movement_time;
1708 last_mouse_scroll_bar = nil;
1712 /* Clear the mouse-moved flag for every frame on this display. */
1713 FOR_EACH_FRAME (tail, frame)
1714 if (FRAME_NS_P (XFRAME (frame))
1715 && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1716 XFRAME (frame)->mouse_moved = 0;
1718 last_mouse_scroll_bar = nil;
1719 if (last_mouse_frame && FRAME_LIVE_P (last_mouse_frame))
1720 f = last_mouse_frame;
1722 f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame
1723 : SELECTED_FRAME ();
1725 if (f && f->output_data.ns) /* TODO: 2nd check no longer needed? */
1727 view = FRAME_NS_VIEW (*fp);
1729 position = [[view window] mouseLocationOutsideOfEventStream];
1730 position = [view convertPoint: position fromView: nil];
1731 remember_mouse_glyph (f, position.x, position.y, &last_mouse_glyph);
1732 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1734 if (bar_window) *bar_window = Qnil;
1735 if (part) *part = 0; /*scroll_bar_handle; */
1737 if (x) XSETINT (*x, lrint (position.x));
1738 if (y) XSETINT (*y, lrint (position.y));
1739 if (time) *time = last_mouse_movement_time;
1749 ns_frame_up_to_date (struct frame *f)
1750 /* --------------------------------------------------------------------------
1751 External (hook): Fix up mouse highlighting right after a full update.
1752 Some highlighting was deferred if GC was happening during
1753 note_mouse_highlight (), while other highlighting was deferred for update.
1754 -------------------------------------------------------------------------- */
1756 NSTRACE (ns_frame_up_to_date);
1760 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1761 if ((dpyinfo->mouse_face_deferred_gc||f ==dpyinfo->mouse_face_mouse_frame)
1762 /*&& dpyinfo->mouse_face_mouse_frame*/)
1766 if (dpyinfo->mouse_face_mouse_frame)
1767 note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
1768 dpyinfo->mouse_face_mouse_x,
1769 dpyinfo->mouse_face_mouse_y);
1770 dpyinfo->mouse_face_deferred_gc = 0;
1779 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1780 /* --------------------------------------------------------------------------
1781 External (RIF): set frame mouse pointer type.
1782 -------------------------------------------------------------------------- */
1784 NSTRACE (ns_define_frame_cursor);
1785 if (FRAME_POINTER_TYPE (f) != cursor)
1787 EmacsView *view = FRAME_NS_VIEW (f);
1788 FRAME_POINTER_TYPE (f) = cursor;
1789 [[view window] invalidateCursorRectsForView: view];
1795 /* ==========================================================================
1799 ========================================================================== */
1803 ns_convert_key (unsigned code)
1804 /* --------------------------------------------------------------------------
1805 Internal call used by NSView-keyDown.
1806 -------------------------------------------------------------------------- */
1808 const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
1809 / sizeof (convert_ns_to_X_keysym[0]));
1811 /* An array would be faster, but less easy to read. */
1812 for (keysym = 0; keysym < last_keysym; keysym += 2)
1813 if (code == convert_ns_to_X_keysym[keysym])
1814 return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
1816 /* if decide to use keyCode and Carbon table, use this line:
1817 return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
1822 x_get_keysym_name (int keysym)
1823 /* --------------------------------------------------------------------------
1824 Called by keyboard.c. Not sure if the return val is important, except
1826 -------------------------------------------------------------------------- */
1828 static char value[16];
1829 NSTRACE (x_get_keysym_name);
1830 sprintf (value, "%d", keysym);
1836 /* ==========================================================================
1838 Block drawing operations
1840 ========================================================================== */
1844 ns_redraw_scroll_bars (struct frame *f)
1848 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
1849 NSTRACE (ns_judge_scroll_bars);
1850 for (i =[subviews count]-1; i >= 0; i--)
1852 view = [subviews objectAtIndex: i];
1853 if (![view isKindOfClass: [EmacsScroller class]]) continue;
1860 ns_clear_frame (struct frame *f)
1861 /* --------------------------------------------------------------------------
1862 External (hook): Erase the entire frame
1863 -------------------------------------------------------------------------- */
1865 NSView *view = FRAME_NS_VIEW (f);
1868 NSTRACE (ns_clear_frame);
1872 /* comes on initial frame because we have
1873 after-make-frame-functions = select-frame */
1874 if (!FRAME_DEFAULT_FACE (f))
1877 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
1879 output_cursor.hpos = output_cursor.vpos = 0;
1880 output_cursor.x = -1;
1885 ns_focus (f, &r, 1);
1886 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
1890 #ifdef NS_IMPL_COCOA
1891 [[view window] display]; /* redraw resize handle */
1894 /* as of 2006/11 or so this is now needed */
1895 ns_redraw_scroll_bars (f);
1901 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
1902 /* --------------------------------------------------------------------------
1903 External (RIF): Clear section of frame
1904 -------------------------------------------------------------------------- */
1906 NSRect r = NSMakeRect (x, y, width, height);
1907 NSView *view = FRAME_NS_VIEW (f);
1908 struct face *face = FRAME_DEFAULT_FACE (f);
1913 NSTRACE (ns_clear_frame_area);
1915 r = NSIntersectionRect (r, [view frame]);
1916 ns_focus (f, &r, 1);
1917 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
1919 #ifdef NS_IMPL_COCOA
1921 /* clip out the resize handle */
1922 NSWindow *window = [FRAME_NS_VIEW (f) window];
1924 = [view convertRect: ns_resize_handle_rect (window) fromView: nil];
1926 ir = NSIntersectionRect (r, ir);
1927 if (NSIsEmptyRect (ir))
1933 #ifdef NS_IMPL_COCOA
1937 NSRect r1 = r, r2 = r; /* upper and lower non-intersecting */
1938 r1.size.height -= ir.size.height;
1939 r2.origin.y += r1.size.height;
1940 r2.size.width -= ir.size.width;
1941 r2.size.height = ir.size.height;
1954 ns_scroll_run (struct window *w, struct run *run)
1955 /* --------------------------------------------------------------------------
1956 External (RIF): Insert or delete n lines at line vpos
1957 -------------------------------------------------------------------------- */
1959 struct frame *f = XFRAME (w->frame);
1960 int x, y, width, height, from_y, to_y, bottom_y;
1962 NSTRACE (ns_scroll_run);
1964 /* begin copy from other terms */
1965 /* Get frame-relative bounding box of the text display area of W,
1966 without mode lines. Include in this box the left and right
1968 window_box (w, -1, &x, &y, &width, &height);
1970 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
1971 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
1972 bottom_y = y + height;
1976 /* Scrolling up. Make sure we don't copy part of the mode
1977 line at the bottom. */
1978 if (from_y + run->height > bottom_y)
1979 height = bottom_y - from_y;
1981 height = run->height;
1985 /* Scolling down. Make sure we don't copy over the mode line.
1987 if (to_y + run->height > bottom_y)
1988 height = bottom_y - to_y;
1990 height = run->height;
1992 /* end copy from other terms */
2003 NSRect srcRect = NSMakeRect (x, from_y, width, height);
2004 NSRect dstRect = NSMakeRect (x, to_y, width, height);
2005 NSPoint dstOrigin = NSMakePoint (x, to_y);
2007 ns_focus (f, &dstRect, 1);
2008 NSCopyBits (0, srcRect , dstOrigin);
2017 ns_after_update_window_line (struct glyph_row *desired_row)
2018 /* --------------------------------------------------------------------------
2019 External (RIF): preparatory to fringe update after text was updated
2020 -------------------------------------------------------------------------- */
2022 struct window *w = updated_window;
2026 NSTRACE (ns_after_update_window_line);
2028 /* begin copy from other terms */
2031 if (!desired_row->mode_line_p && !w->pseudo_window_p)
2032 desired_row->redraw_fringe_bitmaps_p = 1;
2034 /* When a window has disappeared, make sure that no rest of
2035 full-width rows stays visible in the internal border.
2036 Under NS this is drawn inside the fringes. */
2037 if (windows_or_buffers_changed
2038 && (f = XFRAME (w->frame),
2039 width = FRAME_INTERNAL_BORDER_WIDTH (f),
2041 && (height = desired_row->visible_height,
2044 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2046 /* Internal border is drawn below the tool bar. */
2047 if (WINDOWP (f->tool_bar_window)
2048 && w == XWINDOW (f->tool_bar_window))
2050 /* end copy from other terms */
2053 if (!desired_row->full_width_p)
2055 int x1 = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
2056 + WINDOW_LEFT_FRINGE_WIDTH (w);
2057 int x2 = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
2058 + FRAME_PIXEL_WIDTH (f) - NS_SCROLL_BAR_WIDTH (f)
2059 - WINDOW_RIGHT_FRINGE_WIDTH (w)
2060 - FRAME_INTERNAL_BORDER_WIDTH (f);
2061 ns_clear_frame_area (f, x1, y, width, height);
2062 ns_clear_frame_area (f, x2, y, width, height);
2070 ns_shift_glyphs_for_insert (struct frame *f,
2071 int x, int y, int width, int height,
2073 /* --------------------------------------------------------------------------
2074 External (RIF): copy an area horizontally, don't worry about clearing src
2075 -------------------------------------------------------------------------- */
2077 NSRect srcRect = NSMakeRect (x, y, width, height);
2078 NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2079 NSPoint dstOrigin = dstRect.origin;
2081 NSTRACE (ns_shift_glyphs_for_insert);
2083 ns_focus (f, &dstRect, 1);
2084 NSCopyBits (0, srcRect, dstOrigin);
2090 /* ==========================================================================
2092 Character encoding and metrics
2094 ========================================================================== */
2098 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2099 /* --------------------------------------------------------------------------
2100 External (RIF); compute left/right overhang of whole string and set in s
2101 -------------------------------------------------------------------------- */
2103 struct face *face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2104 struct font *font = s->font; /*face->font; */
2108 struct font_metrics metrics;
2109 unsigned int codes[2];
2110 codes[0] = *(s->char2b);
2111 codes[1] = *(s->char2b + s->nchars - 1);
2113 font->driver->text_extents (font, codes, 2, &metrics);
2114 s->left_overhang = -metrics.lbearing;
2116 = metrics.rbearing > metrics.width
2117 ? metrics.rbearing - metrics.width : 0;
2121 s->left_overhang = 0;
2122 s->right_overhang = ((struct nsfont_info *)font)->ital ?
2123 FONT_HEIGHT (font) * 0.2 : 0;
2129 /* ==========================================================================
2131 Fringe and cursor drawing
2133 ========================================================================== */
2136 extern int max_used_fringe_bitmap;
2138 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2139 struct draw_fringe_bitmap_params *p)
2140 /* --------------------------------------------------------------------------
2141 External (RIF); fringe-related
2142 -------------------------------------------------------------------------- */
2144 struct frame *f = XFRAME (WINDOW_FRAME (w));
2145 struct face *face = p->face;
2147 static EmacsImage **bimgs = NULL;
2148 static int nBimgs = 0;
2149 /* NS-specific: move internal border inside fringe */
2150 int x = p->bx < 0 ? p->x : p->bx;
2151 int wd = p->bx < 0 ? p->wd : p->nx;
2152 BOOL fringeOnVeryLeft
2153 = x - WINDOW_LEFT_SCROLL_BAR_COLS (w) * WINDOW_FRAME_COLUMN_WIDTH (w)
2154 - FRAME_INTERNAL_BORDER_WIDTH (f) < 10;
2155 BOOL fringeOnVeryRight
2156 = FRAME_PIXEL_WIDTH (f) - x - wd - FRAME_INTERNAL_BORDER_WIDTH (f)
2157 - WINDOW_RIGHT_SCROLL_BAR_COLS (w) * WINDOW_FRAME_COLUMN_WIDTH (w) < 10;
2158 int xAdjust = FRAME_INTERNAL_BORDER_WIDTH (f) *
2159 (fringeOnVeryLeft ? -1 : (fringeOnVeryRight ? 1 : 0));
2161 /* grow bimgs if needed */
2162 if (nBimgs < max_used_fringe_bitmap)
2164 EmacsImage **newBimgs
2165 = xmalloc (max_used_fringe_bitmap * sizeof (EmacsImage *));
2166 memset (newBimgs, 0, max_used_fringe_bitmap * sizeof (EmacsImage *));
2170 memcpy (newBimgs, bimgs, nBimgs * sizeof (EmacsImage *));
2175 nBimgs = max_used_fringe_bitmap;
2178 /* Must clip because of partially visible lines. */
2179 rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
2180 ns_clip_to_row (w, row, -1, YES);
2182 if (p->bx >= 0 && !p->overlay_p)
2184 int yAdjust = rowY - FRAME_INTERNAL_BORDER_WIDTH (f) < 5 ?
2185 -FRAME_INTERNAL_BORDER_WIDTH (f) : 0;
2186 int yIncr = FRAME_PIXEL_HEIGHT (f) - (p->by+yAdjust + p->ny) < 5 ?
2187 FRAME_INTERNAL_BORDER_WIDTH (f) : 0;
2189 yIncr += FRAME_INTERNAL_BORDER_WIDTH (f);
2190 NSRect r = NSMakeRect (p->bx+xAdjust, p->by+yAdjust, p->nx, p->ny+yIncr);
2192 [ns_lookup_indexed_color(face->background, f) set];
2198 NSRect r = NSMakeRect (p->x+xAdjust, p->y, p->wd, p->h);
2199 NSPoint pt = r.origin;
2200 EmacsImage *img = bimgs[p->which - 1];
2204 unsigned short *bits = p->bits + p->dh;
2205 int len = 8 * p->h/8;
2207 unsigned char *cbits = xmalloc (len);
2209 for (i =0; i<len; i++)
2210 cbits[i] = ~(bits[i] & 0xff);
2211 img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2213 bimgs[p->which - 1] = img;
2218 /* Since we composite the bitmap instead of just blitting it, we need
2219 to erase the whole background. */
2220 [ns_lookup_indexed_color(face->background, f) set];
2223 [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2224 [img compositeToPoint: pt operation: NSCompositeSourceOver];
2231 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2232 int x, int y, int cursor_type, int cursor_width,
2233 int on_p, int active_p)
2234 /* --------------------------------------------------------------------------
2235 External call (RIF): draw cursor
2236 (modeled after x_draw_window_cursor
2237 FIXME: cursor_width is effectively bogus -- it sometimes gets set
2238 in xdisp.c set_frame_cursor_types, sometimes left uninitialized;
2239 DON'T USE IT (no other terms do)
2240 -------------------------------------------------------------------------- */
2244 struct frame *f = WINDOW_XFRAME (w);
2245 struct glyph *phys_cursor_glyph;
2248 NSTRACE (dumpcursor);
2249 //fprintf(stderr, "drawcursor (%d,%d) activep = %d\tonp = %d\tc_type = %d\twidth = %d\n",x,y, active_p,on_p,cursor_type,cursor_width);
2254 w->phys_cursor_type = cursor_type;
2255 w->phys_cursor_on_p = on_p;
2257 if (cursor_type == NO_CURSOR)
2259 w->phys_cursor_width = 0;
2263 if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2265 if (glyph_row->exact_window_width_line_p
2266 && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2268 glyph_row->cursor_in_fringe_p = 1;
2269 draw_fringe_bitmap (w, glyph_row, 0);
2274 get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2276 r.origin.x = fx, r.origin.y = fy;
2278 r.size.width = w->phys_cursor_width;
2280 /* FIXME: if we overwrite the internal border area, it does not get erased;
2281 fix by truncating cursor, but better would be to erase properly */
2282 overspill = r.origin.x + r.size.width -
2283 WINDOW_TEXT_TO_FRAME_PIXEL_X (w, WINDOW_BOX_RIGHT_EDGE_X (w)
2284 - WINDOW_TOTAL_FRINGE_WIDTH (w) - FRAME_INTERNAL_BORDER_WIDTH (f));
2286 r.size.width -= overspill;
2288 /* TODO: only needed in rare cases with last-resort font in HELLO..
2289 should we do this more efficiently? */
2290 ns_clip_to_row (w, glyph_row, -1, NO); /* do ns_focus(f, &r, 1); if remove */
2291 [FRAME_CURSOR_COLOR (f) set];
2293 #ifdef NS_IMPL_COCOA
2294 /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2295 atomic. Cleaner ways of doing this should be investigated.
2296 One way would be to set a global variable DRAWING_CURSOR
2297 when making the call to draw_phys..(), don't focus in that
2298 case, then move the ns_unfocus() here after that call. */
2299 NSDisableScreenUpdates ();
2302 switch (cursor_type)
2306 case FILLED_BOX_CURSOR:
2309 case HOLLOW_BOX_CURSOR:
2311 [FRAME_BACKGROUND_COLOR (f) set];
2312 NSRectFill (NSInsetRect (r, 1, 1));
2313 [FRAME_CURSOR_COLOR (f) set];
2317 s.origin.y += lrint (0.75 * s.size.height);
2318 s.size.height = lrint (s.size.height * 0.25);
2323 s.size.width = min (cursor_width, 2); //FIXME(see above)
2329 /* draw the character under the cursor */
2330 if (cursor_type != NO_CURSOR)
2331 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2333 #ifdef NS_IMPL_COCOA
2334 NSEnableScreenUpdates ();
2341 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2342 /* --------------------------------------------------------------------------
2343 External (RIF): Draw a vertical line.
2344 -------------------------------------------------------------------------- */
2346 struct frame *f = XFRAME (WINDOW_FRAME (w));
2348 NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2350 NSTRACE (ns_draw_vertical_window_border);
2352 face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2354 [ns_lookup_indexed_color(face->foreground, f) set];
2356 ns_focus (f, &r, 1);
2363 show_hourglass (struct atimer *timer)
2365 if (hourglass_shown_p)
2370 /* TODO: add NSProgressIndicator to selected frame (see macfns.c) */
2372 hourglass_shown_p = 1;
2380 if (!hourglass_shown_p)
2385 /* TODO: remove NSProgressIndicator from all frames */
2387 hourglass_shown_p = 0;
2393 /* ==========================================================================
2395 Glyph drawing operations
2397 ========================================================================== */
2400 static inline NSRect
2401 ns_fix_rect_ibw (NSRect r, int fibw, int frame_pixel_width)
2402 /* --------------------------------------------------------------------------
2403 Under NS we draw internal borders inside fringes, and want full-width
2404 rendering to go all the way to edge. This function makes that correction.
2405 -------------------------------------------------------------------------- */
2407 if (r.origin.y <= fibw+1)
2409 r.size.height += r.origin.y;
2412 if (r.origin.x <= fibw+1)
2414 r.size.width += r.origin.x;
2417 if (frame_pixel_width - (r.origin.x+r.size.width) <= fibw+1)
2418 r.size.width += fibw;
2425 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2426 /* --------------------------------------------------------------------------
2427 Wrapper utility to account for internal border width on full-width lines,
2428 and allow top full-width rows to hit the frame top. nr should be pointer
2429 to two successive NSRects. Number of rects actually used is returned.
2430 -------------------------------------------------------------------------- */
2432 int n = get_glyph_string_clip_rects (s, nr, 2);
2433 if (s->row->full_width_p)
2435 *nr = ns_fix_rect_ibw (*nr, FRAME_INTERNAL_BORDER_WIDTH (s->f),
2436 FRAME_PIXEL_WIDTH (s->f));
2438 *nr = ns_fix_rect_ibw (*(nr+1), FRAME_INTERNAL_BORDER_WIDTH (s->f),
2439 FRAME_PIXEL_WIDTH (s->f));
2446 ns_draw_box (NSRect r, float thickness, NSColor *col, char left_p, char right_p)
2447 /* --------------------------------------------------------------------------
2448 Draw an unfilled rect inside r, optionally leaving left and/or right open.
2449 Note we can't just use an NSDrawRect command, because of the possibility
2450 of some sides not being drawn, and because the rect will be filled.
2451 -------------------------------------------------------------------------- */
2457 s.size.height = thickness;
2459 s.origin.y += r.size.height - thickness;
2462 s.size.height = r.size.height;
2463 s.origin.y = r.origin.y;
2465 /* left, right (optional) */
2466 s.size.width = thickness;
2471 s.origin.x += r.size.width - thickness;
2478 ns_draw_relief (NSRect r, int thickness, char raised_p,
2479 char top_p, char bottom_p, char left_p, char right_p,
2480 struct glyph_string *s)
2481 /* --------------------------------------------------------------------------
2482 Draw a relief rect inside r, optionally leaving some sides open.
2483 Note we can't just use an NSDrawBezel command, because of the possibility
2484 of some sides not being drawn, and because the rect will be filled.
2485 -------------------------------------------------------------------------- */
2487 static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2488 NSColor *newBaseCol = nil;
2491 NSTRACE (ns_draw_relief);
2495 if (s->face->use_box_color_for_shadows_p)
2497 newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2499 /* else if (s->first_glyph->type == IMAGE_GLYPH
2501 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2503 newBaseCol = IMAGE_BACKGROUND (s->img, s->f, 0);
2507 newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2510 if (newBaseCol == nil)
2511 newBaseCol = [NSColor grayColor];
2513 if (newBaseCol != baseCol) /* TODO: better check */
2516 baseCol = [newBaseCol retain];
2518 lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2520 darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2523 [(raised_p ? lightCol : darkCol) set];
2525 /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2528 sr.size.height = thickness;
2529 if (top_p) NSRectFill (sr);
2532 sr.size.height = r.size.height;
2533 sr.size.width = thickness;
2534 if (left_p) NSRectFill (sr);
2536 [(raised_p ? darkCol : lightCol) set];
2539 sr.size.width = r.size.width;
2540 sr.size.height = thickness;
2541 sr.origin.y += r.size.height - thickness;
2542 if (bottom_p) NSRectFill (sr);
2545 sr.size.height = r.size.height;
2546 sr.origin.y = r.origin.y;
2547 sr.size.width = thickness;
2548 sr.origin.x += r.size.width - thickness;
2549 if (right_p) NSRectFill (sr);
2554 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2555 /* --------------------------------------------------------------------------
2556 Function modeled after x_draw_glyph_string_box ().
2557 Sets up parameters for drawing.
2558 -------------------------------------------------------------------------- */
2560 int right_x, last_x;
2561 char left_p, right_p;
2562 struct glyph *last_glyph;
2567 if (s->hl == DRAW_MOUSE_FACE)
2570 (s->f, FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
2572 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2577 thickness = face->box_line_width;
2579 NSTRACE (ns_dumpglyphs_box_or_relief);
2581 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2582 ? WINDOW_RIGHT_EDGE_X (s->w)
2583 : window_box_right (s->w, s->area));
2584 last_glyph = (s->cmp || s->img
2585 ? s->first_glyph : s->first_glyph + s->nchars-1);
2587 right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2588 ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2590 left_p = (s->first_glyph->left_box_line_p
2591 || (s->hl == DRAW_MOUSE_FACE
2592 && (s->prev == NULL || s->prev->hl != s->hl)));
2593 right_p = (last_glyph->right_box_line_p
2594 || (s->hl == DRAW_MOUSE_FACE
2595 && (s->next == NULL || s->next->hl != s->hl)));
2597 r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2599 /* expand full-width row over internal borders */
2600 if (s->row->full_width_p)
2601 r = ns_fix_rect_ibw (r, FRAME_INTERNAL_BORDER_WIDTH (s->f),
2602 FRAME_PIXEL_WIDTH (s->f));
2604 /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2605 if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2607 ns_draw_box (r, abs (thickness),
2608 ns_lookup_indexed_color (face->box_color, s->f),
2613 ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2614 1, 1, left_p, right_p, s);
2620 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2621 /* --------------------------------------------------------------------------
2622 Modeled after x_draw_glyph_string_background, which draws BG in
2623 certain cases. Others are left to the text rendering routine.
2624 -------------------------------------------------------------------------- */
2626 NSTRACE (ns_maybe_dumpglyphs_background);
2628 if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2630 int box_line_width = max (s->face->box_line_width, 0);
2631 if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2632 || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2635 if (s->hl == DRAW_MOUSE_FACE)
2638 (s->f, FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
2640 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2643 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2645 [(NS_FACE_BACKGROUND (face) != 0
2646 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2647 : FRAME_BACKGROUND_COLOR (s->f)) set];
2650 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
2651 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2654 if (s->hl != DRAW_CURSOR)
2656 NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2657 s->background_width,
2658 s->height-2*box_line_width);
2660 /* expand full-width row over internal borders */
2661 if (s->row->full_width_p)
2663 int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
2664 if (r.origin.y <= fibw+1 + box_line_width)
2666 r.size.height += r.origin.y;
2669 if (r.origin.x <= fibw+1)
2671 r.size.width += 2*r.origin.x;
2674 if (FRAME_PIXEL_WIDTH (s->f) - (r.origin.x + r.size.width)
2676 r.size.width += fibw;
2682 s->background_filled_p = 1;
2689 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2690 /* --------------------------------------------------------------------------
2691 Renders an image and associated borders.
2692 -------------------------------------------------------------------------- */
2694 EmacsImage *img = s->img->pixmap;
2695 int box_line_vwidth = max (s->face->box_line_width, 0);
2696 int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2697 int bg_x, bg_y, bg_height;
2703 NSTRACE (ns_dumpglyphs_image);
2705 if (s->face->box != FACE_NO_BOX
2706 && s->first_glyph->left_box_line_p && s->slice.x == 0)
2707 x += abs (s->face->box_line_width);
2710 bg_y = s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2711 bg_height = s->height;
2712 /* other terms have this, but was causing problems w/tabbar mode */
2713 /* - 2 * box_line_vwidth; */
2715 if (s->slice.x == 0) x += s->img->hmargin;
2716 if (s->slice.y == 0) y += s->img->vmargin;
2718 /* Draw BG: if we need larger area than image itself cleared, do that,
2719 otherwise, since we composite the image under NS (instead of mucking
2720 with its background color), we must clear just the image area. */
2721 if (s->hl == DRAW_MOUSE_FACE)
2724 (s->f, FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
2726 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2729 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2731 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
2733 if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
2734 || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
2736 br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
2737 s->background_filled_p = 1;
2741 br = NSMakeRect (x, y, s->slice.width, s->slice.height);
2744 /* expand full-width row over internal borders */
2745 if (s->row->full_width_p)
2747 int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
2748 if (br.origin.y <= fibw+1 + box_line_vwidth)
2750 br.size.height += br.origin.y;
2753 if (br.origin.x <= fibw+1 + box_line_vwidth)
2755 br.size.width += br.origin.x;
2758 if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width) <= fibw+1)
2759 br.size.width += fibw;
2764 /* Draw the image.. do we need to draw placeholder if img ==nil? */
2766 [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
2767 operation: NSCompositeSourceOver];
2769 /* Draw relief, if requested */
2770 if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
2772 if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
2774 th = tool_bar_button_relief >= 0 ?
2775 tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
2776 raised_p = (s->hl == DRAW_IMAGE_RAISED);
2780 th = abs (s->img->relief);
2781 raised_p = (s->img->relief > 0);
2784 r.origin.x = x - th;
2785 r.origin.y = y - th;
2786 r.size.width = s->slice.width + 2*th-1;
2787 r.size.height = s->slice.height + 2*th-1;
2788 ns_draw_relief (r, th, raised_p,
2790 s->slice.y + s->slice.height == s->img->height,
2792 s->slice.x + s->slice.width == s->img->width, s);
2798 ns_dumpglyphs_stretch (struct glyph_string *s)
2804 if (!s->background_filled_p)
2806 n = ns_get_glyph_string_clip_rect (s, r);
2807 *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
2811 if (!s->row->full_width_p)
2813 /* truncate to avoid overwriting fringe and/or scrollbar */
2814 int overrun = max (0, (s->x + s->background_width)
2815 - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
2816 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
2817 r[i].size.width -= overrun;
2819 /* XXX: Try to work between problem where a stretch glyph on
2820 a partially-visible bottom row will clear part of the
2821 modeline, and another where list-buffers headers and similar
2822 rows erroneously have visible_height set to 0. Not sure
2823 where this is coming from as other terms seem not to show. */
2824 r[i].size.height = min (s->height, s->row->visible_height);
2827 /* expand full-width rows over internal borders */
2830 r[i] = ns_fix_rect_ibw (r[i], FRAME_INTERNAL_BORDER_WIDTH (s->f),
2831 FRAME_PIXEL_WIDTH (s->f));
2834 /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
2835 overwriting cursor (usually when cursor on a tab) */
2836 if (s->hl == DRAW_CURSOR)
2838 r[i].origin.x += s->width;
2839 r[i].size.width -= s->width;
2843 ns_focus (s->f, r, n);
2845 if (s->hl == DRAW_MOUSE_FACE)
2848 (s->f, FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
2850 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2853 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2855 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
2860 s->background_filled_p = 1;
2866 ns_draw_glyph_string (struct glyph_string *s)
2867 /* --------------------------------------------------------------------------
2868 External (RIF): Main draw-text call.
2869 -------------------------------------------------------------------------- */
2871 /* TODO (optimize): focus for box and contents draw */
2874 char box_drawn_p = 0;
2876 NSTRACE (ns_draw_glyph_string);
2878 if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
2881 struct glyph_string *next;
2883 for (width = 0, next = s->next;
2884 next && width < s->right_overhang;
2885 width += next->width, next = next->next)
2886 if (next->first_glyph->type != IMAGE_GLYPH)
2888 if (next->first_glyph->type != STRETCH_GLYPH)
2890 n = ns_get_glyph_string_clip_rect (s->next, r);
2891 ns_focus (s->f, r, n);
2892 ns_maybe_dumpglyphs_background (s->next, 1);
2897 ns_dumpglyphs_stretch (s->next);
2899 next->num_clips = 0;
2903 if (!s->for_overlaps && s->face->box != FACE_NO_BOX
2904 && (s->first_glyph->type == CHAR_GLYPH
2905 || s->first_glyph->type == COMPOSITE_GLYPH))
2907 n = ns_get_glyph_string_clip_rect (s, r);
2908 ns_focus (s->f, r, n);
2909 ns_maybe_dumpglyphs_background (s, 1);
2910 ns_dumpglyphs_box_or_relief (s);
2915 switch (s->first_glyph->type)
2919 n = ns_get_glyph_string_clip_rect (s, r);
2920 ns_focus (s->f, r, n);
2921 ns_dumpglyphs_image (s, r[0]);
2926 ns_dumpglyphs_stretch (s);
2930 case COMPOSITE_GLYPH:
2931 n = ns_get_glyph_string_clip_rect (s, r);
2932 ns_focus (s->f, r, n);
2934 if (s->for_overlaps || (s->cmp_from > 0
2935 && ! s->first_glyph->u.cmp.automatic))
2936 s->background_filled_p = 1;
2938 ns_maybe_dumpglyphs_background
2939 (s, s->first_glyph->type == COMPOSITE_GLYPH);
2941 ns_tmp_flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
2942 (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
2943 (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
2944 NS_DUMPGLYPH_NORMAL));
2945 ns_tmp_font = (struct nsfont_info *)s->face->font;
2946 if (ns_tmp_font == NULL)
2947 ns_tmp_font = (struct nsfont_info *)FRAME_FONT (s->f);
2949 ns_tmp_font->font.driver->draw
2950 (s, 0, s->nchars, s->x, s->y,
2951 (ns_tmp_flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
2952 || ns_tmp_flags == NS_DUMPGLYPH_MOUSEFACE);
2961 /* Draw box if not done already. */
2962 if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
2964 n = ns_get_glyph_string_clip_rect (s, r);
2965 ns_focus (s->f, r, n);
2966 ns_dumpglyphs_box_or_relief (s);
2975 /* ==========================================================================
2979 ========================================================================== */
2983 ns_send_appdefined (int value)
2984 /* --------------------------------------------------------------------------
2985 Internal: post an appdefined event which EmacsApp-sendEvent will
2986 recognize and take as a command to halt the event loop.
2987 -------------------------------------------------------------------------- */
2989 /*NSTRACE (ns_send_appdefined); */
2991 /* Only post this event if we haven't already posted one. This will end
2992 the [NXApp run] main loop after having processed all events queued at
2994 if (send_appdefined)
2998 /* We only need one NX_APPDEFINED event to stop NXApp from running. */
2999 send_appdefined = NO;
3001 /* Don't need wakeup timer any more */
3004 [timed_entry invalidate];
3005 [timed_entry release];
3009 /* Ditto for file descriptor poller */
3012 [fd_entry invalidate];
3017 nxev = [NSEvent otherEventWithType: NSApplicationDefined
3018 location: NSMakePoint (0, 0)
3021 windowNumber: [[NSApp mainWindow] windowNumber]
3022 context: [NSApp context]
3027 /* Post an application defined event on the event queue. When this is
3028 received the [NXApp run] will return, thus having processed all
3029 events which are currently queued. */
3030 [NSApp postEvent: nxev atStart: NO];
3036 ns_read_socket (struct terminal *terminal, int expected,
3037 struct input_event *hold_quit)
3038 /* --------------------------------------------------------------------------
3039 External (hook): Post an event to ourself and keep reading events until
3040 we read it back again. In effect process all events which were waiting.
3041 From 21+ we have to manage the event buffer ourselves.
3042 -------------------------------------------------------------------------- */
3044 struct input_event ev;
3047 /* NSTRACE (ns_read_socket); */
3049 if (interrupt_input_blocked)
3051 interrupt_input_pending = 1;
3053 pending_signals = 1;
3058 interrupt_input_pending = 0;
3060 pending_signals = pending_atimers;
3064 n_emacs_events_pending = 0;
3067 q_event_ptr = hold_quit;
3069 /* we manage autorelease pools by allocate/reallocate each time around
3070 the loop; strict nesting is occasionally violated but seems not to
3071 matter.. earlier methods using full nesting caused major memory leaks */
3072 [outerpool release];
3073 outerpool = [[NSAutoreleasePool alloc] init];
3075 /* If have pending open-file requests, attend to the next one of those. */
3076 if (ns_pending_files && [ns_pending_files count] != 0
3077 && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3079 [ns_pending_files removeObjectAtIndex: 0];
3081 /* Deal with pending service requests. */
3082 else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3084 NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3085 withArg: [ns_pending_service_args objectAtIndex: 0]])
3087 [ns_pending_service_names removeObjectAtIndex: 0];
3088 [ns_pending_service_args removeObjectAtIndex: 0];
3092 /* Run and wait for events. We must always send one NX_APPDEFINED event
3093 to ourself, otherwise [NXApp run] will never exit. */
3094 send_appdefined = YES;
3096 /* If called via ns_select, this is called once with expected=1,
3097 because we expect either the timeout or file descriptor activity.
3098 In this case the first event through will either be real input or
3099 one of these. read_avail_input() then calls once more with expected=0
3100 and in that case we need to return quickly if there is nothing.
3101 If we're being called outside of that, it's also OK to return quickly
3102 after one iteration through the event loop, since other terms do
3103 this and emacs expects it. */
3104 if (!(inNsSelect && expected))
3106 /* Post an application defined event on the event queue. When this is
3107 received the [NXApp run] will return, thus having processed all
3108 events which are currently queued, if any. */
3109 ns_send_appdefined (-1);
3115 nevents = n_emacs_events_pending;
3116 n_emacs_events_pending = 0;
3117 emacs_event = q_event_ptr = NULL;
3125 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3126 fd_set *exceptfds, struct timeval *timeout)
3127 /* --------------------------------------------------------------------------
3128 Replacement for select, checking for events
3129 -------------------------------------------------------------------------- */
3134 /* NSTRACE (ns_select); */
3136 if (NSApp == nil || inNsSelect == 1 /* || ([NSApp isActive] == NO &&
3137 [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil
3138 inMode:NSDefaultRunLoopMode dequeue:NO] == nil) */)
3139 return select (nfds, readfds, writefds, exceptfds, timeout);
3141 /* Save file descriptor set, which gets overwritten in calls to select ()
3142 Note, this is called from process.c, and only readfds is ever set */
3145 memcpy (&select_readfds, readfds, sizeof (fd_set));
3151 /* Try an initial select for pending data on input files */
3152 select_timeout.tv_sec = select_timeout.tv_usec = 0;
3153 result = select (nfds, readfds, writefds, exceptfds, &select_timeout);
3157 /* if (!timeout || timed_entry || fd_entry)
3158 fprintf (stderr, "assertion failed: timeout null or timed_entry/fd_entry non-null in ns_select\n"); */
3160 /* set a timeout and run the main AppKit event loop while continuing
3161 to monitor the files */
3162 time = ((double) timeout->tv_sec) + ((double) timeout->tv_usec)/1000000.0;
3163 timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3165 selector: @selector (timeout_handler:)
3167 repeats: YES] /* for safe removal */
3170 /* set a periodic task to try the select () again */
3171 fd_entry = [[NSTimer scheduledTimerWithTimeInterval: 0.1
3173 selector: @selector (fd_handler:)
3178 /* Let Application dispatch events until it receives an event of the type
3179 NX_APPDEFINED, which should only be sent by timeout_handler.
3180 We tell read_avail_input() that input is "expected" because we do expect
3181 either the timeout or fd handler to fire, and if they don't, the original
3182 call from process.c that got us here expects us to wait until some input
3186 ev = last_appdefined_event;
3192 if ([ev type] != NSApplicationDefined)
3196 last_appdefined_event = 0;
3200 /* The NX_APPDEFINED event we received was a timeout. */
3205 /* The NX_APPDEFINED event we received was the result of
3206 at least one real input event arriving. */
3212 /* Received back from select () in fd_handler; copy the results */
3214 memcpy (readfds, &select_readfds, sizeof (fd_set));
3218 /* never reached, shut compiler up */
3224 /* ==========================================================================
3228 ========================================================================== */
3232 ns_set_vertical_scroll_bar (struct window *window,
3233 int portion, int whole, int position)
3234 /* --------------------------------------------------------------------------
3235 External (hook): Update or add scrollbar
3236 -------------------------------------------------------------------------- */
3240 struct frame *f = XFRAME (WINDOW_FRAME (window));
3241 EmacsView *view = FRAME_NS_VIEW (f);
3242 int window_y, window_height;
3243 BOOL barOnVeryLeft, barOnVeryRight;
3244 int top, left, height, width, sb_width, sb_left;
3246 static int count = 0;
3248 /* optimization; display engine sends WAY too many of these.. */
3249 if (!NILP (window->vertical_scroll_bar))
3251 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3252 if ([bar checkSamePosition: position portion: portion whole: whole])
3254 if (view->scrollbarsNeedingUpdate == 0)
3256 if (!windows_or_buffers_changed)
3260 view->scrollbarsNeedingUpdate--;
3264 NSTRACE (ns_set_vertical_scroll_bar);
3266 /* Get dimensions. */
3267 window_box (window, -1, 0, &window_y, 0, &window_height);
3269 height = window_height;
3270 width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3271 left = WINDOW_SCROLL_BAR_AREA_X (window);
3273 if (top < 5) /* top scrollbar adjustment */
3275 top -= FRAME_INTERNAL_BORDER_WIDTH (f);
3276 height += FRAME_INTERNAL_BORDER_WIDTH (f);
3279 /* allow for displaying a skinnier scrollbar than char area allotted */
3280 sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3281 WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3283 barOnVeryLeft = left < 5;
3284 barOnVeryRight = FRAME_PIXEL_WIDTH (f) - left - width < 5;
3285 sb_left = left + FRAME_INTERNAL_BORDER_WIDTH (f)
3286 * (barOnVeryLeft ? -1 : (barOnVeryRight ? 1 : 0));
3288 r = NSMakeRect (sb_left, top, sb_width, height);
3289 /* the parent view is flipped, so we need to flip y value */
3291 r.origin.y = (v.size.height - r.size.height - r.origin.y);
3293 XSETWINDOW (win, window);
3296 /* we want at least 5 lines to display a scrollbar */
3297 if (WINDOW_TOTAL_LINES (window) < 5)
3299 if (!NILP (window->vertical_scroll_bar))
3301 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3302 [bar removeFromSuperview];
3303 window->vertical_scroll_bar = Qnil;
3305 ns_clear_frame_area (f, sb_left, top, width, height);
3310 if (NILP (window->vertical_scroll_bar))
3312 ns_clear_frame_area (f, sb_left, top, width, height);
3313 bar = [[EmacsScroller alloc] initFrame: r window: win];
3314 window->vertical_scroll_bar = make_save_value (bar, 0);
3319 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3320 oldRect = [bar frame];
3321 r.size.width = oldRect.size.width;
3322 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3324 if (oldRect.origin.x != r.origin.x)
3325 ns_clear_frame_area (f, sb_left, top, width, height);
3330 [bar setPosition: position portion: portion whole: whole];
3336 ns_condemn_scroll_bars (struct frame *f)
3337 /* --------------------------------------------------------------------------
3338 External (hook): arrange for all frame's scrollbars to be removed
3339 at next call to judge_scroll_bars, except for those redeemed.
3340 -------------------------------------------------------------------------- */
3344 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3346 NSTRACE (ns_condemn_scroll_bars);
3348 for (i =[subviews count]-1; i >= 0; i--)
3350 view = [subviews objectAtIndex: i];
3351 if ([view isKindOfClass: [EmacsScroller class]])
3358 ns_redeem_scroll_bar (struct window *window)
3359 /* --------------------------------------------------------------------------
3360 External (hook): arrange to spare this window's scrollbar
3361 at next call to judge_scroll_bars.
3362 -------------------------------------------------------------------------- */
3365 NSTRACE (ns_redeem_scroll_bar);
3366 if (!NILP (window->vertical_scroll_bar))
3368 bar =XNS_SCROLL_BAR (window->vertical_scroll_bar);
3375 ns_judge_scroll_bars (struct frame *f)
3376 /* --------------------------------------------------------------------------
3377 External (hook): destroy all scrollbars on frame that weren't
3378 redeemed after call to condemn_scroll_bars.
3379 -------------------------------------------------------------------------- */
3383 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3384 NSTRACE (ns_judge_scroll_bars);
3385 for (i =[subviews count]-1; i >= 0; i--)
3387 view = [subviews objectAtIndex: i];
3388 if (![view isKindOfClass: [EmacsScroller class]]) continue;
3395 x_wm_set_icon_position (struct frame *f, int icon_x, int icon_y)
3397 /* XXX irrelevant under NS */
3402 /* ==========================================================================
3406 ========================================================================== */
3409 x_display_pixel_height (dpyinfo)
3410 struct ns_display_info *dpyinfo;
3412 NSScreen *screen = [NSScreen mainScreen];
3413 return [screen frame].size.height;
3417 x_display_pixel_width (dpyinfo)
3418 struct ns_display_info *dpyinfo;
3420 NSScreen *screen = [NSScreen mainScreen];
3421 return [screen frame].size.width;
3425 static Lisp_Object ns_string_to_lispmod (const char *s)
3426 /* --------------------------------------------------------------------------
3427 Convert modifier name to lisp symbol
3428 -------------------------------------------------------------------------- */
3430 if (!strncmp (SDATA (SYMBOL_NAME (Qmeta)), s, 10))
3432 else if (!strncmp (SDATA (SYMBOL_NAME (Qsuper)), s, 10))
3434 else if (!strncmp (SDATA (SYMBOL_NAME (Qcontrol)), s, 10))
3436 else if (!strncmp (SDATA (SYMBOL_NAME (Qalt)), s, 10))
3438 else if (!strncmp (SDATA (SYMBOL_NAME (Qhyper)), s, 10))
3440 else if (!strncmp (SDATA (SYMBOL_NAME (Qnone)), s, 10))
3447 static Lisp_Object ns_mod_to_lisp (int m)
3448 /* --------------------------------------------------------------------------
3449 Convert modifier code (see lisp.h) to lisp symbol
3450 -------------------------------------------------------------------------- */
3454 else if (m == CHAR_SUPER)
3456 else if (m == CHAR_CTL)
3458 else if (m == CHAR_ALT)
3460 else if (m == CHAR_HYPER)
3462 else /* if (m == 0) */
3468 ns_default (const char *parameter, Lisp_Object *result,
3469 Lisp_Object yesval, Lisp_Object noval,
3470 BOOL is_float, BOOL is_modstring)
3471 /* --------------------------------------------------------------------------
3472 Check a parameter value in user's preferences
3473 -------------------------------------------------------------------------- */
3477 if ( (value =[[[NSUserDefaults standardUserDefaults]
3478 stringForKey: [NSString stringWithUTF8String: parameter]]
3483 if (strcasecmp (value, "YES") == 0)
3485 else if (strcasecmp (value, "NO") == 0)
3487 else if (is_float && (f = strtod (value, &pos), pos != value))
3488 *result = make_float (f);
3489 else if (is_modstring && value)
3490 *result = ns_string_to_lispmod (value);
3491 else fprintf (stderr,
3492 "Bad value for default \"%s\": \"%s\"\n", parameter, value);
3498 ns_initialize_display_info (struct ns_display_info *dpyinfo)
3499 /* --------------------------------------------------------------------------
3500 Initialize global info and storage for display.
3501 -------------------------------------------------------------------------- */
3503 NSScreen *screen = [NSScreen mainScreen];
3504 NSWindowDepth depth = [screen depth];
3506 dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
3507 dpyinfo->resy = 72.27;
3508 dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
3509 NSColorSpaceFromDepth (depth)]
3510 && ![NSCalibratedWhiteColorSpace isEqualToString:
3511 NSColorSpaceFromDepth (depth)];
3512 dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
3513 dpyinfo->image_cache = make_image_cache ();
3514 dpyinfo->color_table
3515 = (struct ns_color_table *)xmalloc (sizeof (struct ns_color_table));
3516 dpyinfo->color_table->colors = NULL;
3517 dpyinfo->root_window = 42; /* a placeholder.. */
3519 dpyinfo->mouse_face_mouse_frame = NULL;
3520 dpyinfo->mouse_face_deferred_gc = 0;
3521 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
3522 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
3523 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
3524 dpyinfo->mouse_face_window = dpyinfo->mouse_face_overlay = Qnil;
3525 dpyinfo->mouse_face_hidden = 0;
3527 dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
3528 dpyinfo->mouse_face_defer = 0;
3530 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
3532 dpyinfo->n_fonts = 0;
3533 dpyinfo->smallest_font_height = 1;
3534 dpyinfo->smallest_char_width = 1;
3538 /* This and next define (many of the) public functions in this file. */
3539 /* x_... are generic versions in xdisp.c that we, and other terms, get away
3540 with using despite presence in the "system dependent" redisplay
3541 interface. In addition, many of the ns_ methods have code that is
3542 shared with all terms, indicating need for further refactoring. */
3543 extern frame_parm_handler ns_frame_parm_handlers[];
3544 static struct redisplay_interface ns_redisplay_interface =
3546 ns_frame_parm_handlers,
3550 x_clear_end_of_line,
3552 ns_after_update_window_line,
3553 ns_update_window_begin,
3554 ns_update_window_end,
3557 0, /* flush_display_optional */
3558 x_clear_window_mouse_face,
3559 x_get_glyph_overhangs,
3560 x_fix_overlapping_area,
3561 ns_draw_fringe_bitmap,
3562 0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
3563 0, /* destroy_fringe_bitmap */
3564 ns_compute_glyph_string_overhangs,
3565 ns_draw_glyph_string, /* interface to nsfont.m */
3566 ns_define_frame_cursor,
3567 ns_clear_frame_area,
3568 ns_draw_window_cursor,
3569 ns_draw_vertical_window_border,
3570 ns_shift_glyphs_for_insert
3575 ns_delete_display (struct ns_display_info *dpyinfo)
3581 /* This function is called when the last frame on a display is deleted. */
3583 ns_delete_terminal (struct terminal *terminal)
3585 struct ns_display_info *dpyinfo = terminal->display_info.ns;
3588 /* Protect against recursive calls. delete_frame in
3589 delete_terminal calls us back when it deletes our last frame. */
3590 if (!terminal->name)
3595 x_destroy_all_bitmaps (dpyinfo);
3596 ns_delete_display (dpyinfo);
3601 static struct terminal *
3602 ns_create_terminal (struct ns_display_info *dpyinfo)
3603 /* --------------------------------------------------------------------------
3604 Set up use of NS before we make the first connection.
3605 -------------------------------------------------------------------------- */
3607 struct terminal *terminal;
3609 NSTRACE (ns_create_terminal);
3611 terminal = create_terminal ();
3613 terminal->type = output_ns;
3614 terminal->display_info.ns = dpyinfo;
3615 dpyinfo->terminal = terminal;
3617 terminal->rif = &ns_redisplay_interface;
3619 terminal->clear_frame_hook = ns_clear_frame;
3620 terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
3621 terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
3622 terminal->ring_bell_hook = ns_ring_bell;
3623 terminal->reset_terminal_modes_hook = ns_reset_terminal_modes;
3624 terminal->set_terminal_modes_hook = ns_set_terminal_modes;
3625 terminal->update_begin_hook = ns_update_begin;
3626 terminal->update_end_hook = ns_update_end;
3627 terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
3628 terminal->read_socket_hook = ns_read_socket;
3629 terminal->frame_up_to_date_hook = ns_frame_up_to_date;
3630 terminal->mouse_position_hook = ns_mouse_position;
3631 terminal->frame_rehighlight_hook = ns_frame_rehighlight;
3632 terminal->frame_raise_lower_hook = ns_frame_raise_lower;
3634 terminal->fullscreen_hook = 0; /* see XTfullscreen_hook */
3636 terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
3637 terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
3638 terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
3639 terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
3641 terminal->delete_frame_hook = x_destroy_window;
3642 terminal->delete_terminal_hook = ns_delete_terminal;
3644 terminal->scroll_region_ok = 1;
3645 terminal->char_ins_del_ok = 1;
3646 terminal->line_ins_del_ok = 1;
3647 terminal->fast_clear_end_of_line = 1;
3648 terminal->memory_below_frame = 0;
3654 struct ns_display_info *
3655 ns_term_init (Lisp_Object display_name)
3656 /* --------------------------------------------------------------------------
3657 Start the Application and get things rolling.
3658 -------------------------------------------------------------------------- */
3660 struct terminal *terminal;
3661 struct ns_display_info *dpyinfo;
3662 static int ns_initialized = 0;
3665 NSTRACE (ns_term_init);
3667 /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
3668 /*GSDebugAllocationActive (YES); */
3670 handling_signal = 0;
3672 if (!ns_initialized)
3675 Fset_input_interrupt_mode (Qnil);
3679 ns_pending_files = [[NSMutableArray alloc] init];
3680 ns_pending_service_names = [[NSMutableArray alloc] init];
3681 ns_pending_service_args = [[NSMutableArray alloc] init];
3683 /* Start app and create the main menu, window, view.
3684 Needs to be here because ns_initialize_display_info () uses AppKit classes.
3685 The view will then ask the NSApp to stop and return to Emacs. */
3686 [EmacsApp sharedApplication];
3689 [NSApp setDelegate: NSApp];
3691 /* debugging: log all notifications */
3692 /* [[NSNotificationCenter defaultCenter] addObserver: NSApp
3693 selector: @selector (logNotification:)
3694 name: nil object: nil]; */
3696 dpyinfo = (struct ns_display_info *)xmalloc (sizeof (struct ns_display_info));
3697 memset (dpyinfo, 0, sizeof (struct ns_display_info));
3699 ns_initialize_display_info (dpyinfo);
3700 terminal = ns_create_terminal (dpyinfo);
3702 terminal->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
3703 init_kboard (terminal->kboard);
3704 terminal->kboard->Vwindow_system = Qns;
3705 terminal->kboard->next_kboard = all_kboards;
3706 all_kboards = terminal->kboard;
3707 /* Don't let the initial kboard remain current longer than necessary.
3708 That would cause problems if a file loaded on startup tries to
3709 prompt in the mini-buffer. */
3710 if (current_kboard == initial_kboard)
3711 current_kboard = terminal->kboard;
3712 terminal->kboard->reference_count++;
3714 dpyinfo->next = x_display_list;
3715 x_display_list = dpyinfo;
3717 /* Put it on ns_display_name_list */
3718 ns_display_name_list = Fcons (Fcons (display_name, Qnil),
3719 ns_display_name_list);
3720 dpyinfo->name_list_element = XCAR (ns_display_name_list);
3722 /* Set the name of the terminal. */
3723 terminal->name = (char *) xmalloc (SBYTES (display_name) + 1);
3724 strncpy (terminal->name, SDATA (display_name), SBYTES (display_name));
3725 terminal->name[SBYTES (display_name)] = 0;
3729 if (!inhibit_x_resources)
3731 ns_default ("GSFontAntiAlias", &ns_antialias_text,
3734 /* this is a standard variable */
3735 ns_default ("AppleAntiAliasingThreshold", &tmp,
3736 make_float (10.0), make_float (6.0), YES, NO);
3737 ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
3740 ns_selection_color = [[NSUserDefaults standardUserDefaults]
3741 stringForKey: @"AppleHighlightColor"];
3742 if (ns_selection_color == nil)
3743 ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
3746 NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
3750 Lisp_Object color_file, color_map, color;
3755 color_file = Fexpand_file_name (build_string ("rgb.txt"),
3756 Fsymbol_value (intern ("data-directory")));
3757 if (NILP (Ffile_readable_p (color_file)))
3758 fatal ("Could not find %s.\n", SDATA (color_file));
3760 color_map = Fx_load_color_file (color_file);
3761 if (NILP (color_map))
3762 fatal ("Could not read %s.\n", SDATA (color_file));
3764 cl = [[NSColorList alloc] initWithName: @"Emacs"];
3765 for ( ; CONSP (color_map); color_map = XCDR (color_map))
3767 color = XCAR (color_map);
3768 name = SDATA (XCAR (color));
3769 c = XINT (XCDR (color));
3771 [NSColor colorWithCalibratedRed: RED_FROM_ULONG (c) / 255.0
3772 green: GREEN_FROM_ULONG (c) / 255.0
3773 blue: BLUE_FROM_ULONG (c) / 255.0
3775 forKey: [NSString stringWithUTF8String: name]];
3777 [cl writeToFile: nil];
3783 #ifdef NS_IMPL_GNUSTEP
3784 strncpy (c, gnustep_base_version, sizeof (c));
3786 /*PSnextrelease (128, c); */
3787 snprintf (c, sizeof (c), "%g", NSAppKitVersionNumber);
3789 Vwindow_system_version = build_string (c);
3792 delete_keyboard_wait_descriptor (0);
3794 ns_app_name = [[NSProcessInfo processInfo] processName];
3796 /* Set up OS X app menu */
3797 #ifdef NS_IMPL_COCOA
3801 /* set up the application menu */
3802 svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
3803 [svcsMenu setAutoenablesItems: NO];
3804 appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
3805 [appMenu setAutoenablesItems: NO];
3806 mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
3807 dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
3809 [appMenu insertItemWithTitle: @"About Emacs"
3810 action: @selector (orderFrontStandardAboutPanel:)
3813 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
3814 [appMenu insertItemWithTitle: @"Preferences..."
3815 action: @selector (showPreferencesWindow:)
3818 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
3819 item = [appMenu insertItemWithTitle: @"Services"
3820 action: @selector (menuDown:)
3823 [appMenu setSubmenu: svcsMenu forItem: item];
3824 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
3825 [appMenu insertItemWithTitle: @"Hide Emacs"
3826 action: @selector (hide:)
3829 item = [appMenu insertItemWithTitle: @"Hide Others"
3830 action: @selector (hideOtherApplications:)
3833 [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
3834 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
3835 [appMenu insertItemWithTitle: @"Quit Emacs"
3836 action: @selector (terminate:)
3840 item = [mainMenu insertItemWithTitle: ns_app_name
3841 action: @selector (menuDown:)
3844 [mainMenu setSubmenu: appMenu forItem: item];
3845 [dockMenu insertItemWithTitle: @"New Frame"
3846 action: @selector (newFrame:)
3850 [NSApp setMainMenu: mainMenu];
3851 [NSApp setAppleMenu: appMenu];
3852 [NSApp setServicesMenu: svcsMenu];
3853 /* Needed at least on Cocoa, to get dock menu to show windows */
3854 [NSApp setWindowsMenu: [[NSMenu alloc] init]];
3856 #endif /* MAC OS X menu setup */
3864 extern Lisp_Object Vauto_save_list_file_name;
3866 ns_term_shutdown (int sig)
3868 /* code not reached in emacs.c after this is called by shut_down_emacs: */
3869 if (STRINGP (Vauto_save_list_file_name))
3870 unlink (SDATA (Vauto_save_list_file_name));
3872 if (sig == 0 || sig == SIGTERM)
3874 [NSApp terminate: NSApp];
3876 else // force a stack trace to happen
3883 /* ==========================================================================
3885 EmacsApp implementation
3887 ========================================================================== */
3890 @implementation EmacsApp
3892 - (void)logNotification: (NSNotification *)notification
3894 const char *name = [[notification name] UTF8String];
3895 if (!strstr (name, "Update") && !strstr (name, "NSMenu")
3896 && !strstr (name, "WindowNumber"))
3897 NSLog (@"notification: '%@'", [notification name]);
3901 - (void)sendEvent: (NSEvent *)theEvent
3902 /* --------------------------------------------------------------------------
3903 Called when NSApp is running for each event received. Used to stop
3904 the loop when we choose, since there's no way to just run one iteration.
3905 -------------------------------------------------------------------------- */
3907 int type = [theEvent type];
3908 NSWindow *window = [theEvent window];
3909 /* NSTRACE (sendEvent); */
3910 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
3912 if (type == NSCursorUpdate && window == nil)
3914 fprintf (stderr, "Dropping external cursor update event.\n");
3918 #ifdef NS_IMPL_COCOA
3919 /* pass mouse down in resize handle and subsequent drags directly to
3920 EmacsWindow so we can generate continuous redisplays */
3923 if (type == NSLeftMouseDragged)
3925 [window mouseDragged: theEvent];
3928 else if (type == NSLeftMouseUp)
3930 [window mouseUp: theEvent];
3934 else if (type == NSLeftMouseDown)
3936 NSRect r = ns_resize_handle_rect (window);
3937 if (NSPointInRect ([theEvent locationInWindow], r))
3940 [window mouseDown: theEvent];
3946 if (type == NSApplicationDefined)
3948 /* Events posted by ns_send_appdefined interrupt the run loop here.
3949 But, if a modal window is up, an appdefined can still come through,
3950 (e.g., from a makeKeyWindow event) but stopping self also stops the
3951 modal loop. Just defer it until later. */
3952 if ([NSApp modalWindow] == nil)
3954 last_appdefined_event = theEvent;
3959 send_appdefined = YES;
3963 [super sendEvent: theEvent];
3967 - (void)showPreferencesWindow: (id)sender
3969 struct frame *emacsframe = SELECTED_FRAME ();
3970 NSEvent *theEvent = [NSApp currentEvent];
3974 emacs_event->kind = NS_NONKEY_EVENT;
3975 emacs_event->code = KEY_NS_SHOW_PREFS;
3976 emacs_event->modifiers = 0;
3977 EV_TRAILER (theEvent);
3981 - (void)newFrame: (id)sender
3983 struct frame *emacsframe = SELECTED_FRAME ();
3984 NSEvent *theEvent = [NSApp currentEvent];
3988 emacs_event->kind = NS_NONKEY_EVENT;
3989 emacs_event->code = KEY_NS_NEW_FRAME;
3990 emacs_event->modifiers = 0;
3991 EV_TRAILER (theEvent);
3995 /* Open a file (used by below, after going into queue read by ns_read_socket) */
3996 - (BOOL) openFile: (NSString *)fileName
3998 struct frame *emacsframe = SELECTED_FRAME ();
3999 NSEvent *theEvent = [NSApp currentEvent];
4004 emacs_event->kind = NS_NONKEY_EVENT;
4005 emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4006 ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4007 ns_input_line = Qnil; /* can be start or cons start,end */
4008 emacs_event->modifiers =0;
4009 EV_TRAILER (theEvent);
4015 /* **************************************************************************
4017 EmacsApp delegate implementation
4019 ************************************************************************** */
4021 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4022 /* --------------------------------------------------------------------------
4023 When application is loaded, terminate event loop in ns_term_init
4024 -------------------------------------------------------------------------- */
4026 NSTRACE (applicationDidFinishLaunching);
4027 [NSApp setServicesProvider: NSApp];
4028 ns_send_appdefined (-2);
4032 /* Termination sequences:
4035 MenuBar | File | Exit:
4036 Select Quit from App menubar:
4038 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4041 Select Quit from Dock menu:
4044 Cancel -> Nothing else
4048 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4053 - (void) terminate: (id)sender
4055 struct frame *emacsframe = SELECTED_FRAME ();
4060 emacs_event->kind = NS_NONKEY_EVENT;
4061 emacs_event->code = KEY_NS_POWER_OFF;
4062 emacs_event->arg = Qt; /* mark as non-key event */
4063 EV_TRAILER ((id)nil);
4067 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4071 if (NILP (ns_confirm_quit)) // || ns_shutdown_properly --> TO DO
4072 return NSTerminateNow;
4074 ret = NSRunAlertPanel(ns_app_name,
4075 [NSString stringWithUTF8String:"Exit requested. Would you like to Save Buffers and Exit, or Cancel the request?"],
4076 @"Save Buffers and Exit", @"Cancel", nil);
4078 if (ret == NSAlertDefaultReturn)
4079 return NSTerminateNow;
4080 else if (ret == NSAlertAlternateReturn)
4081 return NSTerminateCancel;
4082 return NSTerminateNow; /* just in case */
4086 /* Notification from the Workspace to open a file */
4087 - (BOOL)application: sender openFile: (NSString *)file
4089 [ns_pending_files addObject: file];
4094 /* Open a file as a temporary file */
4095 - (BOOL)application: sender openTempFile: (NSString *)file
4097 [ns_pending_files addObject: file];
4102 /* Notification from the Workspace to open a file noninteractively (?) */
4103 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4105 [ns_pending_files addObject: file];
4110 /* Notification from the Workspace to open multiple files */
4111 - (void)application: sender openFiles: (NSArray *)fileList
4113 NSEnumerator *files = [fileList objectEnumerator];
4115 while ((file = [files nextObject]) != nil)
4116 [ns_pending_files addObject: file];
4118 [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4123 /* Handle dock menu requests. */
4124 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4130 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4131 - (void)applicationWillBecomeActive: (NSNotification *)notification
4133 //ns_app_active=YES;
4135 - (void)applicationDidBecomeActive: (NSNotification *)notification
4137 //ns_app_active=YES;
4139 - (void)applicationDidResignActive: (NSNotification *)notification
4142 ns_send_appdefined (-1);
4147 /* ==========================================================================
4149 EmacsApp aux handlers for managing event loop
4151 ========================================================================== */
4154 - (void)timeout_handler: (NSTimer *)timedEntry
4155 /* --------------------------------------------------------------------------
4156 The timeout specified to ns_select has passed.
4157 -------------------------------------------------------------------------- */
4159 /*NSTRACE (timeout_handler); */
4160 ns_send_appdefined (-2);
4163 - (void)fd_handler: (NSTimer *) fdEntry
4164 /* --------------------------------------------------------------------------
4165 Check data waiting on file descriptors and terminate if so
4166 -------------------------------------------------------------------------- */
4169 /* NSTRACE (fd_handler); */
4171 if (select_nfds == 0)
4174 memcpy (&t_readfds, &select_readfds, sizeof (fd_set));
4176 select_timeout.tv_sec = select_timeout.tv_usec = 0;
4177 result = select (select_nfds, &t_readfds, (SELECT_TYPE *)0, (SELECT_TYPE *)0,
4181 memcpy (&select_readfds, &t_readfds, sizeof (fd_set));
4182 ns_send_appdefined (result);
4188 /* ==========================================================================
4192 ========================================================================== */
4194 /* called from system: queue for next pass through event loop */
4195 - (void)requestService: (NSPasteboard *)pboard
4196 userData: (NSString *)userData
4197 error: (NSString **)error
4199 [ns_pending_service_names addObject: userData];
4200 [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4201 SDATA (ns_string_from_pasteboard (pboard))]];
4205 /* called from ns_read_socket to clear queue */
4206 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4208 struct frame *emacsframe = SELECTED_FRAME ();
4209 NSEvent *theEvent = [NSApp currentEvent];
4214 emacs_event->kind = NS_NONKEY_EVENT;
4215 emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4216 ns_input_spi_name = build_string ([name UTF8String]);
4217 ns_input_spi_arg = build_string ([arg UTF8String]);
4218 emacs_event->modifiers = EV_MODIFIERS (theEvent);
4219 EV_TRAILER (theEvent);
4229 /* ==========================================================================
4231 EmacsView implementation
4233 ========================================================================== */
4236 @implementation EmacsView
4238 /* needed to inform when window closed from LISP */
4239 - (void) setWindowClosing: (BOOL)closing
4241 windowClosing = closing;
4247 NSTRACE (EmacsView_dealloc);
4253 /* called on font panel selection */
4254 - (void)changeFont: (id)sender
4256 NSEvent *e =[[self window] currentEvent];
4257 struct face *face =FRAME_DEFAULT_FACE (emacsframe);
4261 NSTRACE (changeFont);
4265 if (newFont = [sender convertFont:
4266 ((struct nsfont_info *)face->font)->nsfont])
4268 SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
4270 emacs_event->kind = NS_NONKEY_EVENT;
4271 emacs_event->modifiers = 0;
4272 emacs_event->code = KEY_NS_CHANGE_FONT;
4274 size = [newFont pointSize];
4275 ns_input_fontsize = make_number (lrint (size));
4276 ns_input_font = build_string ([[newFont familyName] UTF8String]);
4282 - (BOOL)acceptsFirstResponder
4284 NSTRACE (acceptsFirstResponder);
4289 - (void)resetCursorRects
4291 NSRect visible = [self visibleRect];
4292 NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
4293 NSTRACE (resetCursorRects);
4295 if (currentCursor == nil)
4296 currentCursor = [NSCursor arrowCursor];
4298 if (!NSIsEmptyRect (visible))
4299 [self addCursorRect: visible cursor: currentCursor];
4300 [currentCursor setOnMouseEntered: YES];
4305 /*****************************************************************************/
4306 /* Keyboard handling. */
4309 - (void)keyDown: (NSEvent *)theEvent
4311 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
4313 unsigned fnKeysym = 0;
4315 static NSMutableArray *nsEvArray;
4316 static BOOL firstTime = YES;
4320 /* Rhapsody and OS X give up and down events for the arrow keys */
4321 if (ns_fake_keydown == YES)
4322 ns_fake_keydown = NO;
4323 else if ([theEvent type] != NSKeyDown)
4329 if (![[self window] isKeyWindow]
4330 && [[theEvent window] isKindOfClass: [EmacsWindow class]]
4331 /* we must avoid an infinite loop here. */
4332 && (EmacsView *)[[theEvent window] delegate] != self)
4334 /* XXX: There is an occasional condition in which, when Emacs display
4335 updates a different frame from the current one, and temporarily
4336 selects it, then processes some interrupt-driven input
4337 (dispnew.c:3878), OS will send the event to the correct NSWindow, but
4338 for some reason that window has its first responder set to the NSView
4339 most recently updated (I guess), which is not the correct one. */
4340 [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
4344 if (nsEvArray == nil)
4345 nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
4347 [NSCursor setHiddenUntilMouseMoves: YES];
4349 if (dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
4351 clear_mouse_face (dpyinfo);
4352 dpyinfo->mouse_face_hidden = 1;
4355 if (!processingCompose)
4357 code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
4358 0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
4359 /* (Carbon way: [theEvent keyCode]) */
4361 /* is it a "function key"? */
4362 fnKeysym = ns_convert_key (code);
4365 /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
4366 because Emacs treats Delete and KP-Delete same (in simple.el). */
4367 if (fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
4368 code = 0xFF08; /* backspace */
4373 /* are there modifiers? */
4374 emacs_event->modifiers = 0;
4375 flags = [theEvent modifierFlags];
4377 if (flags & NSHelpKeyMask)
4378 emacs_event->modifiers |= hyper_modifier;
4380 if (flags & NSShiftKeyMask)
4381 emacs_event->modifiers |= shift_modifier;
4383 if (flags & NSCommandKeyMask)
4385 emacs_event->modifiers |= parse_solitary_modifier (ns_command_modifier);
4386 /* if super (default), take input manager's word so things like
4387 dvorak / qwerty layout work */
4388 if (EQ (ns_command_modifier, Qsuper)
4390 && [[theEvent characters] length] != 0)
4392 /* XXX: the code we get will be unshifted, so if we have
4393 a shift modifier, must convert ourselves */
4394 if (!(flags & NSShiftKeyMask))
4395 code = [[theEvent characters] characterAtIndex: 0];
4397 /* this is ugly and also requires linking w/Carbon framework
4398 (for LMGetKbdType) so for now leave this rare (?) case
4399 undealt with.. in future look into CGEvent methods */
4402 long smv = GetScriptManagerVariable (smKeyScript);
4403 Handle uchrHandle = GetResource
4404 ('uchr', GetScriptVariable (smv, smScriptKeys));
4406 UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
4407 [[theEvent characters] characterAtIndex: 0],
4408 kUCKeyActionDisplay,
4409 (flags & ~NSCommandKeyMask) >> 8,
4410 LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
4411 &dummy, 1, &dummy, &code);
4418 if (flags & NSControlKeyMask)
4419 emacs_event->modifiers |=
4420 parse_solitary_modifier (ns_control_modifier);
4422 if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
4423 emacs_event->modifiers |=
4424 parse_solitary_modifier (ns_function_modifier);
4426 if (flags & NSAlternateKeyMask) /* default = meta */
4428 if ((NILP (ns_alternate_modifier) || EQ (ns_alternate_modifier, Qnone))
4430 { /* accept pre-interp alt comb */
4431 if ([[theEvent characters] length] > 0)
4432 code = [[theEvent characters] characterAtIndex: 0];
4433 /*HACK: clear lone shift modifier to stop next if from firing */
4434 if (emacs_event->modifiers == shift_modifier)
4435 emacs_event->modifiers = 0;
4438 emacs_event->modifiers |=
4439 parse_solitary_modifier (ns_alternate_modifier);
4443 fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
4444 code, fnKeysym, flags, emacs_event->modifiers);
4446 /* if it was a function key or had modifiers, pass it directly to emacs */
4447 if (fnKeysym || (emacs_event->modifiers
4448 && [[theEvent charactersIgnoringModifiers] length] > 0))
4449 /*[[theEvent characters] length] */
4451 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4453 code |= (1<<28)|(3<<16);
4454 else if (code == 0x7f)
4455 code |= (1<<28)|(3<<16);
4457 emacs_event->kind = code > 0xFF
4458 ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4460 emacs_event->code = code;
4461 EV_TRAILER (theEvent);
4466 /* if we get here we should send the key for input manager processing */
4467 if (firstTime && [[NSInputManager currentInputManager]
4468 wantsToDelayTextChangeNotifications] == NO)
4470 "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
4473 if (NS_KEYLOG && !processingCompose)
4474 fprintf (stderr, "keyDown: Begin compose sequence.\n");
4476 processingCompose = YES;
4477 [nsEvArray addObject: theEvent];
4478 [self interpretKeyEvents: nsEvArray];
4479 [nsEvArray removeObject: theEvent];
4483 #ifdef NS_IMPL_COCOA
4484 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
4485 decided not to send key-down for.
4486 See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
4487 This only applies on Tiger and earlier.
4488 If it matches one of these, send it on to keyDown. */
4489 -(void)keyUp: (NSEvent *)theEvent
4491 int flags = [theEvent modifierFlags];
4492 int code = [theEvent keyCode];
4493 if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
4494 code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
4497 fprintf (stderr, "keyUp: passed test");
4498 ns_fake_keydown = YES;
4499 [self keyDown: theEvent];
4505 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
4508 /* <NSTextInput>: called when done composing;
4509 NOTE: also called when we delete over working text, followed immed.
4510 by doCommandBySelector: deleteBackward: */
4511 - (void)insertText: (id)aString
4514 int len = [(NSString *)aString length];
4518 NSLog (@"insertText '%@'\tlen = %d", aString, len);
4519 processingCompose = NO;
4524 /* first, clear any working text */
4525 if (workingText != nil)
4526 [self deleteWorkingText];
4528 /* now insert the string as keystrokes */
4529 for (i =0; i<len; i++)
4531 code = [aString characterAtIndex: i];
4532 /* TODO: still need this? */
4534 code = '~'; /* 0x7E */
4535 emacs_event->modifiers = 0;
4537 = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4538 emacs_event->code = code;
4539 EV_TRAILER ((id)nil);
4544 /* <NSTextInput>: inserts display of composing characters */
4545 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
4547 NSString *str = [aString respondsToSelector: @selector (string)] ?
4548 [aString string] : aString;
4550 NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
4551 selRange.length, selRange.location);
4553 if (workingText != nil)
4554 [self deleteWorkingText];
4555 if ([str length] == 0)
4561 processingCompose = YES;
4562 workingText = [str copy];
4563 ns_working_text = build_string ([workingText UTF8String]);
4565 emacs_event->kind = NS_TEXT_EVENT;
4566 emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
4567 EV_TRAILER ((id)nil);
4571 /* delete display of composing characters [not in <NSTextInput>] */
4572 - (void)deleteWorkingText
4574 if (workingText == nil)
4577 NSLog(@"deleteWorkingText len =%d\n", [workingText length]);
4578 [workingText release];
4580 processingCompose = NO;
4585 emacs_event->kind = NS_TEXT_EVENT;
4586 emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
4587 EV_TRAILER ((id)nil);
4591 - (BOOL)hasMarkedText
4593 return workingText != nil;
4597 - (NSRange)markedRange
4599 NSRange rng = workingText != nil
4600 ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
4602 NSLog (@"markedRange request");
4610 NSLog (@"unmark (accept) text");
4611 [self deleteWorkingText];
4612 processingCompose = NO;
4616 /* used to position char selection windows, etc. */
4617 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
4621 struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
4623 NSLog (@"firstRectForCharRange request");
4625 rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
4626 rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
4627 pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
4628 pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
4629 +FRAME_LINE_HEIGHT (emacsframe));
4631 pt = [self convertPoint: pt toView: nil];
4632 pt = [[self window] convertBaseToScreen: pt];
4638 - (long)conversationIdentifier
4644 - (void)doCommandBySelector: (SEL)aSelector
4647 NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
4649 if (aSelector == @selector (deleteBackward:))
4651 /* happens when user backspaces over an ongoing composition:
4652 throw a 'delete' into the event queue */
4655 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4656 emacs_event->code = 0xFF08;
4657 EV_TRAILER ((id)nil);
4661 - (NSArray *)validAttributesForMarkedText
4663 static NSArray *arr = nil;
4664 if (arr == nil) arr = [NSArray new];
4665 /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
4669 - (NSRange)selectedRange
4672 NSLog (@"selectedRange request");
4673 return NSMakeRange (NSNotFound, 0);
4676 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
4679 NSLog (@"characterIndexForPoint request");
4683 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
4685 static NSAttributedString *str = nil;
4686 if (str == nil) str = [NSAttributedString new];
4688 NSLog (@"attributedSubstringFromRange request");
4692 /* End <NSTextInput> impl. */
4693 /*****************************************************************************/
4696 /* This is what happens when the user presses a mouse button. */
4697 - (void)mouseDown: (NSEvent *)theEvent
4699 NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
4702 NSTRACE (mouseDown);
4704 [self deleteWorkingText];
4709 last_mouse_frame = emacsframe;
4710 /* appears to be needed to prevent spurious movement events generated on
4712 last_mouse_frame->mouse_moved = 0;
4714 if ([theEvent type] == NSScrollWheel)
4716 float delta = [theEvent deltaY];
4717 /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
4720 emacs_event->kind = WHEEL_EVENT;
4721 emacs_event->code = 0;
4722 emacs_event->modifiers = EV_MODIFIERS (theEvent) |
4723 ((delta > 0) ? up_modifier : down_modifier);
4727 emacs_event->kind = MOUSE_CLICK_EVENT;
4728 emacs_event->code = EV_BUTTON (theEvent);
4729 emacs_event->modifiers = EV_MODIFIERS (theEvent)
4730 | EV_UDMODIFIERS (theEvent);
4732 XSETINT (emacs_event->x, lrint (p.x));
4733 XSETINT (emacs_event->y, lrint (p.y));
4734 EV_TRAILER (theEvent);
4738 - (void)rightMouseDown: (NSEvent *)theEvent
4740 NSTRACE (rightMouseDown);
4741 [self mouseDown: theEvent];
4745 - (void)otherMouseDown: (NSEvent *)theEvent
4747 NSTRACE (otherMouseDown);
4748 [self mouseDown: theEvent];
4752 - (void)mouseUp: (NSEvent *)theEvent
4755 [self mouseDown: theEvent];
4759 - (void)rightMouseUp: (NSEvent *)theEvent
4761 NSTRACE (rightMouseUp);
4762 [self mouseDown: theEvent];
4766 - (void)otherMouseUp: (NSEvent *)theEvent
4768 NSTRACE (otherMouseUp);
4769 [self mouseDown: theEvent];
4773 - (void) scrollWheel: (NSEvent *)theEvent
4775 NSTRACE (scrollWheel);
4776 [self mouseDown: theEvent];
4780 /* Tell emacs the mouse has moved. */
4781 - (void)mouseMoved: (NSEvent *)e
4783 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
4786 // NSTRACE (mouseMoved);
4788 last_mouse_movement_time = EV_TIMESTAMP (e);
4789 last_mouse_motion_position
4790 = [self convertPoint: [e locationInWindow] fromView: nil];
4792 /* update any mouse face */
4793 if (dpyinfo->mouse_face_hidden)
4795 dpyinfo->mouse_face_hidden = 0;
4796 clear_mouse_face (dpyinfo);
4799 /* tooltip handling */
4800 previous_help_echo_string = help_echo_string;
4801 help_echo_string = Qnil;
4803 if (!note_mouse_movement (emacsframe, last_mouse_motion_position.x,
4804 last_mouse_motion_position.y))
4805 help_echo_string = previous_help_echo_string;
4807 XSETFRAME (frame, emacsframe);
4808 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
4810 /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
4811 (note_mouse_highlight), which is called through the
4812 note_mouse_movement () call above */
4813 gen_help_event (help_echo_string, frame, help_echo_window,
4814 help_echo_object, help_echo_pos);
4818 help_echo_string = Qnil;
4819 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
4822 if (emacsframe->mouse_moved && send_appdefined)
4823 ns_send_appdefined (-1);
4827 - (void)mouseDragged: (NSEvent *)e
4829 NSTRACE (mouseDragged);
4830 [self mouseMoved: e];
4834 - (void)rightMouseDragged: (NSEvent *)e
4836 NSTRACE (rightMouseDragged);
4837 [self mouseMoved: e];
4841 - (void)otherMouseDragged: (NSEvent *)e
4843 NSTRACE (otherMouseDragged);
4844 [self mouseMoved: e];
4848 - (BOOL)windowShouldClose: (id)sender
4850 NSEvent *e =[[self window] currentEvent];
4852 NSTRACE (windowShouldClose);
4853 windowClosing = YES;
4856 emacs_event->kind = DELETE_WINDOW_EVENT;
4857 emacs_event->modifiers = 0;
4858 emacs_event->code = 0;
4860 /* Don't close this window, let this be done from lisp code. */
4865 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
4866 /* normalize frame to gridded text size */
4868 NSTRACE (windowWillResize);
4869 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
4871 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe,
4872 #ifdef NS_IMPL_GNUSTEP
4873 frameSize.width + 3);
4877 if (cols < MINWIDTH)
4879 frameSize.width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (emacsframe, cols);
4881 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, frameSize.height
4882 #ifdef NS_IMPL_GNUSTEP
4883 - FRAME_NS_TITLEBAR_HEIGHT (emacsframe) + 3
4884 - FRAME_TOOLBAR_HEIGHT (emacsframe));
4886 - FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
4887 - FRAME_TOOLBAR_HEIGHT (emacsframe));
4889 if (rows < MINHEIGHT)
4891 frameSize.height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (emacsframe, rows)
4892 + FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
4893 + FRAME_TOOLBAR_HEIGHT (emacsframe);
4894 #ifdef NS_IMPL_COCOA
4896 /* this sets window title to have size in it; the wm does this under GS */
4897 NSRect r = [[self window] frame];
4898 if (r.size.height == frameSize.height && r.size.width == frameSize.width)
4909 NSWindow *window = [self window];
4912 const char *t = [[[self window] title] UTF8String];
4913 char *pos = strstr (t, " — ");
4916 old_title = (char *) xmalloc (strlen (t) + 1);
4917 strcpy (old_title, t);
4919 size_title = xmalloc (strlen (old_title) + 40);
4920 sprintf (size_title, "%s — (%d x %d)", old_title, cols, rows);
4921 [window setTitle: [NSString stringWithUTF8String: size_title]];
4926 #endif /* NS_IMPL_COCOA */
4927 /*fprintf (stderr," ...size became %.0f x %.0f (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
4933 - (void)windowDidResize: (NSNotification *)notification
4935 NSWindow *theWindow = [notification object];
4937 #ifdef NS_IMPL_GNUSTEP
4938 /* in GNUstep, at least currently, it's possible to get a didResize
4939 without getting a willResize.. therefore we need to act as if we got
4940 the willResize now */
4941 NSSize sz = [theWindow frame].size;
4942 sz = [self windowWillResize: theWindow toSize: sz];
4943 #endif /* NS_IMPL_GNUSTEP */
4945 NSTRACE (windowDidResize);
4946 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
4948 #ifdef NS_IMPL_COCOA
4954 #endif /* NS_IMPL_COCOA */
4956 /* Avoid loop under GNUstep due to call at beginning of this function.
4957 (x_set_window_size causes a resize which causes
4958 a "windowDidResize" which calls x_set_window_size). */
4959 #ifndef NS_IMPL_GNUSTEP
4960 if (cols > 0 && rows > 0)
4961 x_set_window_size (emacsframe, 0, cols, rows);
4964 ns_send_appdefined (-1);
4968 - (void)windowDidBecomeKey: (NSNotification *)notification
4969 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
4971 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
4972 struct frame *old_focus = dpyinfo->x_focus_frame;
4974 NSTRACE (windowDidBecomeKey);
4976 if (emacsframe != old_focus)
4977 dpyinfo->x_focus_frame = emacsframe;
4979 ns_frame_rehighlight (emacsframe);
4983 emacs_event->kind = FOCUS_IN_EVENT;
4984 EV_TRAILER ((id)nil);
4989 - (void)windowDidResignKey: (NSNotification *)notification
4990 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
4992 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
4993 NSTRACE (windowDidResignKey);
4995 if (dpyinfo->x_focus_frame == emacsframe)
4996 dpyinfo->x_focus_frame = 0;
4998 ns_frame_rehighlight (emacsframe);
5000 /* FIXME: for some reason needed on second and subsequent clicks away
5001 from sole-frame Emacs to get hollow box to show */
5002 if (!windowClosing && [[self window] isVisible] == YES)
5004 x_update_cursor (emacsframe, 1);
5005 x_set_frame_alpha (emacsframe);
5010 [self deleteWorkingText];
5011 emacs_event->kind = FOCUS_IN_EVENT;
5012 EV_TRAILER ((id)nil);
5017 - (void)windowWillMiniaturize: sender
5019 NSTRACE (windowWillMiniaturize);
5035 - initFrameFromEmacs: (struct frame *)f
5040 NSButton *toggleButton;
5041 int vbextra = NS_SCROLL_BAR_WIDTH (f);
5046 NSTRACE (initFrameFromEmacs);
5049 processingCompose = NO;
5050 scrollbarsNeedingUpdate = 0;
5052 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5054 r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5055 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5056 [self initWithFrame: r];
5057 [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
5059 FRAME_NS_VIEW (f) = self;
5063 win = [[EmacsWindow alloc]
5064 initWithContentRect: r
5065 styleMask: (NSResizableWindowMask |
5066 NSMiniaturizableWindowMask |
5067 NSClosableWindowMask)
5068 backing: NSBackingStoreBuffered
5072 f->border_width = wr.size.width - r.size.width;
5073 FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
5075 [win setAcceptsMouseMovedEvents: YES];
5076 [win setDelegate: self];
5077 [win useOptimizedDrawing: YES];
5079 sz.width = FRAME_COLUMN_WIDTH (f);
5080 sz.height = FRAME_LINE_HEIGHT (f);
5081 [win setResizeIncrements: sz];
5083 [[win contentView] addSubview: self];
5086 [self registerForDraggedTypes: ns_drag_types];
5089 name = [NSString stringWithUTF8String:
5090 NILP (tem) ? (unsigned char *)"Emacs" : SDATA (tem)];
5091 [win setTitle: name];
5093 /* toolbar support */
5094 toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
5095 [NSString stringWithFormat: @"Emacs Frame %d",
5097 [win setToolbar: toolbar];
5098 [toolbar setVisible: NO];
5099 #ifdef NS_IMPL_COCOA
5100 toggleButton = [win standardWindowButton: NSWindowToolbarButton];
5101 [toggleButton setTarget: self];
5102 [toggleButton setAction: @selector (toggleToolbar: )];
5104 FRAME_TOOLBAR_HEIGHT (f) = 0;
5108 [win setMiniwindowTitle:
5109 [NSString stringWithUTF8String: SDATA (tem)]];
5112 NSScreen *screen = [win screen];
5115 [win setFrameTopLeftPoint: NSMakePoint
5116 (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
5117 IN_BOUND (-SCREENMAX,
5118 [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
5121 [win makeFirstResponder: self];
5123 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5124 (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
5125 [win setBackgroundColor: col];
5126 if ([col alphaComponent] != 1.0)
5127 [win setOpaque: NO];
5129 [self allocateGState];
5136 - (void)windowDidMove: sender
5138 NSWindow *win = [self window];
5139 NSRect r = [win frame];
5140 NSScreen *screen = [win screen];
5142 NSTRACE (windowDidMove);
5144 if (!emacsframe->output_data.ns)
5148 emacsframe->left_pos = r.origin.x;
5149 emacsframe->top_pos =
5150 [screen frame].size.height - (r.origin.y + r.size.height);
5155 /* Called AFTER method below, but before our windowWillResize call there leads
5156 to windowDidResize -> x_set_window_size. Update emacs' notion of frame
5157 location so set_window_size moves the frame. */
5158 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
5160 NSTRACE (windowShouldZoom);
5161 emacsframe->left_pos = (int)newFrame.origin.x;
5162 emacsframe->top_pos = [[sender screen] frame].size.height
5163 - (newFrame.origin.y+newFrame.size.height);
5168 /* Override to do something slightly nonstandard, but nice. First click on
5169 zoom button will zoom vertically. Second will zoom completely. Third
5170 returns to original. */
5171 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
5172 defaultFrame:(NSRect)defaultFrame
5174 NSRect result = [sender frame];
5175 static NSRect ns_userRect = { 0, 0, 0, 0 };
5177 NSTRACE (windowWillUseStandardFrame);
5179 if (abs (defaultFrame.size.height - result.size.height)
5180 > FRAME_LINE_HEIGHT (emacsframe))
5183 ns_userRect = result;
5184 result.size.height = defaultFrame.size.height;
5185 result.origin.y = defaultFrame.origin.y;
5189 if (abs (defaultFrame.size.width - result.size.width)
5190 > FRAME_COLUMN_WIDTH (emacsframe))
5191 result = defaultFrame; /* second click */
5193 result = ns_userRect.size.height ? ns_userRect : result; /* restore */
5196 [self windowWillResize: sender toSize: result.size];
5201 - (void)windowDidDeminiaturize: sender
5203 NSTRACE (windowDidDeminiaturize);
5204 if (!emacsframe->output_data.ns)
5206 emacsframe->async_iconified = 0;
5207 emacsframe->async_visible = 1;
5208 windows_or_buffers_changed++;
5212 emacs_event->kind = ICONIFY_EVENT;
5213 EV_TRAILER ((id)nil);
5218 - (void)windowDidExpose: sender
5220 NSTRACE (windowDidExpose);
5221 if (!emacsframe->output_data.ns)
5223 emacsframe->async_visible = 1;
5224 SET_FRAME_GARBAGED (emacsframe);
5226 if (send_appdefined)
5227 ns_send_appdefined (-1);
5231 - (void)windowDidMiniaturize: sender
5233 NSTRACE (windowDidMiniaturize);
5234 if (!emacsframe->output_data.ns)
5237 emacsframe->async_iconified = 1;
5238 emacsframe->async_visible = 0;
5242 emacs_event->kind = ICONIFY_EVENT;
5243 EV_TRAILER ((id)nil);
5248 - (void)mouseEntered: (NSEvent *)theEvent
5250 NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5251 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5252 NSTRACE (mouseEntered);
5254 last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5258 - (void)mouseExited: (NSEvent *)theEvent
5260 NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5262 struct ns_display_info *dpyinfo
5263 = emacsframe ? FRAME_NS_DISPLAY_INFO (emacsframe) : NULL;
5265 NSTRACE (mouseExited);
5267 if (dpyinfo || !emacsframe)
5270 last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5272 if (emacsframe == dpyinfo->mouse_face_mouse_frame)
5274 clear_mouse_face (dpyinfo);
5275 dpyinfo->mouse_face_mouse_frame = 0;
5283 if (context_menu_value == -1)
5284 context_menu_value = [sender tag];
5286 find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
5287 emacsframe->menu_bar_vector,
5288 (void *)[sender tag]);
5289 ns_send_appdefined (-1);
5294 - (EmacsToolbar *)toolbar
5300 /* this gets called on toolbar button click */
5301 - toolbarClicked: (id)item
5304 int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
5306 NSTRACE (toolbarClicked);
5311 /* send first event (for some reason two needed) */
5312 theEvent = [[self window] currentEvent];
5313 emacs_event->kind = TOOL_BAR_EVENT;
5314 XSETFRAME (emacs_event->arg, emacsframe);
5315 EV_TRAILER (theEvent);
5317 emacs_event->kind = TOOL_BAR_EVENT;
5318 /* XSETINT (emacs_event->code, 0); */
5319 emacs_event->arg = AREF (emacsframe->tool_bar_items,
5320 idx + TOOL_BAR_ITEM_KEY);
5321 emacs_event->modifiers = EV_MODIFIERS (theEvent);
5322 EV_TRAILER (theEvent);
5327 - toggleToolbar: (id)sender
5332 emacs_event->kind = NS_NONKEY_EVENT;
5333 emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
5334 EV_TRAILER ((id)nil);
5339 - (void)drawRect: (NSRect)rect
5341 int x = NSMinX (rect), y = NSMinY (rect);
5342 int width = NSWidth (rect), height = NSHeight (rect);
5346 if (!emacsframe || !emacsframe->output_data.ns || ns_in_resize)
5349 ns_clear_frame_area (emacsframe, x, y, width, height);
5350 expose_frame (emacsframe, x, y, width, height);
5353 drawRect: may be called (at least in OS X 10.5) for invisible
5354 views as well for some reason. Thus, do not infer visibility
5357 emacsframe->async_visible = 1;
5358 emacsframe->async_iconified = 0;
5363 /* NSDraggingDestination protocol methods. Actually this is not really a
5364 protocol, but a category of Object. O well... */
5366 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
5368 NSTRACE (draggingEntered);
5369 return NSDragOperationGeneric;
5373 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
5379 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
5384 NSEvent *theEvent = [[self window] currentEvent];
5387 NSTRACE (performDragOperation);
5392 position = [self convertPoint: [sender draggingLocation] fromView: nil];
5393 x = lrint (position.x); y = lrint (position.y);
5395 pb = [sender draggingPasteboard];
5396 type = [pb availableTypeFromArray: ns_drag_types];
5401 else if ([type isEqualToString: NSFilenamesPboardType])
5404 NSEnumerator *fenum;
5407 if (!(files = [pb propertyListForType: type]))
5410 fenum = [files objectEnumerator];
5411 while ( (file = [fenum nextObject]) )
5413 emacs_event->kind = NS_NONKEY_EVENT;
5414 emacs_event->code = KEY_NS_DRAG_FILE;
5415 XSETINT (emacs_event->x, x);
5416 XSETINT (emacs_event->y, y);
5417 ns_input_file = append2 (ns_input_file,
5418 build_string ([file UTF8String]));
5419 emacs_event->modifiers = EV_MODIFIERS (theEvent);
5420 EV_TRAILER (theEvent);
5424 else if ([type isEqualToString: NSURLPboardType])
5429 if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
5430 [fileURL isFileURL] == NO)
5433 file = [fileURL path];
5434 emacs_event->kind = NS_NONKEY_EVENT;
5435 emacs_event->code = KEY_NS_DRAG_FILE;
5436 XSETINT (emacs_event->x, x);
5437 XSETINT (emacs_event->y, y);
5438 ns_input_file = append2 (ns_input_file, build_string ([file UTF8String]));
5439 emacs_event->modifiers = EV_MODIFIERS (theEvent);
5440 EV_TRAILER (theEvent);
5443 else if ([type isEqualToString: NSStringPboardType]
5444 || [type isEqualToString: NSTabularTextPboardType])
5448 if (! (data = [pb stringForType: type]))
5451 emacs_event->kind = NS_NONKEY_EVENT;
5452 emacs_event->code = KEY_NS_DRAG_TEXT;
5453 XSETINT (emacs_event->x, x);
5454 XSETINT (emacs_event->y, y);
5455 ns_input_text = build_string ([data UTF8String]);
5456 emacs_event->modifiers = EV_MODIFIERS (theEvent);
5457 EV_TRAILER (theEvent);
5460 else if ([type isEqualToString: NSColorPboardType])
5462 NSColor *c = [NSColor colorFromPasteboard: pb];
5463 emacs_event->kind = NS_NONKEY_EVENT;
5464 emacs_event->code = KEY_NS_DRAG_COLOR;
5465 XSETINT (emacs_event->x, x);
5466 XSETINT (emacs_event->y, y);
5467 ns_input_color = ns_color_to_lisp (c);
5468 emacs_event->modifiers = EV_MODIFIERS (theEvent);
5469 EV_TRAILER (theEvent);
5472 else if ([type isEqualToString: NSFontPboardType])
5474 /* impl based on GNUstep NSTextView.m */
5475 NSData *data = [pb dataForType: NSFontPboardType];
5476 NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
5477 NSFont *font = [dict objectForKey: NSFontAttributeName];
5483 emacs_event->kind = NS_NONKEY_EVENT;
5484 emacs_event->code = KEY_NS_CHANGE_FONT;
5485 XSETINT (emacs_event->x, x);
5486 XSETINT (emacs_event->y, y);
5487 ns_input_font = build_string ([[font fontName] UTF8String]);
5488 snprintf (fontSize, 10, "%f", [font pointSize]);
5489 ns_input_fontsize = build_string (fontSize);
5490 emacs_event->modifiers = EV_MODIFIERS (theEvent);
5491 EV_TRAILER (theEvent);
5496 error ("Invalid data type in dragging pasteboard.");
5502 - validRequestorForSendType: (NSString *)typeSent
5503 returnType: (NSString *)typeReturned
5505 NSTRACE (validRequestorForSendType);
5506 if ([ns_send_types indexOfObjectIdenticalTo: typeSent] != NSNotFound &&
5507 [ns_return_types indexOfObjectIdenticalTo: typeSent] != NSNotFound)
5510 return [super validRequestorForSendType: typeSent
5511 returnType: typeReturned];
5515 /* The next two methods are part of NSServicesRequests informal protocol,
5516 supposedly called when a services menu item is chosen from this app.
5517 But this should not happen because we override the services menu with our
5518 own entries which call ns-perform-service.
5519 Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
5520 So let's at least stub them out until further investigation can be done. */
5522 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
5524 /* we could call ns_string_from_pasteboard(pboard) here but then it should
5525 be written into the buffer in place of the existing selection..
5526 ordinary service calls go through functions defined in ns-win.el */
5530 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
5532 /* supposed to write for as many of types as we are able */
5537 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
5538 (gives a miniaturized version of the window); currently we use the latter for
5539 frames whose active buffer doesn't correspond to any file
5540 (e.g., '*scratch*') */
5541 - setMiniwindowImage: (BOOL) setMini
5543 id image = [[self window] miniwindowImage];
5544 NSTRACE (setMiniwindowImage);
5546 /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
5547 about "AppleDockIconEnabled" notwithstanding, however the set message
5548 below has its effect nonetheless. */
5549 if (image != emacsframe->output_data.ns->miniimage)
5551 if (image && [image isKindOfClass: [EmacsImage class]])
5553 [[self window] setMiniwindowImage:
5554 setMini ? emacsframe->output_data.ns->miniimage : nil];
5561 - (void) setRows: (int) r andColumns: (int) c
5567 @end /* EmacsView */
5571 /* ==========================================================================
5573 EmacsWindow implementation
5575 ========================================================================== */
5577 @implementation EmacsWindow
5579 /* called only on resize clicks by special case in EmacsApp-sendEvent */
5580 - (void)mouseDown: (NSEvent *)theEvent
5584 NSSize size = [[theEvent window] frame].size;
5585 grabOffset = [theEvent locationInWindow];
5586 grabOffset.x = size.width - grabOffset.x;
5589 [super mouseDown: theEvent];
5594 - (void)mouseUp: (NSEvent *)theEvent
5598 struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
5600 ns_set_name_as_filename (f);
5602 ns_send_appdefined (-1);
5605 [super mouseUp: theEvent];
5609 /* send resize events */
5610 - (void)mouseDragged: (NSEvent *)theEvent
5614 NSPoint p = [theEvent locationInWindow];
5615 NSSize size, vettedSize, origSize = [self frame].size;
5617 size.width = p.x + grabOffset.x;
5618 size.height = origSize.height - p.y + grabOffset.y;
5620 if (size.width == origSize.width && size.height == origSize.height)
5623 vettedSize = [[self delegate] windowWillResize: self toSize: size];
5624 if (vettedSize.width != size.width || vettedSize.height != size.height)
5626 [[NSNotificationCenter defaultCenter]
5627 postNotificationName: NSWindowDidResizeNotification
5632 [super mouseDragged: theEvent];
5635 @end /* EmacsWindow */
5638 /* ==========================================================================
5640 EmacsScroller implementation
5642 ========================================================================== */
5645 @implementation EmacsScroller
5647 /* for repeat button push */
5648 #define SCROLL_BAR_FIRST_DELAY 0.5
5649 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
5651 + (CGFloat) scrollerWidth
5653 /* TODO: if we want to allow variable widths, this is the place to do it,
5654 however neither GNUstep nor Cocoa support it very well */
5655 return [NSScroller scrollerWidth];
5659 - initFrame: (NSRect )r window: (Lisp_Object)nwin
5661 NSTRACE (EmacsScroller_initFrame);
5663 r.size.width = [EmacsScroller scrollerWidth];
5664 [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
5665 [self setContinuous: YES];
5666 [self setEnabled: YES];
5668 /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
5669 locked against the top and bottom edges, and right edge on OS X, where
5670 scrollers are on right. */
5671 #ifdef NS_IMPL_GNUSTEP
5672 [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
5674 [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
5679 pixel_height = NSHeight (r);
5680 min_portion = 20 / pixel_height;
5682 frame = XFRAME (XWINDOW (win)->frame);
5683 if (FRAME_LIVE_P (frame))
5686 EmacsView *view = FRAME_NS_VIEW (frame);
5687 NSView *sview = [[view window] contentView];
5688 NSArray *subs = [sview subviews];
5690 /* disable optimization stopping redraw of other scrollbars */
5691 view->scrollbarsNeedingUpdate = 0;
5692 for (i =[subs count]-1; i >= 0; i--)
5693 if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
5694 view->scrollbarsNeedingUpdate++;
5695 [sview addSubview: self];
5698 /* [self setFrame: r]; */
5704 - (void)setFrame: (NSRect)newRect
5706 NSTRACE (EmacsScroller_setFrame);
5708 pixel_height = NSHeight (newRect);
5709 min_portion = 20 / pixel_height;
5710 [super setFrame: newRect];
5712 /* UNBLOCK_INPUT; */
5718 NSTRACE (EmacsScroller_dealloc);
5720 XWINDOW (win)->vertical_scroll_bar = Qnil;
5747 /* ensure other scrollbar updates after deletion */
5748 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
5750 view->scrollbarsNeedingUpdate++;
5751 [self removeFromSuperview];
5759 - (void)resetCursorRects
5761 NSRect visible = [self visibleRect];
5762 NSTRACE (resetCursorRects);
5764 if (!NSIsEmptyRect (visible))
5765 [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
5766 [[NSCursor arrowCursor] setOnMouseEntered: YES];
5770 - (int) checkSamePosition: (int) position portion: (int) portion
5773 return em_position ==position && em_portion ==portion && em_whole ==whole
5774 && portion != whole; /* needed for resize empty buf */
5778 - setPosition: (int)position portion: (int)portion whole: (int)whole
5780 NSTRACE (setPosition);
5782 em_position = position;
5783 em_portion = portion;
5786 if (portion >= whole)
5787 [self setFloatValue: 0.0 knobProportion: 1.0];
5791 portion = max ((float)whole*min_portion/pixel_height, portion);
5792 pos = (float)position / (whole - portion);
5793 por = (float)portion/whole;
5794 [self setFloatValue: pos knobProportion: por];
5799 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
5800 drag events will go directly to the EmacsScroller. Leaving in for now. */
5801 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
5802 x: (Lisp_Object *)x y: ( Lisp_Object *)y
5804 *part = last_hit_part;
5806 XSETINT (*y, pixel_height);
5807 if ([self floatValue] > 0.999)
5808 XSETINT (*x, pixel_height);
5810 XSETINT (*x, pixel_height * [self floatValue]);
5814 /* set up emacs_event */
5815 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
5820 emacs_event->part = last_hit_part;
5821 emacs_event->code = 0;
5822 emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
5823 emacs_event->frame_or_window = win;
5824 emacs_event->timestamp = EV_TIMESTAMP (e);
5825 emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
5826 emacs_event->arg = Qnil;
5827 XSETINT (emacs_event->x, loc * pixel_height);
5828 XSETINT (emacs_event->y, pixel_height-20);
5830 n_emacs_events_pending++;
5831 kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
5832 EVENT_INIT (*emacs_event);
5833 ns_send_appdefined (-1);
5837 /* called manually thru timer to implement repeated button action w/hold-down */
5838 - repeatScroll: (NSTimer *)scrollEntry
5840 NSEvent *e = [[self window] currentEvent];
5841 NSPoint p = [[self window] mouseLocationOutsideOfEventStream];
5842 BOOL inKnob = [self testPart: p] == NSScrollerKnob;
5844 /* clear timer if need be */
5845 if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
5847 [scroll_repeat_entry invalidate];
5848 [scroll_repeat_entry release];
5849 scroll_repeat_entry = nil;
5855 = [[NSTimer scheduledTimerWithTimeInterval:
5856 SCROLL_BAR_CONTINUOUS_DELAY
5858 selector: @selector (repeatScroll:)
5864 [self sendScrollEventAtLoc: 0 fromEvent: e];
5869 /* Asynchronous mouse tracking for scroller. This allows us to dispatch
5870 mouseDragged events without going into a modal loop. */
5871 - (void)mouseDown: (NSEvent *)e
5874 /* hitPart is only updated AFTER event is passed on */
5875 NSScrollerPart part = [self testPart: [e locationInWindow]];
5876 double inc = 0.0, loc, kloc, pos;
5879 NSTRACE (EmacsScroller_mouseDown);
5883 case NSScrollerDecrementPage:
5884 last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
5885 case NSScrollerIncrementPage:
5886 last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
5887 case NSScrollerDecrementLine:
5888 last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
5889 case NSScrollerIncrementLine:
5890 last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
5891 case NSScrollerKnob:
5892 last_hit_part = scroll_bar_handle; break;
5893 case NSScrollerKnobSlot: /* GNUstep-only */
5894 last_hit_part = scroll_bar_move_ratio; break;
5895 default: /* NSScrollerNoPart? */
5896 fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
5903 pos = 0; /* ignored */
5905 /* set a timer to repeat, as we can't let superclass do this modally */
5907 = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
5909 selector: @selector (repeatScroll:)
5916 /* handle, or on GNUstep possibly slot */
5917 NSEvent *fake_event;
5919 /* compute float loc in slot and mouse offset on knob */
5920 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
5922 loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
5928 else if (loc >= NSHeight (sr))
5930 loc = NSHeight (sr);
5938 kr = [self convertRect: [self rectForPart: NSScrollerKnob]
5940 kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
5942 last_mouse_offset = kloc;
5944 /* if knob, tell emacs a location offset by knob pos
5945 (to indicate top of handle) */
5946 if (part == NSScrollerKnob)
5947 pos = (loc - last_mouse_offset) / NSHeight (sr);
5949 /* else this is a slot click on GNUstep: go straight there */
5950 pos = loc / NSHeight (sr);
5952 /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
5953 fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
5954 location: [e locationInWindow]
5955 modifierFlags: [e modifierFlags]
5956 timestamp: [e timestamp]
5957 windowNumber: [e windowNumber]
5958 context: [e context]
5959 eventNumber: [e eventNumber]
5960 clickCount: [e clickCount]
5961 pressure: [e pressure]];
5962 [super mouseUp: fake_event];
5965 if (part != NSScrollerKnob)
5966 [self sendScrollEventAtLoc: pos fromEvent: e];
5970 /* Called as we manually track scroller drags, rather than superclass. */
5971 - (void)mouseDragged: (NSEvent *)e
5977 NSTRACE (EmacsScroller_mouseDragged);
5979 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
5981 loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
5988 else if (loc >= NSHeight (sr) + last_mouse_offset)
5990 loc = NSHeight (sr) + last_mouse_offset;
5994 pos = /*(edge ? loc :*/ (loc - last_mouse_offset) / NSHeight (sr);
5995 [self sendScrollEventAtLoc: pos fromEvent: e];
5999 - (void)mouseUp: (NSEvent *)e
6001 if (scroll_repeat_entry)
6003 [scroll_repeat_entry invalidate];
6004 [scroll_repeat_entry release];
6005 scroll_repeat_entry = nil;
6011 /* treat scrollwheel events in the bar as though they were in the main window */
6012 - (void) scrollWheel: (NSEvent *)theEvent
6014 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
6015 [view mouseDown: theEvent];
6018 @end /* EmacsScroller */
6023 /* ==========================================================================
6025 Font-related functions; these used to be in nsfaces.m
6027 ========================================================================== */
6031 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
6033 struct font *font = XFONT_OBJECT (font_object);
6036 fontset = fontset_from_font (font_object);
6037 FRAME_FONTSET (f) = fontset;
6039 if (FRAME_FONT (f) == font)
6040 /* This font is already set in frame F. There's nothing more to
6044 FRAME_FONT (f) = font;
6046 FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
6047 FRAME_COLUMN_WIDTH (f) = font->average_width;
6048 FRAME_SPACE_WIDTH (f) = font->space_width;
6049 FRAME_LINE_HEIGHT (f) = font->height;
6051 compute_fringe_widths (f, 1);
6053 /* Compute the scroll bar width in character columns. */
6054 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
6056 int wid = FRAME_COLUMN_WIDTH (f);
6057 FRAME_CONFIG_SCROLL_BAR_COLS (f)
6058 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
6062 int wid = FRAME_COLUMN_WIDTH (f);
6063 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
6066 /* Now make the frame display the given font. */
6067 if (FRAME_NS_WINDOW (f) != 0)
6068 x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
6074 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
6075 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
6079 ns_xlfd_to_fontname (const char *xlfd)
6080 /* --------------------------------------------------------------------------
6081 Convert an X font name (XLFD) to an NS font name.
6082 Only family is used.
6083 The string returned is temporarily allocated.
6084 -------------------------------------------------------------------------- */
6086 char *name = xmalloc (180);
6090 if (!strncmp (xlfd, "--", 2))
6091 sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
6093 sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
6095 /* stopgap for malformed XLFD input */
6096 if (strlen (name) == 0)
6097 strcpy (name, "Monaco");
6099 /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
6100 also uppercase after '-' or ' ' */
6101 name[0] = toupper (name[0]);
6102 for (len =strlen (name), i =0; i<len; i++)
6108 name[i+1] = toupper (name[i+1]);
6110 else if (name[i] == '_')
6114 name[i+1] = toupper (name[i+1]);
6117 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name); */
6118 ret = [[NSString stringWithUTF8String: name] UTF8String];
6127 NSTRACE (syms_of_nsterm);
6129 ns_antialias_threshold = 10.0;
6131 /* from 23+ we need to tell emacs what modifiers there are.. */
6132 DEFSYM (Qmodifier_value, "modifier-value");
6133 DEFSYM (Qalt, "alt");
6134 DEFSYM (Qhyper, "hyper");
6135 DEFSYM (Qmeta, "meta");
6136 DEFSYM (Qsuper, "super");
6137 DEFSYM (Qcontrol, "control");
6138 DEFSYM (Qnone, "none");
6139 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
6140 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
6141 Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
6142 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
6143 Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
6145 DEFVAR_LISP ("ns-input-file", &ns_input_file,
6146 "The file specified in the last NS event.");
6147 ns_input_file =Qnil;
6149 DEFVAR_LISP ("ns-input-text", &ns_input_text,
6150 "The data received in the last NS text drag event.");
6151 ns_input_text =Qnil;
6153 DEFVAR_LISP ("ns-working-text", &ns_working_text,
6154 "String for visualizing working composition sequence.");
6155 ns_working_text =Qnil;
6157 DEFVAR_LISP ("ns-input-font", &ns_input_font,
6158 "The font specified in the last NS event.");
6159 ns_input_font =Qnil;
6161 DEFVAR_LISP ("ns-input-fontsize", &ns_input_fontsize,
6162 "The fontsize specified in the last NS event.");
6163 ns_input_fontsize =Qnil;
6165 DEFVAR_LISP ("ns-input-line", &ns_input_line,
6166 "The line specified in the last NS event.");
6167 ns_input_line =Qnil;
6169 DEFVAR_LISP ("ns-input-color", &ns_input_color,
6170 "The color specified in the last NS event.");
6171 ns_input_color =Qnil;
6173 DEFVAR_LISP ("ns-input-spi-name", &ns_input_spi_name,
6174 "The service name specified in the last NS event.");
6175 ns_input_spi_name =Qnil;
6177 DEFVAR_LISP ("ns-input-spi-arg", &ns_input_spi_arg,
6178 "The service argument specified in the last NS event.");
6179 ns_input_spi_arg =Qnil;
6181 DEFVAR_LISP ("ns-alternate-modifier", &ns_alternate_modifier,
6182 "This variable describes the behavior of the alternate or option key.\n\
6183 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6184 Set to none means that the alternate / option key is not interpreted by Emacs\n\
6185 at all, allowing it to be used at a lower level for accented character entry.");
6186 ns_alternate_modifier = Qmeta;
6188 DEFVAR_LISP ("ns-command-modifier", &ns_command_modifier,
6189 "This variable describes the behavior of the command key.\n\
6190 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
6191 ns_command_modifier = Qsuper;
6193 DEFVAR_LISP ("ns-control-modifier", &ns_control_modifier,
6194 "This variable describes the behavior of the control key.\n\
6195 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
6196 ns_control_modifier = Qcontrol;
6198 DEFVAR_LISP ("ns-function-modifier", &ns_function_modifier,
6199 "This variable describes the behavior of the function key (on laptops).\n\
6200 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6201 Set to none means that the function key is not interpreted by Emacs at all,\n\
6202 allowing it to be used at a lower level for accented character entry.");
6203 ns_function_modifier = Qnone;
6205 DEFVAR_LISP ("ns-antialias-text", &ns_antialias_text,
6206 "Non-nil (the default) means to render text antialiased. Only has an effect on OS X Panther and above.");
6207 ns_antialias_text = Qt;
6209 DEFVAR_LISP ("ns-confirm-quit", &ns_confirm_quit,
6210 "Whether to confirm application quit using dialog.");
6211 ns_confirm_quit = Qnil;
6213 staticpro (&ns_display_name_list);
6214 ns_display_name_list = Qnil;
6216 staticpro (&last_mouse_motion_frame);
6217 last_mouse_motion_frame = Qnil;
6219 /* TODO: move to common code */
6220 DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars,
6221 doc: /* If not nil, Emacs uses toolkit scroll bars. */);
6222 #ifdef USE_TOOLKIT_SCROLL_BARS
6223 Vx_toolkit_scroll_bars = Qt;
6225 Vx_toolkit_scroll_bars = Qnil;
6228 /* these are unsupported but we need the declarations to avoid whining
6229 messages from cus-start.el */
6230 DEFVAR_BOOL ("x-use-underline-position-properties",
6231 &x_use_underline_position_properties,
6232 doc: /* NOT SUPPORTED UNDER NS.
6233 *Non-nil means make use of UNDERLINE_POSITION font properties.
6234 A value of nil means ignore them. If you encounter fonts with bogus
6235 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
6236 to 4.1, set this to nil.
6238 NOTE: Not supported on Mac yet. */);
6239 x_use_underline_position_properties = 0;
6241 DEFVAR_BOOL ("x-underline-at-descent-line",
6242 &x_underline_at_descent_line,
6243 doc: /* NOT SUPPORTED UNDER NS.
6244 *Non-nil means to draw the underline at the same place as the descent line.
6245 A value of nil means to draw the underline according to the value of the
6246 variable `x-use-underline-position-properties', which is usually at the
6247 baseline level. The default value is nil. */);
6248 x_underline_at_descent_line = 0;
6250 /* Tell emacs about this window system. */
6251 Fprovide (intern ("ns"), Qnil);
6255 // arch-tag: 6eaa8f7d-a69b-4e1c-b43d-ab31defbe0d2