1 /* NeXT/Open/GNUstep / MacOSX communication module.
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2015 Free Software
6 This file is part of GNU Emacs.
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
22 Originally by Carl Edman
23 Updated by Christian Limpach (chris@nice.ch)
24 OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
25 MacOSX/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
26 GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
29 /* This should be the first include, as it may set up #defines affecting
30 interpretation of even the system includes. */
36 #include <sys/types.h>
42 #include <c-strcase.h>
46 #include "blockinput.h"
47 #include "sysselect.h"
50 #include "character.h"
52 #include "composite.h"
55 #include "termhooks.h"
63 #ifdef NS_IMPL_GNUSTEP
73 int term_trace_num = 0;
74 #define NSTRACE(x) fprintf (stderr, "%s:%d: [%d] " #x "\n", \
75 __FILE__, __LINE__, ++term_trace_num)
80 /* Detailed tracing. "S" means "size" and "LL" stands for "lower left". */
82 int term_trace_num = 0;
83 #define NSTRACE_SIZE(str,size) fprintf (stderr, \
85 " (S:%.0f x %.0f)\n", \
86 __FILE__, __LINE__, ++term_trace_num,\
89 #define NSTRACE_RECT(s,r) fprintf (stderr, \
91 " (LL:%.0f x %.0f -> S:%.0f x %.0f)\n", \
92 __FILE__, __LINE__, ++term_trace_num,\
98 #define NSTRACE_SIZE(str,size)
99 #define NSTRACE_RECT(s,r)
102 extern NSString *NSMenuDidBeginTrackingNotification;
104 /* ==========================================================================
106 NSColor, EmacsColor category.
108 ========================================================================== */
109 @implementation NSColor (EmacsColor)
110 + (NSColor *)colorForEmacsRed:(CGFloat)red green:(CGFloat)green
111 blue:(CGFloat)blue alpha:(CGFloat)alpha
114 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
115 if (ns_use_srgb_colorspace)
116 return [NSColor colorWithSRGBRed: red
122 return [NSColor colorWithCalibratedRed: red
128 - (NSColor *)colorUsingDefaultColorSpace
131 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
132 if (ns_use_srgb_colorspace)
133 return [self colorUsingColorSpace: [NSColorSpace sRGBColorSpace]];
136 return [self colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
141 /* ==========================================================================
145 ========================================================================== */
147 /* Convert a symbol indexed with an NSxxx value to a value as defined
148 in keyboard.c (lispy_function_key). I hope this is a correct way
149 of doing things... */
150 static unsigned convert_ns_to_X_keysym[] =
152 NSHomeFunctionKey, 0x50,
153 NSLeftArrowFunctionKey, 0x51,
154 NSUpArrowFunctionKey, 0x52,
155 NSRightArrowFunctionKey, 0x53,
156 NSDownArrowFunctionKey, 0x54,
157 NSPageUpFunctionKey, 0x55,
158 NSPageDownFunctionKey, 0x56,
159 NSEndFunctionKey, 0x57,
160 NSBeginFunctionKey, 0x58,
161 NSSelectFunctionKey, 0x60,
162 NSPrintFunctionKey, 0x61,
163 NSClearLineFunctionKey, 0x0B,
164 NSExecuteFunctionKey, 0x62,
165 NSInsertFunctionKey, 0x63,
166 NSUndoFunctionKey, 0x65,
167 NSRedoFunctionKey, 0x66,
168 NSMenuFunctionKey, 0x67,
169 NSFindFunctionKey, 0x68,
170 NSHelpFunctionKey, 0x6A,
171 NSBreakFunctionKey, 0x6B,
173 NSF1FunctionKey, 0xBE,
174 NSF2FunctionKey, 0xBF,
175 NSF3FunctionKey, 0xC0,
176 NSF4FunctionKey, 0xC1,
177 NSF5FunctionKey, 0xC2,
178 NSF6FunctionKey, 0xC3,
179 NSF7FunctionKey, 0xC4,
180 NSF8FunctionKey, 0xC5,
181 NSF9FunctionKey, 0xC6,
182 NSF10FunctionKey, 0xC7,
183 NSF11FunctionKey, 0xC8,
184 NSF12FunctionKey, 0xC9,
185 NSF13FunctionKey, 0xCA,
186 NSF14FunctionKey, 0xCB,
187 NSF15FunctionKey, 0xCC,
188 NSF16FunctionKey, 0xCD,
189 NSF17FunctionKey, 0xCE,
190 NSF18FunctionKey, 0xCF,
191 NSF19FunctionKey, 0xD0,
192 NSF20FunctionKey, 0xD1,
193 NSF21FunctionKey, 0xD2,
194 NSF22FunctionKey, 0xD3,
195 NSF23FunctionKey, 0xD4,
196 NSF24FunctionKey, 0xD5,
198 NSBackspaceCharacter, 0x08, /* 8: Not on some KBs. */
199 NSDeleteCharacter, 0xFF, /* 127: Big 'delete' key upper right. */
200 NSDeleteFunctionKey, 0x9F, /* 63272: Del forw key off main array. */
202 NSTabCharacter, 0x09,
203 0x19, 0x09, /* left tab->regular since pass shift */
204 NSCarriageReturnCharacter, 0x0D,
205 NSNewlineCharacter, 0x0D,
206 NSEnterCharacter, 0x8D,
208 0x41|NSNumericPadKeyMask, 0xAE, /* KP_Decimal */
209 0x43|NSNumericPadKeyMask, 0xAA, /* KP_Multiply */
210 0x45|NSNumericPadKeyMask, 0xAB, /* KP_Add */
211 0x4B|NSNumericPadKeyMask, 0xAF, /* KP_Divide */
212 0x4E|NSNumericPadKeyMask, 0xAD, /* KP_Subtract */
213 0x51|NSNumericPadKeyMask, 0xBD, /* KP_Equal */
214 0x52|NSNumericPadKeyMask, 0xB0, /* KP_0 */
215 0x53|NSNumericPadKeyMask, 0xB1, /* KP_1 */
216 0x54|NSNumericPadKeyMask, 0xB2, /* KP_2 */
217 0x55|NSNumericPadKeyMask, 0xB3, /* KP_3 */
218 0x56|NSNumericPadKeyMask, 0xB4, /* KP_4 */
219 0x57|NSNumericPadKeyMask, 0xB5, /* KP_5 */
220 0x58|NSNumericPadKeyMask, 0xB6, /* KP_6 */
221 0x59|NSNumericPadKeyMask, 0xB7, /* KP_7 */
222 0x5B|NSNumericPadKeyMask, 0xB8, /* KP_8 */
223 0x5C|NSNumericPadKeyMask, 0xB9, /* KP_9 */
225 0x1B, 0x1B /* escape */
228 static Lisp_Object Qmodifier_value;
229 Lisp_Object Qalt, Qcontrol, Qhyper, Qmeta, Qsuper;
230 extern Lisp_Object Qcursor_color, Qcursor_type, Qns;
232 static Lisp_Object QUTF8_STRING;
233 static Lisp_Object Qcocoa, Qgnustep;
234 static Lisp_Object Qfile, Qurl;
236 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
237 the maximum font size to NOT antialias. On GNUstep there is currently
238 no way to control this behavior. */
239 float ns_antialias_threshold;
241 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
242 NSString *ns_app_name = @"Emacs"; /* default changed later */
244 /* Display variables */
245 struct ns_display_info *x_display_list; /* Chain of existing displays */
246 long context_menu_value = 0;
249 static struct frame *ns_updating_frame;
250 static NSView *focus_view = NULL;
251 static int ns_window_num = 0;
252 #ifdef NS_IMPL_GNUSTEP
255 static BOOL gsaved = NO;
256 static BOOL ns_fake_keydown = NO;
258 static BOOL ns_menu_bar_is_hidden = NO;
260 /*static int debug_lock = 0; */
263 static BOOL send_appdefined = YES;
264 #define NO_APPDEFINED_DATA (-8)
265 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
266 static NSTimer *timed_entry = 0;
267 static NSTimer *scroll_repeat_entry = nil;
268 static fd_set select_readfds, select_writefds;
269 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
270 static int select_nfds = 0, select_valid = 0;
271 static struct timespec select_timeout = { 0, 0 };
272 static int selfds[2] = { -1, -1 };
273 static pthread_mutex_t select_mutex;
274 static int apploopnr = 0;
275 static NSAutoreleasePool *outerpool;
276 static struct input_event *emacs_event = NULL;
277 static struct input_event *q_event_ptr = NULL;
278 static int n_emacs_events_pending = 0;
279 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
280 *ns_pending_service_args;
281 static BOOL ns_do_open_file = NO;
282 static BOOL ns_last_use_native_fullscreen;
284 /* Non-zero means that a HELP_EVENT has been generated since Emacs
287 static BOOL any_help_event_p = NO;
290 struct input_event *q;
296 static NSString *represented_filename = nil;
297 static struct frame *represented_frame = 0;
301 * State for pending menu activation:
302 * MENU_NONE Normal state
303 * MENU_PENDING A menu has been clicked on, but has been canceled so we can
304 * run lisp to update the menu.
305 * MENU_OPENING Menu is up to date, and the click event is redone so the menu
309 #define MENU_PENDING 1
310 #define MENU_OPENING 2
311 static int menu_will_open_state = MENU_NONE;
313 /* Saved position for menu click. */
314 static CGPoint menu_mouse_point;
317 /* Convert modifiers in a NeXTstep event to emacs style modifiers. */
318 #define NS_FUNCTION_KEY_MASK 0x800000
319 #define NSLeftControlKeyMask (0x000001 | NSControlKeyMask)
320 #define NSRightControlKeyMask (0x002000 | NSControlKeyMask)
321 #define NSLeftCommandKeyMask (0x000008 | NSCommandKeyMask)
322 #define NSRightCommandKeyMask (0x000010 | NSCommandKeyMask)
323 #define NSLeftAlternateKeyMask (0x000020 | NSAlternateKeyMask)
324 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
325 #define EV_MODIFIERS2(flags) \
326 (((flags & NSHelpKeyMask) ? \
327 hyper_modifier : 0) \
328 | (!EQ (ns_right_alternate_modifier, Qleft) && \
329 ((flags & NSRightAlternateKeyMask) \
330 == NSRightAlternateKeyMask) ? \
331 parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
332 | ((flags & NSAlternateKeyMask) ? \
333 parse_solitary_modifier (ns_alternate_modifier) : 0) \
334 | ((flags & NSShiftKeyMask) ? \
335 shift_modifier : 0) \
336 | (!EQ (ns_right_control_modifier, Qleft) && \
337 ((flags & NSRightControlKeyMask) \
338 == NSRightControlKeyMask) ? \
339 parse_solitary_modifier (ns_right_control_modifier) : 0) \
340 | ((flags & NSControlKeyMask) ? \
341 parse_solitary_modifier (ns_control_modifier) : 0) \
342 | ((flags & NS_FUNCTION_KEY_MASK) ? \
343 parse_solitary_modifier (ns_function_modifier) : 0) \
344 | (!EQ (ns_right_command_modifier, Qleft) && \
345 ((flags & NSRightCommandKeyMask) \
346 == NSRightCommandKeyMask) ? \
347 parse_solitary_modifier (ns_right_command_modifier) : 0) \
348 | ((flags & NSCommandKeyMask) ? \
349 parse_solitary_modifier (ns_command_modifier):0))
350 #define EV_MODIFIERS(e) EV_MODIFIERS2 ([e modifierFlags])
352 #define EV_UDMODIFIERS(e) \
353 ((([e type] == NSLeftMouseDown) ? down_modifier : 0) \
354 | (([e type] == NSRightMouseDown) ? down_modifier : 0) \
355 | (([e type] == NSOtherMouseDown) ? down_modifier : 0) \
356 | (([e type] == NSLeftMouseDragged) ? down_modifier : 0) \
357 | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
358 | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
359 | (([e type] == NSLeftMouseUp) ? up_modifier : 0) \
360 | (([e type] == NSRightMouseUp) ? up_modifier : 0) \
361 | (([e type] == NSOtherMouseUp) ? up_modifier : 0))
363 #define EV_BUTTON(e) \
364 ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 : \
365 (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
366 [e buttonNumber] - 1)
368 /* Convert the time field to a timestamp in milliseconds. */
369 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
371 /* This is a piece of code which is common to all the event handling
372 methods. Maybe it should even be a function. */
373 #define EV_TRAILER(e) \
375 XSETFRAME (emacs_event->frame_or_window, emacsframe); \
379 #define EV_TRAILER2(e) \
381 if (e) emacs_event->timestamp = EV_TIMESTAMP (e); \
384 n_emacs_events_pending++; \
385 kbd_buffer_store_event_hold (emacs_event, q_event_ptr); \
388 hold_event (emacs_event); \
389 EVENT_INIT (*emacs_event); \
390 ns_send_appdefined (-1); \
393 /* TODO: get rid of need for these forward declarations */
394 static void ns_condemn_scroll_bars (struct frame *f);
395 static void ns_judge_scroll_bars (struct frame *f);
396 void x_set_frame_alpha (struct frame *f);
399 /* ==========================================================================
403 ========================================================================== */
406 ns_set_represented_filename (NSString* fstr, struct frame *f)
408 represented_filename = [fstr retain];
409 represented_frame = f;
413 ns_init_events (struct input_event* ev)
426 hold_event (struct input_event *event)
428 if (hold_event_q.nr == hold_event_q.cap)
430 if (hold_event_q.cap == 0) hold_event_q.cap = 10;
431 else hold_event_q.cap *= 2;
433 xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
436 hold_event_q.q[hold_event_q.nr++] = *event;
437 /* Make sure ns_read_socket is called, i.e. we have input. */
439 send_appdefined = YES;
443 append2 (Lisp_Object list, Lisp_Object item)
444 /* --------------------------------------------------------------------------
445 Utility to append to a list
446 -------------------------------------------------------------------------- */
448 Lisp_Object array[2];
450 array[1] = list1 (item);
451 return Fnconc (2, &array[0]);
456 ns_etc_directory (void)
457 /* If running as a self-contained app bundle, return as a string the
458 filename of the etc directory, if present; else nil. */
460 NSBundle *bundle = [NSBundle mainBundle];
461 NSString *resourceDir = [bundle resourcePath];
462 NSString *resourcePath;
463 NSFileManager *fileManager = [NSFileManager defaultManager];
466 resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
467 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
469 if (isDir) return [resourcePath UTF8String];
477 /* If running as a self-contained app bundle, return as a path string
478 the filenames of the libexec and bin directories, ie libexec:bin.
479 Otherwise, return nil.
480 Normally, Emacs does not add its own bin/ directory to the PATH.
481 However, a self-contained NS build has a different layout, with
482 bin/ and libexec/ subdirectories in the directory that contains
484 We put libexec first, because init_callproc_1 uses the first
485 element to initialize exec-directory. An alternative would be
486 for init_callproc to check for invocation-directory/libexec.
489 NSBundle *bundle = [NSBundle mainBundle];
490 NSString *resourceDir = [bundle resourcePath];
491 NSString *binDir = [bundle bundlePath];
492 NSString *resourcePath, *resourcePaths;
494 NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
495 NSFileManager *fileManager = [NSFileManager defaultManager];
497 NSEnumerator *pathEnum;
500 range = [resourceDir rangeOfString: @"Contents"];
501 if (range.location != NSNotFound)
503 binDir = [binDir stringByAppendingPathComponent: @"Contents"];
505 binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
509 paths = [binDir stringsByAppendingPaths:
510 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
511 pathEnum = [paths objectEnumerator];
514 while ((resourcePath = [pathEnum nextObject]))
516 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
519 if ([resourcePaths length] > 0)
521 = [resourcePaths stringByAppendingString: pathSeparator];
523 = [resourcePaths stringByAppendingString: resourcePath];
526 if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
534 /* If running as a self-contained app bundle, return as a path string
535 the filenames of the site-lisp and lisp directories.
536 Ie, site-lisp:lisp. Otherwise, return nil. */
538 NSBundle *bundle = [NSBundle mainBundle];
539 NSString *resourceDir = [bundle resourcePath];
540 NSString *resourcePath, *resourcePaths;
541 NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
542 NSFileManager *fileManager = [NSFileManager defaultManager];
544 NSArray *paths = [resourceDir stringsByAppendingPaths:
545 [NSArray arrayWithObjects:
546 @"site-lisp", @"lisp", nil]];
547 NSEnumerator *pathEnum = [paths objectEnumerator];
550 /* Hack to skip site-lisp. */
551 if (no_site_lisp) resourcePath = [pathEnum nextObject];
553 while ((resourcePath = [pathEnum nextObject]))
555 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
558 if ([resourcePaths length] > 0)
560 = [resourcePaths stringByAppendingString: pathSeparator];
562 = [resourcePaths stringByAppendingString: resourcePath];
565 if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
571 ns_timeout (int usecs)
572 /* --------------------------------------------------------------------------
573 Blocking timer utility used by ns_ring_bell
574 -------------------------------------------------------------------------- */
576 struct timespec wakeup = timespec_add (current_timespec (),
577 make_timespec (0, usecs * 1000));
579 /* Keep waiting until past the time wakeup. */
582 struct timespec timeout, now = current_timespec ();
583 if (timespec_cmp (wakeup, now) <= 0)
585 timeout = timespec_sub (wakeup, now);
587 /* Try to wait that long--but we might wake up sooner. */
588 pselect (0, NULL, NULL, NULL, &timeout, NULL);
594 ns_release_object (void *obj)
595 /* --------------------------------------------------------------------------
596 Release an object (callable from C)
597 -------------------------------------------------------------------------- */
604 ns_retain_object (void *obj)
605 /* --------------------------------------------------------------------------
606 Retain an object (callable from C)
607 -------------------------------------------------------------------------- */
614 ns_alloc_autorelease_pool (void)
615 /* --------------------------------------------------------------------------
616 Allocate a pool for temporary objects (callable from C)
617 -------------------------------------------------------------------------- */
619 return [[NSAutoreleasePool alloc] init];
624 ns_release_autorelease_pool (void *pool)
625 /* --------------------------------------------------------------------------
626 Free a pool and temporary objects it refers to (callable from C)
627 -------------------------------------------------------------------------- */
629 ns_release_object (pool);
634 /* ==========================================================================
636 Focus (clipping) and screen update
638 ========================================================================== */
641 // Window constraining
642 // -------------------
644 // To ensure that the windows are not placed under the menu bar, they
645 // are typically moved by the call-back constrainFrameRect. However,
646 // by overriding it, it's possible to inhibit this, leaving the window
647 // in it's original position.
649 // It's possible to hide the menu bar. However, technically, it's only
650 // possible to hide it when the application is active. To ensure that
651 // this work properly, the menu bar and window constraining are
652 // deferred until the application becomes active.
654 // Even though it's not possible to manually move a window above the
655 // top of the screen, it is allowed if it's done programmatically,
656 // when the menu is hidden. This allows the editable area to cover the
657 // full screen height.
662 // Use the following extra files:
665 // ;; Hide menu and place frame slightly above the top of the screen.
666 // (setq ns-auto-hide-menu-bar t)
667 // (set-frame-position (selected-frame) 0 -20)
671 // emacs -Q -l init.el
673 // Result: No menu bar, and the title bar should be above the screen.
679 // Result: Menu bar visible, frame placed immediately below the menu.
683 ns_constrain_all_frames (void)
685 Lisp_Object tail, frame;
687 FOR_EACH_FRAME (tail, frame)
689 struct frame *f = XFRAME (frame);
692 NSView *view = FRAME_NS_VIEW (f);
693 /* This no-op will trigger the default window placing
694 * constraint system. */
695 [[view window] setFrameOrigin:[[view window] frame].origin];
701 /* True, if the menu bar should be hidden. */
704 ns_menu_bar_should_be_hidden (void)
706 return !NILP (ns_auto_hide_menu_bar)
707 && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
711 /* Show or hide the menu bar, based on user setting. */
714 ns_update_auto_hide_menu_bar (void)
719 NSTRACE (ns_update_auto_hide_menu_bar);
721 if (NSApp != nil && [NSApp isActive])
723 // Note, "setPresentationOptions" triggers an error unless the
724 // application is active.
725 BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
727 if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
729 NSApplicationPresentationOptions options
730 = NSApplicationPresentationDefault;
732 if (menu_bar_should_be_hidden)
733 options |= NSApplicationPresentationAutoHideMenuBar
734 | NSApplicationPresentationAutoHideDock;
736 [NSApp setPresentationOptions: options];
738 ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
740 if (!ns_menu_bar_is_hidden)
742 ns_constrain_all_frames ();
753 ns_update_begin (struct frame *f)
754 /* --------------------------------------------------------------------------
755 Prepare for a grouped sequence of drawing calls
756 external (RIF) call; whole frame, called before update_window_begin
757 -------------------------------------------------------------------------- */
759 EmacsView *view = FRAME_NS_VIEW (f);
760 NSTRACE (ns_update_begin);
762 ns_update_auto_hide_menu_bar ();
765 if ([view isFullscreen] && [view fsIsNative])
767 // Fix reappearing tool bar in fullscreen for OSX 10.7
768 BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
769 NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
770 if (! tbar_visible != ! [toolbar isVisible])
771 [toolbar setVisible: tbar_visible];
775 ns_updating_frame = f;
778 /* drawRect may have been called for say the minibuffer, and then clip path
779 is for the minibuffer. But the display engine may draw more because
780 we have set the frame as garbaged. So reset clip path to the whole
785 NSRect r = [view frame];
786 NSRect cr = [[view window] frame];
787 /* If a large frame size is set, r may be larger than the window frame
788 before constrained. In that case don't change the clip path, as we
789 will clear in to the tool bar and title bar. */
791 + FRAME_NS_TITLEBAR_HEIGHT (f)
792 + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
794 bp = [[NSBezierPath bezierPathWithRect: r] retain];
801 #ifdef NS_IMPL_GNUSTEP
802 uRect = NSMakeRect (0, 0, 0, 0);
808 ns_update_window_begin (struct window *w)
809 /* --------------------------------------------------------------------------
810 Prepare for a grouped sequence of drawing calls
811 external (RIF) call; for one window, called after update_begin
812 -------------------------------------------------------------------------- */
814 struct frame *f = XFRAME (WINDOW_FRAME (w));
815 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
817 NSTRACE (ns_update_window_begin);
818 w->output_cursor = w->cursor;
822 if (f == hlinfo->mouse_face_mouse_frame)
824 /* Don't do highlighting for mouse motion during the update. */
825 hlinfo->mouse_face_defer = 1;
827 /* If the frame needs to be redrawn,
828 simply forget about any prior mouse highlighting. */
829 if (FRAME_GARBAGED_P (f))
830 hlinfo->mouse_face_window = Qnil;
832 /* (further code for mouse faces ifdef'd out in other terms elided) */
840 ns_update_window_end (struct window *w, bool cursor_on_p,
841 bool mouse_face_overwritten_p)
842 /* --------------------------------------------------------------------------
843 Finished a grouped sequence of drawing calls
844 external (RIF) call; for one window called before update_end
845 -------------------------------------------------------------------------- */
847 /* note: this fn is nearly identical in all terms */
848 if (!w->pseudo_window_p)
853 display_and_set_cursor (w, 1,
854 w->output_cursor.hpos, w->output_cursor.vpos,
855 w->output_cursor.x, w->output_cursor.y);
857 if (draw_window_fringes (w, 1))
859 if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
860 x_draw_right_divider (w);
862 x_draw_vertical_border (w);
868 /* If a row with mouse-face was overwritten, arrange for
869 frame_up_to_date to redisplay the mouse highlight. */
870 if (mouse_face_overwritten_p)
871 reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
873 NSTRACE (update_window_end);
878 ns_update_end (struct frame *f)
879 /* --------------------------------------------------------------------------
880 Finished a grouped sequence of drawing calls
881 external (RIF) call; for whole frame, called after update_window_end
882 -------------------------------------------------------------------------- */
884 EmacsView *view = FRAME_NS_VIEW (f);
886 /* if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
887 MOUSE_HL_INFO (f)->mouse_face_defer = 0;
892 [[view window] flushWindow];
895 ns_updating_frame = NULL;
896 NSTRACE (ns_update_end);
900 ns_focus (struct frame *f, NSRect *r, int n)
901 /* --------------------------------------------------------------------------
902 Internal: Focus on given frame. During small local updates this is used to
903 draw, however during large updates, ns_update_begin and ns_update_end are
904 called to wrap the whole thing, in which case these calls are stubbed out.
905 Except, on GNUstep, we accumulate the rectangle being drawn into, because
906 the back end won't do this automatically, and will just end up flushing
908 -------------------------------------------------------------------------- */
910 // NSTRACE (ns_focus);
912 fprintf (stderr, "focus: %d", c++);
913 if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
914 fprintf (stderr, "\n"); */
916 if (f != ns_updating_frame)
918 NSView *view = FRAME_NS_VIEW (f);
919 if (view != focus_view)
921 if (focus_view != NULL)
923 [focus_view unlockFocus];
924 [[focus_view window] flushWindow];
931 /*if (view) debug_lock++; */
938 [[NSGraphicsContext currentContext] saveGraphicsState];
940 NSRectClipList (r, 2);
949 ns_unfocus (struct frame *f)
950 /* --------------------------------------------------------------------------
951 Internal: Remove focus on given frame
952 -------------------------------------------------------------------------- */
954 // NSTRACE (ns_unfocus);
958 [[NSGraphicsContext currentContext] restoreGraphicsState];
962 if (f != ns_updating_frame)
964 if (focus_view != NULL)
966 [focus_view unlockFocus];
967 [[focus_view window] flushWindow];
976 ns_clip_to_row (struct window *w, struct glyph_row *row,
977 enum glyph_row_area area, BOOL gc)
978 /* --------------------------------------------------------------------------
979 Internal (but parallels other terms): Focus drawing on given row
980 -------------------------------------------------------------------------- */
982 struct frame *f = XFRAME (WINDOW_FRAME (w));
984 int window_x, window_y, window_width;
986 window_box (w, area, &window_x, &window_y, &window_width, 0);
988 clip_rect.origin.x = window_x;
989 clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
990 clip_rect.origin.y = max (clip_rect.origin.y, window_y);
991 clip_rect.size.width = window_width;
992 clip_rect.size.height = row->visible_height;
994 ns_focus (f, &clip_rect, 1);
999 ns_ring_bell (struct frame *f)
1000 /* --------------------------------------------------------------------------
1002 -------------------------------------------------------------------------- */
1004 NSTRACE (ns_ring_bell);
1007 NSAutoreleasePool *pool;
1008 struct frame *frame = SELECTED_FRAME ();
1012 pool = [[NSAutoreleasePool alloc] init];
1014 view = FRAME_NS_VIEW (frame);
1018 NSPoint dim = NSMakePoint (128, 128);
1021 r.origin.x += (r.size.width - dim.x) / 2;
1022 r.origin.y += (r.size.height - dim.y) / 2;
1023 r.size.width = dim.x;
1024 r.size.height = dim.y;
1025 surr = NSInsetRect (r, -2, -2);
1026 ns_focus (frame, &surr, 1);
1027 [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
1028 [ns_lookup_indexed_color (NS_FACE_FOREGROUND
1029 (FRAME_DEFAULT_FACE (frame)), frame) set];
1031 [[view window] flushWindow];
1032 ns_timeout (150000);
1033 [[view window] restoreCachedImage];
1034 [[view window] flushWindow];
1046 /* ==========================================================================
1048 Frame / window manager related functions
1050 ========================================================================== */
1054 ns_raise_frame (struct frame *f)
1055 /* --------------------------------------------------------------------------
1056 Bring window to foreground and make it active
1057 -------------------------------------------------------------------------- */
1060 check_window_system (f);
1061 view = FRAME_NS_VIEW (f);
1063 if (FRAME_VISIBLE_P (f))
1064 [[view window] makeKeyAndOrderFront: NSApp];
1070 ns_lower_frame (struct frame *f)
1071 /* --------------------------------------------------------------------------
1073 -------------------------------------------------------------------------- */
1076 check_window_system (f);
1077 view = FRAME_NS_VIEW (f);
1079 [[view window] orderBack: NSApp];
1085 ns_frame_raise_lower (struct frame *f, bool raise)
1086 /* --------------------------------------------------------------------------
1088 -------------------------------------------------------------------------- */
1090 NSTRACE (ns_frame_raise_lower);
1100 ns_frame_rehighlight (struct frame *frame)
1101 /* --------------------------------------------------------------------------
1102 External (hook): called on things like window switching within frame
1103 -------------------------------------------------------------------------- */
1105 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1106 struct frame *old_highlight = dpyinfo->x_highlight_frame;
1108 NSTRACE (ns_frame_rehighlight);
1109 if (dpyinfo->x_focus_frame)
1111 dpyinfo->x_highlight_frame
1112 = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1113 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1114 : dpyinfo->x_focus_frame);
1115 if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1117 fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1118 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1122 dpyinfo->x_highlight_frame = 0;
1124 if (dpyinfo->x_highlight_frame &&
1125 dpyinfo->x_highlight_frame != old_highlight)
1129 x_update_cursor (old_highlight, 1);
1130 x_set_frame_alpha (old_highlight);
1132 if (dpyinfo->x_highlight_frame)
1134 x_update_cursor (dpyinfo->x_highlight_frame, 1);
1135 x_set_frame_alpha (dpyinfo->x_highlight_frame);
1142 x_make_frame_visible (struct frame *f)
1143 /* --------------------------------------------------------------------------
1144 External: Show the window (X11 semantics)
1145 -------------------------------------------------------------------------- */
1147 NSTRACE (x_make_frame_visible);
1148 /* XXX: at some points in past this was not needed, as the only place that
1149 called this (frame.c:Fraise_frame ()) also called raise_lower;
1150 if this ends up the case again, comment this out again. */
1151 if (!FRAME_VISIBLE_P (f))
1153 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1155 SET_FRAME_VISIBLE (f, 1);
1158 /* Making a new frame from a fullscreen frame will make the new frame
1159 fullscreen also. So skip handleFS as this will print an error. */
1160 if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1161 && [view isFullscreen])
1164 if (f->want_fullscreen != FULLSCREEN_NONE)
1175 x_make_frame_invisible (struct frame *f)
1176 /* --------------------------------------------------------------------------
1177 External: Hide the window (X11 semantics)
1178 -------------------------------------------------------------------------- */
1181 NSTRACE (x_make_frame_invisible);
1182 check_window_system (f);
1183 view = FRAME_NS_VIEW (f);
1184 [[view window] orderOut: NSApp];
1185 SET_FRAME_VISIBLE (f, 0);
1186 SET_FRAME_ICONIFIED (f, 0);
1191 x_iconify_frame (struct frame *f)
1192 /* --------------------------------------------------------------------------
1193 External: Iconify window
1194 -------------------------------------------------------------------------- */
1197 struct ns_display_info *dpyinfo;
1199 NSTRACE (x_iconify_frame);
1200 check_window_system (f);
1201 view = FRAME_NS_VIEW (f);
1202 dpyinfo = FRAME_DISPLAY_INFO (f);
1204 if (dpyinfo->x_highlight_frame == f)
1205 dpyinfo->x_highlight_frame = 0;
1207 if ([[view window] windowNumber] <= 0)
1209 /* the window is still deferred. Make it very small, bring it
1210 on screen and order it out. */
1211 NSRect s = { { 100, 100}, {0, 0} };
1213 t = [[view window] frame];
1214 [[view window] setFrame: s display: NO];
1215 [[view window] orderBack: NSApp];
1216 [[view window] orderOut: NSApp];
1217 [[view window] setFrame: t display: NO];
1219 [[view window] miniaturize: NSApp];
1222 /* Free X resources of frame F. */
1225 x_free_frame_resources (struct frame *f)
1228 struct ns_display_info *dpyinfo;
1229 Mouse_HLInfo *hlinfo;
1231 NSTRACE (x_free_frame_resources);
1232 check_window_system (f);
1233 view = FRAME_NS_VIEW (f);
1234 dpyinfo = FRAME_DISPLAY_INFO (f);
1235 hlinfo = MOUSE_HL_INFO (f);
1237 [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1241 free_frame_menubar (f);
1242 free_frame_faces (f);
1244 if (f == dpyinfo->x_focus_frame)
1245 dpyinfo->x_focus_frame = 0;
1246 if (f == dpyinfo->x_highlight_frame)
1247 dpyinfo->x_highlight_frame = 0;
1248 if (f == hlinfo->mouse_face_mouse_frame)
1249 reset_mouse_highlight (hlinfo);
1251 if (f->output_data.ns->miniimage != nil)
1252 [f->output_data.ns->miniimage release];
1254 [[view window] close];
1257 xfree (f->output_data.ns);
1263 x_destroy_window (struct frame *f)
1264 /* --------------------------------------------------------------------------
1265 External: Delete the window
1266 -------------------------------------------------------------------------- */
1268 NSTRACE (x_destroy_window);
1269 check_window_system (f);
1270 x_free_frame_resources (f);
1276 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1277 /* --------------------------------------------------------------------------
1278 External: Position the window
1279 -------------------------------------------------------------------------- */
1281 NSView *view = FRAME_NS_VIEW (f);
1282 NSArray *screens = [NSScreen screens];
1283 NSScreen *fscreen = [screens objectAtIndex: 0];
1284 NSScreen *screen = [[view window] screen];
1286 NSTRACE (x_set_offset);
1293 if (view != nil && screen && fscreen)
1295 f->left_pos = f->size_hint_flags & XNegative
1296 ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1298 /* We use visibleFrame here to take menu bar into account.
1299 Ideally we should also adjust left/top with visibleFrame.origin. */
1301 f->top_pos = f->size_hint_flags & YNegative
1302 ? ([screen visibleFrame].size.height + f->top_pos
1303 - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1304 - FRAME_TOOLBAR_HEIGHT (f))
1306 #ifdef NS_IMPL_GNUSTEP
1307 if (f->left_pos < 100)
1308 f->left_pos = 100; /* don't overlap menu */
1310 /* Constrain the setFrameTopLeftPoint so we don't move behind the
1312 [[view window] setFrameTopLeftPoint:
1313 NSMakePoint (SCREENMAXBOUND (f->left_pos),
1314 SCREENMAXBOUND ([fscreen frame].size.height
1315 - NS_TOP_POS (f)))];
1316 f->size_hint_flags &= ~(XNegative|YNegative);
1324 x_set_window_size (struct frame *f,
1325 bool change_gravity,
1329 /* --------------------------------------------------------------------------
1330 Adjust window pixel size based on given character grid size
1331 Impl is a bit more complex than other terms, need to do some
1333 -------------------------------------------------------------------------- */
1335 EmacsView *view = FRAME_NS_VIEW (f);
1336 NSWindow *window = [view window];
1337 NSRect wr = [window frame];
1338 int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1339 int pixelwidth, pixelheight;
1342 NSTRACE (x_set_window_size);
1347 /*fprintf (stderr, "\tsetWindowSize: %d x %d, pixelwise %d, font size %d x %d\n", width, height, pixelwise, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f));*/
1353 pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1354 pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1355 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
1356 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelheight);
1360 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, width);
1361 pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1366 /* If we have a toolbar, take its height into account. */
1367 if (tb && ! [view isFullscreen])
1369 /* NOTE: previously this would generate wrong result if toolbar not
1370 yet displayed and fixing toolbar_height=32 helped, but
1371 now (200903) seems no longer needed */
1372 FRAME_TOOLBAR_HEIGHT (f) =
1373 NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1374 - FRAME_NS_TITLEBAR_HEIGHT (f);
1375 #ifdef NS_IMPL_GNUSTEP
1376 FRAME_TOOLBAR_HEIGHT (f) -= 3;
1380 FRAME_TOOLBAR_HEIGHT (f) = 0;
1382 wr.size.width = pixelwidth + f->border_width;
1383 wr.size.height = pixelheight;
1384 if (! [view isFullscreen])
1385 wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1386 + FRAME_TOOLBAR_HEIGHT (f);
1388 /* Do not try to constrain to this screen. We may have multiple
1389 screens, and want Emacs to span those. Constraining to screen
1390 prevents that, and that is not nice to the user. */
1391 if (f->output_data.ns->zooming)
1392 f->output_data.ns->zooming = 0;
1394 wr.origin.y += FRAME_PIXEL_HEIGHT (f) - pixelheight;
1396 [view setRows: rows andColumns: cols];
1397 [window setFrame: wr display: YES];
1399 /* This is a trick to compensate for Emacs' managing the scrollbar area
1400 as a fixed number of standard character columns. Instead of leaving
1401 blank space for the extra, we chopped it off above. Now for
1402 left-hand scrollbars, we shift all rendering to the left by the
1403 difference between the real width and Emacs' imagined one. For
1404 right-hand bars, don't worry about it since the extra is never used.
1405 (Obviously doesn't work for vertically split windows tho..) */
1407 NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1408 ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1409 - NS_SCROLL_BAR_WIDTH (f), 0)
1410 : NSMakePoint (0, 0);
1411 [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1412 [view setBoundsOrigin: origin];
1415 change_frame_size (f, width, height, 0, 1, 0, pixelwise);
1416 /* SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1418 mark_window_cursors_off (XWINDOW (f->root_window));
1419 cancel_mouse_face (f);
1423 do_pending_window_change (0);
1428 ns_fullscreen_hook (struct frame *f)
1430 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1432 if (!FRAME_VISIBLE_P (f))
1435 if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
1437 /* Old style fs don't initiate correctly if created from
1438 init/default-frame alist, so use a timer (not nice...).
1440 [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
1441 selector: @selector (handleFS)
1442 userInfo: nil repeats: NO];
1451 /* ==========================================================================
1455 ========================================================================== */
1459 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1461 struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1462 if (idx < 1 || idx >= color_table->avail)
1464 return color_table->colors[idx];
1469 ns_index_color (NSColor *color, struct frame *f)
1471 struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1475 if (!color_table->colors)
1477 color_table->size = NS_COLOR_CAPACITY;
1478 color_table->avail = 1; /* skip idx=0 as marker */
1479 color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1480 color_table->colors[0] = nil;
1481 color_table->empty_indices = [[NSMutableSet alloc] init];
1484 /* Do we already have this color? */
1485 for (i = 1; i < color_table->avail; i++)
1486 if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1489 if ([color_table->empty_indices count] > 0)
1491 NSNumber *index = [color_table->empty_indices anyObject];
1492 [color_table->empty_indices removeObject: index];
1493 idx = [index unsignedLongValue];
1497 if (color_table->avail == color_table->size)
1498 color_table->colors =
1499 xpalloc (color_table->colors, &color_table->size, 1,
1500 min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1501 idx = color_table->avail++;
1504 color_table->colors[idx] = color;
1506 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1512 ns_free_indexed_color (unsigned long idx, struct frame *f)
1514 struct ns_color_table *color_table;
1521 color_table = FRAME_DISPLAY_INFO (f)->color_table;
1523 if (idx <= 0 || idx >= color_table->size) {
1524 message1 ("ns_free_indexed_color: Color index out of range.\n");
1528 index = [NSNumber numberWithUnsignedInt: idx];
1529 if ([color_table->empty_indices containsObject: index]) {
1530 message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1534 color = color_table->colors[idx];
1536 color_table->colors[idx] = nil;
1537 [color_table->empty_indices addObject: index];
1538 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1543 ns_get_color (const char *name, NSColor **col)
1544 /* --------------------------------------------------------------------------
1546 -------------------------------------------------------------------------- */
1547 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1548 X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1549 See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1552 static char hex[20];
1554 float r = -1.0, g, b;
1555 NSString *nsname = [NSString stringWithUTF8String: name];
1557 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1560 if ([nsname isEqualToString: @"ns_selection_bg_color"])
1562 #ifdef NS_IMPL_COCOA
1563 NSString *defname = [[NSUserDefaults standardUserDefaults]
1564 stringForKey: @"AppleHighlightColor"];
1569 if ((new = [NSColor selectedTextBackgroundColor]) != nil)
1571 *col = [new colorUsingDefaultColorSpace];
1576 nsname = NS_SELECTION_BG_COLOR_DEFAULT;
1578 name = [nsname UTF8String];
1580 else if ([nsname isEqualToString: @"ns_selection_fg_color"])
1582 /* NOTE: OSX applications normally don't set foreground selection, but
1583 text may be unreadable if we don't.
1585 if ((new = [NSColor selectedTextColor]) != nil)
1587 *col = [new colorUsingDefaultColorSpace];
1592 nsname = NS_SELECTION_FG_COLOR_DEFAULT;
1593 name = [nsname UTF8String];
1596 /* First, check for some sort of numeric specification. */
1599 if (name[0] == '0' || name[0] == '1' || name[0] == '.') /* RGB decimal */
1601 NSScanner *scanner = [NSScanner scannerWithString: nsname];
1602 [scanner scanFloat: &r];
1603 [scanner scanFloat: &g];
1604 [scanner scanFloat: &b];
1606 else if (!strncmp(name, "rgb:", 4)) /* A newer X11 format -- rgb:r/g/b */
1607 scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
1608 else if (name[0] == '#') /* An old X11 format; convert to newer */
1610 int len = (strlen(name) - 1);
1611 int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1613 scaling = strlen(name+start) / 3;
1614 for (i = 0; i < 3; i++)
1615 sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
1616 name + start + i * scaling);
1617 hex[3 * (scaling + 1) - 1] = '\0';
1623 float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1624 if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1634 *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
1639 /* Otherwise, color is expected to be from a list */
1641 NSEnumerator *lenum, *cenum;
1645 #ifdef NS_IMPL_GNUSTEP
1646 /* XXX: who is wrong, the requestor or the implementation? */
1647 if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1649 nsname = @"highlightColor";
1652 lenum = [[NSColorList availableColorLists] objectEnumerator];
1653 while ( (clist = [lenum nextObject]) && new == nil)
1655 cenum = [[clist allKeys] objectEnumerator];
1656 while ( (name = [cenum nextObject]) && new == nil )
1658 if ([name compare: nsname
1659 options: NSCaseInsensitiveSearch] == NSOrderedSame )
1660 new = [clist colorWithKey: name];
1666 *col = [new colorUsingDefaultColorSpace];
1673 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1674 /* --------------------------------------------------------------------------
1675 Convert a Lisp string object to a NS color
1676 -------------------------------------------------------------------------- */
1678 NSTRACE (ns_lisp_to_color);
1679 if (STRINGP (color))
1680 return ns_get_color (SSDATA (color), col);
1681 else if (SYMBOLP (color))
1682 return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
1688 ns_color_to_lisp (NSColor *col)
1689 /* --------------------------------------------------------------------------
1690 Convert a color to a lisp string with the RGB equivalent
1691 -------------------------------------------------------------------------- */
1693 EmacsCGFloat red, green, blue, alpha, gray;
1696 NSTRACE (ns_color_to_lisp);
1699 if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1701 if ((str =[[col colorNameComponent] UTF8String]))
1704 return build_string ((char *)str);
1707 [[col colorUsingDefaultColorSpace]
1708 getRed: &red green: &green blue: &blue alpha: &alpha];
1709 if (red == green && red == blue)
1711 [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1712 getWhite: &gray alpha: &alpha];
1713 snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1714 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1716 return build_string (buf);
1719 snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1720 lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1723 return build_string (buf);
1728 ns_query_color(void *col, XColor *color_def, int setPixel)
1729 /* --------------------------------------------------------------------------
1730 Get ARGB values out of NSColor col and put them into color_def.
1731 If setPixel, set the pixel to a concatenated version.
1732 and set color_def pixel to the resulting index.
1733 -------------------------------------------------------------------------- */
1735 EmacsCGFloat r, g, b, a;
1737 [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1738 color_def->red = r * 65535;
1739 color_def->green = g * 65535;
1740 color_def->blue = b * 65535;
1742 if (setPixel == YES)
1744 = ARGB_TO_ULONG((int)(a*255),
1745 (int)(r*255), (int)(g*255), (int)(b*255));
1750 ns_defined_color (struct frame *f,
1755 /* --------------------------------------------------------------------------
1756 Return true if named color found, and set color_def rgb accordingly.
1757 If makeIndex and alloc are nonzero put the color in the color_table,
1758 and set color_def pixel to the resulting index.
1759 If makeIndex is zero, set color_def pixel to ARGB.
1760 Return false if not found
1761 -------------------------------------------------------------------------- */
1764 NSTRACE (ns_defined_color);
1767 if (ns_get_color (name, &col) != 0) /* Color not found */
1772 if (makeIndex && alloc)
1773 color_def->pixel = ns_index_color (col, f);
1774 ns_query_color (col, color_def, !makeIndex);
1781 x_set_frame_alpha (struct frame *f)
1782 /* --------------------------------------------------------------------------
1783 change the entire-frame transparency
1784 -------------------------------------------------------------------------- */
1786 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
1788 double alpha_min = 1.0;
1790 if (dpyinfo->x_highlight_frame == f)
1791 alpha = f->alpha[0];
1793 alpha = f->alpha[1];
1795 if (FLOATP (Vframe_alpha_lower_limit))
1796 alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1797 else if (INTEGERP (Vframe_alpha_lower_limit))
1798 alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1802 else if (1.0 < alpha)
1804 else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1807 #ifdef NS_IMPL_COCOA
1809 EmacsView *view = FRAME_NS_VIEW (f);
1810 [[view window] setAlphaValue: alpha];
1816 /* ==========================================================================
1820 ========================================================================== */
1824 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1825 /* --------------------------------------------------------------------------
1826 Programmatically reposition mouse pointer in pixel coordinates
1827 -------------------------------------------------------------------------- */
1829 NSTRACE (frame_set_mouse_pixel_position);
1832 /* FIXME: this does not work, and what about GNUstep? */
1833 #ifdef NS_IMPL_COCOA
1834 [FRAME_NS_VIEW (f) lockFocus];
1835 PSsetmouse ((float)pix_x, (float)pix_y);
1836 [FRAME_NS_VIEW (f) unlockFocus];
1842 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
1843 /* ------------------------------------------------------------------------
1844 Called by EmacsView on mouseMovement events. Passes on
1845 to emacs mainstream code if we moved off of a rect of interest
1846 known as last_mouse_glyph.
1847 ------------------------------------------------------------------------ */
1849 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1852 // NSTRACE (note_mouse_movement);
1854 dpyinfo->last_mouse_motion_frame = frame;
1855 r = &dpyinfo->last_mouse_glyph;
1857 /* Note, this doesn't get called for enter/leave, since we don't have a
1858 position. Those are taken care of in the corresponding NSView methods. */
1860 /* has movement gone beyond last rect we were tracking? */
1861 if (x < r->origin.x || x >= r->origin.x + r->size.width
1862 || y < r->origin.y || y >= r->origin.y + r->size.height)
1864 ns_update_begin (frame);
1865 frame->mouse_moved = 1;
1866 note_mouse_highlight (frame, x, y);
1867 remember_mouse_glyph (frame, x, y, r);
1868 ns_update_end (frame);
1877 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1878 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1880 /* --------------------------------------------------------------------------
1881 External (hook): inform emacs about mouse position and hit parts.
1882 If a scrollbar is being dragged, set bar_window, part, x, y, time.
1883 x & y should be position in the scrollbar (the whole bar, not the handle)
1884 and length of scrollbar respectively
1885 -------------------------------------------------------------------------- */
1889 Lisp_Object frame, tail;
1891 struct ns_display_info *dpyinfo;
1893 NSTRACE (ns_mouse_position);
1897 fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1901 dpyinfo = FRAME_DISPLAY_INFO (*fp);
1905 /* Clear the mouse-moved flag for every frame on this display. */
1906 FOR_EACH_FRAME (tail, frame)
1907 if (FRAME_NS_P (XFRAME (frame))
1908 && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1909 XFRAME (frame)->mouse_moved = 0;
1911 dpyinfo->last_mouse_scroll_bar = nil;
1912 if (dpyinfo->last_mouse_frame
1913 && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
1914 f = dpyinfo->last_mouse_frame;
1916 f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame : SELECTED_FRAME ();
1918 if (f && FRAME_NS_P (f))
1920 view = FRAME_NS_VIEW (*fp);
1922 position = [[view window] mouseLocationOutsideOfEventStream];
1923 position = [view convertPoint: position fromView: nil];
1924 remember_mouse_glyph (f, position.x, position.y,
1925 &dpyinfo->last_mouse_glyph);
1926 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1928 if (bar_window) *bar_window = Qnil;
1929 if (part) *part = scroll_bar_above_handle;
1931 if (x) XSETINT (*x, lrint (position.x));
1932 if (y) XSETINT (*y, lrint (position.y));
1934 *time = dpyinfo->last_mouse_movement_time;
1943 ns_frame_up_to_date (struct frame *f)
1944 /* --------------------------------------------------------------------------
1945 External (hook): Fix up mouse highlighting right after a full update.
1946 Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
1947 -------------------------------------------------------------------------- */
1949 NSTRACE (ns_frame_up_to_date);
1953 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1954 if (f == hlinfo->mouse_face_mouse_frame)
1958 note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1959 hlinfo->mouse_face_mouse_x,
1960 hlinfo->mouse_face_mouse_y);
1969 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1970 /* --------------------------------------------------------------------------
1971 External (RIF): set frame mouse pointer type.
1972 -------------------------------------------------------------------------- */
1974 NSTRACE (ns_define_frame_cursor);
1975 if (FRAME_POINTER_TYPE (f) != cursor)
1977 EmacsView *view = FRAME_NS_VIEW (f);
1978 FRAME_POINTER_TYPE (f) = cursor;
1979 [[view window] invalidateCursorRectsForView: view];
1980 /* Redisplay assumes this function also draws the changed frame
1981 cursor, but this function doesn't, so do it explicitly. */
1982 x_update_cursor (f, 1);
1988 /* ==========================================================================
1992 ========================================================================== */
1996 ns_convert_key (unsigned code)
1997 /* --------------------------------------------------------------------------
1998 Internal call used by NSView-keyDown.
1999 -------------------------------------------------------------------------- */
2001 const unsigned last_keysym = ARRAYELTS (convert_ns_to_X_keysym);
2003 /* An array would be faster, but less easy to read. */
2004 for (keysym = 0; keysym < last_keysym; keysym += 2)
2005 if (code == convert_ns_to_X_keysym[keysym])
2006 return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
2008 /* if decide to use keyCode and Carbon table, use this line:
2009 return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
2014 x_get_keysym_name (int keysym)
2015 /* --------------------------------------------------------------------------
2016 Called by keyboard.c. Not sure if the return val is important, except
2018 -------------------------------------------------------------------------- */
2020 static char value[16];
2021 NSTRACE (x_get_keysym_name);
2022 sprintf (value, "%d", keysym);
2028 /* ==========================================================================
2030 Block drawing operations
2032 ========================================================================== */
2036 ns_redraw_scroll_bars (struct frame *f)
2040 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2041 NSTRACE (ns_redraw_scroll_bars);
2042 for (i =[subviews count]-1; i >= 0; i--)
2044 view = [subviews objectAtIndex: i];
2045 if (![view isKindOfClass: [EmacsScroller class]]) continue;
2052 ns_clear_frame (struct frame *f)
2053 /* --------------------------------------------------------------------------
2054 External (hook): Erase the entire frame
2055 -------------------------------------------------------------------------- */
2057 NSView *view = FRAME_NS_VIEW (f);
2060 NSTRACE (ns_clear_frame);
2062 /* comes on initial frame because we have
2063 after-make-frame-functions = select-frame */
2064 if (!FRAME_DEFAULT_FACE (f))
2067 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2072 ns_focus (f, &r, 1);
2073 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2077 /* as of 2006/11 or so this is now needed */
2078 ns_redraw_scroll_bars (f);
2084 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2085 /* --------------------------------------------------------------------------
2086 External (RIF): Clear section of frame
2087 -------------------------------------------------------------------------- */
2089 NSRect r = NSMakeRect (x, y, width, height);
2090 NSView *view = FRAME_NS_VIEW (f);
2091 struct face *face = FRAME_DEFAULT_FACE (f);
2096 NSTRACE (ns_clear_frame_area);
2098 r = NSIntersectionRect (r, [view frame]);
2099 ns_focus (f, &r, 1);
2100 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2110 ns_scroll_run (struct window *w, struct run *run)
2111 /* --------------------------------------------------------------------------
2112 External (RIF): Insert or delete n lines at line vpos
2113 -------------------------------------------------------------------------- */
2115 struct frame *f = XFRAME (w->frame);
2116 int x, y, width, height, from_y, to_y, bottom_y;
2118 NSTRACE (ns_scroll_run);
2120 /* begin copy from other terms */
2121 /* Get frame-relative bounding box of the text display area of W,
2122 without mode lines. Include in this box the left and right
2124 window_box (w, ANY_AREA, &x, &y, &width, &height);
2126 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2127 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2128 bottom_y = y + height;
2132 /* Scrolling up. Make sure we don't copy part of the mode
2133 line at the bottom. */
2134 if (from_y + run->height > bottom_y)
2135 height = bottom_y - from_y;
2137 height = run->height;
2141 /* Scrolling down. Make sure we don't copy over the mode line.
2143 if (to_y + run->height > bottom_y)
2144 height = bottom_y - to_y;
2146 height = run->height;
2148 /* end copy from other terms */
2158 NSRect srcRect = NSMakeRect (x, from_y, width, height);
2159 NSRect dstRect = NSMakeRect (x, to_y, width, height);
2160 NSPoint dstOrigin = NSMakePoint (x, to_y);
2162 ns_focus (f, &dstRect, 1);
2163 NSCopyBits (0, srcRect , dstOrigin);
2172 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2173 /* --------------------------------------------------------------------------
2174 External (RIF): preparatory to fringe update after text was updated
2175 -------------------------------------------------------------------------- */
2180 NSTRACE (ns_after_update_window_line);
2182 /* begin copy from other terms */
2185 if (!desired_row->mode_line_p && !w->pseudo_window_p)
2186 desired_row->redraw_fringe_bitmaps_p = 1;
2188 /* When a window has disappeared, make sure that no rest of
2189 full-width rows stays visible in the internal border. */
2190 if (windows_or_buffers_changed
2191 && desired_row->full_width_p
2192 && (f = XFRAME (w->frame),
2193 width = FRAME_INTERNAL_BORDER_WIDTH (f),
2195 && (height = desired_row->visible_height,
2198 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2201 ns_clear_frame_area (f, 0, y, width, height);
2202 ns_clear_frame_area (f,
2203 FRAME_PIXEL_WIDTH (f) - width,
2211 ns_shift_glyphs_for_insert (struct frame *f,
2212 int x, int y, int width, int height,
2214 /* --------------------------------------------------------------------------
2215 External (RIF): copy an area horizontally, don't worry about clearing src
2216 -------------------------------------------------------------------------- */
2218 NSRect srcRect = NSMakeRect (x, y, width, height);
2219 NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2220 NSPoint dstOrigin = dstRect.origin;
2222 NSTRACE (ns_shift_glyphs_for_insert);
2224 ns_focus (f, &dstRect, 1);
2225 NSCopyBits (0, srcRect, dstOrigin);
2231 /* ==========================================================================
2233 Character encoding and metrics
2235 ========================================================================== */
2239 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2240 /* --------------------------------------------------------------------------
2241 External (RIF); compute left/right overhang of whole string and set in s
2242 -------------------------------------------------------------------------- */
2244 struct font *font = s->font;
2248 struct font_metrics metrics;
2249 unsigned int codes[2];
2250 codes[0] = *(s->char2b);
2251 codes[1] = *(s->char2b + s->nchars - 1);
2253 font->driver->text_extents (font, codes, 2, &metrics);
2254 s->left_overhang = -metrics.lbearing;
2256 = metrics.rbearing > metrics.width
2257 ? metrics.rbearing - metrics.width : 0;
2261 s->left_overhang = 0;
2262 if (EQ (font->driver->type, Qns))
2263 s->right_overhang = ((struct nsfont_info *)font)->ital ?
2264 FONT_HEIGHT (font) * 0.2 : 0;
2266 s->right_overhang = 0;
2272 /* ==========================================================================
2274 Fringe and cursor drawing
2276 ========================================================================== */
2279 extern int max_used_fringe_bitmap;
2281 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2282 struct draw_fringe_bitmap_params *p)
2283 /* --------------------------------------------------------------------------
2284 External (RIF); fringe-related
2285 -------------------------------------------------------------------------- */
2287 struct frame *f = XFRAME (WINDOW_FRAME (w));
2288 struct face *face = p->face;
2289 static EmacsImage **bimgs = NULL;
2290 static int nBimgs = 0;
2292 /* grow bimgs if needed */
2293 if (nBimgs < max_used_fringe_bitmap)
2295 bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2296 memset (bimgs + nBimgs, 0,
2297 (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2298 nBimgs = max_used_fringe_bitmap;
2301 /* Must clip because of partially visible lines. */
2302 ns_clip_to_row (w, row, ANY_AREA, YES);
2306 int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2308 if (bx >= 0 && nx > 0)
2310 NSRect r = NSMakeRect (bx, by, nx, ny);
2312 [ns_lookup_indexed_color (face->background, f) set];
2319 NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2320 EmacsImage *img = bimgs[p->which - 1];
2324 unsigned short *bits = p->bits + p->dh;
2327 unsigned char *cbits = xmalloc (len);
2329 for (i = 0; i < len; i++)
2330 cbits[i] = ~(bits[i] & 0xff);
2331 img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2333 bimgs[p->which - 1] = img;
2338 /* Since we composite the bitmap instead of just blitting it, we need
2339 to erase the whole background. */
2340 [ns_lookup_indexed_color(face->background, f) set];
2346 bm_color = ns_lookup_indexed_color(face->foreground, f);
2347 else if (p->overlay_p)
2348 bm_color = ns_lookup_indexed_color(face->background, f);
2350 bm_color = f->output_data.ns->cursor_color;
2351 [img setXBMColor: bm_color];
2354 #ifdef NS_IMPL_COCOA
2356 fromRect: NSZeroRect
2357 operation: NSCompositeSourceOver
2363 NSPoint pt = r.origin;
2365 [img compositeToPoint: pt operation: NSCompositeSourceOver];
2374 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2375 int x, int y, enum text_cursor_kinds cursor_type,
2376 int cursor_width, bool on_p, bool active_p)
2377 /* --------------------------------------------------------------------------
2378 External call (RIF): draw cursor.
2379 Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2380 -------------------------------------------------------------------------- */
2383 int fx, fy, h, cursor_height;
2384 struct frame *f = WINDOW_XFRAME (w);
2385 struct glyph *phys_cursor_glyph;
2386 struct glyph *cursor_glyph;
2388 NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2390 /* If cursor is out of bounds, don't draw garbage. This can happen
2391 in mini-buffer windows when switching between echo area glyphs
2394 NSTRACE (dumpcursor);
2399 w->phys_cursor_type = cursor_type;
2400 w->phys_cursor_on_p = on_p;
2402 if (cursor_type == NO_CURSOR)
2404 w->phys_cursor_width = 0;
2408 if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2410 if (glyph_row->exact_window_width_line_p
2411 && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2413 glyph_row->cursor_in_fringe_p = 1;
2414 draw_fringe_bitmap (w, glyph_row, 0);
2419 /* We draw the cursor (with NSRectFill), then draw the glyph on top
2420 (other terminals do it the other way round). We must set
2421 w->phys_cursor_width to the cursor width. For bar cursors, that
2422 is CURSOR_WIDTH; for box cursors, it is the glyph width. */
2423 get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2425 /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2426 to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2427 if (cursor_type == BAR_CURSOR)
2429 if (cursor_width < 1)
2430 cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2431 w->phys_cursor_width = cursor_width;
2433 /* If we have an HBAR, "cursor_width" MAY specify height. */
2434 else if (cursor_type == HBAR_CURSOR)
2436 cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2437 if (cursor_height > glyph_row->height)
2438 cursor_height = glyph_row->height;
2439 if (h > cursor_height) // Cursor smaller than line height, move down
2440 fy += h - cursor_height;
2444 r.origin.x = fx, r.origin.y = fy;
2446 r.size.width = w->phys_cursor_width;
2448 /* TODO: only needed in rare cases with last-resort font in HELLO..
2449 should we do this more efficiently? */
2450 ns_clip_to_row (w, glyph_row, ANY_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
2453 face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2454 if (face && NS_FACE_BACKGROUND (face)
2455 == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2457 [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2458 hollow_color = FRAME_CURSOR_COLOR (f);
2461 [FRAME_CURSOR_COLOR (f) set];
2463 #ifdef NS_IMPL_COCOA
2464 /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2465 atomic. Cleaner ways of doing this should be investigated.
2466 One way would be to set a global variable DRAWING_CURSOR
2467 when making the call to draw_phys..(), don't focus in that
2468 case, then move the ns_unfocus() here after that call. */
2469 NSDisableScreenUpdates ();
2472 switch (cursor_type)
2476 case FILLED_BOX_CURSOR:
2479 case HOLLOW_BOX_CURSOR:
2482 NSRectFill (NSInsetRect (r, 1, 1));
2483 [FRAME_CURSOR_COLOR (f) set];
2490 /* If the character under cursor is R2L, draw the bar cursor
2491 on the right of its glyph, rather than on the left. */
2492 cursor_glyph = get_phys_cursor_glyph (w);
2493 if ((cursor_glyph->resolved_level & 1) != 0)
2494 s.origin.x += cursor_glyph->pixel_width - s.size.width;
2501 /* draw the character under the cursor */
2502 if (cursor_type != NO_CURSOR)
2503 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2505 #ifdef NS_IMPL_COCOA
2506 NSEnableScreenUpdates ();
2513 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2514 /* --------------------------------------------------------------------------
2515 External (RIF): Draw a vertical line.
2516 -------------------------------------------------------------------------- */
2518 struct frame *f = XFRAME (WINDOW_FRAME (w));
2520 NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2522 NSTRACE (ns_draw_vertical_window_border);
2524 face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2526 [ns_lookup_indexed_color(face->foreground, f) set];
2528 ns_focus (f, &r, 1);
2535 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
2536 /* --------------------------------------------------------------------------
2537 External (RIF): Draw a window divider.
2538 -------------------------------------------------------------------------- */
2540 struct frame *f = XFRAME (WINDOW_FRAME (w));
2542 NSRect r = NSMakeRect (x0, y0, x1-x0, y1-y0);
2544 NSTRACE (ns_draw_window_divider);
2546 face = FACE_FROM_ID (f, WINDOW_DIVIDER_FACE_ID);
2548 [ns_lookup_indexed_color(face->foreground, f) set];
2550 ns_focus (f, &r, 1);
2556 ns_show_hourglass (struct frame *f)
2558 /* TODO: add NSProgressIndicator to all frames. */
2562 ns_hide_hourglass (struct frame *f)
2564 /* TODO: remove NSProgressIndicator from all frames. */
2567 /* ==========================================================================
2569 Glyph drawing operations
2571 ========================================================================== */
2574 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2575 /* --------------------------------------------------------------------------
2576 Wrapper utility to account for internal border width on full-width lines,
2577 and allow top full-width rows to hit the frame top. nr should be pointer
2578 to two successive NSRects. Number of rects actually used is returned.
2579 -------------------------------------------------------------------------- */
2581 int n = get_glyph_string_clip_rects (s, nr, 2);
2585 /* --------------------------------------------------------------------
2586 Draw a wavy line under glyph string s. The wave fills wave_height
2593 wave_height = 3 | * * * *
2594 --------------------------------------------------------------------- */
2597 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
2599 int wave_height = 3, wave_length = 2;
2600 int y, dx, dy, odd, xmax;
2605 dy = wave_height - 1;
2606 y = s->ybase - wave_height + 3;
2609 /* Find and set clipping rectangle */
2610 waveClip = NSMakeRect (x, y, width, wave_height);
2611 [[NSGraphicsContext currentContext] saveGraphicsState];
2612 NSRectClip (waveClip);
2614 /* Draw the waves */
2615 a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
2617 odd = (int)(a.x/dx) % 2;
2618 a.y = b.y = y + 0.5;
2627 [NSBezierPath strokeLineFromPoint:a toPoint:b];
2628 a.x = b.x, a.y = b.y;
2629 b.x += dx, b.y = y + 0.5 + odd*dy;
2633 /* Restore previous clipping rectangle(s) */
2634 [[NSGraphicsContext currentContext] restoreGraphicsState];
2640 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2641 NSColor *defaultCol, CGFloat width, CGFloat x)
2642 /* --------------------------------------------------------------------------
2643 Draw underline, overline, and strike-through on glyph string s.
2644 -------------------------------------------------------------------------- */
2646 if (s->for_overlaps)
2650 if (face->underline_p)
2652 if (s->face->underline_type == FACE_UNDER_WAVE)
2654 if (face->underline_defaulted_p)
2657 [ns_lookup_indexed_color (face->underline_color, s->f) set];
2659 ns_draw_underwave (s, width, x);
2661 else if (s->face->underline_type == FACE_UNDER_LINE)
2665 unsigned long thickness, position;
2667 /* If the prev was underlined, match its appearance. */
2668 if (s->prev && s->prev->face->underline_p
2669 && s->prev->face->underline_type == FACE_UNDER_LINE
2670 && s->prev->underline_thickness > 0)
2672 thickness = s->prev->underline_thickness;
2673 position = s->prev->underline_position;
2678 unsigned long descent;
2681 descent = s->y + s->height - s->ybase;
2683 /* Use underline thickness of font, defaulting to 1. */
2684 thickness = (font && font->underline_thickness > 0)
2685 ? font->underline_thickness : 1;
2687 /* Determine the offset of underlining from the baseline. */
2688 if (x_underline_at_descent_line)
2689 position = descent - thickness;
2690 else if (x_use_underline_position_properties
2691 && font && font->underline_position >= 0)
2692 position = font->underline_position;
2694 position = lround (font->descent / 2);
2696 position = underline_minimum_offset;
2698 position = max (position, underline_minimum_offset);
2700 /* Ensure underlining is not cropped. */
2701 if (descent <= position)
2703 position = descent - 1;
2706 else if (descent < position + thickness)
2710 s->underline_thickness = thickness;
2711 s->underline_position = position;
2713 r = NSMakeRect (x, s->ybase + position, width, thickness);
2715 if (face->underline_defaulted_p)
2718 [ns_lookup_indexed_color (face->underline_color, s->f) set];
2722 /* Do overline. We follow other terms in using a thickness of 1
2723 and ignoring overline_margin. */
2724 if (face->overline_p)
2727 r = NSMakeRect (x, s->y, width, 1);
2729 if (face->overline_color_defaulted_p)
2732 [ns_lookup_indexed_color (face->overline_color, s->f) set];
2736 /* Do strike-through. We follow other terms for thickness and
2737 vertical position.*/
2738 if (face->strike_through_p)
2743 dy = lrint ((s->height - 1) / 2);
2744 r = NSMakeRect (x, s->y + dy, width, 1);
2746 if (face->strike_through_color_defaulted_p)
2749 [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2755 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
2756 char left_p, char right_p)
2757 /* --------------------------------------------------------------------------
2758 Draw an unfilled rect inside r, optionally leaving left and/or right open.
2759 Note we can't just use an NSDrawRect command, because of the possibility
2760 of some sides not being drawn, and because the rect will be filled.
2761 -------------------------------------------------------------------------- */
2767 s.size.height = thickness;
2769 s.origin.y += r.size.height - thickness;
2772 s.size.height = r.size.height;
2773 s.origin.y = r.origin.y;
2775 /* left, right (optional) */
2776 s.size.width = thickness;
2781 s.origin.x += r.size.width - thickness;
2788 ns_draw_relief (NSRect r, int thickness, char raised_p,
2789 char top_p, char bottom_p, char left_p, char right_p,
2790 struct glyph_string *s)
2791 /* --------------------------------------------------------------------------
2792 Draw a relief rect inside r, optionally leaving some sides open.
2793 Note we can't just use an NSDrawBezel command, because of the possibility
2794 of some sides not being drawn, and because the rect will be filled.
2795 -------------------------------------------------------------------------- */
2797 static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2798 NSColor *newBaseCol = nil;
2801 NSTRACE (ns_draw_relief);
2805 if (s->face->use_box_color_for_shadows_p)
2807 newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2809 /* else if (s->first_glyph->type == IMAGE_GLYPH
2811 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2813 newBaseCol = IMAGE_BACKGROUND (s->img, s->f, 0);
2817 newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2820 if (newBaseCol == nil)
2821 newBaseCol = [NSColor grayColor];
2823 if (newBaseCol != baseCol) /* TODO: better check */
2826 baseCol = [newBaseCol retain];
2828 lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2830 darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2833 [(raised_p ? lightCol : darkCol) set];
2835 /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2838 sr.size.height = thickness;
2839 if (top_p) NSRectFill (sr);
2842 sr.size.height = r.size.height;
2843 sr.size.width = thickness;
2844 if (left_p) NSRectFill (sr);
2846 [(raised_p ? darkCol : lightCol) set];
2849 sr.size.width = r.size.width;
2850 sr.size.height = thickness;
2851 sr.origin.y += r.size.height - thickness;
2852 if (bottom_p) NSRectFill (sr);
2855 sr.size.height = r.size.height;
2856 sr.origin.y = r.origin.y;
2857 sr.size.width = thickness;
2858 sr.origin.x += r.size.width - thickness;
2859 if (right_p) NSRectFill (sr);
2864 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2865 /* --------------------------------------------------------------------------
2866 Function modeled after x_draw_glyph_string_box ().
2867 Sets up parameters for drawing.
2868 -------------------------------------------------------------------------- */
2870 int right_x, last_x;
2871 char left_p, right_p;
2872 struct glyph *last_glyph;
2877 if (s->hl == DRAW_MOUSE_FACE)
2879 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2881 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2886 thickness = face->box_line_width;
2888 NSTRACE (ns_dumpglyphs_box_or_relief);
2890 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2891 ? WINDOW_RIGHT_EDGE_X (s->w)
2892 : window_box_right (s->w, s->area));
2893 last_glyph = (s->cmp || s->img
2894 ? s->first_glyph : s->first_glyph + s->nchars-1);
2896 right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2897 ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2899 left_p = (s->first_glyph->left_box_line_p
2900 || (s->hl == DRAW_MOUSE_FACE
2901 && (s->prev == NULL || s->prev->hl != s->hl)));
2902 right_p = (last_glyph->right_box_line_p
2903 || (s->hl == DRAW_MOUSE_FACE
2904 && (s->next == NULL || s->next->hl != s->hl)));
2906 r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2908 /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2909 if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2911 ns_draw_box (r, abs (thickness),
2912 ns_lookup_indexed_color (face->box_color, s->f),
2917 ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2918 1, 1, left_p, right_p, s);
2924 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2925 /* --------------------------------------------------------------------------
2926 Modeled after x_draw_glyph_string_background, which draws BG in
2927 certain cases. Others are left to the text rendering routine.
2928 -------------------------------------------------------------------------- */
2930 NSTRACE (ns_maybe_dumpglyphs_background);
2932 if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2934 int box_line_width = max (s->face->box_line_width, 0);
2935 if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2936 || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2939 if (s->hl == DRAW_MOUSE_FACE)
2941 face = FACE_FROM_ID (s->f,
2942 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2944 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2947 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2949 [(NS_FACE_BACKGROUND (face) != 0
2950 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2951 : FRAME_BACKGROUND_COLOR (s->f)) set];
2954 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
2955 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2958 if (s->hl != DRAW_CURSOR)
2960 NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2961 s->background_width,
2962 s->height-2*box_line_width);
2966 s->background_filled_p = 1;
2973 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2974 /* --------------------------------------------------------------------------
2975 Renders an image and associated borders.
2976 -------------------------------------------------------------------------- */
2978 EmacsImage *img = s->img->pixmap;
2979 int box_line_vwidth = max (s->face->box_line_width, 0);
2980 int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2981 int bg_x, bg_y, bg_height;
2988 NSTRACE (ns_dumpglyphs_image);
2990 if (s->face->box != FACE_NO_BOX
2991 && s->first_glyph->left_box_line_p && s->slice.x == 0)
2992 x += abs (s->face->box_line_width);
2995 bg_y = s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2996 bg_height = s->height;
2997 /* other terms have this, but was causing problems w/tabbar mode */
2998 /* - 2 * box_line_vwidth; */
3000 if (s->slice.x == 0) x += s->img->hmargin;
3001 if (s->slice.y == 0) y += s->img->vmargin;
3003 /* Draw BG: if we need larger area than image itself cleared, do that,
3004 otherwise, since we composite the image under NS (instead of mucking
3005 with its background color), we must clear just the image area. */
3006 if (s->hl == DRAW_MOUSE_FACE)
3008 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3010 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3013 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3015 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3017 if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3018 || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3020 br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3021 s->background_filled_p = 1;
3025 br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3030 /* Draw the image.. do we need to draw placeholder if img ==nil? */
3033 #ifdef NS_IMPL_COCOA
3034 NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3035 NSRect ir = NSMakeRect (s->slice.x, s->slice.y,
3036 s->slice.width, s->slice.height);
3039 operation: NSCompositeSourceOver
3044 [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3045 operation: NSCompositeSourceOver];
3049 if (s->hl == DRAW_CURSOR)
3051 [FRAME_CURSOR_COLOR (s->f) set];
3052 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3053 tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3055 /* Currently on NS img->mask is always 0. Since
3056 get_window_cursor_type specifies a hollow box cursor when on
3057 a non-masked image we never reach this clause. But we put it
3058 in in anticipation of better support for image masks on
3060 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3064 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3067 /* Draw underline, overline, strike-through. */
3068 ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3070 /* Draw relief, if requested */
3071 if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3073 if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3075 th = tool_bar_button_relief >= 0 ?
3076 tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3077 raised_p = (s->hl == DRAW_IMAGE_RAISED);
3081 th = abs (s->img->relief);
3082 raised_p = (s->img->relief > 0);
3085 r.origin.x = x - th;
3086 r.origin.y = y - th;
3087 r.size.width = s->slice.width + 2*th-1;
3088 r.size.height = s->slice.height + 2*th-1;
3089 ns_draw_relief (r, th, raised_p,
3091 s->slice.y + s->slice.height == s->img->height,
3093 s->slice.x + s->slice.width == s->img->width, s);
3096 /* If there is no mask, the background won't be seen,
3097 so draw a rectangle on the image for the cursor.
3098 Do this for all images, getting transparency right is not reliable. */
3099 if (s->hl == DRAW_CURSOR)
3101 int thickness = abs (s->img->relief);
3102 if (thickness == 0) thickness = 1;
3103 ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3109 ns_dumpglyphs_stretch (struct glyph_string *s)
3114 NSColor *fgCol, *bgCol;
3116 if (!s->background_filled_p)
3118 n = ns_get_glyph_string_clip_rect (s, r);
3119 *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3121 ns_focus (s->f, r, n);
3123 if (s->hl == DRAW_MOUSE_FACE)
3125 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3127 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3130 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3132 bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3133 fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3135 for (i = 0; i < n; ++i)
3137 if (!s->row->full_width_p)
3139 int overrun, leftoverrun;
3141 /* truncate to avoid overwriting fringe and/or scrollbar */
3142 overrun = max (0, (s->x + s->background_width)
3143 - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3144 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3145 r[i].size.width -= overrun;
3147 /* truncate to avoid overwriting to left of the window box */
3148 leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3149 + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3151 if (leftoverrun > 0)
3153 r[i].origin.x += leftoverrun;
3154 r[i].size.width -= leftoverrun;
3157 /* XXX: Try to work between problem where a stretch glyph on
3158 a partially-visible bottom row will clear part of the
3159 modeline, and another where list-buffers headers and similar
3160 rows erroneously have visible_height set to 0. Not sure
3161 where this is coming from as other terms seem not to show. */
3162 r[i].size.height = min (s->height, s->row->visible_height);
3167 /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3168 overwriting cursor (usually when cursor on a tab) */
3169 if (s->hl == DRAW_CURSOR)
3174 width = s->w->phys_cursor_width;
3175 r[i].size.width -= width;
3176 r[i].origin.x += width;
3180 /* Draw overlining, etc. on the cursor. */
3181 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3182 ns_draw_text_decoration (s, face, bgCol, width, x);
3184 ns_draw_text_decoration (s, face, fgCol, width, x);
3191 /* Draw overlining, etc. on the stretch glyph (or the part
3192 of the stretch glyph after the cursor). */
3193 ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3197 s->background_filled_p = 1;
3203 ns_draw_glyph_string (struct glyph_string *s)
3204 /* --------------------------------------------------------------------------
3205 External (RIF): Main draw-text call.
3206 -------------------------------------------------------------------------- */
3208 /* TODO (optimize): focus for box and contents draw */
3211 char box_drawn_p = 0;
3212 struct font *font = s->face->font;
3213 if (! font) font = FRAME_FONT (s->f);
3215 NSTRACE (ns_draw_glyph_string);
3217 if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3220 struct glyph_string *next;
3222 for (width = 0, next = s->next;
3223 next && width < s->right_overhang;
3224 width += next->width, next = next->next)
3225 if (next->first_glyph->type != IMAGE_GLYPH)
3227 if (next->first_glyph->type != STRETCH_GLYPH)
3229 n = ns_get_glyph_string_clip_rect (s->next, r);
3230 ns_focus (s->f, r, n);
3231 ns_maybe_dumpglyphs_background (s->next, 1);
3236 ns_dumpglyphs_stretch (s->next);
3238 next->num_clips = 0;
3242 if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3243 && (s->first_glyph->type == CHAR_GLYPH
3244 || s->first_glyph->type == COMPOSITE_GLYPH))
3246 n = ns_get_glyph_string_clip_rect (s, r);
3247 ns_focus (s->f, r, n);
3248 ns_maybe_dumpglyphs_background (s, 1);
3249 ns_dumpglyphs_box_or_relief (s);
3254 switch (s->first_glyph->type)
3258 n = ns_get_glyph_string_clip_rect (s, r);
3259 ns_focus (s->f, r, n);
3260 ns_dumpglyphs_image (s, r[0]);
3265 ns_dumpglyphs_stretch (s);
3269 case COMPOSITE_GLYPH:
3270 n = ns_get_glyph_string_clip_rect (s, r);
3271 ns_focus (s->f, r, n);
3273 if (s->for_overlaps || (s->cmp_from > 0
3274 && ! s->first_glyph->u.cmp.automatic))
3275 s->background_filled_p = 1;
3277 ns_maybe_dumpglyphs_background
3278 (s, s->first_glyph->type == COMPOSITE_GLYPH);
3280 flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3281 (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3282 (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3283 NS_DUMPGLYPH_NORMAL));
3285 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3287 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3288 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3289 NS_FACE_FOREGROUND (s->face) = tmp;
3293 BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
3294 int end = isComposite ? s->cmp_to : s->nchars;
3297 (s, s->cmp_from, end, s->x, s->ybase,
3298 (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3299 || flags == NS_DUMPGLYPH_MOUSEFACE);
3304 NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
3305 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
3307 : FRAME_FOREGROUND_COLOR (s->f));
3310 /* Draw underline, overline, strike-through. */
3311 ns_draw_text_decoration (s, s->face, col, s->width, s->x);
3314 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3316 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3317 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3318 NS_FACE_FOREGROUND (s->face) = tmp;
3324 case GLYPHLESS_GLYPH:
3325 n = ns_get_glyph_string_clip_rect (s, r);
3326 ns_focus (s->f, r, n);
3328 if (s->for_overlaps || (s->cmp_from > 0
3329 && ! s->first_glyph->u.cmp.automatic))
3330 s->background_filled_p = 1;
3332 ns_maybe_dumpglyphs_background
3333 (s, s->first_glyph->type == COMPOSITE_GLYPH);
3335 /* Not yet implemented. */
3344 /* Draw box if not done already. */
3345 if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3347 n = ns_get_glyph_string_clip_rect (s, r);
3348 ns_focus (s->f, r, n);
3349 ns_dumpglyphs_box_or_relief (s);
3358 /* ==========================================================================
3362 ========================================================================== */
3366 ns_send_appdefined (int value)
3367 /* --------------------------------------------------------------------------
3368 Internal: post an appdefined event which EmacsApp-sendEvent will
3369 recognize and take as a command to halt the event loop.
3370 -------------------------------------------------------------------------- */
3372 /*NSTRACE (ns_send_appdefined); */
3374 #ifdef NS_IMPL_GNUSTEP
3375 // GNUstep needs postEvent to happen on the main thread.
3376 if (! [[NSThread currentThread] isMainThread])
3378 EmacsApp *app = (EmacsApp *)NSApp;
3379 app->nextappdefined = value;
3380 [app performSelectorOnMainThread:@selector (sendFromMainThread:)
3387 /* Only post this event if we haven't already posted one. This will end
3388 the [NXApp run] main loop after having processed all events queued at
3391 #ifdef NS_IMPL_COCOA
3392 if (! send_appdefined)
3394 /* OSX 10.10.1 swallows the AppDefined event we are sending ourselves
3395 in certain situations (rapid incoming events).
3396 So check if we have one, if not add one. */
3397 NSEvent *appev = [NSApp nextEventMatchingMask:NSApplicationDefinedMask
3398 untilDate:[NSDate distantPast]
3399 inMode:NSDefaultRunLoopMode
3401 if (! appev) send_appdefined = YES;
3405 if (send_appdefined)
3409 /* We only need one NX_APPDEFINED event to stop NXApp from running. */
3410 send_appdefined = NO;
3412 /* Don't need wakeup timer any more */
3415 [timed_entry invalidate];
3416 [timed_entry release];
3420 nxev = [NSEvent otherEventWithType: NSApplicationDefined
3421 location: NSMakePoint (0, 0)
3424 windowNumber: [[NSApp mainWindow] windowNumber]
3425 context: [NSApp context]
3430 /* Post an application defined event on the event queue. When this is
3431 received the [NXApp run] will return, thus having processed all
3432 events which are currently queued. */
3433 [NSApp postEvent: nxev atStart: NO];
3437 #ifdef HAVE_NATIVE_FS
3441 Lisp_Object frame, tail;
3443 if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
3446 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
3448 FOR_EACH_FRAME (tail, frame)
3450 struct frame *f = XFRAME (frame);
3453 EmacsView *view = FRAME_NS_VIEW (f);
3454 [view updateCollectionBehavior];
3460 /* GNUstep does not have cancelTracking. */
3461 #ifdef NS_IMPL_COCOA
3462 /* Check if menu open should be canceled or continued as normal. */
3464 ns_check_menu_open (NSMenu *menu)
3466 /* Click in menu bar? */
3467 NSArray *a = [[NSApp mainMenu] itemArray];
3471 if (menu == nil) // Menu tracking ended.
3473 if (menu_will_open_state == MENU_OPENING)
3474 menu_will_open_state = MENU_NONE;
3478 for (i = 0; ! found && i < [a count]; i++)
3479 found = menu == [[a objectAtIndex:i] submenu];
3482 if (menu_will_open_state == MENU_NONE && emacs_event)
3484 NSEvent *theEvent = [NSApp currentEvent];
3485 struct frame *emacsframe = SELECTED_FRAME ();
3487 [menu cancelTracking];
3488 menu_will_open_state = MENU_PENDING;
3489 emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
3490 EV_TRAILER (theEvent);
3492 CGEventRef ourEvent = CGEventCreate (NULL);
3493 menu_mouse_point = CGEventGetLocation (ourEvent);
3494 CFRelease (ourEvent);
3496 else if (menu_will_open_state == MENU_OPENING)
3498 menu_will_open_state = MENU_NONE;
3503 /* Redo saved menu click if state is MENU_PENDING. */
3505 ns_check_pending_open_menu ()
3507 if (menu_will_open_state == MENU_PENDING)
3509 CGEventSourceRef source
3510 = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
3512 CGEventRef event = CGEventCreateMouseEvent (source,
3513 kCGEventLeftMouseDown,
3515 kCGMouseButtonLeft);
3516 CGEventSetType (event, kCGEventLeftMouseDown);
3517 CGEventPost (kCGHIDEventTap, event);
3521 menu_will_open_state = MENU_OPENING;
3524 #endif /* NS_IMPL_COCOA */
3527 unwind_apploopnr (Lisp_Object not_used)
3530 n_emacs_events_pending = 0;
3531 ns_finish_events ();
3536 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3537 /* --------------------------------------------------------------------------
3538 External (hook): Post an event to ourself and keep reading events until
3539 we read it back again. In effect process all events which were waiting.
3540 From 21+ we have to manage the event buffer ourselves.
3541 -------------------------------------------------------------------------- */
3543 struct input_event ev;
3546 /* NSTRACE (ns_read_socket); */
3548 #ifdef HAVE_NATIVE_FS
3552 if ([NSApp modalWindow] != nil)
3555 if (hold_event_q.nr > 0)
3558 for (i = 0; i < hold_event_q.nr; ++i)
3559 kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
3560 hold_event_q.nr = 0;
3565 n_emacs_events_pending = 0;
3566 ns_init_events (&ev);
3567 q_event_ptr = hold_quit;
3569 /* we manage autorelease pools by allocate/reallocate each time around
3570 the loop; strict nesting is occasionally violated but seems not to
3571 matter.. earlier methods using full nesting caused major memory leaks */
3572 [outerpool release];
3573 outerpool = [[NSAutoreleasePool alloc] init];
3575 /* If have pending open-file requests, attend to the next one of those. */
3576 if (ns_pending_files && [ns_pending_files count] != 0
3577 && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3579 [ns_pending_files removeObjectAtIndex: 0];
3581 /* Deal with pending service requests. */
3582 else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3584 NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3585 withArg: [ns_pending_service_args objectAtIndex: 0]])
3587 [ns_pending_service_names removeObjectAtIndex: 0];
3588 [ns_pending_service_args removeObjectAtIndex: 0];
3592 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
3593 /* Run and wait for events. We must always send one NX_APPDEFINED event
3594 to ourself, otherwise [NXApp run] will never exit. */
3595 send_appdefined = YES;
3596 ns_send_appdefined (-1);
3598 if (++apploopnr != 1)
3602 record_unwind_protect (unwind_apploopnr, Qt);
3604 unbind_to (specpdl_count, Qnil); /* calls unwind_apploopnr */
3607 nevents = n_emacs_events_pending;
3608 n_emacs_events_pending = 0;
3609 ns_finish_events ();
3618 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3619 fd_set *exceptfds, struct timespec const *timeout,
3620 sigset_t const *sigmask)
3621 /* --------------------------------------------------------------------------
3622 Replacement for select, checking for events
3623 -------------------------------------------------------------------------- */
3627 struct input_event event;
3630 /* NSTRACE (ns_select); */
3632 #ifdef HAVE_NATIVE_FS
3636 if (hold_event_q.nr > 0)
3638 /* We already have events pending. */
3644 for (k = 0; k < nfds+1; k++)
3646 if (readfds && FD_ISSET(k, readfds)) ++nr;
3647 if (writefds && FD_ISSET(k, writefds)) ++nr;
3651 || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
3652 return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
3654 [outerpool release];
3655 outerpool = [[NSAutoreleasePool alloc] init];
3658 send_appdefined = YES;
3661 pthread_mutex_lock (&select_mutex);
3666 select_readfds = *readfds;
3667 select_valid += SELECT_HAVE_READ;
3671 select_writefds = *writefds;
3672 select_valid += SELECT_HAVE_WRITE;
3677 select_timeout = *timeout;
3678 select_valid += SELECT_HAVE_TMO;
3681 pthread_mutex_unlock (&select_mutex);
3683 /* Inform fd_handler that select should be called */
3685 emacs_write_sig (selfds[1], &c, 1);
3687 else if (nr == 0 && timeout)
3689 /* No file descriptor, just a timeout, no need to wake fd_handler */
3690 double time = timespectod (*timeout);
3691 timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3694 @selector (timeout_handler:)
3699 else /* No timeout and no file descriptors, can this happen? */
3701 /* Send appdefined so we exit from the loop */
3702 ns_send_appdefined (-1);
3706 ns_init_events (&event);
3707 if (++apploopnr != 1)
3713 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
3714 record_unwind_protect (unwind_apploopnr, Qt);
3716 unbind_to (specpdl_count, Qnil); /* calls unwind_apploopnr */
3719 ns_finish_events ();
3720 if (nr > 0 && readfds)
3723 emacs_write_sig (selfds[1], &c, 1);
3727 t = last_appdefined_event_data;
3729 if (t != NO_APPDEFINED_DATA)
3731 last_appdefined_event_data = NO_APPDEFINED_DATA;
3735 /* The NX_APPDEFINED event we received was a timeout. */
3740 /* The NX_APPDEFINED event we received was the result of
3741 at least one real input event arriving. */
3747 /* Received back from select () in fd_handler; copy the results */
3748 pthread_mutex_lock (&select_mutex);
3749 if (readfds) *readfds = select_readfds;
3750 if (writefds) *writefds = select_writefds;
3751 pthread_mutex_unlock (&select_mutex);
3766 /* ==========================================================================
3770 ========================================================================== */
3774 ns_set_vertical_scroll_bar (struct window *window,
3775 int portion, int whole, int position)
3776 /* --------------------------------------------------------------------------
3777 External (hook): Update or add scrollbar
3778 -------------------------------------------------------------------------- */
3782 struct frame *f = XFRAME (WINDOW_FRAME (window));
3783 EmacsView *view = FRAME_NS_VIEW (f);
3785 int window_y, window_height;
3786 int top, left, height, width;
3787 BOOL update_p = YES;
3789 /* optimization; display engine sends WAY too many of these.. */
3790 if (!NILP (window->vertical_scroll_bar))
3792 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3793 if ([bar checkSamePosition: position portion: portion whole: whole])
3795 if (view->scrollbarsNeedingUpdate == 0)
3797 if (!windows_or_buffers_changed)
3801 view->scrollbarsNeedingUpdate--;
3806 NSTRACE (ns_set_vertical_scroll_bar);
3808 /* Get dimensions. */
3809 window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
3811 height = window_height;
3812 width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3813 left = WINDOW_SCROLL_BAR_AREA_X (window);
3815 r = NSMakeRect (left, top, width, height);
3816 /* the parent view is flipped, so we need to flip y value */
3818 r.origin.y = (v.size.height - r.size.height - r.origin.y);
3820 XSETWINDOW (win, window);
3823 /* we want at least 5 lines to display a scrollbar */
3824 if (WINDOW_TOTAL_LINES (window) < 5)
3826 if (!NILP (window->vertical_scroll_bar))
3828 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3829 [bar removeFromSuperview];
3830 wset_vertical_scroll_bar (window, Qnil);
3833 ns_clear_frame_area (f, left, top, width, height);
3838 if (NILP (window->vertical_scroll_bar))
3840 if (width > 0 && height > 0)
3841 ns_clear_frame_area (f, left, top, width, height);
3843 bar = [[EmacsScroller alloc] initFrame: r window: win];
3844 wset_vertical_scroll_bar (window, make_save_ptr (bar));
3850 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3851 oldRect = [bar frame];
3852 r.size.width = oldRect.size.width;
3853 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3855 if (oldRect.origin.x != r.origin.x)
3856 ns_clear_frame_area (f, left, top, width, height);
3862 [bar setPosition: position portion: portion whole: whole];
3868 ns_set_horizontal_scroll_bar (struct window *window,
3869 int portion, int whole, int position)
3870 /* --------------------------------------------------------------------------
3871 External (hook): Update or add scrollbar
3872 -------------------------------------------------------------------------- */
3876 struct frame *f = XFRAME (WINDOW_FRAME (window));
3877 EmacsView *view = FRAME_NS_VIEW (f);
3879 int top, height, left, width;
3880 int window_x, window_width;
3881 int pixel_width = WINDOW_PIXEL_WIDTH (window);
3882 BOOL update_p = YES;
3884 /* optimization; display engine sends WAY too many of these.. */
3885 if (!NILP (window->horizontal_scroll_bar))
3887 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
3888 if ([bar checkSamePosition: position portion: portion whole: whole])
3890 if (view->scrollbarsNeedingUpdate == 0)
3892 if (!windows_or_buffers_changed)
3896 view->scrollbarsNeedingUpdate--;
3901 NSTRACE (ns_set_horizontal_scroll_bar);
3903 /* Get dimensions. */
3904 window_box (window, ANY_AREA, 0, &window_x, &window_width, 0);
3906 width = window_width;
3907 height = WINDOW_CONFIG_SCROLL_BAR_LINES (window) * FRAME_LINE_HEIGHT (f);
3908 top = WINDOW_SCROLL_BAR_AREA_Y (window);
3910 r = NSMakeRect (left, top, width, height);
3911 /* the parent view is flipped, so we need to flip y value */
3913 /* ??????? PXW/scrollbars !!!!!!!!!!!!!!!!!!!! */
3914 r.origin.y = (v.size.height - r.size.height - r.origin.y);
3916 XSETWINDOW (win, window);
3919 if (WINDOW_TOTAL_COLS (window) < 5)
3921 if (!NILP (window->horizontal_scroll_bar))
3923 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
3924 [bar removeFromSuperview];
3925 wset_horizontal_scroll_bar (window, Qnil);
3927 ns_clear_frame_area (f, left, top, width, height);
3932 if (NILP (window->horizontal_scroll_bar))
3934 if (width > 0 && height > 0)
3935 ns_clear_frame_area (f, left, top, width, height);
3937 bar = [[EmacsScroller alloc] initFrame: r window: win];
3938 wset_horizontal_scroll_bar (window, make_save_ptr (bar));
3944 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
3945 oldRect = [bar frame];
3946 r.size.width = oldRect.size.width;
3947 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3949 if (oldRect.origin.x != r.origin.x)
3950 ns_clear_frame_area (f, left, top, width, height);
3957 [bar setPosition: position portion: portion whole: whole];
3963 ns_condemn_scroll_bars (struct frame *f)
3964 /* --------------------------------------------------------------------------
3965 External (hook): arrange for all frame's scrollbars to be removed
3966 at next call to judge_scroll_bars, except for those redeemed.
3967 -------------------------------------------------------------------------- */
3971 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3973 NSTRACE (ns_condemn_scroll_bars);
3975 for (i =[subviews count]-1; i >= 0; i--)
3977 view = [subviews objectAtIndex: i];
3978 if ([view isKindOfClass: [EmacsScroller class]])
3985 ns_redeem_scroll_bar (struct window *window)
3986 /* --------------------------------------------------------------------------
3987 External (hook): arrange to spare this window's scrollbar
3988 at next call to judge_scroll_bars.
3989 -------------------------------------------------------------------------- */
3992 NSTRACE (ns_redeem_scroll_bar);
3993 if (!NILP (window->vertical_scroll_bar))
3995 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3999 if (!NILP (window->horizontal_scroll_bar))
4001 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4008 ns_judge_scroll_bars (struct frame *f)
4009 /* --------------------------------------------------------------------------
4010 External (hook): destroy all scrollbars on frame that weren't
4011 redeemed after call to condemn_scroll_bars.
4012 -------------------------------------------------------------------------- */
4016 EmacsView *eview = FRAME_NS_VIEW (f);
4017 NSArray *subviews = [[eview superview] subviews];
4020 NSTRACE (ns_judge_scroll_bars);
4021 for (i = [subviews count]-1; i >= 0; --i)
4023 view = [subviews objectAtIndex: i];
4024 if (![view isKindOfClass: [EmacsScroller class]]) continue;
4030 [eview updateFrameSize: NO];
4033 /* ==========================================================================
4037 ========================================================================== */
4040 x_display_pixel_height (struct ns_display_info *dpyinfo)
4042 NSArray *screens = [NSScreen screens];
4043 NSEnumerator *enumerator = [screens objectEnumerator];
4048 while ((screen = [enumerator nextObject]) != nil)
4049 frame = NSUnionRect (frame, [screen frame]);
4051 return NSHeight (frame);
4055 x_display_pixel_width (struct ns_display_info *dpyinfo)
4057 NSArray *screens = [NSScreen screens];
4058 NSEnumerator *enumerator = [screens objectEnumerator];
4063 while ((screen = [enumerator nextObject]) != nil)
4064 frame = NSUnionRect (frame, [screen frame]);
4066 return NSWidth (frame);
4070 static Lisp_Object ns_string_to_lispmod (const char *s)
4071 /* --------------------------------------------------------------------------
4072 Convert modifier name to lisp symbol
4073 -------------------------------------------------------------------------- */
4075 if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
4077 else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
4079 else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
4081 else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
4083 else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
4085 else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
4093 ns_default (const char *parameter, Lisp_Object *result,
4094 Lisp_Object yesval, Lisp_Object noval,
4095 BOOL is_float, BOOL is_modstring)
4096 /* --------------------------------------------------------------------------
4097 Check a parameter value in user's preferences
4098 -------------------------------------------------------------------------- */
4100 const char *value = ns_get_defaults_value (parameter);
4106 if (c_strcasecmp (value, "YES") == 0)
4108 else if (c_strcasecmp (value, "NO") == 0)
4110 else if (is_float && (f = strtod (value, &pos), pos != value))
4111 *result = make_float (f);
4112 else if (is_modstring && value)
4113 *result = ns_string_to_lispmod (value);
4114 else fprintf (stderr,
4115 "Bad value for default \"%s\": \"%s\"\n", parameter, value);
4121 ns_initialize_display_info (struct ns_display_info *dpyinfo)
4122 /* --------------------------------------------------------------------------
4123 Initialize global info and storage for display.
4124 -------------------------------------------------------------------------- */
4126 NSScreen *screen = [NSScreen mainScreen];
4127 NSWindowDepth depth = [screen depth];
4129 dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
4130 dpyinfo->resy = 72.27;
4131 dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4132 NSColorSpaceFromDepth (depth)]
4133 && ![NSCalibratedWhiteColorSpace isEqualToString:
4134 NSColorSpaceFromDepth (depth)];
4135 dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4136 dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
4137 dpyinfo->color_table->colors = NULL;
4138 dpyinfo->root_window = 42; /* a placeholder.. */
4139 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4140 dpyinfo->n_fonts = 0;
4141 dpyinfo->smallest_font_height = 1;
4142 dpyinfo->smallest_char_width = 1;
4144 reset_mouse_highlight (&dpyinfo->mouse_highlight);
4148 /* This and next define (many of the) public functions in this file. */
4149 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4150 with using despite presence in the "system dependent" redisplay
4151 interface. In addition, many of the ns_ methods have code that is
4152 shared with all terms, indicating need for further refactoring. */
4153 extern frame_parm_handler ns_frame_parm_handlers[];
4154 static struct redisplay_interface ns_redisplay_interface =
4156 ns_frame_parm_handlers,
4160 x_clear_end_of_line,
4162 ns_after_update_window_line,
4163 ns_update_window_begin,
4164 ns_update_window_end,
4165 0, /* flush_display */
4166 x_clear_window_mouse_face,
4167 x_get_glyph_overhangs,
4168 x_fix_overlapping_area,
4169 ns_draw_fringe_bitmap,
4170 0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4171 0, /* destroy_fringe_bitmap */
4172 ns_compute_glyph_string_overhangs,
4173 ns_draw_glyph_string,
4174 ns_define_frame_cursor,
4175 ns_clear_frame_area,
4176 ns_draw_window_cursor,
4177 ns_draw_vertical_window_border,
4178 ns_draw_window_divider,
4179 ns_shift_glyphs_for_insert,
4186 ns_delete_display (struct ns_display_info *dpyinfo)
4192 /* This function is called when the last frame on a display is deleted. */
4194 ns_delete_terminal (struct terminal *terminal)
4196 struct ns_display_info *dpyinfo = terminal->display_info.ns;
4198 /* Protect against recursive calls. delete_frame in
4199 delete_terminal calls us back when it deletes our last frame. */
4200 if (!terminal->name)
4205 x_destroy_all_bitmaps (dpyinfo);
4206 ns_delete_display (dpyinfo);
4211 static struct terminal *
4212 ns_create_terminal (struct ns_display_info *dpyinfo)
4213 /* --------------------------------------------------------------------------
4214 Set up use of NS before we make the first connection.
4215 -------------------------------------------------------------------------- */
4217 struct terminal *terminal;
4219 NSTRACE (ns_create_terminal);
4221 terminal = create_terminal (output_ns, &ns_redisplay_interface);
4223 terminal->display_info.ns = dpyinfo;
4224 dpyinfo->terminal = terminal;
4226 terminal->clear_frame_hook = ns_clear_frame;
4227 terminal->ring_bell_hook = ns_ring_bell;
4228 terminal->update_begin_hook = ns_update_begin;
4229 terminal->update_end_hook = ns_update_end;
4230 terminal->read_socket_hook = ns_read_socket;
4231 terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4232 terminal->mouse_position_hook = ns_mouse_position;
4233 terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4234 terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4235 terminal->fullscreen_hook = ns_fullscreen_hook;
4236 terminal->menu_show_hook = ns_menu_show;
4237 terminal->popup_dialog_hook = ns_popup_dialog;
4238 terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4239 terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4240 terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4241 terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4242 terminal->delete_frame_hook = x_destroy_window;
4243 terminal->delete_terminal_hook = ns_delete_terminal;
4244 /* Other hooks are NULL by default. */
4250 struct ns_display_info *
4251 ns_term_init (Lisp_Object display_name)
4252 /* --------------------------------------------------------------------------
4253 Start the Application and get things rolling.
4254 -------------------------------------------------------------------------- */
4256 struct terminal *terminal;
4257 struct ns_display_info *dpyinfo;
4258 static int ns_initialized = 0;
4261 if (ns_initialized) return x_display_list;
4264 NSTRACE (ns_term_init);
4266 [outerpool release];
4267 outerpool = [[NSAutoreleasePool alloc] init];
4269 /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4270 /*GSDebugAllocationActive (YES); */
4274 Fset_input_interrupt_mode (Qnil);
4276 if (selfds[0] == -1)
4278 if (emacs_pipe (selfds) != 0)
4280 fprintf (stderr, "Failed to create pipe: %s\n",
4281 emacs_strerror (errno));
4285 fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4286 FD_ZERO (&select_readfds);
4287 FD_ZERO (&select_writefds);
4288 pthread_mutex_init (&select_mutex, NULL);
4291 ns_pending_files = [[NSMutableArray alloc] init];
4292 ns_pending_service_names = [[NSMutableArray alloc] init];
4293 ns_pending_service_args = [[NSMutableArray alloc] init];
4295 /* Start app and create the main menu, window, view.
4296 Needs to be here because ns_initialize_display_info () uses AppKit classes.
4297 The view will then ask the NSApp to stop and return to Emacs. */
4298 [EmacsApp sharedApplication];
4301 [NSApp setDelegate: NSApp];
4303 /* Start the select thread. */
4304 [NSThread detachNewThreadSelector:@selector (fd_handler:)
4308 /* debugging: log all notifications */
4309 /* [[NSNotificationCenter defaultCenter] addObserver: NSApp
4310 selector: @selector (logNotification:)
4311 name: nil object: nil]; */
4313 dpyinfo = xzalloc (sizeof *dpyinfo);
4315 ns_initialize_display_info (dpyinfo);
4316 terminal = ns_create_terminal (dpyinfo);
4318 terminal->kboard = allocate_kboard (Qns);
4319 /* Don't let the initial kboard remain current longer than necessary.
4320 That would cause problems if a file loaded on startup tries to
4321 prompt in the mini-buffer. */
4322 if (current_kboard == initial_kboard)
4323 current_kboard = terminal->kboard;
4324 terminal->kboard->reference_count++;
4326 dpyinfo->next = x_display_list;
4327 x_display_list = dpyinfo;
4329 dpyinfo->name_list_element = Fcons (display_name, Qnil);
4331 terminal->name = xstrdup (SSDATA (display_name));
4335 if (!inhibit_x_resources)
4337 ns_default ("GSFontAntiAlias", &ns_antialias_text,
4340 /* this is a standard variable */
4341 ns_default ("AppleAntiAliasingThreshold", &tmp,
4342 make_float (10.0), make_float (6.0), YES, NO);
4343 ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4347 NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4351 Lisp_Object color_file, color_map, color;
4355 color_file = Fexpand_file_name (build_string ("rgb.txt"),
4356 Fsymbol_value (intern ("data-directory")));
4358 color_map = Fx_load_color_file (color_file);
4359 if (NILP (color_map))
4360 fatal ("Could not read %s.\n", SDATA (color_file));
4362 cl = [[NSColorList alloc] initWithName: @"Emacs"];
4363 for ( ; CONSP (color_map); color_map = XCDR (color_map))
4365 color = XCAR (color_map);
4366 name = SSDATA (XCAR (color));
4367 c = XINT (XCDR (color));
4369 [NSColor colorForEmacsRed: RED_FROM_ULONG (c) / 255.0
4370 green: GREEN_FROM_ULONG (c) / 255.0
4371 blue: BLUE_FROM_ULONG (c) / 255.0
4373 forKey: [NSString stringWithUTF8String: name]];
4375 [cl writeToFile: nil];
4380 #ifdef NS_IMPL_GNUSTEP
4381 Vwindow_system_version = build_string (gnustep_base_version);
4383 /*PSnextrelease (128, c); */
4384 char c[DBL_BUFSIZE_BOUND];
4385 int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4386 Vwindow_system_version = make_unibyte_string (c, len);
4390 delete_keyboard_wait_descriptor (0);
4392 ns_app_name = [[NSProcessInfo processInfo] processName];
4394 /* Set up OS X app menu */
4395 #ifdef NS_IMPL_COCOA
4399 /* set up the application menu */
4400 svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4401 [svcsMenu setAutoenablesItems: NO];
4402 appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4403 [appMenu setAutoenablesItems: NO];
4404 mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4405 dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4407 [appMenu insertItemWithTitle: @"About Emacs"
4408 action: @selector (orderFrontStandardAboutPanel:)
4411 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4412 [appMenu insertItemWithTitle: @"Preferences..."
4413 action: @selector (showPreferencesWindow:)
4416 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4417 item = [appMenu insertItemWithTitle: @"Services"
4418 action: @selector (menuDown:)
4421 [appMenu setSubmenu: svcsMenu forItem: item];
4422 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4423 [appMenu insertItemWithTitle: @"Hide Emacs"
4424 action: @selector (hide:)
4427 item = [appMenu insertItemWithTitle: @"Hide Others"
4428 action: @selector (hideOtherApplications:)
4431 [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4432 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4433 [appMenu insertItemWithTitle: @"Quit Emacs"
4434 action: @selector (terminate:)
4438 item = [mainMenu insertItemWithTitle: ns_app_name
4439 action: @selector (menuDown:)
4442 [mainMenu setSubmenu: appMenu forItem: item];
4443 [dockMenu insertItemWithTitle: @"New Frame"
4444 action: @selector (newFrame:)
4448 [NSApp setMainMenu: mainMenu];
4449 [NSApp setAppleMenu: appMenu];
4450 [NSApp setServicesMenu: svcsMenu];
4451 /* Needed at least on Cocoa, to get dock menu to show windows */
4452 [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4454 [[NSNotificationCenter defaultCenter]
4455 addObserver: mainMenu
4456 selector: @selector (trackingNotification:)
4457 name: NSMenuDidBeginTrackingNotification object: mainMenu];
4458 [[NSNotificationCenter defaultCenter]
4459 addObserver: mainMenu
4460 selector: @selector (trackingNotification:)
4461 name: NSMenuDidEndTrackingNotification object: mainMenu];
4463 #endif /* MAC OS X menu setup */
4465 /* Register our external input/output types, used for determining
4466 applicable services and also drag/drop eligibility. */
4467 ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
4468 ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
4470 ns_drag_types = [[NSArray arrayWithObjects:
4472 NSTabularTextPboardType,
4473 NSFilenamesPboardType,
4474 NSURLPboardType, nil] retain];
4476 /* If fullscreen is in init/default-frame-alist, focus isn't set
4477 right for fullscreen windows, so set this. */
4478 [NSApp activateIgnoringOtherApps:YES];
4481 ns_do_open_file = YES;
4483 #ifdef NS_IMPL_GNUSTEP
4484 /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
4485 We must re-catch it so subprocess works. */
4486 catch_child_signal ();
4493 ns_term_shutdown (int sig)
4495 [[NSUserDefaults standardUserDefaults] synchronize];
4497 /* code not reached in emacs.c after this is called by shut_down_emacs: */
4498 if (STRINGP (Vauto_save_list_file_name))
4499 unlink (SSDATA (Vauto_save_list_file_name));
4501 if (sig == 0 || sig == SIGTERM)
4503 [NSApp terminate: NSApp];
4505 else // force a stack trace to happen
4512 /* ==========================================================================
4514 EmacsApp implementation
4516 ========================================================================== */
4519 @implementation EmacsApp
4523 if (self = [super init])
4525 #ifdef NS_IMPL_COCOA
4526 self->isFirst = YES;
4528 #ifdef NS_IMPL_GNUSTEP
4529 self->applicationDidFinishLaunchingCalled = NO;
4536 #ifdef NS_IMPL_COCOA
4539 #ifndef NSAppKitVersionNumber10_9
4540 #define NSAppKitVersionNumber10_9 1265
4543 if ((int)NSAppKitVersionNumber != NSAppKitVersionNumber10_9)
4549 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
4551 if (isFirst) [self finishLaunching];
4554 shouldKeepRunning = YES;
4558 pool = [[NSAutoreleasePool alloc] init];
4561 [self nextEventMatchingMask:NSAnyEventMask
4562 untilDate:[NSDate distantFuture]
4563 inMode:NSDefaultRunLoopMode
4566 [self sendEvent:event];
4567 [self updateWindows];
4568 } while (shouldKeepRunning);
4573 - (void)stop: (id)sender
4575 shouldKeepRunning = NO;
4576 // Stop possible dialog also. Noop if no dialog present.
4577 // The file dialog still leaks 7k - 10k on 10.9 though.
4578 [super stop:sender];
4580 #endif /* NS_IMPL_COCOA */
4582 - (void)logNotification: (NSNotification *)notification
4584 const char *name = [[notification name] UTF8String];
4585 if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4586 && !strstr (name, "WindowNumber"))
4587 NSLog (@"notification: '%@'", [notification name]);
4591 - (void)sendEvent: (NSEvent *)theEvent
4592 /* --------------------------------------------------------------------------
4593 Called when NSApp is running for each event received. Used to stop
4594 the loop when we choose, since there's no way to just run one iteration.
4595 -------------------------------------------------------------------------- */
4597 int type = [theEvent type];
4598 NSWindow *window = [theEvent window];
4600 /* NSTRACE (sendEvent); */
4601 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4603 #ifdef NS_IMPL_GNUSTEP
4604 // Keyboard events aren't propagated to file dialogs for some reason.
4605 if ([NSApp modalWindow] != nil &&
4606 (type == NSKeyDown || type == NSKeyUp || type == NSFlagsChanged))
4608 [[NSApp modalWindow] sendEvent: theEvent];
4613 if (represented_filename != nil && represented_frame)
4615 NSString *fstr = represented_filename;
4616 NSView *view = FRAME_NS_VIEW (represented_frame);
4617 #ifdef NS_IMPL_COCOA
4618 /* work around a bug observed on 10.3 and later where
4619 setTitleWithRepresentedFilename does not clear out previous state
4620 if given filename does not exist */
4621 if (! [[NSFileManager defaultManager] fileExistsAtPath: fstr])
4622 [[view window] setRepresentedFilename: @""];
4624 [[view window] setRepresentedFilename: fstr];
4625 [represented_filename release];
4626 represented_filename = nil;
4627 represented_frame = NULL;
4630 if (type == NSApplicationDefined)
4632 switch ([theEvent data2])
4634 #ifdef NS_IMPL_COCOA
4635 case NSAPP_DATA2_RUNASSCRIPT:
4640 case NSAPP_DATA2_RUNFILEDIALOG:
4641 ns_run_file_dialog ();
4647 if (type == NSCursorUpdate && window == nil)
4649 fprintf (stderr, "Dropping external cursor update event.\n");
4653 if (type == NSApplicationDefined)
4655 /* Events posted by ns_send_appdefined interrupt the run loop here.
4656 But, if a modal window is up, an appdefined can still come through,
4657 (e.g., from a makeKeyWindow event) but stopping self also stops the
4658 modal loop. Just defer it until later. */
4659 if ([NSApp modalWindow] == nil)
4661 last_appdefined_event_data = [theEvent data1];
4666 send_appdefined = YES;
4671 #ifdef NS_IMPL_COCOA
4672 /* If no dialog and none of our frames have focus and it is a move, skip it.
4673 It is a mouse move in an auxiliary menu, i.e. on the top right on OSX,
4674 such as Wifi, sound, date or similar.
4675 This prevents "spooky" highlighting in the frame under the menu. */
4676 if (type == NSMouseMoved && [NSApp modalWindow] == nil)
4678 struct ns_display_info *di;
4679 BOOL has_focus = NO;
4680 for (di = x_display_list; ! has_focus && di; di = di->next)
4681 has_focus = di->x_focus_frame != 0;
4687 [super sendEvent: theEvent];
4691 - (void)showPreferencesWindow: (id)sender
4693 struct frame *emacsframe = SELECTED_FRAME ();
4694 NSEvent *theEvent = [NSApp currentEvent];
4698 emacs_event->kind = NS_NONKEY_EVENT;
4699 emacs_event->code = KEY_NS_SHOW_PREFS;
4700 emacs_event->modifiers = 0;
4701 EV_TRAILER (theEvent);
4705 - (void)newFrame: (id)sender
4707 struct frame *emacsframe = SELECTED_FRAME ();
4708 NSEvent *theEvent = [NSApp currentEvent];
4712 emacs_event->kind = NS_NONKEY_EVENT;
4713 emacs_event->code = KEY_NS_NEW_FRAME;
4714 emacs_event->modifiers = 0;
4715 EV_TRAILER (theEvent);
4719 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4720 - (BOOL) openFile: (NSString *)fileName
4722 struct frame *emacsframe = SELECTED_FRAME ();
4723 NSEvent *theEvent = [NSApp currentEvent];
4728 emacs_event->kind = NS_NONKEY_EVENT;
4729 emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4730 ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4731 ns_input_line = Qnil; /* can be start or cons start,end */
4732 emacs_event->modifiers =0;
4733 EV_TRAILER (theEvent);
4739 /* **************************************************************************
4741 EmacsApp delegate implementation
4743 ************************************************************************** */
4745 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4746 /* --------------------------------------------------------------------------
4747 When application is loaded, terminate event loop in ns_term_init
4748 -------------------------------------------------------------------------- */
4750 NSTRACE (applicationDidFinishLaunching);
4751 #ifdef NS_IMPL_GNUSTEP
4752 ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
4754 [NSApp setServicesProvider: NSApp];
4756 [self antialiasThresholdDidChange:nil];
4757 #ifdef NS_IMPL_COCOA
4758 [[NSNotificationCenter defaultCenter]
4760 selector:@selector(antialiasThresholdDidChange:)
4761 name:NSAntialiasThresholdChangedNotification
4765 ns_send_appdefined (-2);
4768 - (void)antialiasThresholdDidChange:(NSNotification *)notification
4770 #ifdef NS_IMPL_COCOA
4771 macfont_update_antialias_threshold ();
4776 /* Termination sequences:
4779 MenuBar | File | Exit:
4780 Select Quit from App menubar:
4782 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4785 Select Quit from Dock menu:
4788 Cancel -> Nothing else
4792 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4797 - (void) terminate: (id)sender
4799 struct frame *emacsframe = SELECTED_FRAME ();
4804 emacs_event->kind = NS_NONKEY_EVENT;
4805 emacs_event->code = KEY_NS_POWER_OFF;
4806 emacs_event->arg = Qt; /* mark as non-key event */
4807 EV_TRAILER ((id)nil);
4811 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4815 if (NILP (ns_confirm_quit)) // || ns_shutdown_properly --> TO DO
4816 return NSTerminateNow;
4818 ret = NSRunAlertPanel(ns_app_name,
4819 @"Exit requested. Would you like to Save Buffers and Exit, or Cancel the request?",
4820 @"Save Buffers and Exit", @"Cancel", nil);
4822 if (ret == NSAlertDefaultReturn)
4823 return NSTerminateNow;
4824 else if (ret == NSAlertAlternateReturn)
4825 return NSTerminateCancel;
4826 return NSTerminateNow; /* just in case */
4830 not_in_argv (NSString *arg)
4833 const char *a = [arg UTF8String];
4834 for (k = 1; k < initial_argc; ++k)
4835 if (strcmp (a, initial_argv[k]) == 0) return 0;
4839 /* Notification from the Workspace to open a file */
4840 - (BOOL)application: sender openFile: (NSString *)file
4842 if (ns_do_open_file || not_in_argv (file))
4843 [ns_pending_files addObject: file];
4848 /* Open a file as a temporary file */
4849 - (BOOL)application: sender openTempFile: (NSString *)file
4851 if (ns_do_open_file || not_in_argv (file))
4852 [ns_pending_files addObject: file];
4857 /* Notification from the Workspace to open a file noninteractively (?) */
4858 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4860 if (ns_do_open_file || not_in_argv (file))
4861 [ns_pending_files addObject: file];
4865 /* Notification from the Workspace to open multiple files */
4866 - (void)application: sender openFiles: (NSArray *)fileList
4868 NSEnumerator *files = [fileList objectEnumerator];
4870 /* Don't open files from the command line unconditionally,
4871 Cocoa parses the command line wrong, --option value tries to open value
4872 if --option is the last option. */
4873 while ((file = [files nextObject]) != nil)
4874 if (ns_do_open_file || not_in_argv (file))
4875 [ns_pending_files addObject: file];
4877 [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4882 /* Handle dock menu requests. */
4883 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4889 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4890 - (void)applicationWillBecomeActive: (NSNotification *)notification
4892 //ns_app_active=YES;
4894 - (void)applicationDidBecomeActive: (NSNotification *)notification
4896 NSTRACE (applicationDidBecomeActive);
4898 #ifdef NS_IMPL_GNUSTEP
4899 if (! applicationDidFinishLaunchingCalled)
4900 [self applicationDidFinishLaunching:notification];
4902 //ns_app_active=YES;
4904 ns_update_auto_hide_menu_bar ();
4905 // No constraining takes place when the application is not active.
4906 ns_constrain_all_frames ();
4908 - (void)applicationDidResignActive: (NSNotification *)notification
4911 ns_send_appdefined (-1);
4916 /* ==========================================================================
4918 EmacsApp aux handlers for managing event loop
4920 ========================================================================== */
4923 - (void)timeout_handler: (NSTimer *)timedEntry
4924 /* --------------------------------------------------------------------------
4925 The timeout specified to ns_select has passed.
4926 -------------------------------------------------------------------------- */
4928 /*NSTRACE (timeout_handler); */
4929 ns_send_appdefined (-2);
4932 #ifdef NS_IMPL_GNUSTEP
4933 - (void)sendFromMainThread:(id)unused
4935 ns_send_appdefined (nextappdefined);
4939 - (void)fd_handler:(id)unused
4940 /* --------------------------------------------------------------------------
4941 Check data waiting on file descriptors and terminate if so
4942 -------------------------------------------------------------------------- */
4945 int waiting = 1, nfds;
4948 fd_set readfds, writefds, *wfds;
4949 struct timespec timeout, *tmo;
4950 NSAutoreleasePool *pool = nil;
4952 /* NSTRACE (fd_handler); */
4957 pool = [[NSAutoreleasePool alloc] init];
4963 FD_SET (selfds[0], &fds);
4964 result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
4965 if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
4970 pthread_mutex_lock (&select_mutex);
4973 if (select_valid & SELECT_HAVE_READ)
4974 readfds = select_readfds;
4978 if (select_valid & SELECT_HAVE_WRITE)
4980 writefds = select_writefds;
4985 if (select_valid & SELECT_HAVE_TMO)
4987 timeout = select_timeout;
4993 pthread_mutex_unlock (&select_mutex);
4995 FD_SET (selfds[0], &readfds);
4996 if (selfds[0] >= nfds) nfds = selfds[0]+1;
4998 result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
5001 ns_send_appdefined (-2);
5002 else if (result > 0)
5004 if (FD_ISSET (selfds[0], &readfds))
5006 if (read (selfds[0], &c, 1) == 1 && c == 's')
5011 pthread_mutex_lock (&select_mutex);
5012 if (select_valid & SELECT_HAVE_READ)
5013 select_readfds = readfds;
5014 if (select_valid & SELECT_HAVE_WRITE)
5015 select_writefds = writefds;
5016 if (select_valid & SELECT_HAVE_TMO)
5017 select_timeout = timeout;
5018 pthread_mutex_unlock (&select_mutex);
5020 ns_send_appdefined (result);
5030 /* ==========================================================================
5034 ========================================================================== */
5036 /* called from system: queue for next pass through event loop */
5037 - (void)requestService: (NSPasteboard *)pboard
5038 userData: (NSString *)userData
5039 error: (NSString **)error
5041 [ns_pending_service_names addObject: userData];
5042 [ns_pending_service_args addObject: [NSString stringWithUTF8String:
5043 SSDATA (ns_string_from_pasteboard (pboard))]];
5047 /* called from ns_read_socket to clear queue */
5048 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
5050 struct frame *emacsframe = SELECTED_FRAME ();
5051 NSEvent *theEvent = [NSApp currentEvent];
5056 emacs_event->kind = NS_NONKEY_EVENT;
5057 emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
5058 ns_input_spi_name = build_string ([name UTF8String]);
5059 ns_input_spi_arg = build_string ([arg UTF8String]);
5060 emacs_event->modifiers = EV_MODIFIERS (theEvent);
5061 EV_TRAILER (theEvent);
5071 /* ==========================================================================
5073 EmacsView implementation
5075 ========================================================================== */
5078 @implementation EmacsView
5080 /* needed to inform when window closed from LISP */
5081 - (void) setWindowClosing: (BOOL)closing
5083 windowClosing = closing;
5089 NSTRACE (EmacsView_dealloc);
5091 if (fs_state == FULLSCREEN_BOTH)
5092 [nonfs_window release];
5097 /* called on font panel selection */
5098 - (void)changeFont: (id)sender
5100 NSEvent *e = [[self window] currentEvent];
5101 struct face *face = FRAME_DEFAULT_FACE (emacsframe);
5102 struct font *font = face->font;
5107 NSTRACE (changeFont);
5112 #ifdef NS_IMPL_GNUSTEP
5113 nsfont = ((struct nsfont_info *)font)->nsfont;
5115 #ifdef NS_IMPL_COCOA
5116 nsfont = (NSFont *) macfont_get_nsctfont (font);
5119 if ((newFont = [sender convertFont: nsfont]))
5121 SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
5123 emacs_event->kind = NS_NONKEY_EVENT;
5124 emacs_event->modifiers = 0;
5125 emacs_event->code = KEY_NS_CHANGE_FONT;
5127 size = [newFont pointSize];
5128 ns_input_fontsize = make_number (lrint (size));
5129 ns_input_font = build_string ([[newFont familyName] UTF8String]);
5135 - (BOOL)acceptsFirstResponder
5137 NSTRACE (acceptsFirstResponder);
5142 - (void)resetCursorRects
5144 NSRect visible = [self visibleRect];
5145 NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
5146 NSTRACE (resetCursorRects);
5148 if (currentCursor == nil)
5149 currentCursor = [NSCursor arrowCursor];
5151 if (!NSIsEmptyRect (visible))
5152 [self addCursorRect: visible cursor: currentCursor];
5153 [currentCursor setOnMouseEntered: YES];
5158 /*****************************************************************************/
5159 /* Keyboard handling. */
5162 - (void)keyDown: (NSEvent *)theEvent
5164 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5166 unsigned fnKeysym = 0;
5167 static NSMutableArray *nsEvArray;
5168 #ifdef NS_IMPL_GNUSTEP
5169 static BOOL firstTime = YES;
5172 unsigned int flags = [theEvent modifierFlags];
5176 /* Rhapsody and OS X give up and down events for the arrow keys */
5177 if (ns_fake_keydown == YES)
5178 ns_fake_keydown = NO;
5179 else if ([theEvent type] != NSKeyDown)
5185 if (![[self window] isKeyWindow]
5186 && [[theEvent window] isKindOfClass: [EmacsWindow class]]
5187 /* we must avoid an infinite loop here. */
5188 && (EmacsView *)[[theEvent window] delegate] != self)
5190 /* XXX: There is an occasional condition in which, when Emacs display
5191 updates a different frame from the current one, and temporarily
5192 selects it, then processes some interrupt-driven input
5193 (dispnew.c:3878), OS will send the event to the correct NSWindow, but
5194 for some reason that window has its first responder set to the NSView
5195 most recently updated (I guess), which is not the correct one. */
5196 [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
5200 if (nsEvArray == nil)
5201 nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
5203 [NSCursor setHiddenUntilMouseMoves: YES];
5205 if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
5207 clear_mouse_face (hlinfo);
5208 hlinfo->mouse_face_hidden = 1;
5211 if (!processingCompose)
5213 /* When using screen sharing, no left or right information is sent,
5214 so use Left key in those cases. */
5215 int is_left_key, is_right_key;
5217 code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
5218 0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
5220 /* (Carbon way: [theEvent keyCode]) */
5222 /* is it a "function key"? */
5223 /* Note: Sometimes a plain key will have the NSNumericPadKeyMask
5224 flag set (this is probably a bug in the OS).
5226 if (code < 0x00ff && (flags&NSNumericPadKeyMask))
5228 fnKeysym = ns_convert_key ([theEvent keyCode] | NSNumericPadKeyMask);
5232 fnKeysym = ns_convert_key (code);
5237 /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
5238 because Emacs treats Delete and KP-Delete same (in simple.el). */
5239 if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
5240 #ifdef NS_IMPL_GNUSTEP
5241 /* GNUstep uses incompatible keycodes, even for those that are
5242 supposed to be hardware independent. Just check for delete.
5243 Keypad delete does not have keysym 0xFFFF.
5244 See http://savannah.gnu.org/bugs/?25395
5246 || (fnKeysym == 0xFFFF && code == 127)
5249 code = 0xFF08; /* backspace */
5254 /* are there modifiers? */
5255 emacs_event->modifiers = 0;
5257 if (flags & NSHelpKeyMask)
5258 emacs_event->modifiers |= hyper_modifier;
5260 if (flags & NSShiftKeyMask)
5261 emacs_event->modifiers |= shift_modifier;
5263 is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
5264 is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
5265 || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
5268 emacs_event->modifiers |= parse_solitary_modifier
5269 (EQ (ns_right_command_modifier, Qleft)
5270 ? ns_command_modifier
5271 : ns_right_command_modifier);
5275 emacs_event->modifiers |= parse_solitary_modifier
5276 (ns_command_modifier);
5278 /* if super (default), take input manager's word so things like
5279 dvorak / qwerty layout work */
5280 if (EQ (ns_command_modifier, Qsuper)
5282 && [[theEvent characters] length] != 0)
5284 /* XXX: the code we get will be unshifted, so if we have
5285 a shift modifier, must convert ourselves */
5286 if (!(flags & NSShiftKeyMask))
5287 code = [[theEvent characters] characterAtIndex: 0];
5289 /* this is ugly and also requires linking w/Carbon framework
5290 (for LMGetKbdType) so for now leave this rare (?) case
5291 undealt with.. in future look into CGEvent methods */
5294 long smv = GetScriptManagerVariable (smKeyScript);
5295 Handle uchrHandle = GetResource
5296 ('uchr', GetScriptVariable (smv, smScriptKeys));
5298 UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
5299 [[theEvent characters] characterAtIndex: 0],
5300 kUCKeyActionDisplay,
5301 (flags & ~NSCommandKeyMask) >> 8,
5302 LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
5303 &dummy, 1, &dummy, &code);
5310 is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
5311 is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
5312 || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
5315 emacs_event->modifiers |= parse_solitary_modifier
5316 (EQ (ns_right_control_modifier, Qleft)
5317 ? ns_control_modifier
5318 : ns_right_control_modifier);
5321 emacs_event->modifiers |= parse_solitary_modifier
5322 (ns_control_modifier);
5324 if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
5325 emacs_event->modifiers |=
5326 parse_solitary_modifier (ns_function_modifier);
5328 left_is_none = NILP (ns_alternate_modifier)
5329 || EQ (ns_alternate_modifier, Qnone);
5331 is_right_key = (flags & NSRightAlternateKeyMask)
5332 == NSRightAlternateKeyMask;
5333 is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
5335 && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
5339 if ((NILP (ns_right_alternate_modifier)
5340 || EQ (ns_right_alternate_modifier, Qnone)
5341 || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
5343 { /* accept pre-interp alt comb */
5344 if ([[theEvent characters] length] > 0)
5345 code = [[theEvent characters] characterAtIndex: 0];
5346 /*HACK: clear lone shift modifier to stop next if from firing */
5347 if (emacs_event->modifiers == shift_modifier)
5348 emacs_event->modifiers = 0;
5351 emacs_event->modifiers |= parse_solitary_modifier
5352 (EQ (ns_right_alternate_modifier, Qleft)
5353 ? ns_alternate_modifier
5354 : ns_right_alternate_modifier);
5357 if (is_left_key) /* default = meta */
5359 if (left_is_none && !fnKeysym)
5360 { /* accept pre-interp alt comb */
5361 if ([[theEvent characters] length] > 0)
5362 code = [[theEvent characters] characterAtIndex: 0];
5363 /*HACK: clear lone shift modifier to stop next if from firing */
5364 if (emacs_event->modifiers == shift_modifier)
5365 emacs_event->modifiers = 0;
5368 emacs_event->modifiers |=
5369 parse_solitary_modifier (ns_alternate_modifier);
5373 fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
5374 code, fnKeysym, flags, emacs_event->modifiers);
5376 /* if it was a function key or had modifiers, pass it directly to emacs */
5377 if (fnKeysym || (emacs_event->modifiers
5378 && (emacs_event->modifiers != shift_modifier)
5379 && [[theEvent charactersIgnoringModifiers] length] > 0))
5380 /*[[theEvent characters] length] */
5382 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5384 code |= (1<<28)|(3<<16);
5385 else if (code == 0x7f)
5386 code |= (1<<28)|(3<<16);
5388 emacs_event->kind = code > 0xFF
5389 ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5391 emacs_event->code = code;
5392 EV_TRAILER (theEvent);
5393 processingCompose = NO;
5399 #ifdef NS_IMPL_GNUSTEP
5400 /* if we get here we should send the key for input manager processing */
5401 /* Disable warning, there is nothing a user can do about it anyway, and
5402 it does not seem to matter. */
5404 if (firstTime && [[NSInputManager currentInputManager]
5405 wantsToDelayTextChangeNotifications] == NO)
5407 "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
5411 if (NS_KEYLOG && !processingCompose)
5412 fprintf (stderr, "keyDown: Begin compose sequence.\n");
5414 processingCompose = YES;
5415 [nsEvArray addObject: theEvent];
5416 [self interpretKeyEvents: nsEvArray];
5417 [nsEvArray removeObject: theEvent];
5421 #ifdef NS_IMPL_COCOA
5422 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
5423 decided not to send key-down for.
5424 See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
5425 This only applies on Tiger and earlier.
5426 If it matches one of these, send it on to keyDown. */
5427 -(void)keyUp: (NSEvent *)theEvent
5429 int flags = [theEvent modifierFlags];
5430 int code = [theEvent keyCode];
5431 if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
5432 code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
5435 fprintf (stderr, "keyUp: passed test");
5436 ns_fake_keydown = YES;
5437 [self keyDown: theEvent];
5443 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
5446 /* <NSTextInput>: called when done composing;
5447 NOTE: also called when we delete over working text, followed immed.
5448 by doCommandBySelector: deleteBackward: */
5449 - (void)insertText: (id)aString
5452 int len = [(NSString *)aString length];
5456 NSLog (@"insertText '%@'\tlen = %d", aString, len);
5457 processingCompose = NO;
5462 /* first, clear any working text */
5463 if (workingText != nil)
5464 [self deleteWorkingText];
5466 /* now insert the string as keystrokes */
5467 for (i =0; i<len; i++)
5469 code = [aString characterAtIndex: i];
5470 /* TODO: still need this? */
5472 code = '~'; /* 0x7E */
5473 if (code != 32) /* Space */
5474 emacs_event->modifiers = 0;
5476 = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5477 emacs_event->code = code;
5478 EV_TRAILER ((id)nil);
5483 /* <NSTextInput>: inserts display of composing characters */
5484 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
5486 NSString *str = [aString respondsToSelector: @selector (string)] ?
5487 [aString string] : aString;
5489 NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
5490 str, (unsigned long)[str length],
5491 (unsigned long)selRange.length,
5492 (unsigned long)selRange.location);
5494 if (workingText != nil)
5495 [self deleteWorkingText];
5496 if ([str length] == 0)
5502 processingCompose = YES;
5503 workingText = [str copy];
5504 ns_working_text = build_string ([workingText UTF8String]);
5506 emacs_event->kind = NS_TEXT_EVENT;
5507 emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5508 EV_TRAILER ((id)nil);
5512 /* delete display of composing characters [not in <NSTextInput>] */
5513 - (void)deleteWorkingText
5515 if (workingText == nil)
5518 NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
5519 [workingText release];
5521 processingCompose = NO;
5526 emacs_event->kind = NS_TEXT_EVENT;
5527 emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5528 EV_TRAILER ((id)nil);
5532 - (BOOL)hasMarkedText
5534 return workingText != nil;
5538 - (NSRange)markedRange
5540 NSRange rng = workingText != nil
5541 ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5543 NSLog (@"markedRange request");
5551 NSLog (@"unmark (accept) text");
5552 [self deleteWorkingText];
5553 processingCompose = NO;
5557 /* used to position char selection windows, etc. */
5558 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5562 struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5564 NSLog (@"firstRectForCharRange request");
5566 rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5567 rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5568 pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5569 pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5570 +FRAME_LINE_HEIGHT (emacsframe));
5572 pt = [self convertPoint: pt toView: nil];
5573 pt = [[self window] convertBaseToScreen: pt];
5579 - (NSInteger)conversationIdentifier
5581 return (NSInteger)self;
5585 - (void)doCommandBySelector: (SEL)aSelector
5588 NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5590 processingCompose = NO;
5591 if (aSelector == @selector (deleteBackward:))
5593 /* happens when user backspaces over an ongoing composition:
5594 throw a 'delete' into the event queue */
5597 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5598 emacs_event->code = 0xFF08;
5599 EV_TRAILER ((id)nil);
5603 - (NSArray *)validAttributesForMarkedText
5605 static NSArray *arr = nil;
5606 if (arr == nil) arr = [NSArray new];
5607 /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5611 - (NSRange)selectedRange
5614 NSLog (@"selectedRange request");
5615 return NSMakeRange (NSNotFound, 0);
5618 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
5619 GNUSTEP_GUI_MINOR_VERSION > 22
5620 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5622 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
5626 NSLog (@"characterIndexForPoint request");
5630 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5632 static NSAttributedString *str = nil;
5633 if (str == nil) str = [NSAttributedString new];
5635 NSLog (@"attributedSubstringFromRange request");
5639 /* End <NSTextInput> impl. */
5640 /*****************************************************************************/
5643 /* This is what happens when the user presses a mouse button. */
5644 - (void)mouseDown: (NSEvent *)theEvent
5646 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5647 NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5649 NSTRACE (mouseDown);
5651 [self deleteWorkingText];
5656 dpyinfo->last_mouse_frame = emacsframe;
5657 /* appears to be needed to prevent spurious movement events generated on
5659 emacsframe->mouse_moved = 0;
5661 if ([theEvent type] == NSScrollWheel)
5663 CGFloat delta = [theEvent deltaY];
5664 /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5667 delta = [theEvent deltaX];
5670 NSTRACE (deltaIsZero);
5673 emacs_event->kind = HORIZ_WHEEL_EVENT;
5676 emacs_event->kind = WHEEL_EVENT;
5678 emacs_event->code = 0;
5679 emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5680 ((delta > 0) ? up_modifier : down_modifier);
5684 emacs_event->kind = MOUSE_CLICK_EVENT;
5685 emacs_event->code = EV_BUTTON (theEvent);
5686 emacs_event->modifiers = EV_MODIFIERS (theEvent)
5687 | EV_UDMODIFIERS (theEvent);
5689 XSETINT (emacs_event->x, lrint (p.x));
5690 XSETINT (emacs_event->y, lrint (p.y));
5691 EV_TRAILER (theEvent);
5695 - (void)rightMouseDown: (NSEvent *)theEvent
5697 NSTRACE (rightMouseDown);
5698 [self mouseDown: theEvent];
5702 - (void)otherMouseDown: (NSEvent *)theEvent
5704 NSTRACE (otherMouseDown);
5705 [self mouseDown: theEvent];
5709 - (void)mouseUp: (NSEvent *)theEvent
5712 [self mouseDown: theEvent];
5716 - (void)rightMouseUp: (NSEvent *)theEvent
5718 NSTRACE (rightMouseUp);
5719 [self mouseDown: theEvent];
5723 - (void)otherMouseUp: (NSEvent *)theEvent
5725 NSTRACE (otherMouseUp);
5726 [self mouseDown: theEvent];
5730 - (void) scrollWheel: (NSEvent *)theEvent
5732 NSTRACE (scrollWheel);
5733 [self mouseDown: theEvent];
5737 /* Tell emacs the mouse has moved. */
5738 - (void)mouseMoved: (NSEvent *)e
5740 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5741 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5745 // NSTRACE (mouseMoved);
5747 dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
5748 pt = [self convertPoint: [e locationInWindow] fromView: nil];
5749 dpyinfo->last_mouse_motion_x = pt.x;
5750 dpyinfo->last_mouse_motion_y = pt.y;
5752 /* update any mouse face */
5753 if (hlinfo->mouse_face_hidden)
5755 hlinfo->mouse_face_hidden = 0;
5756 clear_mouse_face (hlinfo);
5759 /* tooltip handling */
5760 previous_help_echo_string = help_echo_string;
5761 help_echo_string = Qnil;
5763 if (!NILP (Vmouse_autoselect_window))
5765 NSTRACE (mouse_autoselect_window);
5766 static Lisp_Object last_mouse_window;
5768 = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
5770 if (WINDOWP (window)
5771 && !EQ (window, last_mouse_window)
5772 && !EQ (window, selected_window)
5773 && (focus_follows_mouse
5774 || (EQ (XWINDOW (window)->frame,
5775 XWINDOW (selected_window)->frame))))
5777 NSTRACE (in_window);
5778 emacs_event->kind = SELECT_WINDOW_EVENT;
5779 emacs_event->frame_or_window = window;
5782 /* Remember the last window where we saw the mouse. */
5783 last_mouse_window = window;
5786 if (!note_mouse_movement (emacsframe, pt.x, pt.y))
5787 help_echo_string = previous_help_echo_string;
5789 XSETFRAME (frame, emacsframe);
5790 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5792 /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5793 (note_mouse_highlight), which is called through the
5794 note_mouse_movement () call above */
5795 any_help_event_p = YES;
5796 gen_help_event (help_echo_string, frame, help_echo_window,
5797 help_echo_object, help_echo_pos);
5800 if (emacsframe->mouse_moved && send_appdefined)
5801 ns_send_appdefined (-1);
5805 - (void)mouseDragged: (NSEvent *)e
5807 NSTRACE (mouseDragged);
5808 [self mouseMoved: e];
5812 - (void)rightMouseDragged: (NSEvent *)e
5814 NSTRACE (rightMouseDragged);
5815 [self mouseMoved: e];
5819 - (void)otherMouseDragged: (NSEvent *)e
5821 NSTRACE (otherMouseDragged);
5822 [self mouseMoved: e];
5826 - (BOOL)windowShouldClose: (id)sender
5828 NSEvent *e =[[self window] currentEvent];
5830 NSTRACE (windowShouldClose);
5831 windowClosing = YES;
5834 emacs_event->kind = DELETE_WINDOW_EVENT;
5835 emacs_event->modifiers = 0;
5836 emacs_event->code = 0;
5838 /* Don't close this window, let this be done from lisp code. */
5842 - (void) updateFrameSize: (BOOL) delay;
5844 NSWindow *window = [self window];
5845 NSRect wr = [window frame];
5847 int oldc = cols, oldr = rows;
5848 int oldw = FRAME_PIXEL_WIDTH (emacsframe);
5849 int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
5852 NSTRACE (updateFrameSize);
5853 NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
5855 if (! [self isFullscreen])
5857 #ifdef NS_IMPL_GNUSTEP
5858 // GNUstep does not always update the tool bar height. Force it.
5859 if (toolbar && [toolbar isVisible])
5860 update_frame_tool_bar (emacsframe);
5863 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5864 + FRAME_TOOLBAR_HEIGHT (emacsframe);
5867 if (wait_for_tool_bar)
5869 if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0)
5871 wait_for_tool_bar = NO;
5874 neww = (int)wr.size.width - emacsframe->border_width;
5875 newh = (int)wr.size.height - extra;
5877 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
5878 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
5880 if (cols < MINWIDTH)
5883 if (rows < MINHEIGHT)
5886 if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
5888 NSView *view = FRAME_NS_VIEW (emacsframe);
5889 NSWindow *win = [view window];
5890 NSSize sz = [win resizeIncrements];
5892 change_frame_size (emacsframe,
5893 FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
5894 FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
5896 SET_FRAME_GARBAGED (emacsframe);
5897 cancel_mouse_face (emacsframe);
5899 // Did resize increments change because of a font change?
5900 if (sz.width != FRAME_COLUMN_WIDTH (emacsframe) ||
5901 sz.height != FRAME_LINE_HEIGHT (emacsframe) ||
5902 (frame_resize_pixelwise && sz.width != 1))
5904 sz.width = frame_resize_pixelwise
5905 ? 1 : FRAME_COLUMN_WIDTH (emacsframe);
5906 sz.height = frame_resize_pixelwise
5907 ? 1 : FRAME_LINE_HEIGHT (emacsframe);
5908 [win setResizeIncrements: sz];
5910 NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
5913 [view setFrame: NSMakeRect (0, 0, neww, newh)];
5914 [self windowDidMove:nil]; // Update top/left.
5918 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5919 /* normalize frame to gridded text size */
5923 NSTRACE (windowWillResize);
5924 NSTRACE_SIZE ("Original size", frameSize);
5925 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5927 if (fs_state == FULLSCREEN_MAXIMIZED
5928 && (maximized_width != (int)frameSize.width
5929 || maximized_height != (int)frameSize.height))
5930 [self setFSValue: FULLSCREEN_NONE];
5931 else if (fs_state == FULLSCREEN_WIDTH
5932 && maximized_width != (int)frameSize.width)
5933 [self setFSValue: FULLSCREEN_NONE];
5934 else if (fs_state == FULLSCREEN_HEIGHT
5935 && maximized_height != (int)frameSize.height)
5936 [self setFSValue: FULLSCREEN_NONE];
5937 if (fs_state == FULLSCREEN_NONE)
5938 maximized_width = maximized_height = -1;
5940 if (! [self isFullscreen])
5942 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5943 + FRAME_TOOLBAR_HEIGHT (emacsframe);
5946 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
5947 if (cols < MINWIDTH)
5950 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
5951 frameSize.height - extra);
5952 if (rows < MINHEIGHT)
5954 #ifdef NS_IMPL_COCOA
5956 /* this sets window title to have size in it; the wm does this under GS */
5957 NSRect r = [[self window] frame];
5958 if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5966 else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize)
5969 NSWindow *window = [self window];
5972 char *t = strdup ([[[self window] title] UTF8String]);
5973 char *pos = strstr (t, " — ");
5978 size_title = xmalloc (strlen (old_title) + 40);
5979 esprintf (size_title, "%s — (%d x %d)", old_title, cols, rows);
5980 [window setTitle: [NSString stringWithUTF8String: size_title]];
5985 #endif /* NS_IMPL_COCOA */
5986 /*fprintf (stderr," ...size became %.0f x %.0f (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5992 - (void)windowDidResize: (NSNotification *)notification
5994 if (! [self fsIsNative])
5996 NSWindow *theWindow = [notification object];
5997 /* We can get notification on the non-FS window when in
5999 if ([self window] != theWindow) return;
6002 #ifdef NS_IMPL_GNUSTEP
6003 NSWindow *theWindow = [notification object];
6005 /* In GNUstep, at least currently, it's possible to get a didResize
6006 without getting a willResize.. therefore we need to act as if we got
6007 the willResize now */
6008 NSSize sz = [theWindow frame].size;
6009 sz = [self windowWillResize: theWindow toSize: sz];
6010 #endif /* NS_IMPL_GNUSTEP */
6012 NSTRACE (windowDidResize);
6013 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
6015 if (cols > 0 && rows > 0)
6017 [self updateFrameSize: YES];
6020 ns_send_appdefined (-1);
6023 #ifdef NS_IMPL_COCOA
6024 - (void)viewDidEndLiveResize
6026 [super viewDidEndLiveResize];
6029 [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
6033 maximizing_resize = NO;
6035 #endif /* NS_IMPL_COCOA */
6038 - (void)windowDidBecomeKey: (NSNotification *)notification
6039 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6041 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6042 struct frame *old_focus = dpyinfo->x_focus_frame;
6044 NSTRACE (windowDidBecomeKey);
6046 if (emacsframe != old_focus)
6047 dpyinfo->x_focus_frame = emacsframe;
6049 ns_frame_rehighlight (emacsframe);
6053 emacs_event->kind = FOCUS_IN_EVENT;
6054 EV_TRAILER ((id)nil);
6059 - (void)windowDidResignKey: (NSNotification *)notification
6060 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6062 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6063 BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
6064 NSTRACE (windowDidResignKey);
6067 dpyinfo->x_focus_frame = 0;
6069 emacsframe->mouse_moved = 0;
6070 ns_frame_rehighlight (emacsframe);
6072 /* FIXME: for some reason needed on second and subsequent clicks away
6073 from sole-frame Emacs to get hollow box to show */
6074 if (!windowClosing && [[self window] isVisible] == YES)
6076 x_update_cursor (emacsframe, 1);
6077 x_set_frame_alpha (emacsframe);
6080 if (any_help_event_p)
6083 XSETFRAME (frame, emacsframe);
6084 help_echo_string = Qnil;
6085 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
6088 if (emacs_event && is_focus_frame)
6090 [self deleteWorkingText];
6091 emacs_event->kind = FOCUS_OUT_EVENT;
6092 EV_TRAILER ((id)nil);
6097 - (void)windowWillMiniaturize: sender
6099 NSTRACE (windowWillMiniaturize);
6115 - initFrameFromEmacs: (struct frame *)f
6124 NSTRACE (initFrameFromEmacs);
6127 processingCompose = NO;
6128 scrollbarsNeedingUpdate = 0;
6129 fs_state = FULLSCREEN_NONE;
6130 fs_before_fs = next_maximized = -1;
6131 #ifdef HAVE_NATIVE_FS
6132 fs_is_native = ns_use_native_fullscreen;
6136 maximized_width = maximized_height = -1;
6139 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
6141 ns_userRect = NSMakeRect (0, 0, 0, 0);
6142 r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
6143 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
6144 [self initWithFrame: r];
6145 [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
6147 FRAME_NS_VIEW (f) = self;
6149 #ifdef NS_IMPL_COCOA
6151 maximizing_resize = NO;
6154 win = [[EmacsWindow alloc]
6155 initWithContentRect: r
6156 styleMask: (NSResizableWindowMask |
6157 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
6158 NSTitledWindowMask |
6160 NSMiniaturizableWindowMask |
6161 NSClosableWindowMask)
6162 backing: NSBackingStoreBuffered
6165 #ifdef HAVE_NATIVE_FS
6166 [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
6170 bwidth = f->border_width = wr.size.width - r.size.width;
6171 tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
6173 [win setAcceptsMouseMovedEvents: YES];
6174 [win setDelegate: self];
6175 [win useOptimizedDrawing: YES];
6177 sz.width = frame_resize_pixelwise ? 1 : FRAME_COLUMN_WIDTH (f);
6178 sz.height = frame_resize_pixelwise ? 1 : FRAME_LINE_HEIGHT (f);
6179 [win setResizeIncrements: sz];
6181 [[win contentView] addSubview: self];
6184 [self registerForDraggedTypes: ns_drag_types];
6187 name = [NSString stringWithUTF8String:
6188 NILP (tem) ? "Emacs" : SSDATA (tem)];
6189 [win setTitle: name];
6191 /* toolbar support */
6192 toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
6193 [NSString stringWithFormat: @"Emacs Frame %d",
6195 [win setToolbar: toolbar];
6196 [toolbar setVisible: NO];
6198 /* Don't set frame garbaged until tool bar is up to date?
6199 This avoids an extra clear and redraw (flicker) at frame creation. */
6200 if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
6201 else wait_for_tool_bar = NO;
6204 #ifdef NS_IMPL_COCOA
6206 NSButton *toggleButton;
6207 toggleButton = [win standardWindowButton: NSWindowToolbarButton];
6208 [toggleButton setTarget: self];
6209 [toggleButton setAction: @selector (toggleToolbar: )];
6212 FRAME_TOOLBAR_HEIGHT (f) = 0;
6216 [win setMiniwindowTitle:
6217 [NSString stringWithUTF8String: SSDATA (tem)]];
6220 NSScreen *screen = [win screen];
6223 [win setFrameTopLeftPoint: NSMakePoint
6224 (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
6225 IN_BOUND (-SCREENMAX,
6226 [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
6229 [win makeFirstResponder: self];
6231 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6232 (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
6233 [win setBackgroundColor: col];
6234 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6235 [win setOpaque: NO];
6237 [self allocateGState];
6239 [NSApp registerServicesMenuSendTypes: ns_send_types
6247 - (void)windowDidMove: sender
6249 NSWindow *win = [self window];
6250 NSRect r = [win frame];
6251 NSArray *screens = [NSScreen screens];
6252 NSScreen *screen = [screens objectAtIndex: 0];
6254 NSTRACE (windowDidMove);
6256 if (!emacsframe->output_data.ns)
6260 emacsframe->left_pos = r.origin.x;
6261 emacsframe->top_pos =
6262 [screen frame].size.height - (r.origin.y + r.size.height);
6267 /* Called AFTER method below, but before our windowWillResize call there leads
6268 to windowDidResize -> x_set_window_size. Update emacs' notion of frame
6269 location so set_window_size moves the frame. */
6270 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
6272 emacsframe->output_data.ns->zooming = 1;
6277 /* Override to do something slightly nonstandard, but nice. First click on
6278 zoom button will zoom vertically. Second will zoom completely. Third
6279 returns to original. */
6280 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
6281 defaultFrame:(NSRect)defaultFrame
6283 NSRect result = [sender frame];
6285 NSTRACE (windowWillUseStandardFrame);
6287 if (fs_before_fs != -1) /* Entering fullscreen */
6289 result = defaultFrame;
6291 else if (next_maximized == FULLSCREEN_HEIGHT
6292 || (next_maximized == -1
6293 && abs (defaultFrame.size.height - result.size.height)
6294 > FRAME_LINE_HEIGHT (emacsframe)))
6297 ns_userRect = result;
6298 maximized_height = result.size.height = defaultFrame.size.height;
6299 maximized_width = -1;
6300 result.origin.y = defaultFrame.origin.y;
6301 [self setFSValue: FULLSCREEN_HEIGHT];
6302 #ifdef NS_IMPL_COCOA
6303 maximizing_resize = YES;
6306 else if (next_maximized == FULLSCREEN_WIDTH)
6308 ns_userRect = result;
6309 maximized_width = result.size.width = defaultFrame.size.width;
6310 maximized_height = -1;
6311 result.origin.x = defaultFrame.origin.x;
6312 [self setFSValue: FULLSCREEN_WIDTH];
6314 else if (next_maximized == FULLSCREEN_MAXIMIZED
6315 || (next_maximized == -1
6316 && abs (defaultFrame.size.width - result.size.width)
6317 > FRAME_COLUMN_WIDTH (emacsframe)))
6319 result = defaultFrame; /* second click */
6320 maximized_width = result.size.width;
6321 maximized_height = result.size.height;
6322 [self setFSValue: FULLSCREEN_MAXIMIZED];
6323 #ifdef NS_IMPL_COCOA
6324 maximizing_resize = YES;
6330 result = ns_userRect.size.height ? ns_userRect : result;
6331 ns_userRect = NSMakeRect (0, 0, 0, 0);
6332 #ifdef NS_IMPL_COCOA
6333 maximizing_resize = fs_state != FULLSCREEN_NONE;
6335 [self setFSValue: FULLSCREEN_NONE];
6336 maximized_width = maximized_height = -1;
6339 if (fs_before_fs == -1) next_maximized = -1;
6340 [self windowWillResize: sender toSize: result.size];
6345 - (void)windowDidDeminiaturize: sender
6347 NSTRACE (windowDidDeminiaturize);
6348 if (!emacsframe->output_data.ns)
6351 SET_FRAME_ICONIFIED (emacsframe, 0);
6352 SET_FRAME_VISIBLE (emacsframe, 1);
6353 windows_or_buffers_changed = 63;
6357 emacs_event->kind = DEICONIFY_EVENT;
6358 EV_TRAILER ((id)nil);
6363 - (void)windowDidExpose: sender
6365 NSTRACE (windowDidExpose);
6366 if (!emacsframe->output_data.ns)
6369 SET_FRAME_VISIBLE (emacsframe, 1);
6370 SET_FRAME_GARBAGED (emacsframe);
6372 if (send_appdefined)
6373 ns_send_appdefined (-1);
6377 - (void)windowDidMiniaturize: sender
6379 NSTRACE (windowDidMiniaturize);
6380 if (!emacsframe->output_data.ns)
6383 SET_FRAME_ICONIFIED (emacsframe, 1);
6384 SET_FRAME_VISIBLE (emacsframe, 0);
6388 emacs_event->kind = ICONIFY_EVENT;
6389 EV_TRAILER ((id)nil);
6393 #ifdef HAVE_NATIVE_FS
6394 - (NSApplicationPresentationOptions)window:(NSWindow *)window
6395 willUseFullScreenPresentationOptions:
6396 (NSApplicationPresentationOptions)proposedOptions
6398 return proposedOptions|NSApplicationPresentationAutoHideToolbar;
6402 - (void)windowWillEnterFullScreen:(NSNotification *)notification
6404 fs_before_fs = fs_state;
6407 - (void)windowDidEnterFullScreen:(NSNotification *)notification
6409 [self setFSValue: FULLSCREEN_BOTH];
6410 if (! [self fsIsNative])
6412 [self windowDidBecomeKey:notification];
6413 [nonfs_window orderOut:self];
6417 BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
6418 #ifdef NS_IMPL_COCOA
6419 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
6420 unsigned val = (unsigned)[NSApp presentationOptions];
6422 // OSX 10.7 bug fix, the menu won't appear without this.
6423 // val is non-zero on other OSX versions.
6426 NSApplicationPresentationOptions options
6427 = NSApplicationPresentationAutoHideDock
6428 | NSApplicationPresentationAutoHideMenuBar
6429 | NSApplicationPresentationFullScreen
6430 | NSApplicationPresentationAutoHideToolbar;
6432 [NSApp setPresentationOptions: options];
6436 [toolbar setVisible:tbar_visible];
6440 - (void)windowWillExitFullScreen:(NSNotification *)notification
6442 if (next_maximized != -1)
6443 fs_before_fs = next_maximized;
6446 - (void)windowDidExitFullScreen:(NSNotification *)notification
6448 [self setFSValue: fs_before_fs];
6450 #ifdef HAVE_NATIVE_FS
6451 [self updateCollectionBehavior];
6453 if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
6455 [toolbar setVisible:YES];
6456 update_frame_tool_bar (emacsframe);
6457 [self updateFrameSize:YES];
6458 [[self window] display];
6461 [toolbar setVisible:NO];
6463 if (next_maximized != -1)
6464 [[self window] performZoom:self];
6469 return fs_is_native;
6472 - (BOOL)isFullscreen
6474 if (! fs_is_native) return nonfs_window != nil;
6475 #ifdef HAVE_NATIVE_FS
6476 return ([[self window] styleMask] & NSFullScreenWindowMask) != 0;
6482 #ifdef HAVE_NATIVE_FS
6483 - (void)updateCollectionBehavior
6485 if (! [self isFullscreen])
6487 NSWindow *win = [self window];
6488 NSWindowCollectionBehavior b = [win collectionBehavior];
6489 if (ns_use_native_fullscreen)
6490 b |= NSWindowCollectionBehaviorFullScreenPrimary;
6492 b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
6494 [win setCollectionBehavior: b];
6495 fs_is_native = ns_use_native_fullscreen;
6500 - (void)toggleFullScreen: (id)sender
6511 #ifdef HAVE_NATIVE_FS
6512 [[self window] toggleFullScreen:sender];
6518 onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
6521 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6522 (FRAME_DEFAULT_FACE (f)),
6525 sz.width = frame_resize_pixelwise ? 1 : FRAME_COLUMN_WIDTH (f);
6526 sz.height = frame_resize_pixelwise ? 1 : FRAME_LINE_HEIGHT (f);
6528 if (fs_state != FULLSCREEN_BOTH)
6530 NSScreen *screen = [w screen];
6532 #if defined (NS_IMPL_COCOA) && \
6533 MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
6534 /* Hide ghost menu bar on secondary monitor? */
6535 if (! onFirstScreen)
6536 onFirstScreen = [NSScreen screensHaveSeparateSpaces];
6538 /* Hide dock and menubar if we are on the primary screen. */
6541 #ifdef NS_IMPL_COCOA
6542 NSApplicationPresentationOptions options
6543 = NSApplicationPresentationAutoHideDock
6544 | NSApplicationPresentationAutoHideMenuBar;
6546 [NSApp setPresentationOptions: options];
6548 [NSMenu setMenuBarVisible:NO];
6552 fw = [[EmacsFSWindow alloc]
6553 initWithContentRect:[w contentRectForFrameRect:wr]
6554 styleMask:NSBorderlessWindowMask
6555 backing:NSBackingStoreBuffered
6559 [fw setContentView:[w contentView]];
6560 [fw setTitle:[w title]];
6561 [fw setDelegate:self];
6562 [fw setAcceptsMouseMovedEvents: YES];
6563 [fw useOptimizedDrawing: YES];
6564 [fw setResizeIncrements: sz];
6565 [fw setBackgroundColor: col];
6566 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6569 f->border_width = 0;
6570 FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
6571 tobar_height = FRAME_TOOLBAR_HEIGHT (f);
6572 FRAME_TOOLBAR_HEIGHT (f) = 0;
6576 [self windowWillEnterFullScreen:nil];
6577 [fw makeKeyAndOrderFront:NSApp];
6578 [fw makeFirstResponder:self];
6580 r = [fw frameRectForContentRect:[screen frame]];
6581 [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
6582 [self windowDidEnterFullScreen:nil];
6593 #ifdef NS_IMPL_COCOA
6594 [NSApp setPresentationOptions: NSApplicationPresentationDefault];
6596 [NSMenu setMenuBarVisible:YES];
6600 [w setContentView:[fw contentView]];
6601 [w setResizeIncrements: sz];
6602 [w setBackgroundColor: col];
6603 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6606 f->border_width = bwidth;
6607 FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
6608 if (FRAME_EXTERNAL_TOOL_BAR (f))
6609 FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
6611 [self windowWillExitFullScreen:nil];
6612 [fw setFrame: [w frame] display:YES animate:ns_use_fullscreen_animation];
6614 [w makeKeyAndOrderFront:NSApp];
6615 [self windowDidExitFullScreen:nil];
6616 [self updateFrameSize:YES];
6622 if (fs_state != emacsframe->want_fullscreen)
6624 if (fs_state == FULLSCREEN_BOTH)
6626 [self toggleFullScreen:self];
6629 switch (emacsframe->want_fullscreen)
6631 case FULLSCREEN_BOTH:
6632 [self toggleFullScreen:self];
6634 case FULLSCREEN_WIDTH:
6635 next_maximized = FULLSCREEN_WIDTH;
6636 if (fs_state != FULLSCREEN_BOTH)
6637 [[self window] performZoom:self];
6639 case FULLSCREEN_HEIGHT:
6640 next_maximized = FULLSCREEN_HEIGHT;
6641 if (fs_state != FULLSCREEN_BOTH)
6642 [[self window] performZoom:self];
6644 case FULLSCREEN_MAXIMIZED:
6645 next_maximized = FULLSCREEN_MAXIMIZED;
6646 if (fs_state != FULLSCREEN_BOTH)
6647 [[self window] performZoom:self];
6649 case FULLSCREEN_NONE:
6650 if (fs_state != FULLSCREEN_BOTH)
6652 next_maximized = FULLSCREEN_NONE;
6653 [[self window] performZoom:self];
6658 emacsframe->want_fullscreen = FULLSCREEN_NONE;
6663 - (void) setFSValue: (int)value
6665 Lisp_Object lval = Qnil;
6668 case FULLSCREEN_BOTH:
6671 case FULLSCREEN_WIDTH:
6674 case FULLSCREEN_HEIGHT:
6677 case FULLSCREEN_MAXIMIZED:
6681 store_frame_param (emacsframe, Qfullscreen, lval);
6685 - (void)mouseEntered: (NSEvent *)theEvent
6687 NSTRACE (mouseEntered);
6689 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
6690 = EV_TIMESTAMP (theEvent);
6694 - (void)mouseExited: (NSEvent *)theEvent
6696 Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
6698 NSTRACE (mouseExited);
6703 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
6704 = EV_TIMESTAMP (theEvent);
6706 if (emacsframe == hlinfo->mouse_face_mouse_frame)
6708 clear_mouse_face (hlinfo);
6709 hlinfo->mouse_face_mouse_frame = 0;
6717 if (context_menu_value == -1)
6718 context_menu_value = [sender tag];
6721 NSInteger tag = [sender tag];
6722 find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
6723 emacsframe->menu_bar_vector,
6727 ns_send_appdefined (-1);
6732 - (EmacsToolbar *)toolbar
6738 /* this gets called on toolbar button click */
6739 - toolbarClicked: (id)item
6742 int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
6744 NSTRACE (toolbarClicked);
6749 /* send first event (for some reason two needed) */
6750 theEvent = [[self window] currentEvent];
6751 emacs_event->kind = TOOL_BAR_EVENT;
6752 XSETFRAME (emacs_event->arg, emacsframe);
6753 EV_TRAILER (theEvent);
6755 emacs_event->kind = TOOL_BAR_EVENT;
6756 /* XSETINT (emacs_event->code, 0); */
6757 emacs_event->arg = AREF (emacsframe->tool_bar_items,
6758 idx + TOOL_BAR_ITEM_KEY);
6759 emacs_event->modifiers = EV_MODIFIERS (theEvent);
6760 EV_TRAILER (theEvent);
6765 - toggleToolbar: (id)sender
6770 emacs_event->kind = NS_NONKEY_EVENT;
6771 emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
6772 EV_TRAILER ((id)nil);
6777 - (void)drawRect: (NSRect)rect
6779 int x = NSMinX (rect), y = NSMinY (rect);
6780 int width = NSWidth (rect), height = NSHeight (rect);
6784 if (!emacsframe || !emacsframe->output_data.ns)
6787 ns_clear_frame_area (emacsframe, x, y, width, height);
6788 expose_frame (emacsframe, x, y, width, height);
6791 drawRect: may be called (at least in OS X 10.5) for invisible
6792 views as well for some reason. Thus, do not infer visibility
6795 emacsframe->async_visible = 1;
6796 emacsframe->async_iconified = 0;
6801 /* NSDraggingDestination protocol methods. Actually this is not really a
6802 protocol, but a category of Object. O well... */
6804 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
6806 NSTRACE (draggingEntered);
6807 return NSDragOperationGeneric;
6811 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
6817 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
6822 NSEvent *theEvent = [[self window] currentEvent];
6824 NSDragOperation op = [sender draggingSourceOperationMask];
6827 NSTRACE (performDragOperation);
6832 position = [self convertPoint: [sender draggingLocation] fromView: nil];
6833 x = lrint (position.x); y = lrint (position.y);
6835 pb = [sender draggingPasteboard];
6836 type = [pb availableTypeFromArray: ns_drag_types];
6838 if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
6839 // URL drags contain all operations (0xf), don't allow all to be set.
6842 if (op & NSDragOperationLink)
6843 modifiers |= NSControlKeyMask;
6844 if (op & NSDragOperationCopy)
6845 modifiers |= NSAlternateKeyMask;
6846 if (op & NSDragOperationGeneric)
6847 modifiers |= NSCommandKeyMask;
6850 modifiers = EV_MODIFIERS2 (modifiers);
6855 else if ([type isEqualToString: NSFilenamesPboardType])
6858 NSEnumerator *fenum;
6861 if (!(files = [pb propertyListForType: type]))
6864 fenum = [files objectEnumerator];
6865 while ( (file = [fenum nextObject]) )
6867 emacs_event->kind = DRAG_N_DROP_EVENT;
6868 XSETINT (emacs_event->x, x);
6869 XSETINT (emacs_event->y, y);
6870 ns_input_file = append2 (ns_input_file,
6871 build_string ([file UTF8String]));
6872 emacs_event->modifiers = modifiers;
6873 emacs_event->arg = list2 (Qfile, build_string ([file UTF8String]));
6874 EV_TRAILER (theEvent);
6878 else if ([type isEqualToString: NSURLPboardType])
6880 NSURL *url = [NSURL URLFromPasteboard: pb];
6881 if (url == nil) return NO;
6883 emacs_event->kind = DRAG_N_DROP_EVENT;
6884 XSETINT (emacs_event->x, x);
6885 XSETINT (emacs_event->y, y);
6886 emacs_event->modifiers = modifiers;
6887 emacs_event->arg = list2 (Qurl,
6888 build_string ([[url absoluteString]
6890 EV_TRAILER (theEvent);
6892 if ([url isFileURL] != NO)
6894 NSString *file = [url path];
6895 ns_input_file = append2 (ns_input_file,
6896 build_string ([file UTF8String]));
6900 else if ([type isEqualToString: NSStringPboardType]
6901 || [type isEqualToString: NSTabularTextPboardType])
6905 if (! (data = [pb stringForType: type]))
6908 emacs_event->kind = DRAG_N_DROP_EVENT;
6909 XSETINT (emacs_event->x, x);
6910 XSETINT (emacs_event->y, y);
6911 emacs_event->modifiers = modifiers;
6912 emacs_event->arg = list2 (Qnil, build_string ([data UTF8String]));
6913 EV_TRAILER (theEvent);
6918 fprintf (stderr, "Invalid data type in dragging pasteboard");
6924 - (id) validRequestorForSendType: (NSString *)typeSent
6925 returnType: (NSString *)typeReturned
6927 NSTRACE (validRequestorForSendType);
6928 if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
6929 && typeReturned == nil)
6931 if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
6935 return [super validRequestorForSendType: typeSent
6936 returnType: typeReturned];
6940 /* The next two methods are part of NSServicesRequests informal protocol,
6941 supposedly called when a services menu item is chosen from this app.
6942 But this should not happen because we override the services menu with our
6943 own entries which call ns-perform-service.
6944 Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
6945 So let's at least stub them out until further investigation can be done. */
6947 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
6949 /* we could call ns_string_from_pasteboard(pboard) here but then it should
6950 be written into the buffer in place of the existing selection..
6951 ordinary service calls go through functions defined in ns-win.el */
6955 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
6957 NSArray *typesDeclared;
6960 /* We only support NSStringPboardType */
6961 if ([types containsObject:NSStringPboardType] == NO) {
6965 val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6966 if (CONSP (val) && SYMBOLP (XCAR (val)))
6969 if (CONSP (val) && NILP (XCDR (val)))
6972 if (! STRINGP (val))
6975 typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
6976 [pb declareTypes:typesDeclared owner:nil];
6977 ns_string_to_pasteboard (pb, val);
6982 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
6983 (gives a miniaturized version of the window); currently we use the latter for
6984 frames whose active buffer doesn't correspond to any file
6985 (e.g., '*scratch*') */
6986 - setMiniwindowImage: (BOOL) setMini
6988 id image = [[self window] miniwindowImage];
6989 NSTRACE (setMiniwindowImage);
6991 /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
6992 about "AppleDockIconEnabled" notwithstanding, however the set message
6993 below has its effect nonetheless. */
6994 if (image != emacsframe->output_data.ns->miniimage)
6996 if (image && [image isKindOfClass: [EmacsImage class]])
6998 [[self window] setMiniwindowImage:
6999 setMini ? emacsframe->output_data.ns->miniimage : nil];
7006 - (void) setRows: (int) r andColumns: (int) c
7012 @end /* EmacsView */
7016 /* ==========================================================================
7018 EmacsWindow implementation
7020 ========================================================================== */
7022 @implementation EmacsWindow
7024 #ifdef NS_IMPL_COCOA
7025 - (id)accessibilityAttributeValue:(NSString *)attribute
7027 Lisp_Object str = Qnil;
7028 struct frame *f = SELECTED_FRAME ();
7029 struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
7031 if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
7032 return NSAccessibilityTextFieldRole;
7034 if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
7035 && curbuf && ! NILP (BVAR (curbuf, mark_active)))
7037 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7039 else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
7041 if (! NILP (BVAR (curbuf, mark_active)))
7042 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7046 ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
7047 ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
7048 ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
7050 if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
7051 str = make_uninit_multibyte_string (range, byte_range);
7053 str = make_uninit_string (range);
7054 /* To check: This returns emacs-utf-8, which is a superset of utf-8.
7055 Is this a problem? */
7056 memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
7063 if (CONSP (str) && SYMBOLP (XCAR (str)))
7066 if (CONSP (str) && NILP (XCDR (str)))
7071 const char *utfStr = SSDATA (str);
7072 NSString *nsStr = [NSString stringWithUTF8String: utfStr];
7077 return [super accessibilityAttributeValue:attribute];
7079 #endif /* NS_IMPL_COCOA */
7081 /* If we have multiple monitors, one above the other, we don't want to
7082 restrict the height to just one monitor. So we override this. */
7083 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
7085 /* When making the frame visible for the first time or if there is just
7086 one screen, we want to constrain. Other times not. */
7087 NSArray *screens = [NSScreen screens];
7088 NSUInteger nr_screens = [screens count], nr_eff_screens = 0, i;
7089 struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
7090 NSTRACE (constrainFrameRect);
7091 NSTRACE_RECT ("input", frameRect);
7093 if (ns_menu_bar_should_be_hidden ())
7096 if (nr_screens == 1)
7097 return [super constrainFrameRect:frameRect toScreen:screen];
7099 #ifdef NS_IMPL_COCOA
7100 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
7101 // If separate spaces is on, it is like each screen is independent. There is
7102 // no spanning of frames across screens.
7103 if ([NSScreen screensHaveSeparateSpaces])
7104 return [super constrainFrameRect:frameRect toScreen:screen];
7108 for (i = 0; i < nr_screens; ++i)
7110 NSScreen *s = [screens objectAtIndex: i];
7111 NSRect scrrect = [s frame];
7112 NSRect intersect = NSIntersectionRect (frameRect, scrrect);
7114 if (intersect.size.width > 0 || intersect.size.height > 0)
7118 if (nr_eff_screens == 1)
7119 return [super constrainFrameRect:frameRect toScreen:screen];
7121 /* The default implementation does two things 1) ensure that the top
7122 of the rectangle is below the menu bar (or below the top of the
7123 screen) and 2) resizes windows larger than the screen. As we
7124 don't want the latter, a smaller rectangle is used. */
7125 #define FAKE_HEIGHT 64
7126 float old_top = frameRect.origin.y + frameRect.size.height;
7128 r.size.height = FAKE_HEIGHT;
7129 r.size.width = frameRect.size.width;
7130 r.origin.x = frameRect.origin.x;
7131 r.origin.y = old_top - FAKE_HEIGHT;
7133 NSTRACE_RECT ("input to super", r);
7135 r = [super constrainFrameRect:r toScreen:screen];
7137 NSTRACE_RECT ("output from super", r);
7139 float new_top = r.origin.y + FAKE_HEIGHT;
7140 if (new_top < old_top)
7142 frameRect.origin.y = new_top - frameRect.size.height;
7145 NSTRACE_RECT ("output", frameRect);
7151 @end /* EmacsWindow */
7154 @implementation EmacsFSWindow
7156 - (BOOL)canBecomeKeyWindow
7161 - (BOOL)canBecomeMainWindow
7168 /* ==========================================================================
7170 EmacsScroller implementation
7172 ========================================================================== */
7175 @implementation EmacsScroller
7177 /* for repeat button push */
7178 #define SCROLL_BAR_FIRST_DELAY 0.5
7179 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
7181 + (CGFloat) scrollerWidth
7183 /* TODO: if we want to allow variable widths, this is the place to do it,
7184 however neither GNUstep nor Cocoa support it very well */
7185 return [NSScroller scrollerWidth];
7189 - initFrame: (NSRect )r window: (Lisp_Object)nwin
7191 NSTRACE (EmacsScroller_initFrame);
7193 r.size.width = [EmacsScroller scrollerWidth];
7194 [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
7195 [self setContinuous: YES];
7196 [self setEnabled: YES];
7198 /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
7199 locked against the top and bottom edges, and right edge on OS X, where
7200 scrollers are on right. */
7201 #ifdef NS_IMPL_GNUSTEP
7202 [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
7204 [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
7207 window = XWINDOW (nwin);
7209 pixel_height = NSHeight (r);
7210 if (pixel_height == 0) pixel_height = 1;
7211 min_portion = 20 / pixel_height;
7213 frame = XFRAME (window->frame);
7214 if (FRAME_LIVE_P (frame))
7217 EmacsView *view = FRAME_NS_VIEW (frame);
7218 NSView *sview = [[view window] contentView];
7219 NSArray *subs = [sview subviews];
7221 /* disable optimization stopping redraw of other scrollbars */
7222 view->scrollbarsNeedingUpdate = 0;
7223 for (i =[subs count]-1; i >= 0; i--)
7224 if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
7225 view->scrollbarsNeedingUpdate++;
7226 [sview addSubview: self];
7229 /* [self setFrame: r]; */
7235 - (void)setFrame: (NSRect)newRect
7237 NSTRACE (EmacsScroller_setFrame);
7238 /* block_input (); */
7239 pixel_height = NSHeight (newRect);
7240 if (pixel_height == 0) pixel_height = 1;
7241 min_portion = 20 / pixel_height;
7242 [super setFrame: newRect];
7243 /* unblock_input (); */
7249 NSTRACE (EmacsScroller_dealloc);
7251 wset_vertical_scroll_bar (window, Qnil);
7276 bool ret = condemned;
7281 /* ensure other scrollbar updates after deletion */
7282 view = (EmacsView *)FRAME_NS_VIEW (frame);
7284 view->scrollbarsNeedingUpdate++;
7286 wset_vertical_scroll_bar (window, Qnil);
7288 [self removeFromSuperview];
7296 - (void)resetCursorRects
7298 NSRect visible = [self visibleRect];
7299 NSTRACE (resetCursorRects);
7301 if (!NSIsEmptyRect (visible))
7302 [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
7303 [[NSCursor arrowCursor] setOnMouseEntered: YES];
7307 - (int) checkSamePosition: (int) position portion: (int) portion
7310 return em_position ==position && em_portion ==portion && em_whole ==whole
7311 && portion != whole; /* needed for resize empty buf */
7315 - setPosition: (int)position portion: (int)portion whole: (int)whole
7317 NSTRACE (setPosition);
7319 em_position = position;
7320 em_portion = portion;
7323 if (portion >= whole)
7325 #ifdef NS_IMPL_COCOA
7326 [self setKnobProportion: 1.0];
7327 [self setDoubleValue: 1.0];
7329 [self setFloatValue: 0.0 knobProportion: 1.0];
7336 portion = max ((float)whole*min_portion/pixel_height, portion);
7337 pos = (float)position / (whole - portion);
7338 por = (CGFloat)portion/whole;
7339 #ifdef NS_IMPL_COCOA
7340 [self setKnobProportion: por];
7341 [self setDoubleValue: pos];
7343 [self setFloatValue: pos knobProportion: por];
7350 /* set up emacs_event */
7351 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
7357 emacs_event->part = last_hit_part;
7358 emacs_event->code = 0;
7359 emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
7360 XSETWINDOW (win, window);
7361 emacs_event->frame_or_window = win;
7362 emacs_event->timestamp = EV_TIMESTAMP (e);
7363 emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
7364 emacs_event->arg = Qnil;
7365 XSETINT (emacs_event->x, loc * pixel_height);
7366 XSETINT (emacs_event->y, pixel_height-20);
7370 n_emacs_events_pending++;
7371 kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
7374 hold_event (emacs_event);
7375 EVENT_INIT (*emacs_event);
7376 ns_send_appdefined (-1);
7380 /* called manually thru timer to implement repeated button action w/hold-down */
7381 - repeatScroll: (NSTimer *)scrollEntry
7383 NSEvent *e = [[self window] currentEvent];
7384 NSPoint p = [[self window] mouseLocationOutsideOfEventStream];
7385 BOOL inKnob = [self testPart: p] == NSScrollerKnob;
7387 /* clear timer if need be */
7388 if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
7390 [scroll_repeat_entry invalidate];
7391 [scroll_repeat_entry release];
7392 scroll_repeat_entry = nil;
7398 = [[NSTimer scheduledTimerWithTimeInterval:
7399 SCROLL_BAR_CONTINUOUS_DELAY
7401 selector: @selector (repeatScroll:)
7407 [self sendScrollEventAtLoc: 0 fromEvent: e];
7412 /* Asynchronous mouse tracking for scroller. This allows us to dispatch
7413 mouseDragged events without going into a modal loop. */
7414 - (void)mouseDown: (NSEvent *)e
7417 /* hitPart is only updated AFTER event is passed on */
7418 NSScrollerPart part = [self testPart: [e locationInWindow]];
7419 CGFloat inc = 0.0, loc, kloc, pos;
7422 NSTRACE (EmacsScroller_mouseDown);
7426 case NSScrollerDecrementPage:
7427 last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
7428 case NSScrollerIncrementPage:
7429 last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
7430 case NSScrollerDecrementLine:
7431 last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
7432 case NSScrollerIncrementLine:
7433 last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
7434 case NSScrollerKnob:
7435 last_hit_part = scroll_bar_handle; break;
7436 case NSScrollerKnobSlot: /* GNUstep-only */
7437 last_hit_part = scroll_bar_move_ratio; break;
7438 default: /* NSScrollerNoPart? */
7439 fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
7446 pos = 0; /* ignored */
7448 /* set a timer to repeat, as we can't let superclass do this modally */
7450 = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
7452 selector: @selector (repeatScroll:)
7459 /* handle, or on GNUstep possibly slot */
7460 NSEvent *fake_event;
7462 /* compute float loc in slot and mouse offset on knob */
7463 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7465 loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7471 else if (loc >= NSHeight (sr))
7473 loc = NSHeight (sr);
7481 kr = [self convertRect: [self rectForPart: NSScrollerKnob]
7483 kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
7485 last_mouse_offset = kloc;
7487 /* if knob, tell emacs a location offset by knob pos
7488 (to indicate top of handle) */
7489 if (part == NSScrollerKnob)
7490 pos = (loc - last_mouse_offset) / NSHeight (sr);
7492 /* else this is a slot click on GNUstep: go straight there */
7493 pos = loc / NSHeight (sr);
7495 /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
7496 fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
7497 location: [e locationInWindow]
7498 modifierFlags: [e modifierFlags]
7499 timestamp: [e timestamp]
7500 windowNumber: [e windowNumber]
7501 context: [e context]
7502 eventNumber: [e eventNumber]
7503 clickCount: [e clickCount]
7504 pressure: [e pressure]];
7505 [super mouseUp: fake_event];
7508 if (part != NSScrollerKnob)
7509 [self sendScrollEventAtLoc: pos fromEvent: e];
7513 /* Called as we manually track scroller drags, rather than superclass. */
7514 - (void)mouseDragged: (NSEvent *)e
7519 NSTRACE (EmacsScroller_mouseDragged);
7521 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7523 loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7529 else if (loc >= NSHeight (sr) + last_mouse_offset)
7531 loc = NSHeight (sr) + last_mouse_offset;
7534 pos = (loc - last_mouse_offset) / NSHeight (sr);
7535 [self sendScrollEventAtLoc: pos fromEvent: e];
7539 - (void)mouseUp: (NSEvent *)e
7541 if (scroll_repeat_entry)
7543 [scroll_repeat_entry invalidate];
7544 [scroll_repeat_entry release];
7545 scroll_repeat_entry = nil;
7547 last_hit_part = scroll_bar_above_handle;
7551 /* treat scrollwheel events in the bar as though they were in the main window */
7552 - (void) scrollWheel: (NSEvent *)theEvent
7554 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
7555 [view mouseDown: theEvent];
7558 @end /* EmacsScroller */
7561 #ifdef NS_IMPL_GNUSTEP
7562 /* Dummy class to get rid of startup warnings. */
7563 @implementation EmacsDocument
7569 /* ==========================================================================
7571 Font-related functions; these used to be in nsfaces.m
7573 ========================================================================== */
7577 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
7579 struct font *font = XFONT_OBJECT (font_object);
7580 EmacsView *view = FRAME_NS_VIEW (f);
7583 fontset = fontset_from_font (font_object);
7584 FRAME_FONTSET (f) = fontset;
7586 if (FRAME_FONT (f) == font)
7587 /* This font is already set in frame F. There's nothing more to
7591 FRAME_FONT (f) = font;
7593 FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
7594 FRAME_COLUMN_WIDTH (f) = font->average_width;
7595 FRAME_LINE_HEIGHT (f) = font->height;
7597 /* Compute the scroll bar width in character columns. */
7598 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
7600 int wid = FRAME_COLUMN_WIDTH (f);
7601 FRAME_CONFIG_SCROLL_BAR_COLS (f)
7602 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
7606 int wid = FRAME_COLUMN_WIDTH (f);
7607 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
7610 /* Compute the scroll bar height in character lines. */
7611 if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0)
7613 int height = FRAME_LINE_HEIGHT (f);
7614 FRAME_CONFIG_SCROLL_BAR_LINES (f)
7615 = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
7619 int height = FRAME_LINE_HEIGHT (f);
7620 FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
7623 /* Now make the frame display the given font. */
7624 if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
7625 x_set_window_size (f, false, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
7626 FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), true);
7632 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
7633 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
7637 ns_xlfd_to_fontname (const char *xlfd)
7638 /* --------------------------------------------------------------------------
7639 Convert an X font name (XLFD) to an NS font name.
7640 Only family is used.
7641 The string returned is temporarily allocated.
7642 -------------------------------------------------------------------------- */
7644 char *name = xmalloc (180);
7648 if (!strncmp (xlfd, "--", 2))
7649 sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
7651 sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
7653 /* stopgap for malformed XLFD input */
7654 if (strlen (name) == 0)
7655 strcpy (name, "Monaco");
7657 /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
7658 also uppercase after '-' or ' ' */
7659 name[0] = c_toupper (name[0]);
7660 for (len =strlen (name), i =0; i<len; i++)
7666 name[i+1] = c_toupper (name[i+1]);
7668 else if (name[i] == '_')
7672 name[i+1] = c_toupper (name[i+1]);
7675 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name); */
7676 ret = [[NSString stringWithUTF8String: name] UTF8String];
7683 syms_of_nsterm (void)
7685 NSTRACE (syms_of_nsterm);
7687 ns_antialias_threshold = 10.0;
7689 /* from 23+ we need to tell emacs what modifiers there are.. */
7690 DEFSYM (Qmodifier_value, "modifier-value");
7691 DEFSYM (Qalt, "alt");
7692 DEFSYM (Qhyper, "hyper");
7693 DEFSYM (Qmeta, "meta");
7694 DEFSYM (Qsuper, "super");
7695 DEFSYM (Qcontrol, "control");
7696 DEFSYM (QUTF8_STRING, "UTF8_STRING");
7698 DEFSYM (Qfile, "file");
7699 DEFSYM (Qurl, "url");
7701 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
7702 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
7703 Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
7704 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
7705 Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
7707 DEFVAR_LISP ("ns-input-file", ns_input_file,
7708 "The file specified in the last NS event.");
7709 ns_input_file =Qnil;
7711 DEFVAR_LISP ("ns-working-text", ns_working_text,
7712 "String for visualizing working composition sequence.");
7713 ns_working_text =Qnil;
7715 DEFVAR_LISP ("ns-input-font", ns_input_font,
7716 "The font specified in the last NS event.");
7717 ns_input_font =Qnil;
7719 DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
7720 "The fontsize specified in the last NS event.");
7721 ns_input_fontsize =Qnil;
7723 DEFVAR_LISP ("ns-input-line", ns_input_line,
7724 "The line specified in the last NS event.");
7725 ns_input_line =Qnil;
7727 DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
7728 "The service name specified in the last NS event.");
7729 ns_input_spi_name =Qnil;
7731 DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
7732 "The service argument specified in the last NS event.");
7733 ns_input_spi_arg =Qnil;
7735 DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
7736 "This variable describes the behavior of the alternate or option key.\n\
7737 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7738 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7739 at all, allowing it to be used at a lower level for accented character entry.");
7740 ns_alternate_modifier = Qmeta;
7742 DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
7743 "This variable describes the behavior of the right alternate or option key.\n\
7744 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7745 Set to left means be the same key as `ns-alternate-modifier'.\n\
7746 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7747 at all, allowing it to be used at a lower level for accented character entry.");
7748 ns_right_alternate_modifier = Qleft;
7750 DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
7751 "This variable describes the behavior of the command key.\n\
7752 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7753 ns_command_modifier = Qsuper;
7755 DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
7756 "This variable describes the behavior of the right command key.\n\
7757 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7758 Set to left means be the same key as `ns-command-modifier'.\n\
7759 Set to none means that the command / option key is not interpreted by Emacs\n\
7760 at all, allowing it to be used at a lower level for accented character entry.");
7761 ns_right_command_modifier = Qleft;
7763 DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
7764 "This variable describes the behavior of the control key.\n\
7765 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7766 ns_control_modifier = Qcontrol;
7768 DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
7769 "This variable describes the behavior of the right control key.\n\
7770 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7771 Set to left means be the same key as `ns-control-modifier'.\n\
7772 Set to none means that the control / option key is not interpreted by Emacs\n\
7773 at all, allowing it to be used at a lower level for accented character entry.");
7774 ns_right_control_modifier = Qleft;
7776 DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
7777 "This variable describes the behavior of the function key (on laptops).\n\
7778 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7779 Set to none means that the function key is not interpreted by Emacs at all,\n\
7780 allowing it to be used at a lower level for accented character entry.");
7781 ns_function_modifier = Qnone;
7783 DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
7784 "Non-nil (the default) means to render text antialiased.");
7785 ns_antialias_text = Qt;
7787 DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
7788 "Whether to confirm application quit using dialog.");
7789 ns_confirm_quit = Qnil;
7791 DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
7792 doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
7793 Only works on OSX 10.6 or later. */);
7794 ns_auto_hide_menu_bar = Qnil;
7796 DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
7797 doc: /*Non-nil means to use native fullscreen on OSX >= 10.7.
7798 Nil means use fullscreen the old (< 10.7) way. The old way works better with
7799 multiple monitors, but lacks tool bar. This variable is ignored on OSX < 10.7.
7800 Default is t for OSX >= 10.7, nil otherwise. */);
7801 #ifdef HAVE_NATIVE_FS
7802 ns_use_native_fullscreen = YES;
7804 ns_use_native_fullscreen = NO;
7806 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
7808 DEFVAR_BOOL ("ns-use-fullscreen-animation", ns_use_fullscreen_animation,
7809 doc: /*Non-nil means use animation on non-native fullscreen.
7810 For native fullscreen, this does nothing.
7811 Default is nil. */);
7812 ns_use_fullscreen_animation = NO;
7814 DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
7815 doc: /*Non-nil means to use sRGB colorspace on OSX >= 10.7.
7816 Note that this does not apply to images.
7817 This variable is ignored on OSX < 10.7 and GNUstep. */);
7818 ns_use_srgb_colorspace = YES;
7820 /* TODO: move to common code */
7821 DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
7822 doc: /* Which toolkit scroll bars Emacs uses, if any.
7823 A value of nil means Emacs doesn't use toolkit scroll bars.
7824 With the X Window system, the value is a symbol describing the
7825 X toolkit. Possible values are: gtk, motif, xaw, or xaw3d.
7826 With MS Windows or Nextstep, the value is t. */);
7827 Vx_toolkit_scroll_bars = Qt;
7829 DEFVAR_BOOL ("x-use-underline-position-properties",
7830 x_use_underline_position_properties,
7831 doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
7832 A value of nil means ignore them. If you encounter fonts with bogus
7833 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
7834 to 4.1, set this to nil. */);
7835 x_use_underline_position_properties = 0;
7837 DEFVAR_BOOL ("x-underline-at-descent-line",
7838 x_underline_at_descent_line,
7839 doc: /* Non-nil means to draw the underline at the same place as the descent line.
7840 A value of nil means to draw the underline according to the value of the
7841 variable `x-use-underline-position-properties', which is usually at the
7842 baseline level. The default value is nil. */);
7843 x_underline_at_descent_line = 0;
7845 /* Tell Emacs about this window system. */
7846 Fprovide (Qns, Qnil);
7848 DEFSYM (Qcocoa, "cocoa");
7849 DEFSYM (Qgnustep, "gnustep");
7851 #ifdef NS_IMPL_COCOA
7852 Fprovide (Qcocoa, Qnil);
7855 Fprovide (Qgnustep, Qnil);