1 /* NeXT/Open/GNUstep / macOS communication module. -*- coding: utf-8 -*-
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2017 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 (at
11 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 macOS/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
71 static EmacsMenu *dockMenu;
73 static EmacsMenu *mainMenu;
76 /* ==========================================================================
78 NSTRACE, Trace support.
80 ========================================================================== */
84 /* The following use "volatile" since they can be accessed from
86 volatile int nstrace_num = 0;
87 volatile int nstrace_depth = 0;
89 /* When 0, no trace is emitted. This is used by NSTRACE_WHEN and
90 NSTRACE_UNLESS to silence functions called.
92 TODO: This should really be a thread-local variable, to avoid that
93 a function with disabled trace thread silence trace output in
94 another. However, in practice this seldom is a problem. */
95 volatile int nstrace_enabled_global = 1;
97 /* Called when nstrace_enabled goes out of scope. */
98 void nstrace_leave(int * pointer_to_nstrace_enabled)
100 if (*pointer_to_nstrace_enabled)
107 /* Called when nstrace_saved_enabled_global goes out of scope. */
108 void nstrace_restore_global_trace_state(int * pointer_to_saved_enabled_global)
110 nstrace_enabled_global = *pointer_to_saved_enabled_global;
114 char const * nstrace_fullscreen_type_name (int fs_type)
118 case -1: return "-1";
119 case FULLSCREEN_NONE: return "FULLSCREEN_NONE";
120 case FULLSCREEN_WIDTH: return "FULLSCREEN_WIDTH";
121 case FULLSCREEN_HEIGHT: return "FULLSCREEN_HEIGHT";
122 case FULLSCREEN_BOTH: return "FULLSCREEN_BOTH";
123 case FULLSCREEN_MAXIMIZED: return "FULLSCREEN_MAXIMIZED";
124 default: return "FULLSCREEN_?????";
130 /* ==========================================================================
132 NSColor, EmacsColor category.
134 ========================================================================== */
135 @implementation NSColor (EmacsColor)
136 + (NSColor *)colorForEmacsRed:(CGFloat)red green:(CGFloat)green
137 blue:(CGFloat)blue alpha:(CGFloat)alpha
139 #if defined (NS_IMPL_COCOA) \
140 && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
141 if (ns_use_srgb_colorspace
142 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
143 && [NSColor respondsToSelector:
144 @selector(colorWithSRGBRed:green:blue:alpha:)]
147 return [NSColor colorWithSRGBRed: red
152 return [NSColor colorWithCalibratedRed: red
158 - (NSColor *)colorUsingDefaultColorSpace
160 /* FIXMES: We're checking for colorWithSRGBRed here so this will
161 only work in the same place as in the method above. It should
162 really be a check whether we're on macOS 10.7 or above. */
163 #if defined (NS_IMPL_COCOA) \
164 && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
165 if (ns_use_srgb_colorspace
166 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
167 && [NSColor respondsToSelector:
168 @selector(colorWithSRGBRed:green:blue:alpha:)]
171 return [self colorUsingColorSpace: [NSColorSpace sRGBColorSpace]];
173 return [self colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
178 /* ==========================================================================
182 ========================================================================== */
184 /* Convert a symbol indexed with an NSxxx value to a value as defined
185 in keyboard.c (lispy_function_key). I hope this is a correct way
186 of doing things... */
187 static unsigned convert_ns_to_X_keysym[] =
189 NSHomeFunctionKey, 0x50,
190 NSLeftArrowFunctionKey, 0x51,
191 NSUpArrowFunctionKey, 0x52,
192 NSRightArrowFunctionKey, 0x53,
193 NSDownArrowFunctionKey, 0x54,
194 NSPageUpFunctionKey, 0x55,
195 NSPageDownFunctionKey, 0x56,
196 NSEndFunctionKey, 0x57,
197 NSBeginFunctionKey, 0x58,
198 NSSelectFunctionKey, 0x60,
199 NSPrintFunctionKey, 0x61,
200 NSClearLineFunctionKey, 0x0B,
201 NSExecuteFunctionKey, 0x62,
202 NSInsertFunctionKey, 0x63,
203 NSUndoFunctionKey, 0x65,
204 NSRedoFunctionKey, 0x66,
205 NSMenuFunctionKey, 0x67,
206 NSFindFunctionKey, 0x68,
207 NSHelpFunctionKey, 0x6A,
208 NSBreakFunctionKey, 0x6B,
210 NSF1FunctionKey, 0xBE,
211 NSF2FunctionKey, 0xBF,
212 NSF3FunctionKey, 0xC0,
213 NSF4FunctionKey, 0xC1,
214 NSF5FunctionKey, 0xC2,
215 NSF6FunctionKey, 0xC3,
216 NSF7FunctionKey, 0xC4,
217 NSF8FunctionKey, 0xC5,
218 NSF9FunctionKey, 0xC6,
219 NSF10FunctionKey, 0xC7,
220 NSF11FunctionKey, 0xC8,
221 NSF12FunctionKey, 0xC9,
222 NSF13FunctionKey, 0xCA,
223 NSF14FunctionKey, 0xCB,
224 NSF15FunctionKey, 0xCC,
225 NSF16FunctionKey, 0xCD,
226 NSF17FunctionKey, 0xCE,
227 NSF18FunctionKey, 0xCF,
228 NSF19FunctionKey, 0xD0,
229 NSF20FunctionKey, 0xD1,
230 NSF21FunctionKey, 0xD2,
231 NSF22FunctionKey, 0xD3,
232 NSF23FunctionKey, 0xD4,
233 NSF24FunctionKey, 0xD5,
235 NSBackspaceCharacter, 0x08, /* 8: Not on some KBs. */
236 NSDeleteCharacter, 0xFF, /* 127: Big 'delete' key upper right. */
237 NSDeleteFunctionKey, 0x9F, /* 63272: Del forw key off main array. */
239 NSTabCharacter, 0x09,
240 0x19, 0x09, /* left tab->regular since pass shift */
241 NSCarriageReturnCharacter, 0x0D,
242 NSNewlineCharacter, 0x0D,
243 NSEnterCharacter, 0x8D,
245 0x41|NSEventModifierFlagNumericPad, 0xAE, /* KP_Decimal */
246 0x43|NSEventModifierFlagNumericPad, 0xAA, /* KP_Multiply */
247 0x45|NSEventModifierFlagNumericPad, 0xAB, /* KP_Add */
248 0x4B|NSEventModifierFlagNumericPad, 0xAF, /* KP_Divide */
249 0x4E|NSEventModifierFlagNumericPad, 0xAD, /* KP_Subtract */
250 0x51|NSEventModifierFlagNumericPad, 0xBD, /* KP_Equal */
251 0x52|NSEventModifierFlagNumericPad, 0xB0, /* KP_0 */
252 0x53|NSEventModifierFlagNumericPad, 0xB1, /* KP_1 */
253 0x54|NSEventModifierFlagNumericPad, 0xB2, /* KP_2 */
254 0x55|NSEventModifierFlagNumericPad, 0xB3, /* KP_3 */
255 0x56|NSEventModifierFlagNumericPad, 0xB4, /* KP_4 */
256 0x57|NSEventModifierFlagNumericPad, 0xB5, /* KP_5 */
257 0x58|NSEventModifierFlagNumericPad, 0xB6, /* KP_6 */
258 0x59|NSEventModifierFlagNumericPad, 0xB7, /* KP_7 */
259 0x5B|NSEventModifierFlagNumericPad, 0xB8, /* KP_8 */
260 0x5C|NSEventModifierFlagNumericPad, 0xB9, /* KP_9 */
262 0x1B, 0x1B /* escape */
265 /* On macOS picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
266 the maximum font size to NOT antialias. On GNUstep there is currently
267 no way to control this behavior. */
268 float ns_antialias_threshold;
270 NSArray *ns_send_types = 0, *ns_return_types = 0;
271 static NSArray *ns_drag_types = 0;
272 NSString *ns_app_name = @"Emacs"; /* default changed later */
274 /* Display variables */
275 struct ns_display_info *x_display_list; /* Chain of existing displays */
276 long context_menu_value = 0;
279 static struct frame *ns_updating_frame;
280 static NSView *focus_view = NULL;
281 static int ns_window_num = 0;
282 #ifdef NS_IMPL_GNUSTEP
283 static NSRect uRect; // TODO: This is dead, remove it?
285 static BOOL gsaved = NO;
286 static BOOL ns_fake_keydown = NO;
288 static BOOL ns_menu_bar_is_hidden = NO;
290 /*static int debug_lock = 0; */
293 static BOOL send_appdefined = YES;
294 #define NO_APPDEFINED_DATA (-8)
295 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
296 static NSTimer *timed_entry = 0;
297 static NSTimer *scroll_repeat_entry = nil;
298 static fd_set select_readfds, select_writefds;
299 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
300 static int select_nfds = 0, select_valid = 0;
301 static struct timespec select_timeout = { 0, 0 };
302 static int selfds[2] = { -1, -1 };
303 static pthread_mutex_t select_mutex;
304 static NSAutoreleasePool *outerpool;
305 static struct input_event *emacs_event = NULL;
306 static struct input_event *q_event_ptr = NULL;
307 static int n_emacs_events_pending = 0;
308 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
309 *ns_pending_service_args;
310 static BOOL ns_do_open_file = NO;
311 static BOOL ns_last_use_native_fullscreen;
313 /* Non-zero means that a HELP_EVENT has been generated since Emacs
316 static BOOL any_help_event_p = NO;
319 struct input_event *q;
325 static NSString *represented_filename = nil;
326 static struct frame *represented_frame = 0;
330 * State for pending menu activation:
331 * MENU_NONE Normal state
332 * MENU_PENDING A menu has been clicked on, but has been canceled so we can
333 * run lisp to update the menu.
334 * MENU_OPENING Menu is up to date, and the click event is redone so the menu
338 #define MENU_PENDING 1
339 #define MENU_OPENING 2
340 static int menu_will_open_state = MENU_NONE;
342 /* Saved position for menu click. */
343 static CGPoint menu_mouse_point;
346 /* Convert modifiers in a NeXTstep event to emacs style modifiers. */
347 #define NS_FUNCTION_KEY_MASK 0x800000
348 #define NSLeftControlKeyMask (0x000001 | NSEventModifierFlagControl)
349 #define NSRightControlKeyMask (0x002000 | NSEventModifierFlagControl)
350 #define NSLeftCommandKeyMask (0x000008 | NSEventModifierFlagCommand)
351 #define NSRightCommandKeyMask (0x000010 | NSEventModifierFlagCommand)
352 #define NSLeftAlternateKeyMask (0x000020 | NSEventModifierFlagOption)
353 #define NSRightAlternateKeyMask (0x000040 | NSEventModifierFlagOption)
354 #define EV_MODIFIERS2(flags) \
355 (((flags & NSEventModifierFlagHelp) ? \
356 hyper_modifier : 0) \
357 | (!EQ (ns_right_alternate_modifier, Qleft) && \
358 ((flags & NSRightAlternateKeyMask) \
359 == NSRightAlternateKeyMask) ? \
360 parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
361 | ((flags & NSEventModifierFlagOption) ? \
362 parse_solitary_modifier (ns_alternate_modifier) : 0) \
363 | ((flags & NSEventModifierFlagShift) ? \
364 shift_modifier : 0) \
365 | (!EQ (ns_right_control_modifier, Qleft) && \
366 ((flags & NSRightControlKeyMask) \
367 == NSRightControlKeyMask) ? \
368 parse_solitary_modifier (ns_right_control_modifier) : 0) \
369 | ((flags & NSEventModifierFlagControl) ? \
370 parse_solitary_modifier (ns_control_modifier) : 0) \
371 | ((flags & NS_FUNCTION_KEY_MASK) ? \
372 parse_solitary_modifier (ns_function_modifier) : 0) \
373 | (!EQ (ns_right_command_modifier, Qleft) && \
374 ((flags & NSRightCommandKeyMask) \
375 == NSRightCommandKeyMask) ? \
376 parse_solitary_modifier (ns_right_command_modifier) : 0) \
377 | ((flags & NSEventModifierFlagCommand) ? \
378 parse_solitary_modifier (ns_command_modifier):0))
379 #define EV_MODIFIERS(e) EV_MODIFIERS2 ([e modifierFlags])
381 #define EV_UDMODIFIERS(e) \
382 ((([e type] == NSEventTypeLeftMouseDown) ? down_modifier : 0) \
383 | (([e type] == NSEventTypeRightMouseDown) ? down_modifier : 0) \
384 | (([e type] == NSEventTypeOtherMouseDown) ? down_modifier : 0) \
385 | (([e type] == NSEventTypeLeftMouseDragged) ? down_modifier : 0) \
386 | (([e type] == NSEventTypeRightMouseDragged) ? down_modifier : 0) \
387 | (([e type] == NSEventTypeOtherMouseDragged) ? down_modifier : 0) \
388 | (([e type] == NSEventTypeLeftMouseUp) ? up_modifier : 0) \
389 | (([e type] == NSEventTypeRightMouseUp) ? up_modifier : 0) \
390 | (([e type] == NSEventTypeOtherMouseUp) ? up_modifier : 0))
392 #define EV_BUTTON(e) \
393 ((([e type] == NSEventTypeLeftMouseDown) || ([e type] == NSEventTypeLeftMouseUp)) ? 0 : \
394 (([e type] == NSEventTypeRightMouseDown) || ([e type] == NSEventTypeRightMouseUp)) ? 2 : \
395 [e buttonNumber] - 1)
397 /* Convert the time field to a timestamp in milliseconds. */
398 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
400 /* This is a piece of code which is common to all the event handling
401 methods. Maybe it should even be a function. */
402 #define EV_TRAILER(e) \
404 XSETFRAME (emacs_event->frame_or_window, emacsframe); \
408 #define EV_TRAILER2(e) \
410 if (e) emacs_event->timestamp = EV_TIMESTAMP (e); \
413 Lisp_Object tem = Vinhibit_quit; \
414 Vinhibit_quit = Qt; \
415 n_emacs_events_pending++; \
416 kbd_buffer_store_event_hold (emacs_event, q_event_ptr); \
417 Vinhibit_quit = tem; \
420 hold_event (emacs_event); \
421 EVENT_INIT (*emacs_event); \
422 ns_send_appdefined (-1); \
426 /* GNUstep always shows decorations if the window is resizable,
427 miniaturizable or closable, but Cocoa does strange things in native
428 fullscreen mode if you don't have at least resizable enabled.
430 These flags will be OR'd or XOR'd with the NSWindow's styleMask
431 property depending on what we're doing. */
433 #define FRAME_DECORATED_FLAGS NSWindowStyleMaskTitled
435 #define FRAME_DECORATED_FLAGS (NSWindowStyleMaskTitled \
436 | NSWindowStyleMaskResizable \
437 | NSWindowStyleMaskMiniaturizable \
438 | NSWindowStyleMaskClosable)
440 #define FRAME_UNDECORATED_FLAGS NSWindowStyleMaskBorderless
442 /* TODO: get rid of need for these forward declarations */
443 static void ns_condemn_scroll_bars (struct frame *f);
444 static void ns_judge_scroll_bars (struct frame *f);
447 /* ==========================================================================
451 ========================================================================== */
454 ns_set_represented_filename (NSString *fstr, struct frame *f)
456 represented_filename = [fstr retain];
457 represented_frame = f;
461 ns_init_events (struct input_event *ev)
468 ns_finish_events (void)
474 hold_event (struct input_event *event)
476 if (hold_event_q.nr == hold_event_q.cap)
478 if (hold_event_q.cap == 0) hold_event_q.cap = 10;
479 else hold_event_q.cap *= 2;
481 xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
484 hold_event_q.q[hold_event_q.nr++] = *event;
485 /* Make sure ns_read_socket is called, i.e. we have input. */
487 send_appdefined = YES;
491 append2 (Lisp_Object list, Lisp_Object item)
492 /* --------------------------------------------------------------------------
493 Utility to append to a list
494 -------------------------------------------------------------------------- */
496 return CALLN (Fnconc, list, list1 (item));
501 ns_etc_directory (void)
502 /* If running as a self-contained app bundle, return as a string the
503 filename of the etc directory, if present; else nil. */
505 NSBundle *bundle = [NSBundle mainBundle];
506 NSString *resourceDir = [bundle resourcePath];
507 NSString *resourcePath;
508 NSFileManager *fileManager = [NSFileManager defaultManager];
511 resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
512 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
514 if (isDir) return [resourcePath UTF8String];
522 /* If running as a self-contained app bundle, return as a path string
523 the filenames of the libexec and bin directories, ie libexec:bin.
524 Otherwise, return nil.
525 Normally, Emacs does not add its own bin/ directory to the PATH.
526 However, a self-contained NS build has a different layout, with
527 bin/ and libexec/ subdirectories in the directory that contains
529 We put libexec first, because init_callproc_1 uses the first
530 element to initialize exec-directory. An alternative would be
531 for init_callproc to check for invocation-directory/libexec.
534 NSBundle *bundle = [NSBundle mainBundle];
535 NSString *resourceDir = [bundle resourcePath];
536 NSString *binDir = [bundle bundlePath];
537 NSString *resourcePath, *resourcePaths;
539 NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
540 NSFileManager *fileManager = [NSFileManager defaultManager];
542 NSEnumerator *pathEnum;
545 range = [resourceDir rangeOfString: @"Contents"];
546 if (range.location != NSNotFound)
548 binDir = [binDir stringByAppendingPathComponent: @"Contents"];
550 binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
554 paths = [binDir stringsByAppendingPaths:
555 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
556 pathEnum = [paths objectEnumerator];
559 while ((resourcePath = [pathEnum nextObject]))
561 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
564 if ([resourcePaths length] > 0)
566 = [resourcePaths stringByAppendingString: pathSeparator];
568 = [resourcePaths stringByAppendingString: resourcePath];
571 if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
579 /* If running as a self-contained app bundle, return as a path string
580 the filenames of the site-lisp and lisp directories.
581 Ie, site-lisp:lisp. Otherwise, return nil. */
583 NSBundle *bundle = [NSBundle mainBundle];
584 NSString *resourceDir = [bundle resourcePath];
585 NSString *resourcePath, *resourcePaths;
586 NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
587 NSFileManager *fileManager = [NSFileManager defaultManager];
589 NSArray *paths = [resourceDir stringsByAppendingPaths:
590 [NSArray arrayWithObjects:
591 @"site-lisp", @"lisp", nil]];
592 NSEnumerator *pathEnum = [paths objectEnumerator];
595 /* Hack to skip site-lisp. */
596 if (no_site_lisp) resourcePath = [pathEnum nextObject];
598 while ((resourcePath = [pathEnum nextObject]))
600 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
603 if ([resourcePaths length] > 0)
605 = [resourcePaths stringByAppendingString: pathSeparator];
607 = [resourcePaths stringByAppendingString: resourcePath];
610 if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
617 ns_init_locale (void)
618 /* macOS doesn't set any environment variables for the locale when run
619 from the GUI. Get the locale from the OS and set LANG. */
621 NSLocale *locale = [NSLocale currentLocale];
623 NSTRACE ("ns_init_locale");
627 /* It seems macOS should probably use UTF-8 everywhere.
628 'localeIdentifier' does not specify the encoding, and I can't
629 find any way to get the OS to tell us which encoding to use,
630 so hard-code '.UTF-8'. */
631 NSString *localeID = [NSString stringWithFormat:@"%@.UTF-8",
632 [locale localeIdentifier]];
634 /* Set LANG to locale, but not if LANG is already set. */
635 setenv("LANG", [localeID UTF8String], 0);
637 @catch (NSException *e)
639 NSLog (@"Locale detection failed: %@: %@", [e name], [e reason]);
645 ns_release_object (void *obj)
646 /* --------------------------------------------------------------------------
647 Release an object (callable from C)
648 -------------------------------------------------------------------------- */
655 ns_retain_object (void *obj)
656 /* --------------------------------------------------------------------------
657 Retain an object (callable from C)
658 -------------------------------------------------------------------------- */
665 ns_alloc_autorelease_pool (void)
666 /* --------------------------------------------------------------------------
667 Allocate a pool for temporary objects (callable from C)
668 -------------------------------------------------------------------------- */
670 return [[NSAutoreleasePool alloc] init];
675 ns_release_autorelease_pool (void *pool)
676 /* --------------------------------------------------------------------------
677 Free a pool and temporary objects it refers to (callable from C)
678 -------------------------------------------------------------------------- */
680 ns_release_object (pool);
685 ns_menu_bar_should_be_hidden (void)
686 /* True, if the menu bar should be hidden. */
688 return !NILP (ns_auto_hide_menu_bar)
689 && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
702 static struct EmacsMargins
703 ns_screen_margins (NSScreen *screen)
704 /* The parts of SCREEN used by the operating system. */
706 NSTRACE ("ns_screen_margins");
708 struct EmacsMargins margins;
710 NSRect screenFrame = [screen frame];
711 NSRect screenVisibleFrame = [screen visibleFrame];
713 /* Sometimes, visibleFrame isn't up-to-date with respect to a hidden
714 menu bar, check this explicitly. */
715 if (ns_menu_bar_should_be_hidden())
721 CGFloat frameTop = screenFrame.origin.y + screenFrame.size.height;
722 CGFloat visibleFrameTop = (screenVisibleFrame.origin.y
723 + screenVisibleFrame.size.height);
725 margins.top = frameTop - visibleFrameTop;
729 CGFloat frameRight = screenFrame.origin.x + screenFrame.size.width;
730 CGFloat visibleFrameRight = (screenVisibleFrame.origin.x
731 + screenVisibleFrame.size.width);
732 margins.right = frameRight - visibleFrameRight;
735 margins.bottom = screenVisibleFrame.origin.y - screenFrame.origin.y;
736 margins.left = screenVisibleFrame.origin.x - screenFrame.origin.x;
738 NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
748 /* A screen margin between 1 and DOCK_IGNORE_LIMIT (inclusive) is
749 assumed to contain a hidden dock. macOS currently use 4 pixels for
750 this, however, to be future compatible, a larger value is used. */
751 #define DOCK_IGNORE_LIMIT 6
753 static struct EmacsMargins
754 ns_screen_margins_ignoring_hidden_dock (NSScreen *screen)
755 /* The parts of SCREEN used by the operating system, excluding the parts
756 reserved for an hidden dock. */
758 NSTRACE ("ns_screen_margins_ignoring_hidden_dock");
760 struct EmacsMargins margins = ns_screen_margins(screen);
762 /* macOS (currently) reserved 4 pixels along the edge where a hidden
763 dock is located. Unfortunately, it's not possible to find the
764 location and information about if the dock is hidden. Instead,
765 it is assumed that if the margin of an edge is less than
766 DOCK_IGNORE_LIMIT, it contains a hidden dock. */
767 if (margins.left <= DOCK_IGNORE_LIMIT)
771 if (margins.right <= DOCK_IGNORE_LIMIT)
775 if (margins.top <= DOCK_IGNORE_LIMIT)
779 /* Note: This doesn't occur in current versions of macOS, but
780 included for completeness and future compatibility. */
781 if (margins.bottom <= DOCK_IGNORE_LIMIT)
786 NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
797 ns_menu_bar_height (NSScreen *screen)
798 /* The height of the menu bar, if visible.
800 Note: Don't use this when fullscreen is enabled -- the screen
801 sometimes includes, sometimes excludes the menu bar area. */
803 struct EmacsMargins margins = ns_screen_margins(screen);
805 CGFloat res = margins.top;
807 NSTRACE ("ns_menu_bar_height " NSTRACE_FMT_RETURN " %.0f", res);
813 /* ==========================================================================
815 Focus (clipping) and screen update
817 ========================================================================== */
820 // Window constraining
821 // -------------------
823 // To ensure that the windows are not placed under the menu bar, they
824 // are typically moved by the call-back constrainFrameRect. However,
825 // by overriding it, it's possible to inhibit this, leaving the window
826 // in it's original position.
828 // It's possible to hide the menu bar. However, technically, it's only
829 // possible to hide it when the application is active. To ensure that
830 // this work properly, the menu bar and window constraining are
831 // deferred until the application becomes active.
833 // Even though it's not possible to manually move a window above the
834 // top of the screen, it is allowed if it's done programmatically,
835 // when the menu is hidden. This allows the editable area to cover the
836 // full screen height.
841 // Use the following extra files:
844 // ;; Hide menu and place frame slightly above the top of the screen.
845 // (setq ns-auto-hide-menu-bar t)
846 // (set-frame-position (selected-frame) 0 -20)
850 // emacs -Q -l init.el
852 // Result: No menu bar, and the title bar should be above the screen.
858 // Result: Menu bar visible, frame placed immediately below the menu.
861 static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
863 NSTRACE ("constrain_frame_rect(" NSTRACE_FMT_RECT ")",
864 NSTRACE_ARG_RECT (frameRect));
866 // --------------------
867 // Collect information about the screen the frame is covering.
870 NSArray *screens = [NSScreen screens];
871 NSUInteger nr_screens = [screens count];
875 // The height of the menu bar, if present in any screen the frame is
877 int menu_bar_height = 0;
879 // A rectangle covering all the screen the frame is displayed in.
880 NSRect multiscreenRect = NSMakeRect(0, 0, 0, 0);
881 for (i = 0; i < nr_screens; ++i )
883 NSScreen *s = [screens objectAtIndex: i];
884 NSRect scrRect = [s frame];
886 NSTRACE_MSG ("Screen %d: " NSTRACE_FMT_RECT,
887 i, NSTRACE_ARG_RECT (scrRect));
889 if (NSIntersectionRect (frameRect, scrRect).size.height != 0)
891 multiscreenRect = NSUnionRect (multiscreenRect, scrRect);
895 CGFloat screen_menu_bar_height = ns_menu_bar_height (s);
896 menu_bar_height = max(menu_bar_height, screen_menu_bar_height);
901 NSTRACE_RECT ("multiscreenRect", multiscreenRect);
903 NSTRACE_MSG ("menu_bar_height: %d", menu_bar_height);
905 if (multiscreenRect.size.width == 0
906 || multiscreenRect.size.height == 0)
908 // Failed to find any monitor, give up.
909 NSTRACE_MSG ("multiscreenRect empty");
910 NSTRACE_RETURN_RECT (frameRect);
915 // --------------------
916 // Find a suitable placement.
919 if (ns_menu_bar_should_be_hidden())
921 // When the menu bar is hidden, the user may place part of the
922 // frame above the top of the screen, for example to hide the
925 // Hence, keep the original position.
929 // Ensure that the frame is below the menu bar, or below the top
932 // This assume that the menu bar is placed at the top in the
933 // rectangle that covers the monitors. (It doesn't have to be,
934 // but if it's not it's hard to do anything useful.)
935 CGFloat topOfWorkArea = (multiscreenRect.origin.y
936 + multiscreenRect.size.height
939 CGFloat topOfFrame = frameRect.origin.y + frameRect.size.height;
940 if (topOfFrame > topOfWorkArea)
942 frameRect.origin.y -= topOfFrame - topOfWorkArea;
943 NSTRACE_RECT ("After placement adjust", frameRect);
947 // Include the following section to restrict frame to the screens.
948 // (If so, update it to allow the frame to stretch down below the
951 // --------------------
952 // Ensure frame doesn't stretch below the screens.
955 CGFloat diff = multiscreenRect.origin.y - frameRect.origin.y;
959 frameRect.origin.y = multiscreenRect.origin.y;
960 frameRect.size.height -= diff;
964 NSTRACE_RETURN_RECT (frameRect);
970 ns_constrain_all_frames (void)
971 /* --------------------------------------------------------------------------
972 Ensure that the menu bar doesn't cover any frames.
973 -------------------------------------------------------------------------- */
975 Lisp_Object tail, frame;
977 NSTRACE ("ns_constrain_all_frames");
981 FOR_EACH_FRAME (tail, frame)
983 struct frame *f = XFRAME (frame);
986 EmacsView *view = FRAME_NS_VIEW (f);
988 if (![view isFullscreen])
991 setFrame:constrain_frame_rect([[view window] frame], false)
1002 ns_update_auto_hide_menu_bar (void)
1003 /* --------------------------------------------------------------------------
1004 Show or hide the menu bar, based on user setting.
1005 -------------------------------------------------------------------------- */
1007 #ifdef NS_IMPL_COCOA
1008 NSTRACE ("ns_update_auto_hide_menu_bar");
1012 if (NSApp != nil && [NSApp isActive])
1014 // Note, "setPresentationOptions" triggers an error unless the
1015 // application is active.
1016 BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
1018 if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
1020 NSApplicationPresentationOptions options
1021 = NSApplicationPresentationDefault;
1023 if (menu_bar_should_be_hidden)
1024 options |= NSApplicationPresentationAutoHideMenuBar
1025 | NSApplicationPresentationAutoHideDock;
1027 [NSApp setPresentationOptions: options];
1029 ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
1031 if (!ns_menu_bar_is_hidden)
1033 ns_constrain_all_frames ();
1044 ns_update_begin (struct frame *f)
1045 /* --------------------------------------------------------------------------
1046 Prepare for a grouped sequence of drawing calls
1047 external (RIF) call; whole frame, called before update_window_begin
1048 -------------------------------------------------------------------------- */
1050 EmacsView *view = FRAME_NS_VIEW (f);
1051 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_begin");
1053 ns_update_auto_hide_menu_bar ();
1055 #ifdef NS_IMPL_COCOA
1056 if ([view isFullscreen] && [view fsIsNative])
1058 // Fix reappearing tool bar in fullscreen for Mac OS X 10.7
1059 BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
1060 NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
1061 if (! tbar_visible != ! [toolbar isVisible])
1062 [toolbar setVisible: tbar_visible];
1066 ns_updating_frame = f;
1069 /* drawRect may have been called for say the minibuffer, and then clip path
1070 is for the minibuffer. But the display engine may draw more because
1071 we have set the frame as garbaged. So reset clip path to the whole
1073 #ifdef NS_IMPL_COCOA
1076 NSRect r = [view frame];
1077 NSRect cr = [[view window] frame];
1078 /* If a large frame size is set, r may be larger than the window frame
1079 before constrained. In that case don't change the clip path, as we
1080 will clear in to the tool bar and title bar. */
1082 + FRAME_NS_TITLEBAR_HEIGHT (f)
1083 + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
1085 bp = [[NSBezierPath bezierPathWithRect: r] retain];
1092 #ifdef NS_IMPL_GNUSTEP
1093 uRect = NSMakeRect (0, 0, 0, 0);
1099 ns_update_window_begin (struct window *w)
1100 /* --------------------------------------------------------------------------
1101 Prepare for a grouped sequence of drawing calls
1102 external (RIF) call; for one window, called after update_begin
1103 -------------------------------------------------------------------------- */
1105 struct frame *f = XFRAME (WINDOW_FRAME (w));
1106 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1108 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_begin");
1109 w->output_cursor = w->cursor;
1113 if (f == hlinfo->mouse_face_mouse_frame)
1115 /* Don't do highlighting for mouse motion during the update. */
1116 hlinfo->mouse_face_defer = 1;
1118 /* If the frame needs to be redrawn,
1119 simply forget about any prior mouse highlighting. */
1120 if (FRAME_GARBAGED_P (f))
1121 hlinfo->mouse_face_window = Qnil;
1123 /* (further code for mouse faces ifdef'd out in other terms elided) */
1131 ns_update_window_end (struct window *w, bool cursor_on_p,
1132 bool mouse_face_overwritten_p)
1133 /* --------------------------------------------------------------------------
1134 Finished a grouped sequence of drawing calls
1135 external (RIF) call; for one window called before update_end
1136 -------------------------------------------------------------------------- */
1138 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_end");
1140 /* note: this fn is nearly identical in all terms */
1141 if (!w->pseudo_window_p)
1146 display_and_set_cursor (w, 1,
1147 w->output_cursor.hpos, w->output_cursor.vpos,
1148 w->output_cursor.x, w->output_cursor.y);
1150 if (draw_window_fringes (w, 1))
1152 if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
1153 x_draw_right_divider (w);
1155 x_draw_vertical_border (w);
1161 /* If a row with mouse-face was overwritten, arrange for
1162 frame_up_to_date to redisplay the mouse highlight. */
1163 if (mouse_face_overwritten_p)
1164 reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
1169 ns_update_end (struct frame *f)
1170 /* --------------------------------------------------------------------------
1171 Finished a grouped sequence of drawing calls
1172 external (RIF) call; for whole frame, called after update_window_end
1173 -------------------------------------------------------------------------- */
1175 EmacsView *view = FRAME_NS_VIEW (f);
1177 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_end");
1179 /* if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
1180 MOUSE_HL_INFO (f)->mouse_face_defer = 0;
1185 [[view window] flushWindow];
1188 ns_updating_frame = NULL;
1192 ns_focus (struct frame *f, NSRect *r, int n)
1193 /* --------------------------------------------------------------------------
1194 Internal: Focus on given frame. During small local updates this is used to
1195 draw, however during large updates, ns_update_begin and ns_update_end are
1196 called to wrap the whole thing, in which case these calls are stubbed out.
1197 Except, on GNUstep, we accumulate the rectangle being drawn into, because
1198 the back end won't do this automatically, and will just end up flushing
1200 -------------------------------------------------------------------------- */
1202 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_focus");
1205 NSTRACE_RECT ("r", *r);
1208 if (f != ns_updating_frame)
1210 NSView *view = FRAME_NS_VIEW (f);
1211 if (view != focus_view)
1213 if (focus_view != NULL)
1215 [focus_view unlockFocus];
1216 [[focus_view window] flushWindow];
1223 /*if (view) debug_lock++; */
1230 [[NSGraphicsContext currentContext] saveGraphicsState];
1232 NSRectClipList (r, 2);
1241 ns_unfocus (struct frame *f)
1242 /* --------------------------------------------------------------------------
1243 Internal: Remove focus on given frame
1244 -------------------------------------------------------------------------- */
1246 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_unfocus");
1250 [[NSGraphicsContext currentContext] restoreGraphicsState];
1254 if (f != ns_updating_frame)
1256 if (focus_view != NULL)
1258 [focus_view unlockFocus];
1259 [[focus_view window] flushWindow];
1268 ns_clip_to_row (struct window *w, struct glyph_row *row,
1269 enum glyph_row_area area, BOOL gc)
1270 /* --------------------------------------------------------------------------
1271 Internal (but parallels other terms): Focus drawing on given row
1272 -------------------------------------------------------------------------- */
1274 struct frame *f = XFRAME (WINDOW_FRAME (w));
1276 int window_x, window_y, window_width;
1278 window_box (w, area, &window_x, &window_y, &window_width, 0);
1280 clip_rect.origin.x = window_x;
1281 clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
1282 clip_rect.origin.y = max (clip_rect.origin.y, window_y);
1283 clip_rect.size.width = window_width;
1284 clip_rect.size.height = row->visible_height;
1286 ns_focus (f, &clip_rect, 1);
1290 /* ==========================================================================
1292 Visible bell and beep.
1294 ========================================================================== */
1297 // This bell implementation shows the visual bell image asynchronously
1298 // from the rest of Emacs. This is done by adding a NSView to the
1299 // superview of the Emacs window and removing it using a timer.
1301 // Unfortunately, some Emacs operations, like scrolling, is done using
1302 // low-level primitives that copy the content of the window, including
1303 // the bell image. To some extent, this is handled by removing the
1304 // image prior to scrolling and marking that the window is in need for
1307 // To test this code, make sure that there is no artifacts of the bell
1308 // image in the following situations. Use a non-empty buffer (like the
1309 // tutorial) to ensure that a scroll is performed:
1311 // * Single-window: C-g C-v
1313 // * Side-by-windows: C-x 3 C-g C-v
1315 // * Windows above each other: C-x 2 C-g C-v
1317 @interface EmacsBell : NSImageView
1319 // Number of currently active bell:s.
1320 unsigned int nestCount;
1324 - (void)show:(NSView *)view;
1329 @implementation EmacsBell
1333 NSTRACE ("[EmacsBell init]");
1334 if ((self = [super init]))
1338 #ifdef NS_IMPL_GNUSTEP
1339 // GNUstep doesn't provide named images. This was reported in
1340 // 2011, see https://savannah.gnu.org/bugs/?33396
1342 // As a drop in replacement, a semitransparent gray square is used.
1343 self.image = [[NSImage alloc] initWithSize:NSMakeSize(32 * 5, 32 * 5)];
1344 [self.image lockFocus];
1345 [[NSColor colorForEmacsRed:0.5 green:0.5 blue:0.5 alpha:0.5] set];
1346 NSRectFill(NSMakeRect(0, 0, 32, 32));
1347 [self.image unlockFocus];
1349 self.image = [NSImage imageNamed:NSImageNameCaution];
1350 [self.image setSize:NSMakeSize(self.image.size.width * 5,
1351 self.image.size.height * 5)];
1357 - (void)show:(NSView *)view
1359 NSTRACE ("[EmacsBell show:]");
1360 NSTRACE_MSG ("nestCount: %u", nestCount);
1362 // Show the image, unless it's already shown.
1365 NSRect rect = [view bounds];
1367 pos.x = rect.origin.x + (rect.size.width - self.image.size.width )/2;
1368 pos.y = rect.origin.y + (rect.size.height - self.image.size.height)/2;
1370 [self setFrameOrigin:pos];
1371 [self setFrameSize:self.image.size];
1375 [[[view window] contentView] addSubview:self
1376 positioned:NSWindowAbove
1382 [self performSelector:@selector(hide) withObject:self afterDelay:0.5];
1388 // Note: Trace output from this method isn't shown, reason unknown.
1389 // NSTRACE ("[EmacsBell hide]");
1394 // Remove the image once the last bell became inactive.
1404 NSTRACE ("[EmacsBell remove]");
1407 NSTRACE_MSG ("removeFromSuperview");
1408 [self removeFromSuperview];
1409 mView.needsDisplay = YES;
1417 static EmacsBell * bell_view = nil;
1420 ns_ring_bell (struct frame *f)
1421 /* --------------------------------------------------------------------------
1423 -------------------------------------------------------------------------- */
1425 NSTRACE ("ns_ring_bell");
1428 struct frame *frame = SELECTED_FRAME ();
1431 if (bell_view == nil)
1433 bell_view = [[EmacsBell alloc] init];
1439 view = FRAME_NS_VIEW (frame);
1442 [bell_view show:view];
1456 /* --------------------------------------------------------------------------
1457 Ensure the bell is hidden.
1458 -------------------------------------------------------------------------- */
1460 NSTRACE ("hide_bell");
1462 if (bell_view != nil)
1469 /* ==========================================================================
1471 Frame / window manager related functions
1473 ========================================================================== */
1477 ns_raise_frame (struct frame *f, BOOL make_key)
1478 /* --------------------------------------------------------------------------
1479 Bring window to foreground and if make_key is YES, give it focus.
1480 -------------------------------------------------------------------------- */
1484 check_window_system (f);
1485 view = FRAME_NS_VIEW (f);
1487 if (FRAME_VISIBLE_P (f))
1490 [[view window] makeKeyAndOrderFront: NSApp];
1492 [[view window] orderFront: NSApp];
1499 ns_lower_frame (struct frame *f)
1500 /* --------------------------------------------------------------------------
1502 -------------------------------------------------------------------------- */
1506 check_window_system (f);
1507 view = FRAME_NS_VIEW (f);
1509 [[view window] orderBack: NSApp];
1515 ns_frame_raise_lower (struct frame *f, bool raise)
1516 /* --------------------------------------------------------------------------
1518 -------------------------------------------------------------------------- */
1520 NSTRACE ("ns_frame_raise_lower");
1523 ns_raise_frame (f, YES);
1530 ns_frame_rehighlight (struct frame *frame)
1531 /* --------------------------------------------------------------------------
1532 External (hook): called on things like window switching within frame
1533 -------------------------------------------------------------------------- */
1535 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1536 struct frame *old_highlight = dpyinfo->x_highlight_frame;
1538 NSTRACE ("ns_frame_rehighlight");
1539 if (dpyinfo->x_focus_frame)
1541 dpyinfo->x_highlight_frame
1542 = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1543 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1544 : dpyinfo->x_focus_frame);
1545 if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1547 fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1548 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1552 dpyinfo->x_highlight_frame = 0;
1554 if (dpyinfo->x_highlight_frame &&
1555 dpyinfo->x_highlight_frame != old_highlight)
1559 x_update_cursor (old_highlight, 1);
1560 x_set_frame_alpha (old_highlight);
1562 if (dpyinfo->x_highlight_frame)
1564 x_update_cursor (dpyinfo->x_highlight_frame, 1);
1565 x_set_frame_alpha (dpyinfo->x_highlight_frame);
1572 x_make_frame_visible (struct frame *f)
1573 /* --------------------------------------------------------------------------
1574 External: Show the window (X11 semantics)
1575 -------------------------------------------------------------------------- */
1577 NSTRACE ("x_make_frame_visible");
1578 /* XXX: at some points in past this was not needed, as the only place that
1579 called this (frame.c:Fraise_frame ()) also called raise_lower;
1580 if this ends up the case again, comment this out again. */
1581 if (!FRAME_VISIBLE_P (f))
1583 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1584 NSWindow *window = [view window];
1586 SET_FRAME_VISIBLE (f, 1);
1587 ns_raise_frame (f, ! FRAME_NO_FOCUS_ON_MAP (f));
1589 /* Making a new frame from a fullscreen frame will make the new frame
1590 fullscreen also. So skip handleFS as this will print an error. */
1591 if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1592 && [view isFullscreen])
1595 if (f->want_fullscreen != FULLSCREEN_NONE)
1602 /* Making a frame invisible seems to break the parent->child
1603 relationship, so reinstate it. */
1604 if ([window parentWindow] == nil && FRAME_PARENT_FRAME (f) != NULL)
1606 NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
1609 [parent addChildWindow: window
1610 ordered: NSWindowAbove];
1613 /* If the parent frame moved while the child frame was
1614 invisible, the child frame's position won't have been
1615 updated. Make sure it's in the right place now. */
1616 x_set_offset(f, f->left_pos, f->top_pos, 0);
1623 x_make_frame_invisible (struct frame *f)
1624 /* --------------------------------------------------------------------------
1625 External: Hide the window (X11 semantics)
1626 -------------------------------------------------------------------------- */
1629 NSTRACE ("x_make_frame_invisible");
1630 check_window_system (f);
1631 view = FRAME_NS_VIEW (f);
1632 [[view window] orderOut: NSApp];
1633 SET_FRAME_VISIBLE (f, 0);
1634 SET_FRAME_ICONIFIED (f, 0);
1639 x_iconify_frame (struct frame *f)
1640 /* --------------------------------------------------------------------------
1641 External: Iconify window
1642 -------------------------------------------------------------------------- */
1645 struct ns_display_info *dpyinfo;
1647 NSTRACE ("x_iconify_frame");
1648 check_window_system (f);
1649 view = FRAME_NS_VIEW (f);
1650 dpyinfo = FRAME_DISPLAY_INFO (f);
1652 if (dpyinfo->x_highlight_frame == f)
1653 dpyinfo->x_highlight_frame = 0;
1655 if ([[view window] windowNumber] <= 0)
1657 /* the window is still deferred. Make it very small, bring it
1658 on screen and order it out. */
1659 NSRect s = { { 100, 100}, {0, 0} };
1661 t = [[view window] frame];
1662 [[view window] setFrame: s display: NO];
1663 [[view window] orderBack: NSApp];
1664 [[view window] orderOut: NSApp];
1665 [[view window] setFrame: t display: NO];
1668 /* Processing input while Emacs is being minimized can cause a
1669 crash, so block it for the duration. */
1671 [[view window] miniaturize: NSApp];
1675 /* Free X resources of frame F. */
1678 x_free_frame_resources (struct frame *f)
1681 struct ns_display_info *dpyinfo;
1682 Mouse_HLInfo *hlinfo;
1684 NSTRACE ("x_free_frame_resources");
1685 check_window_system (f);
1686 view = FRAME_NS_VIEW (f);
1687 dpyinfo = FRAME_DISPLAY_INFO (f);
1688 hlinfo = MOUSE_HL_INFO (f);
1690 [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1694 free_frame_menubar (f);
1695 free_frame_faces (f);
1697 if (f == dpyinfo->x_focus_frame)
1698 dpyinfo->x_focus_frame = 0;
1699 if (f == dpyinfo->x_highlight_frame)
1700 dpyinfo->x_highlight_frame = 0;
1701 if (f == hlinfo->mouse_face_mouse_frame)
1702 reset_mouse_highlight (hlinfo);
1704 if (f->output_data.ns->miniimage != nil)
1705 [f->output_data.ns->miniimage release];
1707 [[view window] close];
1710 xfree (f->output_data.ns);
1716 x_destroy_window (struct frame *f)
1717 /* --------------------------------------------------------------------------
1718 External: Delete the window
1719 -------------------------------------------------------------------------- */
1721 NSTRACE ("x_destroy_window");
1723 /* If this frame has a parent window, detach it as not doing so can
1724 cause a crash in GNUStep. */
1725 if (FRAME_PARENT_FRAME (f) != NULL)
1727 NSWindow *child = [FRAME_NS_VIEW (f) window];
1728 NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
1730 [parent removeChildWindow: child];
1733 check_window_system (f);
1734 x_free_frame_resources (f);
1740 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1741 /* --------------------------------------------------------------------------
1742 External: Position the window
1743 -------------------------------------------------------------------------- */
1745 NSView *view = FRAME_NS_VIEW (f);
1746 NSArray *screens = [NSScreen screens];
1747 NSScreen *fscreen = [screens objectAtIndex: 0];
1748 NSScreen *screen = [[view window] screen];
1750 NSTRACE ("x_set_offset");
1757 if (view != nil && screen && fscreen)
1759 f->left_pos = f->size_hint_flags & XNegative
1760 ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1762 /* We use visibleFrame here to take menu bar into account.
1763 Ideally we should also adjust left/top with visibleFrame.origin. */
1765 f->top_pos = f->size_hint_flags & YNegative
1766 ? ([screen visibleFrame].size.height + f->top_pos
1767 - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1768 - FRAME_TOOLBAR_HEIGHT (f))
1770 #ifdef NS_IMPL_GNUSTEP
1771 if (FRAME_PARENT_FRAME (f) == NULL)
1773 if (f->left_pos < 100)
1774 f->left_pos = 100; /* don't overlap menu */
1777 /* Constrain the setFrameTopLeftPoint so we don't move behind the
1779 NSPoint pt = NSMakePoint (SCREENMAXBOUND (f->left_pos
1780 + NS_PARENT_WINDOW_LEFT_POS (f)),
1781 SCREENMAXBOUND (NS_PARENT_WINDOW_TOP_POS (f)
1783 NSTRACE_POINT ("setFrameTopLeftPoint", pt);
1784 [[view window] setFrameTopLeftPoint: pt];
1785 f->size_hint_flags &= ~(XNegative|YNegative);
1793 x_set_window_size (struct frame *f,
1794 bool change_gravity,
1798 /* --------------------------------------------------------------------------
1799 Adjust window pixel size based on given character grid size
1800 Impl is a bit more complex than other terms, need to do some
1802 -------------------------------------------------------------------------- */
1804 EmacsView *view = FRAME_NS_VIEW (f);
1805 NSWindow *window = [view window];
1806 NSRect wr = [window frame];
1807 int pixelwidth, pixelheight;
1808 int orig_height = wr.size.height;
1810 NSTRACE ("x_set_window_size");
1815 NSTRACE_RECT ("current", wr);
1816 NSTRACE_MSG ("Width:%d Height:%d Pixelwise:%d", width, height, pixelwise);
1817 NSTRACE_MSG ("Font %d x %d", FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f));
1823 pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1824 pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1828 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, width);
1829 pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1832 wr.size.width = pixelwidth + f->border_width;
1833 wr.size.height = pixelheight;
1834 if (! [view isFullscreen])
1835 wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1836 + FRAME_TOOLBAR_HEIGHT (f);
1838 /* Do not try to constrain to this screen. We may have multiple
1839 screens, and want Emacs to span those. Constraining to screen
1840 prevents that, and that is not nice to the user. */
1841 if (f->output_data.ns->zooming)
1842 f->output_data.ns->zooming = 0;
1844 wr.origin.y += orig_height - wr.size.height;
1846 frame_size_history_add
1847 (f, Qx_set_window_size_1, width, height,
1848 list5 (Fcons (make_number (pixelwidth), make_number (pixelheight)),
1849 Fcons (make_number (wr.size.width), make_number (wr.size.height)),
1850 make_number (f->border_width),
1851 make_number (FRAME_NS_TITLEBAR_HEIGHT (f)),
1852 make_number (FRAME_TOOLBAR_HEIGHT (f))));
1854 [window setFrame: wr display: YES];
1856 [view updateFrameSize: NO];
1860 #ifdef NS_IMPL_COCOA
1862 x_set_undecorated (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1863 /* --------------------------------------------------------------------------
1864 Set frame F's `undecorated' parameter. If non-nil, F's window-system
1865 window is drawn without decorations, title, minimize/maximize boxes
1866 and external borders. This usually means that the window cannot be
1867 dragged, resized, iconified, maximized or deleted with the mouse. If
1868 nil, draw the frame with all the elements listed above unless these
1869 have been suspended via window manager settings.
1871 GNUStep cannot change an existing window's style.
1872 -------------------------------------------------------------------------- */
1874 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1875 NSWindow *window = [view window];
1877 NSTRACE ("x_set_undecorated");
1879 if (!EQ (new_value, old_value))
1883 if (NILP (new_value))
1885 FRAME_UNDECORATED (f) = false;
1886 [window setStyleMask: ((window.styleMask | FRAME_DECORATED_FLAGS)
1887 ^ FRAME_UNDECORATED_FLAGS)];
1889 [view createToolbar: f];
1893 [window setToolbar: nil];
1894 /* Do I need to release the toolbar here? */
1896 FRAME_UNDECORATED (f) = true;
1897 [window setStyleMask: ((window.styleMask | FRAME_UNDECORATED_FLAGS)
1898 ^ FRAME_DECORATED_FLAGS)];
1901 /* At this point it seems we don't have an active NSResponder,
1902 so some key presses (TAB) are swallowed by the system. */
1903 [window makeFirstResponder: view];
1905 [view updateFrameSize: NO];
1909 #endif /* NS_IMPL_COCOA */
1912 x_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1913 /* --------------------------------------------------------------------------
1914 Set frame F's `parent-frame' parameter. If non-nil, make F a child
1915 frame of the frame specified by that parameter. Technically, this
1916 makes F's window-system window a child window of the parent frame's
1917 window-system window. If nil, make F's window-system window a
1918 top-level window--a child of its display's root window.
1920 A child frame's `left' and `top' parameters specify positions
1921 relative to the top-left corner of its parent frame's native
1922 rectangle. On macOS moving a parent frame moves all its child
1923 frames too, keeping their position relative to the parent
1924 unaltered. When a parent frame is iconified or made invisible, its
1925 child frames are made invisible. When a parent frame is deleted,
1926 its child frames are deleted too.
1928 Whether a child frame has a tool bar may be window-system or window
1929 manager dependent. It's advisable to disable it via the frame
1932 Some window managers may not honor this parameter.
1933 -------------------------------------------------------------------------- */
1935 struct frame *p = NULL;
1936 NSWindow *parent, *child;
1938 NSTRACE ("x_set_parent_frame");
1940 if (!NILP (new_value)
1941 && (!FRAMEP (new_value)
1942 || !FRAME_LIVE_P (p = XFRAME (new_value))
1945 store_frame_param (f, Qparent_frame, old_value);
1946 error ("Invalid specification of `parent-frame'");
1949 if (p != FRAME_PARENT_FRAME (f))
1951 parent = [FRAME_NS_VIEW (p) window];
1952 child = [FRAME_NS_VIEW (f) window];
1955 [parent addChildWindow: child
1956 ordered: NSWindowAbove];
1959 fset_parent_frame (f, new_value);
1964 x_set_no_focus_on_map (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1965 /* Set frame F's `no-focus-on-map' parameter which, if non-nil, means
1966 * that F's window-system window does not want to receive input focus
1967 * when it is mapped. (A frame's window is mapped when the frame is
1968 * displayed for the first time and when the frame changes its state
1969 * from `iconified' or `invisible' to `visible'.)
1971 * Some window managers may not honor this parameter. */
1973 NSTRACE ("x_set_no_focus_on_map");
1975 if (!EQ (new_value, old_value))
1977 FRAME_NO_FOCUS_ON_MAP (f) = !NILP (new_value);
1982 x_set_no_accept_focus (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1983 /* Set frame F's `no-accept-focus' parameter which, if non-nil, hints
1984 * that F's window-system window does not want to receive input focus
1985 * via mouse clicks or by moving the mouse into it.
1987 * If non-nil, this may have the unwanted side-effect that a user cannot
1988 * scroll a non-selected frame with the mouse.
1990 * Some window managers may not honor this parameter. */
1992 NSTRACE ("x_set_no_accept_focus");
1994 if (!EQ (new_value, old_value))
1995 FRAME_NO_ACCEPT_FOCUS (f) = !NILP (new_value);
1999 x_set_z_group (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
2000 /* Set frame F's `z-group' parameter. If `above', F's window-system
2001 window is displayed above all windows that do not have the `above'
2002 property set. If nil, F's window is shown below all windows that
2003 have the `above' property set and above all windows that have the
2004 `below' property set. If `below', F's window is displayed below
2005 all windows that do.
2007 Some window managers may not honor this parameter. */
2009 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2010 NSWindow *window = [view window];
2012 NSTRACE ("x_set_z_group");
2014 if (NILP (new_value))
2016 window.level = NSNormalWindowLevel;
2017 FRAME_Z_GROUP (f) = z_group_none;
2019 else if (EQ (new_value, Qabove))
2021 window.level = NSNormalWindowLevel + 1;
2022 FRAME_Z_GROUP (f) = z_group_above;
2024 else if (EQ (new_value, Qabove_suspended))
2026 /* Not sure what level this should be. */
2027 window.level = NSNormalWindowLevel + 1;
2028 FRAME_Z_GROUP (f) = z_group_above_suspended;
2030 else if (EQ (new_value, Qbelow))
2032 window.level = NSNormalWindowLevel - 1;
2033 FRAME_Z_GROUP (f) = z_group_below;
2036 error ("Invalid z-group specification");
2039 #ifdef NS_IMPL_COCOA
2041 ns_set_appearance (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
2043 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
2044 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2045 NSWindow *window = [view window];
2047 NSTRACE ("ns_set_appearance");
2049 #ifndef NSAppKitVersionNumber10_9
2050 #define NSAppKitVersionNumber10_9 1265
2053 if (NSAppKitVersionNumber < NSAppKitVersionNumber10_9)
2056 if (EQ (new_value, Qdark))
2058 window.appearance = [NSAppearance
2059 appearanceNamed: NSAppearanceNameVibrantDark];
2060 FRAME_NS_APPEARANCE (f) = ns_appearance_vibrant_dark;
2064 window.appearance = [NSAppearance
2065 appearanceNamed: NSAppearanceNameAqua];
2066 FRAME_NS_APPEARANCE (f) = ns_appearance_aqua;
2068 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 */
2072 ns_set_transparent_titlebar (struct frame *f, Lisp_Object new_value,
2073 Lisp_Object old_value)
2075 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
2076 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2077 NSWindow *window = [view window];
2079 NSTRACE ("ns_set_transparent_titlebar");
2081 if ([window respondsToSelector: @selector(titlebarAppearsTransparent)]
2082 && !EQ (new_value, old_value))
2084 window.titlebarAppearsTransparent = !NILP (new_value);
2085 FRAME_NS_TRANSPARENT_TITLEBAR (f) = !NILP (new_value);
2087 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 */
2089 #endif /* NS_IMPL_COCOA */
2092 ns_fullscreen_hook (struct frame *f)
2094 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2096 NSTRACE ("ns_fullscreen_hook");
2098 if (!FRAME_VISIBLE_P (f))
2101 if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
2103 /* Old style fs don't initiate correctly if created from
2104 init/default-frame alist, so use a timer (not nice...).
2106 [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
2107 selector: @selector (handleFS)
2108 userInfo: nil repeats: NO];
2117 /* ==========================================================================
2121 ========================================================================== */
2125 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
2127 struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
2128 if (idx < 1 || idx >= color_table->avail)
2130 return color_table->colors[idx];
2135 ns_index_color (NSColor *color, struct frame *f)
2137 struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
2141 if (!color_table->colors)
2143 color_table->size = NS_COLOR_CAPACITY;
2144 color_table->avail = 1; /* skip idx=0 as marker */
2145 color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
2146 color_table->colors[0] = nil;
2147 color_table->empty_indices = [[NSMutableSet alloc] init];
2150 /* Do we already have this color? */
2151 for (i = 1; i < color_table->avail; i++)
2152 if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
2155 if ([color_table->empty_indices count] > 0)
2157 NSNumber *index = [color_table->empty_indices anyObject];
2158 [color_table->empty_indices removeObject: index];
2159 idx = [index unsignedLongValue];
2163 if (color_table->avail == color_table->size)
2164 color_table->colors =
2165 xpalloc (color_table->colors, &color_table->size, 1,
2166 min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
2167 idx = color_table->avail++;
2170 color_table->colors[idx] = color;
2172 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
2178 ns_get_color (const char *name, NSColor **col)
2179 /* --------------------------------------------------------------------------
2181 -------------------------------------------------------------------------- */
2182 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
2183 X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
2184 See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
2187 static char hex[20];
2189 float r = -1.0, g, b;
2190 NSString *nsname = [NSString stringWithUTF8String: name];
2192 NSTRACE ("ns_get_color(%s, **)", name);
2196 if ([nsname isEqualToString: @"ns_selection_bg_color"])
2198 #ifdef NS_IMPL_COCOA
2199 NSString *defname = [[NSUserDefaults standardUserDefaults]
2200 stringForKey: @"AppleHighlightColor"];
2205 if ((new = [NSColor selectedTextBackgroundColor]) != nil)
2207 *col = [new colorUsingDefaultColorSpace];
2212 nsname = NS_SELECTION_BG_COLOR_DEFAULT;
2214 name = [nsname UTF8String];
2216 else if ([nsname isEqualToString: @"ns_selection_fg_color"])
2218 /* NOTE: macOS applications normally don't set foreground
2219 selection, but text may be unreadable if we don't.
2221 if ((new = [NSColor selectedTextColor]) != nil)
2223 *col = [new colorUsingDefaultColorSpace];
2228 nsname = NS_SELECTION_FG_COLOR_DEFAULT;
2229 name = [nsname UTF8String];
2232 /* First, check for some sort of numeric specification. */
2235 if (name[0] == '0' || name[0] == '1' || name[0] == '.') /* RGB decimal */
2237 NSScanner *scanner = [NSScanner scannerWithString: nsname];
2238 [scanner scanFloat: &r];
2239 [scanner scanFloat: &g];
2240 [scanner scanFloat: &b];
2242 else if (!strncmp(name, "rgb:", 4)) /* A newer X11 format -- rgb:r/g/b */
2243 scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
2244 else if (name[0] == '#') /* An old X11 format; convert to newer */
2246 int len = (strlen(name) - 1);
2247 int start = (len % 3 == 0) ? 1 : len / 4 + 1;
2249 scaling = strlen(name+start) / 3;
2250 for (i = 0; i < 3; i++)
2251 sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
2252 name + start + i * scaling);
2253 hex[3 * (scaling + 1) - 1] = '\0';
2258 unsigned int rr, gg, bb;
2259 float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
2260 if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
2270 *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
2275 /* Otherwise, color is expected to be from a list */
2277 NSEnumerator *lenum, *cenum;
2281 #ifdef NS_IMPL_GNUSTEP
2282 /* XXX: who is wrong, the requestor or the implementation? */
2283 if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
2285 nsname = @"highlightColor";
2288 lenum = [[NSColorList availableColorLists] objectEnumerator];
2289 while ( (clist = [lenum nextObject]) && new == nil)
2291 cenum = [[clist allKeys] objectEnumerator];
2292 while ( (name = [cenum nextObject]) && new == nil )
2294 if ([name compare: nsname
2295 options: NSCaseInsensitiveSearch] == NSOrderedSame )
2296 new = [clist colorWithKey: name];
2302 *col = [new colorUsingDefaultColorSpace];
2309 ns_lisp_to_color (Lisp_Object color, NSColor **col)
2310 /* --------------------------------------------------------------------------
2311 Convert a Lisp string object to a NS color
2312 -------------------------------------------------------------------------- */
2314 NSTRACE ("ns_lisp_to_color");
2315 if (STRINGP (color))
2316 return ns_get_color (SSDATA (color), col);
2317 else if (SYMBOLP (color))
2318 return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
2324 ns_query_color(void *col, XColor *color_def, int setPixel)
2325 /* --------------------------------------------------------------------------
2326 Get ARGB values out of NSColor col and put them into color_def.
2327 If setPixel, set the pixel to a concatenated version.
2328 and set color_def pixel to the resulting index.
2329 -------------------------------------------------------------------------- */
2331 EmacsCGFloat r, g, b, a;
2333 [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
2334 color_def->red = r * 65535;
2335 color_def->green = g * 65535;
2336 color_def->blue = b * 65535;
2338 if (setPixel == YES)
2340 = ARGB_TO_ULONG((int)(a*255),
2341 (int)(r*255), (int)(g*255), (int)(b*255));
2346 ns_defined_color (struct frame *f,
2351 /* --------------------------------------------------------------------------
2352 Return true if named color found, and set color_def rgb accordingly.
2353 If makeIndex and alloc are nonzero put the color in the color_table,
2354 and set color_def pixel to the resulting index.
2355 If makeIndex is zero, set color_def pixel to ARGB.
2356 Return false if not found
2357 -------------------------------------------------------------------------- */
2360 NSTRACE_WHEN (NSTRACE_GROUP_COLOR, "ns_defined_color");
2363 if (ns_get_color (name, &col) != 0) /* Color not found */
2368 if (makeIndex && alloc)
2369 color_def->pixel = ns_index_color (col, f);
2370 ns_query_color (col, color_def, !makeIndex);
2377 x_set_frame_alpha (struct frame *f)
2378 /* --------------------------------------------------------------------------
2379 change the entire-frame transparency
2380 -------------------------------------------------------------------------- */
2382 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2384 double alpha_min = 1.0;
2386 NSTRACE ("x_set_frame_alpha");
2388 if (dpyinfo->x_highlight_frame == f)
2389 alpha = f->alpha[0];
2391 alpha = f->alpha[1];
2393 if (FLOATP (Vframe_alpha_lower_limit))
2394 alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
2395 else if (INTEGERP (Vframe_alpha_lower_limit))
2396 alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
2400 else if (1.0 < alpha)
2402 else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
2405 #ifdef NS_IMPL_COCOA
2407 EmacsView *view = FRAME_NS_VIEW (f);
2408 [[view window] setAlphaValue: alpha];
2414 /* ==========================================================================
2418 ========================================================================== */
2422 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
2423 /* --------------------------------------------------------------------------
2424 Programmatically reposition mouse pointer in pixel coordinates
2425 -------------------------------------------------------------------------- */
2427 NSTRACE ("frame_set_mouse_pixel_position");
2429 /* FIXME: what about GNUstep? */
2430 #ifdef NS_IMPL_COCOA
2432 CGPointMake(f->left_pos + pix_x,
2433 f->top_pos + pix_y +
2434 FRAME_NS_TITLEBAR_HEIGHT(f) + FRAME_TOOLBAR_HEIGHT(f));
2435 CGWarpMouseCursorPosition (mouse_pos);
2440 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
2441 /* ------------------------------------------------------------------------
2442 Called by EmacsView on mouseMovement events. Passes on
2443 to emacs mainstream code if we moved off of a rect of interest
2444 known as last_mouse_glyph.
2445 ------------------------------------------------------------------------ */
2447 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
2450 // NSTRACE ("note_mouse_movement");
2452 dpyinfo->last_mouse_motion_frame = frame;
2453 r = &dpyinfo->last_mouse_glyph;
2455 /* Note, this doesn't get called for enter/leave, since we don't have a
2456 position. Those are taken care of in the corresponding NSView methods. */
2458 /* has movement gone beyond last rect we were tracking? */
2459 if (x < r->origin.x || x >= r->origin.x + r->size.width
2460 || y < r->origin.y || y >= r->origin.y + r->size.height)
2462 ns_update_begin (frame);
2463 frame->mouse_moved = 1;
2464 note_mouse_highlight (frame, x, y);
2465 remember_mouse_glyph (frame, x, y, r);
2466 ns_update_end (frame);
2475 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
2476 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
2478 /* --------------------------------------------------------------------------
2479 External (hook): inform emacs about mouse position and hit parts.
2480 If a scrollbar is being dragged, set bar_window, part, x, y, time.
2481 x & y should be position in the scrollbar (the whole bar, not the handle)
2482 and length of scrollbar respectively
2483 -------------------------------------------------------------------------- */
2487 Lisp_Object frame, tail;
2489 struct ns_display_info *dpyinfo;
2491 NSTRACE ("ns_mouse_position");
2495 fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
2499 dpyinfo = FRAME_DISPLAY_INFO (*fp);
2503 /* Clear the mouse-moved flag for every frame on this display. */
2504 FOR_EACH_FRAME (tail, frame)
2505 if (FRAME_NS_P (XFRAME (frame))
2506 && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
2507 XFRAME (frame)->mouse_moved = 0;
2509 dpyinfo->last_mouse_scroll_bar = nil;
2510 if (dpyinfo->last_mouse_frame
2511 && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
2512 f = dpyinfo->last_mouse_frame;
2514 f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame : SELECTED_FRAME ();
2516 if (f && FRAME_NS_P (f))
2518 view = FRAME_NS_VIEW (*fp);
2520 position = [[view window] mouseLocationOutsideOfEventStream];
2521 position = [view convertPoint: position fromView: nil];
2522 remember_mouse_glyph (f, position.x, position.y,
2523 &dpyinfo->last_mouse_glyph);
2524 NSTRACE_POINT ("position", position);
2526 if (bar_window) *bar_window = Qnil;
2527 if (part) *part = scroll_bar_above_handle;
2529 if (x) XSETINT (*x, lrint (position.x));
2530 if (y) XSETINT (*y, lrint (position.y));
2532 *time = dpyinfo->last_mouse_movement_time;
2541 ns_frame_up_to_date (struct frame *f)
2542 /* --------------------------------------------------------------------------
2543 External (hook): Fix up mouse highlighting right after a full update.
2544 Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
2545 -------------------------------------------------------------------------- */
2547 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_frame_up_to_date");
2551 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
2552 if (f == hlinfo->mouse_face_mouse_frame)
2556 note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
2557 hlinfo->mouse_face_mouse_x,
2558 hlinfo->mouse_face_mouse_y);
2567 ns_define_frame_cursor (struct frame *f, Cursor cursor)
2568 /* --------------------------------------------------------------------------
2569 External (RIF): set frame mouse pointer type.
2570 -------------------------------------------------------------------------- */
2572 NSTRACE ("ns_define_frame_cursor");
2573 if (FRAME_POINTER_TYPE (f) != cursor)
2575 EmacsView *view = FRAME_NS_VIEW (f);
2576 FRAME_POINTER_TYPE (f) = cursor;
2577 [[view window] invalidateCursorRectsForView: view];
2578 /* Redisplay assumes this function also draws the changed frame
2579 cursor, but this function doesn't, so do it explicitly. */
2580 x_update_cursor (f, 1);
2586 /* ==========================================================================
2590 ========================================================================== */
2594 ns_convert_key (unsigned code)
2595 /* --------------------------------------------------------------------------
2596 Internal call used by NSView-keyDown.
2597 -------------------------------------------------------------------------- */
2599 const unsigned last_keysym = ARRAYELTS (convert_ns_to_X_keysym);
2601 /* An array would be faster, but less easy to read. */
2602 for (keysym = 0; keysym < last_keysym; keysym += 2)
2603 if (code == convert_ns_to_X_keysym[keysym])
2604 return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
2606 /* if decide to use keyCode and Carbon table, use this line:
2607 return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
2612 x_get_keysym_name (int keysym)
2613 /* --------------------------------------------------------------------------
2614 Called by keyboard.c. Not sure if the return val is important, except
2616 -------------------------------------------------------------------------- */
2618 static char value[16];
2619 NSTRACE ("x_get_keysym_name");
2620 sprintf (value, "%d", keysym);
2626 /* ==========================================================================
2628 Block drawing operations
2630 ========================================================================== */
2634 ns_redraw_scroll_bars (struct frame *f)
2638 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2639 NSTRACE ("ns_redraw_scroll_bars");
2640 for (i =[subviews count]-1; i >= 0; i--)
2642 view = [subviews objectAtIndex: i];
2643 if (![view isKindOfClass: [EmacsScroller class]]) continue;
2650 ns_clear_frame (struct frame *f)
2651 /* --------------------------------------------------------------------------
2652 External (hook): Erase the entire frame
2653 -------------------------------------------------------------------------- */
2655 NSView *view = FRAME_NS_VIEW (f);
2658 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame");
2660 /* comes on initial frame because we have
2661 after-make-frame-functions = select-frame */
2662 if (!FRAME_DEFAULT_FACE (f))
2665 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2670 ns_focus (f, &r, 1);
2671 [ns_lookup_indexed_color (NS_FACE_BACKGROUND
2672 (FACE_FROM_ID (f, DEFAULT_FACE_ID)), f) set];
2676 /* as of 2006/11 or so this is now needed */
2677 ns_redraw_scroll_bars (f);
2683 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2684 /* --------------------------------------------------------------------------
2685 External (RIF): Clear section of frame
2686 -------------------------------------------------------------------------- */
2688 NSRect r = NSMakeRect (x, y, width, height);
2689 NSView *view = FRAME_NS_VIEW (f);
2690 struct face *face = FRAME_DEFAULT_FACE (f);
2695 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame_area");
2697 r = NSIntersectionRect (r, [view frame]);
2698 ns_focus (f, &r, 1);
2699 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2708 ns_copy_bits (struct frame *f, NSRect src, NSRect dest)
2710 NSTRACE ("ns_copy_bits");
2712 if (FRAME_NS_VIEW (f))
2714 hide_bell(); // Ensure the bell image isn't scrolled.
2716 ns_focus (f, &dest, 1);
2717 [FRAME_NS_VIEW (f) scrollRect: src
2718 by: NSMakeSize (dest.origin.x - src.origin.x,
2719 dest.origin.y - src.origin.y)];
2725 ns_scroll_run (struct window *w, struct run *run)
2726 /* --------------------------------------------------------------------------
2727 External (RIF): Insert or delete n lines at line vpos
2728 -------------------------------------------------------------------------- */
2730 struct frame *f = XFRAME (w->frame);
2731 int x, y, width, height, from_y, to_y, bottom_y;
2733 NSTRACE ("ns_scroll_run");
2735 /* begin copy from other terms */
2736 /* Get frame-relative bounding box of the text display area of W,
2737 without mode lines. Include in this box the left and right
2739 window_box (w, ANY_AREA, &x, &y, &width, &height);
2741 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2742 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2743 bottom_y = y + height;
2747 /* Scrolling up. Make sure we don't copy part of the mode
2748 line at the bottom. */
2749 if (from_y + run->height > bottom_y)
2750 height = bottom_y - from_y;
2752 height = run->height;
2756 /* Scrolling down. Make sure we don't copy over the mode line.
2758 if (to_y + run->height > bottom_y)
2759 height = bottom_y - to_y;
2761 height = run->height;
2763 /* end copy from other terms */
2773 NSRect srcRect = NSMakeRect (x, from_y, width, height);
2774 NSRect dstRect = NSMakeRect (x, to_y, width, height);
2776 ns_copy_bits (f, srcRect , dstRect);
2784 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2785 /* --------------------------------------------------------------------------
2786 External (RIF): preparatory to fringe update after text was updated
2787 -------------------------------------------------------------------------- */
2792 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_after_update_window_line");
2794 /* begin copy from other terms */
2797 if (!desired_row->mode_line_p && !w->pseudo_window_p)
2798 desired_row->redraw_fringe_bitmaps_p = 1;
2800 /* When a window has disappeared, make sure that no rest of
2801 full-width rows stays visible in the internal border. */
2802 if (windows_or_buffers_changed
2803 && desired_row->full_width_p
2804 && (f = XFRAME (w->frame),
2805 width = FRAME_INTERNAL_BORDER_WIDTH (f),
2807 && (height = desired_row->visible_height,
2810 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2813 ns_clear_frame_area (f, 0, y, width, height);
2814 ns_clear_frame_area (f,
2815 FRAME_PIXEL_WIDTH (f) - width,
2823 ns_shift_glyphs_for_insert (struct frame *f,
2824 int x, int y, int width, int height,
2826 /* --------------------------------------------------------------------------
2827 External (RIF): copy an area horizontally, don't worry about clearing src
2828 -------------------------------------------------------------------------- */
2830 NSRect srcRect = NSMakeRect (x, y, width, height);
2831 NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2833 NSTRACE ("ns_shift_glyphs_for_insert");
2835 ns_copy_bits (f, srcRect, dstRect);
2840 /* ==========================================================================
2842 Character encoding and metrics
2844 ========================================================================== */
2848 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2849 /* --------------------------------------------------------------------------
2850 External (RIF); compute left/right overhang of whole string and set in s
2851 -------------------------------------------------------------------------- */
2853 struct font *font = s->font;
2857 struct font_metrics metrics;
2858 unsigned int codes[2];
2859 codes[0] = *(s->char2b);
2860 codes[1] = *(s->char2b + s->nchars - 1);
2862 font->driver->text_extents (font, codes, 2, &metrics);
2863 s->left_overhang = -metrics.lbearing;
2865 = metrics.rbearing > metrics.width
2866 ? metrics.rbearing - metrics.width : 0;
2870 s->left_overhang = 0;
2871 if (EQ (font->driver->type, Qns))
2872 s->right_overhang = ((struct nsfont_info *)font)->ital ?
2873 FONT_HEIGHT (font) * 0.2 : 0;
2875 s->right_overhang = 0;
2881 /* ==========================================================================
2883 Fringe and cursor drawing
2885 ========================================================================== */
2888 extern int max_used_fringe_bitmap;
2890 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2891 struct draw_fringe_bitmap_params *p)
2892 /* --------------------------------------------------------------------------
2893 External (RIF); fringe-related
2894 -------------------------------------------------------------------------- */
2896 /* Fringe bitmaps comes in two variants, normal and periodic. A
2897 periodic bitmap is used to create a continuous pattern. Since a
2898 bitmap is rendered one text line at a time, the start offset (dh)
2899 of the bitmap varies. Concretely, this is used for the empty
2902 For a bitmap, "h + dh" is the full height and is always
2903 invariant. For a normal bitmap "dh" is zero.
2905 For example, when the period is three and the full height is 72
2906 the following combinations exists:
2912 struct frame *f = XFRAME (WINDOW_FRAME (w));
2913 struct face *face = p->face;
2914 static EmacsImage **bimgs = NULL;
2915 static int nBimgs = 0;
2917 NSTRACE_WHEN (NSTRACE_GROUP_FRINGE, "ns_draw_fringe_bitmap");
2918 NSTRACE_MSG ("which:%d cursor:%d overlay:%d width:%d height:%d period:%d",
2919 p->which, p->cursor_p, p->overlay_p, p->wd, p->h, p->dh);
2921 /* grow bimgs if needed */
2922 if (nBimgs < max_used_fringe_bitmap)
2924 bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2925 memset (bimgs + nBimgs, 0,
2926 (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2927 nBimgs = max_used_fringe_bitmap;
2930 /* Must clip because of partially visible lines. */
2931 ns_clip_to_row (w, row, ANY_AREA, YES);
2935 int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2937 if (bx >= 0 && nx > 0)
2939 NSRect r = NSMakeRect (bx, by, nx, ny);
2941 [ns_lookup_indexed_color (face->background, f) set];
2948 NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2949 EmacsImage *img = bimgs[p->which - 1];
2953 // Note: For "periodic" images, allocate one EmacsImage for
2954 // the base image, and use it for all dh:s.
2955 unsigned short *bits = p->bits;
2956 int full_height = p->h + p->dh;
2958 unsigned char *cbits = xmalloc (full_height);
2960 for (i = 0; i < full_height; i++)
2962 img = [[EmacsImage alloc] initFromXBM: cbits width: 8
2965 bimgs[p->which - 1] = img;
2969 NSTRACE_RECT ("r", r);
2972 /* Since we composite the bitmap instead of just blitting it, we need
2973 to erase the whole background. */
2974 [ns_lookup_indexed_color(face->background, f) set];
2980 bm_color = ns_lookup_indexed_color(face->foreground, f);
2981 else if (p->overlay_p)
2982 bm_color = ns_lookup_indexed_color(face->background, f);
2984 bm_color = f->output_data.ns->cursor_color;
2985 [img setXBMColor: bm_color];
2988 #ifdef NS_IMPL_COCOA
2989 // Note: For periodic images, the full image height is "h + hd".
2990 // By using the height h, a suitable part of the image is used.
2991 NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h);
2993 NSTRACE_RECT ("fromRect", fromRect);
2997 operation: NSCompositingOperationSourceOver
3003 NSPoint pt = r.origin;
3005 [img compositeToPoint: pt operation: NSCompositingOperationSourceOver];
3014 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
3015 int x, int y, enum text_cursor_kinds cursor_type,
3016 int cursor_width, bool on_p, bool active_p)
3017 /* --------------------------------------------------------------------------
3018 External call (RIF): draw cursor.
3019 Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
3020 -------------------------------------------------------------------------- */
3023 int fx, fy, h, cursor_height;
3024 struct frame *f = WINDOW_XFRAME (w);
3025 struct glyph *phys_cursor_glyph;
3026 struct glyph *cursor_glyph;
3028 NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
3030 /* If cursor is out of bounds, don't draw garbage. This can happen
3031 in mini-buffer windows when switching between echo area glyphs
3034 NSTRACE ("ns_draw_window_cursor");
3039 w->phys_cursor_type = cursor_type;
3040 w->phys_cursor_on_p = on_p;
3042 if (cursor_type == NO_CURSOR)
3044 w->phys_cursor_width = 0;
3048 if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
3050 if (glyph_row->exact_window_width_line_p
3051 && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
3053 glyph_row->cursor_in_fringe_p = 1;
3054 draw_fringe_bitmap (w, glyph_row, 0);
3059 /* We draw the cursor (with NSRectFill), then draw the glyph on top
3060 (other terminals do it the other way round). We must set
3061 w->phys_cursor_width to the cursor width. For bar cursors, that
3062 is CURSOR_WIDTH; for box cursors, it is the glyph width. */
3063 get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
3065 /* The above get_phys_cursor_geometry call set w->phys_cursor_width
3066 to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
3067 if (cursor_type == BAR_CURSOR)
3069 if (cursor_width < 1)
3070 cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
3072 /* The bar cursor should never be wider than the glyph. */
3073 if (cursor_width < w->phys_cursor_width)
3074 w->phys_cursor_width = cursor_width;
3076 /* If we have an HBAR, "cursor_width" MAY specify height. */
3077 else if (cursor_type == HBAR_CURSOR)
3079 cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
3080 if (cursor_height > glyph_row->height)
3081 cursor_height = glyph_row->height;
3082 if (h > cursor_height) // Cursor smaller than line height, move down
3083 fy += h - cursor_height;
3087 r.origin.x = fx, r.origin.y = fy;
3089 r.size.width = w->phys_cursor_width;
3091 /* Prevent the cursor from being drawn outside the text area. */
3092 ns_clip_to_row (w, glyph_row, TEXT_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
3095 face = FACE_FROM_ID_OR_NULL (f, phys_cursor_glyph->face_id);
3096 if (face && NS_FACE_BACKGROUND (face)
3097 == ns_index_color (FRAME_CURSOR_COLOR (f), f))
3099 [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
3100 hollow_color = FRAME_CURSOR_COLOR (f);
3103 [FRAME_CURSOR_COLOR (f) set];
3105 #ifdef NS_IMPL_COCOA
3106 /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
3107 atomic. Cleaner ways of doing this should be investigated.
3108 One way would be to set a global variable DRAWING_CURSOR
3109 when making the call to draw_phys..(), don't focus in that
3110 case, then move the ns_unfocus() here after that call. */
3111 NSDisableScreenUpdates ();
3114 switch (cursor_type)
3116 case DEFAULT_CURSOR:
3119 case FILLED_BOX_CURSOR:
3122 case HOLLOW_BOX_CURSOR:
3125 NSRectFill (NSInsetRect (r, 1, 1));
3126 [FRAME_CURSOR_COLOR (f) set];
3133 /* If the character under cursor is R2L, draw the bar cursor
3134 on the right of its glyph, rather than on the left. */
3135 cursor_glyph = get_phys_cursor_glyph (w);
3136 if ((cursor_glyph->resolved_level & 1) != 0)
3137 s.origin.x += cursor_glyph->pixel_width - s.size.width;
3144 /* draw the character under the cursor */
3145 if (cursor_type != NO_CURSOR)
3146 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
3148 #ifdef NS_IMPL_COCOA
3149 NSEnableScreenUpdates ();
3156 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
3157 /* --------------------------------------------------------------------------
3158 External (RIF): Draw a vertical line.
3159 -------------------------------------------------------------------------- */
3161 struct frame *f = XFRAME (WINDOW_FRAME (w));
3163 NSRect r = NSMakeRect (x, y0, 1, y1-y0);
3165 NSTRACE ("ns_draw_vertical_window_border");
3167 face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID);
3169 ns_focus (f, &r, 1);
3171 [ns_lookup_indexed_color(face->foreground, f) set];
3179 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
3180 /* --------------------------------------------------------------------------
3181 External (RIF): Draw a window divider.
3182 -------------------------------------------------------------------------- */
3184 struct frame *f = XFRAME (WINDOW_FRAME (w));
3186 NSRect r = NSMakeRect (x0, y0, x1-x0, y1-y0);
3188 NSTRACE ("ns_draw_window_divider");
3190 face = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FACE_ID);
3192 ns_focus (f, &r, 1);
3194 [ns_lookup_indexed_color(face->foreground, f) set];
3201 ns_show_hourglass (struct frame *f)
3203 /* TODO: add NSProgressIndicator to all frames. */
3207 ns_hide_hourglass (struct frame *f)
3209 /* TODO: remove NSProgressIndicator from all frames. */
3212 /* ==========================================================================
3214 Glyph drawing operations
3216 ========================================================================== */
3219 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
3220 /* --------------------------------------------------------------------------
3221 Wrapper utility to account for internal border width on full-width lines,
3222 and allow top full-width rows to hit the frame top. nr should be pointer
3223 to two successive NSRects. Number of rects actually used is returned.
3224 -------------------------------------------------------------------------- */
3226 int n = get_glyph_string_clip_rects (s, nr, 2);
3230 /* --------------------------------------------------------------------
3231 Draw a wavy line under glyph string s. The wave fills wave_height
3238 wave_height = 3 | * * * *
3239 --------------------------------------------------------------------- */
3242 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
3244 int wave_height = 3, wave_length = 2;
3245 int y, dx, dy, odd, xmax;
3250 dy = wave_height - 1;
3251 y = s->ybase - wave_height + 3;
3254 /* Find and set clipping rectangle */
3255 waveClip = NSMakeRect (x, y, width, wave_height);
3256 [[NSGraphicsContext currentContext] saveGraphicsState];
3257 NSRectClip (waveClip);
3259 /* Draw the waves */
3260 a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
3262 odd = (int)(a.x/dx) % 2;
3263 a.y = b.y = y + 0.5;
3272 [NSBezierPath strokeLineFromPoint:a toPoint:b];
3273 a.x = b.x, a.y = b.y;
3274 b.x += dx, b.y = y + 0.5 + odd*dy;
3278 /* Restore previous clipping rectangle(s) */
3279 [[NSGraphicsContext currentContext] restoreGraphicsState];
3285 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
3286 NSColor *defaultCol, CGFloat width, CGFloat x)
3287 /* --------------------------------------------------------------------------
3288 Draw underline, overline, and strike-through on glyph string s.
3289 -------------------------------------------------------------------------- */
3291 if (s->for_overlaps)
3295 if (face->underline_p)
3297 if (s->face->underline_type == FACE_UNDER_WAVE)
3299 if (face->underline_defaulted_p)
3302 [ns_lookup_indexed_color (face->underline_color, s->f) set];
3304 ns_draw_underwave (s, width, x);
3306 else if (s->face->underline_type == FACE_UNDER_LINE)
3310 unsigned long thickness, position;
3312 /* If the prev was underlined, match its appearance. */
3313 if (s->prev && s->prev->face->underline_p
3314 && s->prev->face->underline_type == FACE_UNDER_LINE
3315 && s->prev->underline_thickness > 0)
3317 thickness = s->prev->underline_thickness;
3318 position = s->prev->underline_position;
3322 struct font *font = font_for_underline_metrics (s);
3323 unsigned long descent = s->y + s->height - s->ybase;
3325 /* Use underline thickness of font, defaulting to 1. */
3326 thickness = (font && font->underline_thickness > 0)
3327 ? font->underline_thickness : 1;
3329 /* Determine the offset of underlining from the baseline. */
3330 if (x_underline_at_descent_line)
3331 position = descent - thickness;
3332 else if (x_use_underline_position_properties
3333 && font && font->underline_position >= 0)
3334 position = font->underline_position;
3336 position = lround (font->descent / 2);
3338 position = underline_minimum_offset;
3340 position = max (position, underline_minimum_offset);
3342 /* Ensure underlining is not cropped. */
3343 if (descent <= position)
3345 position = descent - 1;
3348 else if (descent < position + thickness)
3352 s->underline_thickness = thickness;
3353 s->underline_position = position;
3355 r = NSMakeRect (x, s->ybase + position, width, thickness);
3357 if (face->underline_defaulted_p)
3360 [ns_lookup_indexed_color (face->underline_color, s->f) set];
3364 /* Do overline. We follow other terms in using a thickness of 1
3365 and ignoring overline_margin. */
3366 if (face->overline_p)
3369 r = NSMakeRect (x, s->y, width, 1);
3371 if (face->overline_color_defaulted_p)
3374 [ns_lookup_indexed_color (face->overline_color, s->f) set];
3378 /* Do strike-through. We follow other terms for thickness and
3379 vertical position.*/
3380 if (face->strike_through_p)
3383 /* Y-coordinate and height of the glyph string's first glyph.
3384 We cannot use s->y and s->height because those could be
3385 larger if there are taller display elements (e.g., characters
3386 displayed with a larger font) in the same glyph row. */
3387 int glyph_y = s->ybase - s->first_glyph->ascent;
3388 int glyph_height = s->first_glyph->ascent + s->first_glyph->descent;
3389 /* Strike-through width and offset from the glyph string's
3391 unsigned long h = 1;
3394 dy = lrint ((glyph_height - h) / 2);
3395 r = NSMakeRect (x, glyph_y + dy, width, 1);
3397 if (face->strike_through_color_defaulted_p)
3400 [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
3406 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
3407 char left_p, char right_p)
3408 /* --------------------------------------------------------------------------
3409 Draw an unfilled rect inside r, optionally leaving left and/or right open.
3410 Note we can't just use an NSDrawRect command, because of the possibility
3411 of some sides not being drawn, and because the rect will be filled.
3412 -------------------------------------------------------------------------- */
3418 s.size.height = thickness;
3420 s.origin.y += r.size.height - thickness;
3423 s.size.height = r.size.height;
3424 s.origin.y = r.origin.y;
3426 /* left, right (optional) */
3427 s.size.width = thickness;
3432 s.origin.x += r.size.width - thickness;
3439 ns_draw_relief (NSRect r, int thickness, char raised_p,
3440 char top_p, char bottom_p, char left_p, char right_p,
3441 struct glyph_string *s)
3442 /* --------------------------------------------------------------------------
3443 Draw a relief rect inside r, optionally leaving some sides open.
3444 Note we can't just use an NSDrawBezel command, because of the possibility
3445 of some sides not being drawn, and because the rect will be filled.
3446 -------------------------------------------------------------------------- */
3448 static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
3449 NSColor *newBaseCol = nil;
3452 NSTRACE ("ns_draw_relief");
3456 if (s->face->use_box_color_for_shadows_p)
3458 newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
3460 /* else if (s->first_glyph->type == IMAGE_GLYPH
3462 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3464 newBaseCol = IMAGE_BACKGROUND (s->img, s->f, 0);
3468 newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
3471 if (newBaseCol == nil)
3472 newBaseCol = [NSColor grayColor];
3474 if (newBaseCol != baseCol) /* TODO: better check */
3477 baseCol = [newBaseCol retain];
3479 lightCol = [[baseCol highlightWithLevel: 0.2] retain];
3481 darkCol = [[baseCol shadowWithLevel: 0.3] retain];
3484 [(raised_p ? lightCol : darkCol) set];
3486 /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
3489 sr.size.height = thickness;
3490 if (top_p) NSRectFill (sr);
3493 sr.size.height = r.size.height;
3494 sr.size.width = thickness;
3495 if (left_p) NSRectFill (sr);
3497 [(raised_p ? darkCol : lightCol) set];
3500 sr.size.width = r.size.width;
3501 sr.size.height = thickness;
3502 sr.origin.y += r.size.height - thickness;
3503 if (bottom_p) NSRectFill (sr);
3506 sr.size.height = r.size.height;
3507 sr.origin.y = r.origin.y;
3508 sr.size.width = thickness;
3509 sr.origin.x += r.size.width - thickness;
3510 if (right_p) NSRectFill (sr);
3515 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
3516 /* --------------------------------------------------------------------------
3517 Function modeled after x_draw_glyph_string_box ().
3518 Sets up parameters for drawing.
3519 -------------------------------------------------------------------------- */
3521 int right_x, last_x;
3522 char left_p, right_p;
3523 struct glyph *last_glyph;
3528 if (s->hl == DRAW_MOUSE_FACE)
3530 face = FACE_FROM_ID_OR_NULL (s->f,
3531 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3533 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3538 thickness = face->box_line_width;
3540 NSTRACE ("ns_dumpglyphs_box_or_relief");
3542 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
3543 ? WINDOW_RIGHT_EDGE_X (s->w)
3544 : window_box_right (s->w, s->area));
3545 last_glyph = (s->cmp || s->img
3546 ? s->first_glyph : s->first_glyph + s->nchars-1);
3548 right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
3549 ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
3551 left_p = (s->first_glyph->left_box_line_p
3552 || (s->hl == DRAW_MOUSE_FACE
3553 && (s->prev == NULL || s->prev->hl != s->hl)));
3554 right_p = (last_glyph->right_box_line_p
3555 || (s->hl == DRAW_MOUSE_FACE
3556 && (s->next == NULL || s->next->hl != s->hl)));
3558 r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
3560 /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
3561 if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
3563 ns_draw_box (r, abs (thickness),
3564 ns_lookup_indexed_color (face->box_color, s->f),
3569 ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
3570 1, 1, left_p, right_p, s);
3576 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
3577 /* --------------------------------------------------------------------------
3578 Modeled after x_draw_glyph_string_background, which draws BG in
3579 certain cases. Others are left to the text rendering routine.
3580 -------------------------------------------------------------------------- */
3582 NSTRACE ("ns_maybe_dumpglyphs_background");
3584 if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
3586 int box_line_width = max (s->face->box_line_width, 0);
3587 if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
3588 /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font
3589 dimensions, since the actual glyphs might be much
3590 smaller. So in that case we always clear the rectangle
3591 with background color. */
3592 || FONT_TOO_HIGH (s->font)
3593 || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
3596 if (s->hl == DRAW_MOUSE_FACE)
3599 = FACE_FROM_ID_OR_NULL (s->f,
3600 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3602 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3605 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3607 [(NS_FACE_BACKGROUND (face) != 0
3608 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
3609 : FRAME_BACKGROUND_COLOR (s->f)) set];
3612 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
3613 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
3616 if (s->hl != DRAW_CURSOR)
3618 NSRect r = NSMakeRect (s->x, s->y + box_line_width,
3619 s->background_width,
3620 s->height-2*box_line_width);
3624 s->background_filled_p = 1;
3631 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3632 /* --------------------------------------------------------------------------
3633 Renders an image and associated borders.
3634 -------------------------------------------------------------------------- */
3636 EmacsImage *img = s->img->pixmap;
3637 int box_line_vwidth = max (s->face->box_line_width, 0);
3638 int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3639 int bg_x, bg_y, bg_height;
3646 NSTRACE ("ns_dumpglyphs_image");
3648 if (s->face->box != FACE_NO_BOX
3649 && s->first_glyph->left_box_line_p && s->slice.x == 0)
3650 x += abs (s->face->box_line_width);
3653 bg_y = s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
3654 bg_height = s->height;
3655 /* other terms have this, but was causing problems w/tabbar mode */
3656 /* - 2 * box_line_vwidth; */
3658 if (s->slice.x == 0) x += s->img->hmargin;
3659 if (s->slice.y == 0) y += s->img->vmargin;
3661 /* Draw BG: if we need larger area than image itself cleared, do that,
3662 otherwise, since we composite the image under NS (instead of mucking
3663 with its background color), we must clear just the image area. */
3664 if (s->hl == DRAW_MOUSE_FACE)
3666 face = FACE_FROM_ID_OR_NULL (s->f,
3667 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3669 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3672 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3674 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3676 if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3677 || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3679 br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3680 s->background_filled_p = 1;
3684 br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3689 /* Draw the image.. do we need to draw placeholder if img ==nil? */
3692 #ifdef NS_IMPL_COCOA
3693 NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3694 NSRect ir = NSMakeRect (s->slice.x,
3695 s->img->height - s->slice.y - s->slice.height,
3696 s->slice.width, s->slice.height);
3699 operation: NSCompositingOperationSourceOver
3704 [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3705 operation: NSCompositingOperationSourceOver];
3709 if (s->hl == DRAW_CURSOR)
3711 [FRAME_CURSOR_COLOR (s->f) set];
3712 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3713 tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3715 /* Currently on NS img->mask is always 0. Since
3716 get_window_cursor_type specifies a hollow box cursor when on
3717 a non-masked image we never reach this clause. But we put it
3718 in in anticipation of better support for image masks on
3720 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3724 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3727 /* Draw underline, overline, strike-through. */
3728 ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3730 /* Draw relief, if requested */
3731 if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3733 if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3735 th = tool_bar_button_relief >= 0 ?
3736 tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3737 raised_p = (s->hl == DRAW_IMAGE_RAISED);
3741 th = abs (s->img->relief);
3742 raised_p = (s->img->relief > 0);
3745 r.origin.x = x - th;
3746 r.origin.y = y - th;
3747 r.size.width = s->slice.width + 2*th-1;
3748 r.size.height = s->slice.height + 2*th-1;
3749 ns_draw_relief (r, th, raised_p,
3751 s->slice.y + s->slice.height == s->img->height,
3753 s->slice.x + s->slice.width == s->img->width, s);
3756 /* If there is no mask, the background won't be seen,
3757 so draw a rectangle on the image for the cursor.
3758 Do this for all images, getting transparency right is not reliable. */
3759 if (s->hl == DRAW_CURSOR)
3761 int thickness = abs (s->img->relief);
3762 if (thickness == 0) thickness = 1;
3763 ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3769 ns_dumpglyphs_stretch (struct glyph_string *s)
3774 NSColor *fgCol, *bgCol;
3776 if (!s->background_filled_p)
3778 n = ns_get_glyph_string_clip_rect (s, r);
3779 *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3781 ns_focus (s->f, r, n);
3783 if (s->hl == DRAW_MOUSE_FACE)
3785 face = FACE_FROM_ID_OR_NULL (s->f,
3786 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3788 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3791 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3793 bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3794 fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3796 for (i = 0; i < n; ++i)
3798 if (!s->row->full_width_p)
3800 int overrun, leftoverrun;
3802 /* truncate to avoid overwriting fringe and/or scrollbar */
3803 overrun = max (0, (s->x + s->background_width)
3804 - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3805 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3806 r[i].size.width -= overrun;
3808 /* truncate to avoid overwriting to left of the window box */
3809 leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3810 + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3812 if (leftoverrun > 0)
3814 r[i].origin.x += leftoverrun;
3815 r[i].size.width -= leftoverrun;
3818 /* XXX: Try to work between problem where a stretch glyph on
3819 a partially-visible bottom row will clear part of the
3820 modeline, and another where list-buffers headers and similar
3821 rows erroneously have visible_height set to 0. Not sure
3822 where this is coming from as other terms seem not to show. */
3823 r[i].size.height = min (s->height, s->row->visible_height);
3828 /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3829 overwriting cursor (usually when cursor on a tab) */
3830 if (s->hl == DRAW_CURSOR)
3835 width = s->w->phys_cursor_width;
3836 r[i].size.width -= width;
3837 r[i].origin.x += width;
3841 /* Draw overlining, etc. on the cursor. */
3842 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3843 ns_draw_text_decoration (s, face, bgCol, width, x);
3845 ns_draw_text_decoration (s, face, fgCol, width, x);
3852 /* Draw overlining, etc. on the stretch glyph (or the part
3853 of the stretch glyph after the cursor). */
3854 ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3858 s->background_filled_p = 1;
3864 ns_draw_glyph_string_foreground (struct glyph_string *s)
3867 struct font *font = s->font;
3869 /* If first glyph of S has a left box line, start drawing the text
3870 of S to the right of that box line. */
3871 if (s->face && s->face->box != FACE_NO_BOX
3872 && s->first_glyph->left_box_line_p)
3873 x = s->x + eabs (s->face->box_line_width);
3877 flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3878 (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3879 (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3880 NS_DUMPGLYPH_NORMAL));
3883 (s, s->cmp_from, s->nchars, x, s->ybase,
3884 (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3885 || flags == NS_DUMPGLYPH_MOUSEFACE);
3890 ns_draw_composite_glyph_string_foreground (struct glyph_string *s)
3893 struct font *font = s->font;
3895 /* If first glyph of S has a left box line, start drawing the text
3896 of S to the right of that box line. */
3897 if (s->face && s->face->box != FACE_NO_BOX
3898 && s->first_glyph->left_box_line_p)
3899 x = s->x + eabs (s->face->box_line_width);
3903 /* S is a glyph string for a composition. S->cmp_from is the index
3904 of the first character drawn for glyphs of this composition.
3905 S->cmp_from == 0 means we are drawing the very first character of
3906 this composition. */
3908 /* Draw a rectangle for the composition if the font for the very
3909 first character of the composition could not be loaded. */
3910 if (s->font_not_found_p)
3912 if (s->cmp_from == 0)
3914 NSRect r = NSMakeRect (s->x, s->y, s->width-1, s->height -1);
3915 ns_draw_box (r, 1, FRAME_CURSOR_COLOR (s->f), 1, 1);
3918 else if (! s->first_glyph->u.cmp.automatic)
3922 for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
3923 /* TAB in a composition means display glyphs with padding
3924 space on the left or right. */
3925 if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
3927 int xx = x + s->cmp->offsets[j * 2];
3928 int yy = y - s->cmp->offsets[j * 2 + 1];
3930 font->driver->draw (s, j, j + 1, xx, yy, false);
3931 if (s->face->overstrike)
3932 font->driver->draw (s, j, j + 1, xx + 1, yy, false);
3937 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
3942 for (i = j = s->cmp_from; i < s->cmp_to; i++)
3944 glyph = LGSTRING_GLYPH (gstring, i);
3945 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
3946 width += LGLYPH_WIDTH (glyph);
3949 int xoff, yoff, wadjust;
3953 font->driver->draw (s, j, i, x, y, false);
3954 if (s->face->overstrike)
3955 font->driver->draw (s, j, i, x + 1, y, false);
3958 xoff = LGLYPH_XOFF (glyph);
3959 yoff = LGLYPH_YOFF (glyph);
3960 wadjust = LGLYPH_WADJUST (glyph);
3961 font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
3962 if (s->face->overstrike)
3963 font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
3972 font->driver->draw (s, j, i, x, y, false);
3973 if (s->face->overstrike)
3974 font->driver->draw (s, j, i, x + 1, y, false);
3980 ns_draw_glyph_string (struct glyph_string *s)
3981 /* --------------------------------------------------------------------------
3982 External (RIF): Main draw-text call.
3983 -------------------------------------------------------------------------- */
3985 /* TODO (optimize): focus for box and contents draw */
3988 char box_drawn_p = 0;
3989 struct font *font = s->face->font;
3990 if (! font) font = FRAME_FONT (s->f);
3992 NSTRACE_WHEN (NSTRACE_GROUP_GLYPHS, "ns_draw_glyph_string");
3994 if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3997 struct glyph_string *next;
3999 for (width = 0, next = s->next;
4000 next && width < s->right_overhang;
4001 width += next->width, next = next->next)
4002 if (next->first_glyph->type != IMAGE_GLYPH)
4004 if (next->first_glyph->type != STRETCH_GLYPH)
4006 n = ns_get_glyph_string_clip_rect (s->next, r);
4007 ns_focus (s->f, r, n);
4008 ns_maybe_dumpglyphs_background (s->next, 1);
4013 ns_dumpglyphs_stretch (s->next);
4015 next->num_clips = 0;
4019 if (!s->for_overlaps && s->face->box != FACE_NO_BOX
4020 && (s->first_glyph->type == CHAR_GLYPH
4021 || s->first_glyph->type == COMPOSITE_GLYPH))
4023 n = ns_get_glyph_string_clip_rect (s, r);
4024 ns_focus (s->f, r, n);
4025 ns_maybe_dumpglyphs_background (s, 1);
4026 ns_dumpglyphs_box_or_relief (s);
4031 switch (s->first_glyph->type)
4035 n = ns_get_glyph_string_clip_rect (s, r);
4036 ns_focus (s->f, r, n);
4037 ns_dumpglyphs_image (s, r[0]);
4042 ns_dumpglyphs_stretch (s);
4046 case COMPOSITE_GLYPH:
4047 n = ns_get_glyph_string_clip_rect (s, r);
4048 ns_focus (s->f, r, n);
4050 if (s->for_overlaps || (s->cmp_from > 0
4051 && ! s->first_glyph->u.cmp.automatic))
4052 s->background_filled_p = 1;
4054 ns_maybe_dumpglyphs_background
4055 (s, s->first_glyph->type == COMPOSITE_GLYPH);
4057 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
4059 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
4060 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
4061 NS_FACE_FOREGROUND (s->face) = tmp;
4065 BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
4068 ns_draw_composite_glyph_string_foreground (s);
4070 ns_draw_glyph_string_foreground (s);
4074 NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
4075 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
4077 : FRAME_FOREGROUND_COLOR (s->f));
4080 /* Draw underline, overline, strike-through. */
4081 ns_draw_text_decoration (s, s->face, col, s->width, s->x);
4084 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
4086 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
4087 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
4088 NS_FACE_FOREGROUND (s->face) = tmp;
4094 case GLYPHLESS_GLYPH:
4095 n = ns_get_glyph_string_clip_rect (s, r);
4096 ns_focus (s->f, r, n);
4098 if (s->for_overlaps || (s->cmp_from > 0
4099 && ! s->first_glyph->u.cmp.automatic))
4100 s->background_filled_p = 1;
4102 ns_maybe_dumpglyphs_background
4103 (s, s->first_glyph->type == COMPOSITE_GLYPH);
4105 /* Not yet implemented. */
4114 /* Draw box if not done already. */
4115 if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
4117 n = ns_get_glyph_string_clip_rect (s, r);
4118 ns_focus (s->f, r, n);
4119 ns_dumpglyphs_box_or_relief (s);
4128 /* ==========================================================================
4132 ========================================================================== */
4136 ns_send_appdefined (int value)
4137 /* --------------------------------------------------------------------------
4138 Internal: post an appdefined event which EmacsApp-sendEvent will
4139 recognize and take as a command to halt the event loop.
4140 -------------------------------------------------------------------------- */
4142 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_send_appdefined(%d)", value);
4144 // GNUstep needs postEvent to happen on the main thread.
4145 // Cocoa needs nextEventMatchingMask to happen on the main thread too.
4146 if (! [[NSThread currentThread] isMainThread])
4148 EmacsApp *app = (EmacsApp *)NSApp;
4149 app->nextappdefined = value;
4150 [app performSelectorOnMainThread:@selector (sendFromMainThread:)
4156 /* Only post this event if we haven't already posted one. This will end
4157 the [NXApp run] main loop after having processed all events queued at
4160 #ifdef NS_IMPL_COCOA
4161 if (! send_appdefined)
4163 /* OS X 10.10.1 swallows the AppDefined event we are sending ourselves
4164 in certain situations (rapid incoming events).
4165 So check if we have one, if not add one. */
4166 NSEvent *appev = [NSApp nextEventMatchingMask:NSEventMaskApplicationDefined
4167 untilDate:[NSDate distantPast]
4168 inMode:NSDefaultRunLoopMode
4170 if (! appev) send_appdefined = YES;
4174 if (send_appdefined)
4178 /* We only need one NX_APPDEFINED event to stop NXApp from running. */
4179 send_appdefined = NO;
4181 /* Don't need wakeup timer any more */
4184 [timed_entry invalidate];
4185 [timed_entry release];
4189 nxev = [NSEvent otherEventWithType: NSEventTypeApplicationDefined
4190 location: NSMakePoint (0, 0)
4193 windowNumber: [[NSApp mainWindow] windowNumber]
4194 context: [NSApp context]
4199 /* Post an application defined event on the event queue. When this is
4200 received the [NXApp run] will return, thus having processed all
4201 events which are currently queued. */
4202 [NSApp postEvent: nxev atStart: NO];
4206 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
4210 Lisp_Object frame, tail;
4212 if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
4215 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
4217 FOR_EACH_FRAME (tail, frame)
4219 struct frame *f = XFRAME (frame);
4222 EmacsView *view = FRAME_NS_VIEW (f);
4223 [view updateCollectionBehavior];
4229 /* GNUstep does not have cancelTracking. */
4230 #ifdef NS_IMPL_COCOA
4231 /* Check if menu open should be canceled or continued as normal. */
4233 ns_check_menu_open (NSMenu *menu)
4235 /* Click in menu bar? */
4236 NSArray *a = [[NSApp mainMenu] itemArray];
4240 if (menu == nil) // Menu tracking ended.
4242 if (menu_will_open_state == MENU_OPENING)
4243 menu_will_open_state = MENU_NONE;
4247 for (i = 0; ! found && i < [a count]; i++)
4248 found = menu == [[a objectAtIndex:i] submenu];
4251 if (menu_will_open_state == MENU_NONE && emacs_event)
4253 NSEvent *theEvent = [NSApp currentEvent];
4254 struct frame *emacsframe = SELECTED_FRAME ();
4256 [menu cancelTracking];
4257 menu_will_open_state = MENU_PENDING;
4258 emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
4259 EV_TRAILER (theEvent);
4261 CGEventRef ourEvent = CGEventCreate (NULL);
4262 menu_mouse_point = CGEventGetLocation (ourEvent);
4263 CFRelease (ourEvent);
4265 else if (menu_will_open_state == MENU_OPENING)
4267 menu_will_open_state = MENU_NONE;
4272 /* Redo saved menu click if state is MENU_PENDING. */
4274 ns_check_pending_open_menu ()
4276 if (menu_will_open_state == MENU_PENDING)
4278 CGEventSourceRef source
4279 = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
4281 CGEventRef event = CGEventCreateMouseEvent (source,
4282 kCGEventLeftMouseDown,
4284 kCGMouseButtonLeft);
4285 CGEventSetType (event, kCGEventLeftMouseDown);
4286 CGEventPost (kCGHIDEventTap, event);
4290 menu_will_open_state = MENU_OPENING;
4293 #endif /* NS_IMPL_COCOA */
4296 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
4297 /* --------------------------------------------------------------------------
4298 External (hook): Post an event to ourself and keep reading events until
4299 we read it back again. In effect process all events which were waiting.
4300 From 21+ we have to manage the event buffer ourselves.
4301 -------------------------------------------------------------------------- */
4303 struct input_event ev;
4306 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_read_socket");
4308 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
4312 if ([NSApp modalWindow] != nil)
4315 if (hold_event_q.nr > 0)
4318 for (i = 0; i < hold_event_q.nr; ++i)
4319 kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
4320 hold_event_q.nr = 0;
4324 if ([NSThread isMainThread])
4327 n_emacs_events_pending = 0;
4328 ns_init_events (&ev);
4329 q_event_ptr = hold_quit;
4331 /* we manage autorelease pools by allocate/reallocate each time around
4332 the loop; strict nesting is occasionally violated but seems not to
4333 matter.. earlier methods using full nesting caused major memory leaks */
4334 [outerpool release];
4335 outerpool = [[NSAutoreleasePool alloc] init];
4337 /* If have pending open-file requests, attend to the next one of those. */
4338 if (ns_pending_files && [ns_pending_files count] != 0
4339 && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
4341 [ns_pending_files removeObjectAtIndex: 0];
4343 /* Deal with pending service requests. */
4344 else if (ns_pending_service_names && [ns_pending_service_names count] != 0
4346 NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
4347 withArg: [ns_pending_service_args objectAtIndex: 0]])
4349 [ns_pending_service_names removeObjectAtIndex: 0];
4350 [ns_pending_service_args removeObjectAtIndex: 0];
4354 /* Run and wait for events. We must always send one NX_APPDEFINED event
4355 to ourself, otherwise [NXApp run] will never exit. */
4356 send_appdefined = YES;
4357 ns_send_appdefined (-1);
4362 nevents = n_emacs_events_pending;
4363 n_emacs_events_pending = 0;
4364 ns_finish_events ();
4376 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
4377 fd_set *exceptfds, struct timespec *timeout,
4379 /* --------------------------------------------------------------------------
4380 Replacement for select, checking for events
4381 -------------------------------------------------------------------------- */
4385 struct input_event event;
4388 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_select");
4390 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
4394 if (hold_event_q.nr > 0)
4396 /* We already have events pending. */
4402 for (k = 0; k < nfds+1; k++)
4404 if (readfds && FD_ISSET(k, readfds)) ++nr;
4405 if (writefds && FD_ISSET(k, writefds)) ++nr;
4409 || ![NSThread isMainThread]
4410 || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
4411 return thread_select(pselect, nfds, readfds, writefds,
4412 exceptfds, timeout, sigmask);
4415 struct timespec t = {0, 0};
4416 thread_select(pselect, 0, NULL, NULL, NULL, &t, sigmask);
4419 [outerpool release];
4420 outerpool = [[NSAutoreleasePool alloc] init];
4423 send_appdefined = YES;
4426 pthread_mutex_lock (&select_mutex);
4431 select_readfds = *readfds;
4432 select_valid += SELECT_HAVE_READ;
4436 select_writefds = *writefds;
4437 select_valid += SELECT_HAVE_WRITE;
4442 select_timeout = *timeout;
4443 select_valid += SELECT_HAVE_TMO;
4446 pthread_mutex_unlock (&select_mutex);
4448 /* Inform fd_handler that select should be called */
4450 emacs_write_sig (selfds[1], &c, 1);
4452 else if (nr == 0 && timeout)
4454 /* No file descriptor, just a timeout, no need to wake fd_handler */
4455 double time = timespectod (*timeout);
4456 timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
4459 @selector (timeout_handler:)
4464 else /* No timeout and no file descriptors, can this happen? */
4466 /* Send appdefined so we exit from the loop */
4467 ns_send_appdefined (-1);
4471 ns_init_events (&event);
4475 ns_finish_events ();
4476 if (nr > 0 && readfds)
4479 emacs_write_sig (selfds[1], &c, 1);
4483 t = last_appdefined_event_data;
4485 if (t != NO_APPDEFINED_DATA)
4487 last_appdefined_event_data = NO_APPDEFINED_DATA;
4491 /* The NX_APPDEFINED event we received was a timeout. */
4496 /* The NX_APPDEFINED event we received was the result of
4497 at least one real input event arriving. */
4503 /* Received back from select () in fd_handler; copy the results */
4504 pthread_mutex_lock (&select_mutex);
4505 if (readfds) *readfds = select_readfds;
4506 if (writefds) *writefds = select_writefds;
4507 pthread_mutex_unlock (&select_mutex);
4522 ns_run_loop_break ()
4523 /* Break out of the NS run loop in ns_select or ns_read_socket. */
4525 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_run_loop_break");
4527 /* If we don't have a GUI, don't send the event. */
4529 ns_send_appdefined(-1);
4534 /* ==========================================================================
4538 ========================================================================== */
4542 ns_set_vertical_scroll_bar (struct window *window,
4543 int portion, int whole, int position)
4544 /* --------------------------------------------------------------------------
4545 External (hook): Update or add scrollbar
4546 -------------------------------------------------------------------------- */
4550 struct frame *f = XFRAME (WINDOW_FRAME (window));
4551 EmacsView *view = FRAME_NS_VIEW (f);
4553 int window_y, window_height;
4554 int top, left, height, width;
4555 BOOL update_p = YES;
4557 /* optimization; display engine sends WAY too many of these.. */
4558 if (!NILP (window->vertical_scroll_bar))
4560 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4561 if ([bar checkSamePosition: position portion: portion whole: whole])
4563 if (view->scrollbarsNeedingUpdate == 0)
4565 if (!windows_or_buffers_changed)
4569 view->scrollbarsNeedingUpdate--;
4574 NSTRACE ("ns_set_vertical_scroll_bar");
4576 /* Get dimensions. */
4577 window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
4579 height = window_height;
4580 width = NS_SCROLL_BAR_WIDTH (f);
4581 left = WINDOW_SCROLL_BAR_AREA_X (window);
4583 r = NSMakeRect (left, top, width, height);
4584 /* the parent view is flipped, so we need to flip y value */
4586 r.origin.y = (v.size.height - r.size.height - r.origin.y);
4588 XSETWINDOW (win, window);
4591 /* we want at least 5 lines to display a scrollbar */
4592 if (WINDOW_TOTAL_LINES (window) < 5)
4594 if (!NILP (window->vertical_scroll_bar))
4596 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4597 [bar removeFromSuperview];
4598 wset_vertical_scroll_bar (window, Qnil);
4601 ns_clear_frame_area (f, left, top, width, height);
4606 if (NILP (window->vertical_scroll_bar))
4608 if (width > 0 && height > 0)
4609 ns_clear_frame_area (f, left, top, width, height);
4611 bar = [[EmacsScroller alloc] initFrame: r window: win];
4612 wset_vertical_scroll_bar (window, make_save_ptr (bar));
4618 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4619 oldRect = [bar frame];
4620 r.size.width = oldRect.size.width;
4621 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4623 if (oldRect.origin.x != r.origin.x)
4624 ns_clear_frame_area (f, left, top, width, height);
4630 [bar setPosition: position portion: portion whole: whole];
4636 ns_set_horizontal_scroll_bar (struct window *window,
4637 int portion, int whole, int position)
4638 /* --------------------------------------------------------------------------
4639 External (hook): Update or add scrollbar
4640 -------------------------------------------------------------------------- */
4644 struct frame *f = XFRAME (WINDOW_FRAME (window));
4645 EmacsView *view = FRAME_NS_VIEW (f);
4647 int top, height, left, width;
4648 int window_x, window_width;
4649 BOOL update_p = YES;
4651 /* optimization; display engine sends WAY too many of these.. */
4652 if (!NILP (window->horizontal_scroll_bar))
4654 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4655 if ([bar checkSamePosition: position portion: portion whole: whole])
4657 if (view->scrollbarsNeedingUpdate == 0)
4659 if (!windows_or_buffers_changed)
4663 view->scrollbarsNeedingUpdate--;
4668 NSTRACE ("ns_set_horizontal_scroll_bar");
4670 /* Get dimensions. */
4671 window_box (window, ANY_AREA, &window_x, 0, &window_width, 0);
4673 width = window_width;
4674 height = NS_SCROLL_BAR_HEIGHT (f);
4675 top = WINDOW_SCROLL_BAR_AREA_Y (window);
4677 r = NSMakeRect (left, top, width, height);
4678 /* the parent view is flipped, so we need to flip y value */
4680 r.origin.y = (v.size.height - r.size.height - r.origin.y);
4682 XSETWINDOW (win, window);
4685 if (NILP (window->horizontal_scroll_bar))
4687 if (width > 0 && height > 0)
4688 ns_clear_frame_area (f, left, top, width, height);
4690 bar = [[EmacsScroller alloc] initFrame: r window: win];
4691 wset_horizontal_scroll_bar (window, make_save_ptr (bar));
4697 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4698 oldRect = [bar frame];
4699 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4701 if (oldRect.origin.y != r.origin.y)
4702 ns_clear_frame_area (f, left, top, width, height);
4708 /* If there are both horizontal and vertical scroll-bars they leave
4709 a square that belongs to neither. We need to clear it otherwise
4710 it fills with junk. */
4711 if (!NILP (window->vertical_scroll_bar))
4712 ns_clear_frame_area (f, WINDOW_SCROLL_BAR_AREA_X (window), top,
4713 NS_SCROLL_BAR_HEIGHT (f), height);
4716 [bar setPosition: position portion: portion whole: whole];
4722 ns_condemn_scroll_bars (struct frame *f)
4723 /* --------------------------------------------------------------------------
4724 External (hook): arrange for all frame's scrollbars to be removed
4725 at next call to judge_scroll_bars, except for those redeemed.
4726 -------------------------------------------------------------------------- */
4730 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
4732 NSTRACE ("ns_condemn_scroll_bars");
4734 for (i =[subviews count]-1; i >= 0; i--)
4736 view = [subviews objectAtIndex: i];
4737 if ([view isKindOfClass: [EmacsScroller class]])
4744 ns_redeem_scroll_bar (struct window *window)
4745 /* --------------------------------------------------------------------------
4746 External (hook): arrange to spare this window's scrollbar
4747 at next call to judge_scroll_bars.
4748 -------------------------------------------------------------------------- */
4751 NSTRACE ("ns_redeem_scroll_bar");
4752 if (!NILP (window->vertical_scroll_bar)
4753 && WINDOW_HAS_VERTICAL_SCROLL_BAR (window))
4755 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4759 if (!NILP (window->horizontal_scroll_bar)
4760 && WINDOW_HAS_HORIZONTAL_SCROLL_BAR (window))
4762 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4769 ns_judge_scroll_bars (struct frame *f)
4770 /* --------------------------------------------------------------------------
4771 External (hook): destroy all scrollbars on frame that weren't
4772 redeemed after call to condemn_scroll_bars.
4773 -------------------------------------------------------------------------- */
4777 EmacsView *eview = FRAME_NS_VIEW (f);
4778 NSArray *subviews = [[eview superview] subviews];
4781 NSTRACE ("ns_judge_scroll_bars");
4782 for (i = [subviews count]-1; i >= 0; --i)
4784 view = [subviews objectAtIndex: i];
4785 if (![view isKindOfClass: [EmacsScroller class]]) continue;
4791 [eview updateFrameSize: NO];
4794 /* ==========================================================================
4798 ========================================================================== */
4801 x_display_pixel_height (struct ns_display_info *dpyinfo)
4803 NSArray *screens = [NSScreen screens];
4804 NSEnumerator *enumerator = [screens objectEnumerator];
4809 while ((screen = [enumerator nextObject]) != nil)
4810 frame = NSUnionRect (frame, [screen frame]);
4812 return NSHeight (frame);
4816 x_display_pixel_width (struct ns_display_info *dpyinfo)
4818 NSArray *screens = [NSScreen screens];
4819 NSEnumerator *enumerator = [screens objectEnumerator];
4824 while ((screen = [enumerator nextObject]) != nil)
4825 frame = NSUnionRect (frame, [screen frame]);
4827 return NSWidth (frame);
4831 static Lisp_Object ns_string_to_lispmod (const char *s)
4832 /* --------------------------------------------------------------------------
4833 Convert modifier name to lisp symbol
4834 -------------------------------------------------------------------------- */
4836 if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
4838 else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
4840 else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
4842 else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
4844 else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
4846 else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
4854 ns_default (const char *parameter, Lisp_Object *result,
4855 Lisp_Object yesval, Lisp_Object noval,
4856 BOOL is_float, BOOL is_modstring)
4857 /* --------------------------------------------------------------------------
4858 Check a parameter value in user's preferences
4859 -------------------------------------------------------------------------- */
4861 const char *value = ns_get_defaults_value (parameter);
4867 if (c_strcasecmp (value, "YES") == 0)
4869 else if (c_strcasecmp (value, "NO") == 0)
4871 else if (is_float && (f = strtod (value, &pos), pos != value))
4872 *result = make_float (f);
4873 else if (is_modstring && value)
4874 *result = ns_string_to_lispmod (value);
4875 else fprintf (stderr,
4876 "Bad value for default \"%s\": \"%s\"\n", parameter, value);
4882 ns_initialize_display_info (struct ns_display_info *dpyinfo)
4883 /* --------------------------------------------------------------------------
4884 Initialize global info and storage for display.
4885 -------------------------------------------------------------------------- */
4887 NSScreen *screen = [NSScreen mainScreen];
4888 NSWindowDepth depth = [screen depth];
4890 dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
4891 dpyinfo->resy = 72.27;
4892 dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4893 NSColorSpaceFromDepth (depth)]
4894 && ![NSCalibratedWhiteColorSpace isEqualToString:
4895 NSColorSpaceFromDepth (depth)];
4896 dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4897 dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
4898 dpyinfo->color_table->colors = NULL;
4899 dpyinfo->root_window = 42; /* a placeholder.. */
4900 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4901 dpyinfo->n_fonts = 0;
4902 dpyinfo->smallest_font_height = 1;
4903 dpyinfo->smallest_char_width = 1;
4905 reset_mouse_highlight (&dpyinfo->mouse_highlight);
4909 /* This and next define (many of the) public functions in this file. */
4910 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4911 with using despite presence in the "system dependent" redisplay
4912 interface. In addition, many of the ns_ methods have code that is
4913 shared with all terms, indicating need for further refactoring. */
4914 extern frame_parm_handler ns_frame_parm_handlers[];
4915 static struct redisplay_interface ns_redisplay_interface =
4917 ns_frame_parm_handlers,
4921 x_clear_end_of_line,
4923 ns_after_update_window_line,
4924 ns_update_window_begin,
4925 ns_update_window_end,
4926 0, /* flush_display */
4927 x_clear_window_mouse_face,
4928 x_get_glyph_overhangs,
4929 x_fix_overlapping_area,
4930 ns_draw_fringe_bitmap,
4931 0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4932 0, /* destroy_fringe_bitmap */
4933 ns_compute_glyph_string_overhangs,
4934 ns_draw_glyph_string,
4935 ns_define_frame_cursor,
4936 ns_clear_frame_area,
4937 ns_draw_window_cursor,
4938 ns_draw_vertical_window_border,
4939 ns_draw_window_divider,
4940 ns_shift_glyphs_for_insert,
4947 ns_delete_display (struct ns_display_info *dpyinfo)
4953 /* This function is called when the last frame on a display is deleted. */
4955 ns_delete_terminal (struct terminal *terminal)
4957 struct ns_display_info *dpyinfo = terminal->display_info.ns;
4959 NSTRACE ("ns_delete_terminal");
4961 /* Protect against recursive calls. delete_frame in
4962 delete_terminal calls us back when it deletes our last frame. */
4963 if (!terminal->name)
4968 x_destroy_all_bitmaps (dpyinfo);
4969 ns_delete_display (dpyinfo);
4974 static struct terminal *
4975 ns_create_terminal (struct ns_display_info *dpyinfo)
4976 /* --------------------------------------------------------------------------
4977 Set up use of NS before we make the first connection.
4978 -------------------------------------------------------------------------- */
4980 struct terminal *terminal;
4982 NSTRACE ("ns_create_terminal");
4984 terminal = create_terminal (output_ns, &ns_redisplay_interface);
4986 terminal->display_info.ns = dpyinfo;
4987 dpyinfo->terminal = terminal;
4989 terminal->clear_frame_hook = ns_clear_frame;
4990 terminal->ring_bell_hook = ns_ring_bell;
4991 terminal->update_begin_hook = ns_update_begin;
4992 terminal->update_end_hook = ns_update_end;
4993 terminal->read_socket_hook = ns_read_socket;
4994 terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4995 terminal->mouse_position_hook = ns_mouse_position;
4996 terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4997 terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4998 terminal->fullscreen_hook = ns_fullscreen_hook;
4999 terminal->menu_show_hook = ns_menu_show;
5000 terminal->popup_dialog_hook = ns_popup_dialog;
5001 terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
5002 terminal->set_horizontal_scroll_bar_hook = ns_set_horizontal_scroll_bar;
5003 terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
5004 terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
5005 terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
5006 terminal->delete_frame_hook = x_destroy_window;
5007 terminal->delete_terminal_hook = ns_delete_terminal;
5008 /* Other hooks are NULL by default. */
5014 struct ns_display_info *
5015 ns_term_init (Lisp_Object display_name)
5016 /* --------------------------------------------------------------------------
5017 Start the Application and get things rolling.
5018 -------------------------------------------------------------------------- */
5020 struct terminal *terminal;
5021 struct ns_display_info *dpyinfo;
5022 static int ns_initialized = 0;
5025 if (ns_initialized) return x_display_list;
5030 NSTRACE ("ns_term_init");
5032 [outerpool release];
5033 outerpool = [[NSAutoreleasePool alloc] init];
5035 /* count object allocs (About, click icon); on macOS use ObjectAlloc tool */
5036 /*GSDebugAllocationActive (YES); */
5040 Fset_input_interrupt_mode (Qnil);
5042 if (selfds[0] == -1)
5044 if (emacs_pipe (selfds) != 0)
5046 fprintf (stderr, "Failed to create pipe: %s\n",
5047 emacs_strerror (errno));
5051 fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
5052 FD_ZERO (&select_readfds);
5053 FD_ZERO (&select_writefds);
5054 pthread_mutex_init (&select_mutex, NULL);
5057 ns_pending_files = [[NSMutableArray alloc] init];
5058 ns_pending_service_names = [[NSMutableArray alloc] init];
5059 ns_pending_service_args = [[NSMutableArray alloc] init];
5061 /* Start app and create the main menu, window, view.
5062 Needs to be here because ns_initialize_display_info () uses AppKit classes.
5063 The view will then ask the NSApp to stop and return to Emacs. */
5064 [EmacsApp sharedApplication];
5067 [NSApp setDelegate: NSApp];
5069 /* Start the select thread. */
5070 [NSThread detachNewThreadSelector:@selector (fd_handler:)
5074 /* debugging: log all notifications */
5075 /* [[NSNotificationCenter defaultCenter] addObserver: NSApp
5076 selector: @selector (logNotification:)
5077 name: nil object: nil]; */
5079 dpyinfo = xzalloc (sizeof *dpyinfo);
5081 ns_initialize_display_info (dpyinfo);
5082 terminal = ns_create_terminal (dpyinfo);
5084 terminal->kboard = allocate_kboard (Qns);
5085 /* Don't let the initial kboard remain current longer than necessary.
5086 That would cause problems if a file loaded on startup tries to
5087 prompt in the mini-buffer. */
5088 if (current_kboard == initial_kboard)
5089 current_kboard = terminal->kboard;
5090 terminal->kboard->reference_count++;
5092 dpyinfo->next = x_display_list;
5093 x_display_list = dpyinfo;
5095 dpyinfo->name_list_element = Fcons (display_name, Qnil);
5097 terminal->name = xlispstrdup (display_name);
5101 if (!inhibit_x_resources)
5103 ns_default ("GSFontAntiAlias", &ns_antialias_text,
5106 /* this is a standard variable */
5107 ns_default ("AppleAntiAliasingThreshold", &tmp,
5108 make_float (10.0), make_float (6.0), YES, NO);
5109 ns_antialias_threshold = NILP (tmp) ? 10.0 : extract_float (tmp);
5112 NSTRACE_MSG ("Colors");
5115 NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
5119 Lisp_Object color_file, color_map, color;
5123 color_file = Fexpand_file_name (build_string ("rgb.txt"),
5124 Fsymbol_value (intern ("data-directory")));
5126 color_map = Fx_load_color_file (color_file);
5127 if (NILP (color_map))
5128 fatal ("Could not read %s.\n", SDATA (color_file));
5130 cl = [[NSColorList alloc] initWithName: @"Emacs"];
5131 for ( ; CONSP (color_map); color_map = XCDR (color_map))
5133 color = XCAR (color_map);
5134 name = SSDATA (XCAR (color));
5135 c = XINT (XCDR (color));
5137 [NSColor colorForEmacsRed: RED_FROM_ULONG (c) / 255.0
5138 green: GREEN_FROM_ULONG (c) / 255.0
5139 blue: BLUE_FROM_ULONG (c) / 255.0
5141 forKey: [NSString stringWithUTF8String: name]];
5143 [cl writeToFile: nil];
5147 NSTRACE_MSG ("Versions");
5150 #ifdef NS_IMPL_GNUSTEP
5151 Vwindow_system_version = build_string (gnustep_base_version);
5153 /*PSnextrelease (128, c); */
5154 char c[DBL_BUFSIZE_BOUND];
5155 int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
5156 Vwindow_system_version = make_unibyte_string (c, len);
5160 delete_keyboard_wait_descriptor (0);
5162 ns_app_name = [[NSProcessInfo processInfo] processName];
5164 /* Set up macOS app menu */
5166 NSTRACE_MSG ("Menu init");
5168 #ifdef NS_IMPL_COCOA
5172 /* set up the application menu */
5173 svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
5174 [svcsMenu setAutoenablesItems: NO];
5175 appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
5176 [appMenu setAutoenablesItems: NO];
5177 mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
5178 dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
5180 [appMenu insertItemWithTitle: @"About Emacs"
5181 action: @selector (orderFrontStandardAboutPanel:)
5184 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
5185 [appMenu insertItemWithTitle: @"Preferences..."
5186 action: @selector (showPreferencesWindow:)
5189 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
5190 item = [appMenu insertItemWithTitle: @"Services"
5191 action: @selector (menuDown:)
5194 [appMenu setSubmenu: svcsMenu forItem: item];
5195 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
5196 [appMenu insertItemWithTitle: @"Hide Emacs"
5197 action: @selector (hide:)
5200 item = [appMenu insertItemWithTitle: @"Hide Others"
5201 action: @selector (hideOtherApplications:)
5204 [item setKeyEquivalentModifierMask: NSEventModifierFlagCommand | NSEventModifierFlagOption];
5205 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
5206 [appMenu insertItemWithTitle: @"Quit Emacs"
5207 action: @selector (terminate:)
5211 item = [mainMenu insertItemWithTitle: ns_app_name
5212 action: @selector (menuDown:)
5215 [mainMenu setSubmenu: appMenu forItem: item];
5216 [dockMenu insertItemWithTitle: @"New Frame"
5217 action: @selector (newFrame:)
5221 [NSApp setMainMenu: mainMenu];
5222 [NSApp setAppleMenu: appMenu];
5223 [NSApp setServicesMenu: svcsMenu];
5224 /* Needed at least on Cocoa, to get dock menu to show windows */
5225 [NSApp setWindowsMenu: [[NSMenu alloc] init]];
5227 [[NSNotificationCenter defaultCenter]
5228 addObserver: mainMenu
5229 selector: @selector (trackingNotification:)
5230 name: NSMenuDidBeginTrackingNotification object: mainMenu];
5231 [[NSNotificationCenter defaultCenter]
5232 addObserver: mainMenu
5233 selector: @selector (trackingNotification:)
5234 name: NSMenuDidEndTrackingNotification object: mainMenu];
5236 #endif /* macOS menu setup */
5238 /* Register our external input/output types, used for determining
5239 applicable services and also drag/drop eligibility. */
5241 NSTRACE_MSG ("Input/output types");
5243 ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
5244 ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
5246 ns_drag_types = [[NSArray arrayWithObjects:
5248 NSTabularTextPboardType,
5249 NSFilenamesPboardType,
5250 NSURLPboardType, nil] retain];
5252 /* If fullscreen is in init/default-frame-alist, focus isn't set
5253 right for fullscreen windows, so set this. */
5254 [NSApp activateIgnoringOtherApps:YES];
5256 NSTRACE_MSG ("Call NSApp run");
5259 ns_do_open_file = YES;
5261 #ifdef NS_IMPL_GNUSTEP
5262 /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
5263 We must re-catch it so subprocess works. */
5264 catch_child_signal ();
5267 NSTRACE_MSG ("ns_term_init done");
5276 ns_term_shutdown (int sig)
5278 [[NSUserDefaults standardUserDefaults] synchronize];
5280 /* code not reached in emacs.c after this is called by shut_down_emacs: */
5281 if (STRINGP (Vauto_save_list_file_name))
5282 unlink (SSDATA (Vauto_save_list_file_name));
5284 if (sig == 0 || sig == SIGTERM)
5286 [NSApp terminate: NSApp];
5288 else // force a stack trace to happen
5295 /* ==========================================================================
5297 EmacsApp implementation
5299 ========================================================================== */
5302 @implementation EmacsApp
5306 NSTRACE ("[EmacsApp init]");
5308 if ((self = [super init]))
5310 #ifdef NS_IMPL_COCOA
5311 self->isFirst = YES;
5313 #ifdef NS_IMPL_GNUSTEP
5314 self->applicationDidFinishLaunchingCalled = NO;
5321 #ifdef NS_IMPL_COCOA
5324 NSTRACE ("[EmacsApp run]");
5326 #ifndef NSAppKitVersionNumber10_9
5327 #define NSAppKitVersionNumber10_9 1265
5330 if ((int)NSAppKitVersionNumber != NSAppKitVersionNumber10_9)
5336 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5338 if (isFirst) [self finishLaunching];
5341 shouldKeepRunning = YES;
5345 pool = [[NSAutoreleasePool alloc] init];
5348 [self nextEventMatchingMask:NSEventMaskAny
5349 untilDate:[NSDate distantFuture]
5350 inMode:NSDefaultRunLoopMode
5353 [self sendEvent:event];
5354 [self updateWindows];
5355 } while (shouldKeepRunning);
5360 - (void)stop: (id)sender
5362 NSTRACE ("[EmacsApp stop:]");
5364 shouldKeepRunning = NO;
5365 // Stop possible dialog also. Noop if no dialog present.
5366 // The file dialog still leaks 7k - 10k on 10.9 though.
5367 [super stop:sender];
5369 #endif /* NS_IMPL_COCOA */
5371 - (void)logNotification: (NSNotification *)notification
5373 NSTRACE ("[EmacsApp logNotification:]");
5375 const char *name = [[notification name] UTF8String];
5376 if (!strstr (name, "Update") && !strstr (name, "NSMenu")
5377 && !strstr (name, "WindowNumber"))
5378 NSLog (@"notification: '%@'", [notification name]);
5382 - (void)sendEvent: (NSEvent *)theEvent
5383 /* --------------------------------------------------------------------------
5384 Called when NSApp is running for each event received. Used to stop
5385 the loop when we choose, since there's no way to just run one iteration.
5386 -------------------------------------------------------------------------- */
5388 int type = [theEvent type];
5389 NSWindow *window = [theEvent window];
5391 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsApp sendEvent:]");
5392 NSTRACE_MSG ("Type: %d", type);
5394 #ifdef NS_IMPL_GNUSTEP
5395 // Keyboard events aren't propagated to file dialogs for some reason.
5396 if ([NSApp modalWindow] != nil &&
5397 (type == NSEventTypeKeyDown || type == NSEventTypeKeyUp || type == NSEventTypeFlagsChanged))
5399 [[NSApp modalWindow] sendEvent: theEvent];
5404 if (represented_filename != nil && represented_frame)
5406 NSString *fstr = represented_filename;
5407 NSView *view = FRAME_NS_VIEW (represented_frame);
5408 #ifdef NS_IMPL_COCOA
5409 /* work around a bug observed on 10.3 and later where
5410 setTitleWithRepresentedFilename does not clear out previous state
5411 if given filename does not exist */
5412 if (! [[NSFileManager defaultManager] fileExistsAtPath: fstr])
5413 [[view window] setRepresentedFilename: @""];
5415 [[view window] setRepresentedFilename: fstr];
5416 [represented_filename release];
5417 represented_filename = nil;
5418 represented_frame = NULL;
5421 if (type == NSEventTypeApplicationDefined)
5423 switch ([theEvent data2])
5425 #ifdef NS_IMPL_COCOA
5426 case NSAPP_DATA2_RUNASSCRIPT:
5431 case NSAPP_DATA2_RUNFILEDIALOG:
5432 ns_run_file_dialog ();
5438 if (type == NSEventTypeCursorUpdate && window == nil)
5440 fprintf (stderr, "Dropping external cursor update event.\n");
5444 if (type == NSEventTypeApplicationDefined)
5446 /* Events posted by ns_send_appdefined interrupt the run loop here.
5447 But, if a modal window is up, an appdefined can still come through,
5448 (e.g., from a makeKeyWindow event) but stopping self also stops the
5449 modal loop. Just defer it until later. */
5450 if ([NSApp modalWindow] == nil)
5452 last_appdefined_event_data = [theEvent data1];
5457 send_appdefined = YES;
5462 #ifdef NS_IMPL_COCOA
5463 /* If no dialog and none of our frames have focus and it is a move, skip it.
5464 It is a mouse move in an auxiliary menu, i.e. on the top right on macOS,
5465 such as Wifi, sound, date or similar.
5466 This prevents "spooky" highlighting in the frame under the menu. */
5467 if (type == NSEventTypeMouseMoved && [NSApp modalWindow] == nil)
5469 struct ns_display_info *di;
5470 BOOL has_focus = NO;
5471 for (di = x_display_list; ! has_focus && di; di = di->next)
5472 has_focus = di->x_focus_frame != 0;
5478 NSTRACE_UNSILENCE();
5480 [super sendEvent: theEvent];
5484 - (void)showPreferencesWindow: (id)sender
5486 struct frame *emacsframe = SELECTED_FRAME ();
5487 NSEvent *theEvent = [NSApp currentEvent];
5491 emacs_event->kind = NS_NONKEY_EVENT;
5492 emacs_event->code = KEY_NS_SHOW_PREFS;
5493 emacs_event->modifiers = 0;
5494 EV_TRAILER (theEvent);
5498 - (void)newFrame: (id)sender
5500 NSTRACE ("[EmacsApp newFrame:]");
5502 struct frame *emacsframe = SELECTED_FRAME ();
5503 NSEvent *theEvent = [NSApp currentEvent];
5507 emacs_event->kind = NS_NONKEY_EVENT;
5508 emacs_event->code = KEY_NS_NEW_FRAME;
5509 emacs_event->modifiers = 0;
5510 EV_TRAILER (theEvent);
5514 /* Open a file (used by below, after going into queue read by ns_read_socket) */
5515 - (BOOL) openFile: (NSString *)fileName
5517 NSTRACE ("[EmacsApp openFile:]");
5519 struct frame *emacsframe = SELECTED_FRAME ();
5520 NSEvent *theEvent = [NSApp currentEvent];
5525 emacs_event->kind = NS_NONKEY_EVENT;
5526 emacs_event->code = KEY_NS_OPEN_FILE_LINE;
5527 ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
5528 ns_input_line = Qnil; /* can be start or cons start,end */
5529 emacs_event->modifiers =0;
5530 EV_TRAILER (theEvent);
5536 /* **************************************************************************
5538 EmacsApp delegate implementation
5540 ************************************************************************** */
5542 - (void)applicationDidFinishLaunching: (NSNotification *)notification
5543 /* --------------------------------------------------------------------------
5544 When application is loaded, terminate event loop in ns_term_init
5545 -------------------------------------------------------------------------- */
5547 NSTRACE ("[EmacsApp applicationDidFinishLaunching:]");
5549 #ifdef NS_IMPL_GNUSTEP
5550 ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
5552 [NSApp setServicesProvider: NSApp];
5554 [self antialiasThresholdDidChange:nil];
5555 #ifdef NS_IMPL_COCOA
5556 [[NSNotificationCenter defaultCenter]
5558 selector:@selector(antialiasThresholdDidChange:)
5559 name:NSAntialiasThresholdChangedNotification
5563 #ifdef NS_IMPL_COCOA
5564 if ([NSApp activationPolicy] == NSApplicationActivationPolicyProhibited) {
5565 /* Set the app's activation policy to regular when we run outside
5566 of a bundle. This is already done for us by Info.plist when we
5567 run inside a bundle. */
5568 [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
5569 [NSApp setApplicationIconImage:
5572 build_string("icons/hicolor/128x128/apps/emacs.png")]];
5576 ns_send_appdefined (-2);
5579 - (void)antialiasThresholdDidChange:(NSNotification *)notification
5581 #ifdef NS_IMPL_COCOA
5582 macfont_update_antialias_threshold ();
5587 /* Termination sequences:
5590 MenuBar | File | Exit:
5591 Select Quit from App menubar:
5593 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5596 Select Quit from Dock menu:
5599 Cancel -> Nothing else
5603 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5608 - (void) terminate: (id)sender
5610 NSTRACE ("[EmacsApp terminate:]");
5612 struct frame *emacsframe = SELECTED_FRAME ();
5617 emacs_event->kind = NS_NONKEY_EVENT;
5618 emacs_event->code = KEY_NS_POWER_OFF;
5619 emacs_event->arg = Qt; /* mark as non-key event */
5620 EV_TRAILER ((id)nil);
5624 runAlertPanel(NSString *title,
5625 NSString *msgFormat,
5626 NSString *defaultButton,
5627 NSString *alternateButton)
5629 #ifdef NS_IMPL_GNUSTEP
5630 return NSRunAlertPanel(title, msgFormat, defaultButton, alternateButton, nil)
5631 == NSAlertDefaultReturn;
5633 NSAlert *alert = [[NSAlert alloc] init];
5634 [alert setAlertStyle: NSAlertStyleCritical];
5635 [alert setMessageText: msgFormat];
5636 [alert addButtonWithTitle: defaultButton];
5637 [alert addButtonWithTitle: alternateButton];
5638 NSInteger ret = [alert runModal];
5640 return ret == NSAlertFirstButtonReturn;
5645 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
5647 NSTRACE ("[EmacsApp applicationShouldTerminate:]");
5651 if (NILP (ns_confirm_quit)) // || ns_shutdown_properly --> TO DO
5652 return NSTerminateNow;
5654 ret = runAlertPanel(ns_app_name,
5655 @"Exit requested. Would you like to Save Buffers and Exit, or Cancel the request?",
5656 @"Save Buffers and Exit", @"Cancel");
5658 return ret ? NSTerminateNow : NSTerminateCancel;
5662 not_in_argv (NSString *arg)
5665 const char *a = [arg UTF8String];
5666 for (k = 1; k < initial_argc; ++k)
5667 if (strcmp (a, initial_argv[k]) == 0) return 0;
5671 /* Notification from the Workspace to open a file */
5672 - (BOOL)application: sender openFile: (NSString *)file
5674 if (ns_do_open_file || not_in_argv (file))
5675 [ns_pending_files addObject: file];
5680 /* Open a file as a temporary file */
5681 - (BOOL)application: sender openTempFile: (NSString *)file
5683 if (ns_do_open_file || not_in_argv (file))
5684 [ns_pending_files addObject: file];
5689 /* Notification from the Workspace to open a file noninteractively (?) */
5690 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
5692 if (ns_do_open_file || not_in_argv (file))
5693 [ns_pending_files addObject: file];
5697 /* Notification from the Workspace to open multiple files */
5698 - (void)application: sender openFiles: (NSArray *)fileList
5700 NSEnumerator *files = [fileList objectEnumerator];
5702 /* Don't open files from the command line unconditionally,
5703 Cocoa parses the command line wrong, --option value tries to open value
5704 if --option is the last option. */
5705 while ((file = [files nextObject]) != nil)
5706 if (ns_do_open_file || not_in_argv (file))
5707 [ns_pending_files addObject: file];
5709 [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
5714 /* Handle dock menu requests. */
5715 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
5721 /* TODO: these may help w/IO switching btwn terminal and NSApp */
5722 - (void)applicationWillBecomeActive: (NSNotification *)notification
5724 NSTRACE ("[EmacsApp applicationWillBecomeActive:]");
5725 //ns_app_active=YES;
5728 - (void)applicationDidBecomeActive: (NSNotification *)notification
5730 NSTRACE ("[EmacsApp applicationDidBecomeActive:]");
5732 #ifdef NS_IMPL_GNUSTEP
5733 if (! applicationDidFinishLaunchingCalled)
5734 [self applicationDidFinishLaunching:notification];
5736 //ns_app_active=YES;
5738 ns_update_auto_hide_menu_bar ();
5739 // No constraining takes place when the application is not active.
5740 ns_constrain_all_frames ();
5742 - (void)applicationDidResignActive: (NSNotification *)notification
5744 NSTRACE ("[EmacsApp applicationDidResignActive:]");
5747 ns_send_appdefined (-1);
5752 /* ==========================================================================
5754 EmacsApp aux handlers for managing event loop
5756 ========================================================================== */
5759 - (void)timeout_handler: (NSTimer *)timedEntry
5760 /* --------------------------------------------------------------------------
5761 The timeout specified to ns_select has passed.
5762 -------------------------------------------------------------------------- */
5764 /*NSTRACE ("timeout_handler"); */
5765 ns_send_appdefined (-2);
5768 - (void)sendFromMainThread:(id)unused
5770 ns_send_appdefined (nextappdefined);
5773 - (void)fd_handler:(id)unused
5774 /* --------------------------------------------------------------------------
5775 Check data waiting on file descriptors and terminate if so
5776 -------------------------------------------------------------------------- */
5779 int waiting = 1, nfds;
5782 fd_set readfds, writefds, *wfds;
5783 struct timespec timeout, *tmo;
5784 NSAutoreleasePool *pool = nil;
5786 /* NSTRACE ("fd_handler"); */
5791 pool = [[NSAutoreleasePool alloc] init];
5797 FD_SET (selfds[0], &fds);
5798 result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
5799 if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
5804 pthread_mutex_lock (&select_mutex);
5807 if (select_valid & SELECT_HAVE_READ)
5808 readfds = select_readfds;
5812 if (select_valid & SELECT_HAVE_WRITE)
5814 writefds = select_writefds;
5819 if (select_valid & SELECT_HAVE_TMO)
5821 timeout = select_timeout;
5827 pthread_mutex_unlock (&select_mutex);
5829 FD_SET (selfds[0], &readfds);
5830 if (selfds[0] >= nfds) nfds = selfds[0]+1;
5832 result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
5835 ns_send_appdefined (-2);
5836 else if (result > 0)
5838 if (FD_ISSET (selfds[0], &readfds))
5840 if (read (selfds[0], &c, 1) == 1 && c == 's')
5845 pthread_mutex_lock (&select_mutex);
5846 if (select_valid & SELECT_HAVE_READ)
5847 select_readfds = readfds;
5848 if (select_valid & SELECT_HAVE_WRITE)
5849 select_writefds = writefds;
5850 if (select_valid & SELECT_HAVE_TMO)
5851 select_timeout = timeout;
5852 pthread_mutex_unlock (&select_mutex);
5854 ns_send_appdefined (result);
5864 /* ==========================================================================
5868 ========================================================================== */
5870 /* called from system: queue for next pass through event loop */
5871 - (void)requestService: (NSPasteboard *)pboard
5872 userData: (NSString *)userData
5873 error: (NSString **)error
5875 [ns_pending_service_names addObject: userData];
5876 [ns_pending_service_args addObject: [NSString stringWithUTF8String:
5877 SSDATA (ns_string_from_pasteboard (pboard))]];
5881 /* called from ns_read_socket to clear queue */
5882 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
5884 struct frame *emacsframe = SELECTED_FRAME ();
5885 NSEvent *theEvent = [NSApp currentEvent];
5887 NSTRACE ("[EmacsApp fulfillService:withArg:]");
5892 emacs_event->kind = NS_NONKEY_EVENT;
5893 emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
5894 ns_input_spi_name = build_string ([name UTF8String]);
5895 ns_input_spi_arg = build_string ([arg UTF8String]);
5896 emacs_event->modifiers = EV_MODIFIERS (theEvent);
5897 EV_TRAILER (theEvent);
5907 /* ==========================================================================
5909 EmacsView implementation
5911 ========================================================================== */
5914 @implementation EmacsView
5916 /* needed to inform when window closed from LISP */
5917 - (void) setWindowClosing: (BOOL)closing
5919 NSTRACE ("[EmacsView setWindowClosing:%d]", closing);
5921 windowClosing = closing;
5927 NSTRACE ("[EmacsView dealloc]");
5929 if (fs_state == FULLSCREEN_BOTH)
5930 [nonfs_window release];
5935 /* called on font panel selection */
5936 - (void)changeFont: (id)sender
5938 NSEvent *e = [[self window] currentEvent];
5939 struct face *face = FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID);
5940 struct font *font = face->font;
5945 NSTRACE ("[EmacsView changeFont:]");
5950 #ifdef NS_IMPL_GNUSTEP
5951 nsfont = ((struct nsfont_info *)font)->nsfont;
5953 #ifdef NS_IMPL_COCOA
5954 nsfont = (NSFont *) macfont_get_nsctfont (font);
5957 if ((newFont = [sender convertFont: nsfont]))
5959 SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
5961 emacs_event->kind = NS_NONKEY_EVENT;
5962 emacs_event->modifiers = 0;
5963 emacs_event->code = KEY_NS_CHANGE_FONT;
5965 size = [newFont pointSize];
5966 ns_input_fontsize = make_number (lrint (size));
5967 ns_input_font = build_string ([[newFont familyName] UTF8String]);
5973 - (BOOL)acceptsFirstResponder
5975 NSTRACE ("[EmacsView acceptsFirstResponder]");
5980 - (void)resetCursorRects
5982 NSRect visible = [self visibleRect];
5983 NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
5984 NSTRACE ("[EmacsView resetCursorRects]");
5986 if (currentCursor == nil)
5987 currentCursor = [NSCursor arrowCursor];
5989 if (!NSIsEmptyRect (visible))
5990 [self addCursorRect: visible cursor: currentCursor];
5991 [currentCursor setOnMouseEntered: YES];
5996 /*****************************************************************************/
5997 /* Keyboard handling. */
6000 - (void)keyDown: (NSEvent *)theEvent
6002 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
6004 unsigned fnKeysym = 0;
6005 static NSMutableArray *nsEvArray;
6007 unsigned int flags = [theEvent modifierFlags];
6009 NSTRACE ("[EmacsView keyDown:]");
6011 /* Rhapsody and macOS give up and down events for the arrow keys */
6012 if (ns_fake_keydown == YES)
6013 ns_fake_keydown = NO;
6014 else if ([theEvent type] != NSEventTypeKeyDown)
6020 if (![[self window] isKeyWindow]
6021 && [[theEvent window] isKindOfClass: [EmacsWindow class]]
6022 /* we must avoid an infinite loop here. */
6023 && (EmacsView *)[[theEvent window] delegate] != self)
6025 /* XXX: There is an occasional condition in which, when Emacs display
6026 updates a different frame from the current one, and temporarily
6027 selects it, then processes some interrupt-driven input
6028 (dispnew.c:3878), OS will send the event to the correct NSWindow, but
6029 for some reason that window has its first responder set to the NSView
6030 most recently updated (I guess), which is not the correct one. */
6031 [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
6035 if (nsEvArray == nil)
6036 nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
6038 [NSCursor setHiddenUntilMouseMoves: YES];
6040 if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
6042 clear_mouse_face (hlinfo);
6043 hlinfo->mouse_face_hidden = 1;
6046 if (!processingCompose)
6048 /* When using screen sharing, no left or right information is sent,
6049 so use Left key in those cases. */
6050 int is_left_key, is_right_key;
6052 code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
6053 0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
6055 /* (Carbon way: [theEvent keyCode]) */
6057 /* is it a "function key"? */
6058 /* Note: Sometimes a plain key will have the NSEventModifierFlagNumericPad
6059 flag set (this is probably a bug in the OS).
6061 if (code < 0x00ff && (flags&NSEventModifierFlagNumericPad))
6063 fnKeysym = ns_convert_key ([theEvent keyCode] | NSEventModifierFlagNumericPad);
6067 fnKeysym = ns_convert_key (code);
6072 /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
6073 because Emacs treats Delete and KP-Delete same (in simple.el). */
6074 if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
6075 #ifdef NS_IMPL_GNUSTEP
6076 /* GNUstep uses incompatible keycodes, even for those that are
6077 supposed to be hardware independent. Just check for delete.
6078 Keypad delete does not have keysym 0xFFFF.
6079 See http://savannah.gnu.org/bugs/?25395
6081 || (fnKeysym == 0xFFFF && code == 127)
6084 code = 0xFF08; /* backspace */
6089 /* are there modifiers? */
6090 emacs_event->modifiers = 0;
6092 if (flags & NSEventModifierFlagHelp)
6093 emacs_event->modifiers |= hyper_modifier;
6095 if (flags & NSEventModifierFlagShift)
6096 emacs_event->modifiers |= shift_modifier;
6098 is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
6099 is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
6100 || (! is_right_key && (flags & NSEventModifierFlagCommand) == NSEventModifierFlagCommand);
6103 emacs_event->modifiers |= parse_solitary_modifier
6104 (EQ (ns_right_command_modifier, Qleft)
6105 ? ns_command_modifier
6106 : ns_right_command_modifier);
6110 emacs_event->modifiers |= parse_solitary_modifier
6111 (ns_command_modifier);
6113 /* if super (default), take input manager's word so things like
6114 dvorak / qwerty layout work */
6115 if (EQ (ns_command_modifier, Qsuper)
6117 && [[theEvent characters] length] != 0)
6119 /* XXX: the code we get will be unshifted, so if we have
6120 a shift modifier, must convert ourselves */
6121 if (!(flags & NSEventModifierFlagShift))
6122 code = [[theEvent characters] characterAtIndex: 0];
6124 /* this is ugly and also requires linking w/Carbon framework
6125 (for LMGetKbdType) so for now leave this rare (?) case
6126 undealt with.. in future look into CGEvent methods */
6129 long smv = GetScriptManagerVariable (smKeyScript);
6130 Handle uchrHandle = GetResource
6131 ('uchr', GetScriptVariable (smv, smScriptKeys));
6133 UCKeyTranslate ((UCKeyboardLayout *) *uchrHandle,
6134 [[theEvent characters] characterAtIndex: 0],
6135 kUCKeyActionDisplay,
6136 (flags & ~NSEventModifierFlagCommand) >> 8,
6137 LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
6138 &dummy, 1, &dummy, &code);
6145 is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
6146 is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
6147 || (! is_right_key && (flags & NSEventModifierFlagControl) == NSEventModifierFlagControl);
6150 emacs_event->modifiers |= parse_solitary_modifier
6151 (EQ (ns_right_control_modifier, Qleft)
6152 ? ns_control_modifier
6153 : ns_right_control_modifier);
6156 emacs_event->modifiers |= parse_solitary_modifier
6157 (ns_control_modifier);
6159 if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
6160 emacs_event->modifiers |=
6161 parse_solitary_modifier (ns_function_modifier);
6163 left_is_none = NILP (ns_alternate_modifier)
6164 || EQ (ns_alternate_modifier, Qnone);
6166 is_right_key = (flags & NSRightAlternateKeyMask)
6167 == NSRightAlternateKeyMask;
6168 is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
6170 && (flags & NSEventModifierFlagOption) == NSEventModifierFlagOption);
6174 if ((NILP (ns_right_alternate_modifier)
6175 || EQ (ns_right_alternate_modifier, Qnone)
6176 || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
6178 { /* accept pre-interp alt comb */
6179 if ([[theEvent characters] length] > 0)
6180 code = [[theEvent characters] characterAtIndex: 0];
6181 /*HACK: clear lone shift modifier to stop next if from firing */
6182 if (emacs_event->modifiers == shift_modifier)
6183 emacs_event->modifiers = 0;
6186 emacs_event->modifiers |= parse_solitary_modifier
6187 (EQ (ns_right_alternate_modifier, Qleft)
6188 ? ns_alternate_modifier
6189 : ns_right_alternate_modifier);
6192 if (is_left_key) /* default = meta */
6194 if (left_is_none && !fnKeysym)
6195 { /* accept pre-interp alt comb */
6196 if ([[theEvent characters] length] > 0)
6197 code = [[theEvent characters] characterAtIndex: 0];
6198 /*HACK: clear lone shift modifier to stop next if from firing */
6199 if (emacs_event->modifiers == shift_modifier)
6200 emacs_event->modifiers = 0;
6203 emacs_event->modifiers |=
6204 parse_solitary_modifier (ns_alternate_modifier);
6208 fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
6209 (unsigned) code, fnKeysym, flags, emacs_event->modifiers);
6211 /* if it was a function key or had modifiers, pass it directly to emacs */
6212 if (fnKeysym || (emacs_event->modifiers
6213 && (emacs_event->modifiers != shift_modifier)
6214 && [[theEvent charactersIgnoringModifiers] length] > 0))
6215 /*[[theEvent characters] length] */
6217 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6219 code |= (1<<28)|(3<<16);
6220 else if (code == 0x7f)
6221 code |= (1<<28)|(3<<16);
6223 emacs_event->kind = code > 0xFF
6224 ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6226 emacs_event->code = code;
6227 EV_TRAILER (theEvent);
6228 processingCompose = NO;
6234 if (NS_KEYLOG && !processingCompose)
6235 fprintf (stderr, "keyDown: Begin compose sequence.\n");
6237 processingCompose = YES;
6238 [nsEvArray addObject: theEvent];
6239 [self interpretKeyEvents: nsEvArray];
6240 [nsEvArray removeObject: theEvent];
6244 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
6247 /* <NSTextInput>: called when done composing;
6248 NOTE: also called when we delete over working text, followed immed.
6249 by doCommandBySelector: deleteBackward: */
6250 - (void)insertText: (id)aString
6253 int len = [(NSString *)aString length];
6256 NSTRACE ("[EmacsView insertText:]");
6259 NSLog (@"insertText '%@'\tlen = %d", aString, len);
6260 processingCompose = NO;
6265 /* first, clear any working text */
6266 if (workingText != nil)
6267 [self deleteWorkingText];
6269 /* now insert the string as keystrokes */
6270 for (i =0; i<len; i++)
6272 code = [aString characterAtIndex: i];
6273 /* TODO: still need this? */
6275 code = '~'; /* 0x7E */
6276 if (code != 32) /* Space */
6277 emacs_event->modifiers = 0;
6279 = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6280 emacs_event->code = code;
6281 EV_TRAILER ((id)nil);
6286 /* <NSTextInput>: inserts display of composing characters */
6287 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
6289 NSString *str = [aString respondsToSelector: @selector (string)] ?
6290 [aString string] : aString;
6292 NSTRACE ("[EmacsView setMarkedText:selectedRange:]");
6295 NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
6296 str, (unsigned long)[str length],
6297 (unsigned long)selRange.length,
6298 (unsigned long)selRange.location);
6300 if (workingText != nil)
6301 [self deleteWorkingText];
6302 if ([str length] == 0)
6308 processingCompose = YES;
6309 workingText = [str copy];
6310 ns_working_text = build_string ([workingText UTF8String]);
6312 emacs_event->kind = NS_TEXT_EVENT;
6313 emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
6314 EV_TRAILER ((id)nil);
6318 /* delete display of composing characters [not in <NSTextInput>] */
6319 - (void)deleteWorkingText
6321 NSTRACE ("[EmacsView deleteWorkingText]");
6323 if (workingText == nil)
6326 NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
6327 [workingText release];
6329 processingCompose = NO;
6334 emacs_event->kind = NS_TEXT_EVENT;
6335 emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
6336 EV_TRAILER ((id)nil);
6340 - (BOOL)hasMarkedText
6342 NSTRACE ("[EmacsView hasMarkedText]");
6344 return workingText != nil;
6348 - (NSRange)markedRange
6350 NSTRACE ("[EmacsView markedRange]");
6352 NSRange rng = workingText != nil
6353 ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
6355 NSLog (@"markedRange request");
6362 NSTRACE ("[EmacsView unmarkText]");
6365 NSLog (@"unmark (accept) text");
6366 [self deleteWorkingText];
6367 processingCompose = NO;
6371 /* used to position char selection windows, etc. */
6372 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
6376 struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
6378 NSTRACE ("[EmacsView firstRectForCharacterRange:]");
6381 NSLog (@"firstRectForCharRange request");
6383 rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
6384 rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
6385 pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
6386 pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
6387 +FRAME_LINE_HEIGHT (emacsframe));
6389 pt = [self convertPoint: pt toView: nil];
6391 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
6392 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6393 if ([[self window] respondsToSelector: @selector(convertRectToScreen:)])
6397 rect = [(EmacsWindow *) [self window] convertRectToScreen: rect];
6398 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6402 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
6403 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 \
6404 || defined (NS_IMPL_GNUSTEP)
6406 pt = [[self window] convertBaseToScreen: pt];
6415 - (NSInteger)conversationIdentifier
6417 return (NSInteger)self;
6421 - (void)doCommandBySelector: (SEL)aSelector
6423 NSTRACE ("[EmacsView doCommandBySelector:]");
6426 NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
6428 processingCompose = NO;
6429 if (aSelector == @selector (deleteBackward:))
6431 /* happens when user backspaces over an ongoing composition:
6432 throw a 'delete' into the event queue */
6435 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6436 emacs_event->code = 0xFF08;
6437 EV_TRAILER ((id)nil);
6441 - (NSArray *)validAttributesForMarkedText
6443 static NSArray *arr = nil;
6444 if (arr == nil) arr = [NSArray new];
6445 /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
6449 - (NSRange)selectedRange
6452 NSLog (@"selectedRange request");
6453 return NSMakeRange (NSNotFound, 0);
6456 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
6457 GNUSTEP_GUI_MINOR_VERSION > 22
6458 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
6460 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
6464 NSLog (@"characterIndexForPoint request");
6468 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
6470 static NSAttributedString *str = nil;
6471 if (str == nil) str = [NSAttributedString new];
6473 NSLog (@"attributedSubstringFromRange request");
6477 /* End <NSTextInput> impl. */
6478 /*****************************************************************************/
6481 /* This is what happens when the user presses a mouse button. */
6482 - (void)mouseDown: (NSEvent *)theEvent
6484 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6485 NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
6487 NSTRACE ("[EmacsView mouseDown:]");
6489 [self deleteWorkingText];
6494 dpyinfo->last_mouse_frame = emacsframe;
6495 /* appears to be needed to prevent spurious movement events generated on
6497 emacsframe->mouse_moved = 0;
6499 if ([theEvent type] == NSEventTypeScrollWheel)
6501 CGFloat delta = [theEvent deltaY];
6502 /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
6505 delta = [theEvent deltaX];
6508 NSTRACE_MSG ("deltaIsZero");
6511 emacs_event->kind = HORIZ_WHEEL_EVENT;
6514 emacs_event->kind = WHEEL_EVENT;
6516 emacs_event->code = 0;
6517 emacs_event->modifiers = EV_MODIFIERS (theEvent) |
6518 ((delta > 0) ? up_modifier : down_modifier);
6522 emacs_event->kind = MOUSE_CLICK_EVENT;
6523 emacs_event->code = EV_BUTTON (theEvent);
6524 emacs_event->modifiers = EV_MODIFIERS (theEvent)
6525 | EV_UDMODIFIERS (theEvent);
6527 XSETINT (emacs_event->x, lrint (p.x));
6528 XSETINT (emacs_event->y, lrint (p.y));
6529 EV_TRAILER (theEvent);
6533 - (void)rightMouseDown: (NSEvent *)theEvent
6535 NSTRACE ("[EmacsView rightMouseDown:]");
6536 [self mouseDown: theEvent];
6540 - (void)otherMouseDown: (NSEvent *)theEvent
6542 NSTRACE ("[EmacsView otherMouseDown:]");
6543 [self mouseDown: theEvent];
6547 - (void)mouseUp: (NSEvent *)theEvent
6549 NSTRACE ("[EmacsView mouseUp:]");
6550 [self mouseDown: theEvent];
6554 - (void)rightMouseUp: (NSEvent *)theEvent
6556 NSTRACE ("[EmacsView rightMouseUp:]");
6557 [self mouseDown: theEvent];
6561 - (void)otherMouseUp: (NSEvent *)theEvent
6563 NSTRACE ("[EmacsView otherMouseUp:]");
6564 [self mouseDown: theEvent];
6568 - (void) scrollWheel: (NSEvent *)theEvent
6570 NSTRACE ("[EmacsView scrollWheel:]");
6571 [self mouseDown: theEvent];
6575 /* Tell emacs the mouse has moved. */
6576 - (void)mouseMoved: (NSEvent *)e
6578 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
6579 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6583 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsView mouseMoved:]");
6585 dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
6586 pt = [self convertPoint: [e locationInWindow] fromView: nil];
6587 dpyinfo->last_mouse_motion_x = pt.x;
6588 dpyinfo->last_mouse_motion_y = pt.y;
6590 /* update any mouse face */
6591 if (hlinfo->mouse_face_hidden)
6593 hlinfo->mouse_face_hidden = 0;
6594 clear_mouse_face (hlinfo);
6597 /* tooltip handling */
6598 previous_help_echo_string = help_echo_string;
6599 help_echo_string = Qnil;
6601 if (!NILP (Vmouse_autoselect_window))
6603 NSTRACE_MSG ("mouse_autoselect_window");
6604 static Lisp_Object last_mouse_window;
6606 = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
6608 if (WINDOWP (window)
6609 && !EQ (window, last_mouse_window)
6610 && !EQ (window, selected_window)
6611 && (!NILP (focus_follows_mouse)
6612 || (EQ (XWINDOW (window)->frame,
6613 XWINDOW (selected_window)->frame))))
6615 NSTRACE_MSG ("in_window");
6616 emacs_event->kind = SELECT_WINDOW_EVENT;
6617 emacs_event->frame_or_window = window;
6620 /* Remember the last window where we saw the mouse. */
6621 last_mouse_window = window;
6624 if (!note_mouse_movement (emacsframe, pt.x, pt.y))
6625 help_echo_string = previous_help_echo_string;
6627 XSETFRAME (frame, emacsframe);
6628 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
6630 /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
6631 (note_mouse_highlight), which is called through the
6632 note_mouse_movement () call above */
6633 any_help_event_p = YES;
6634 gen_help_event (help_echo_string, frame, help_echo_window,
6635 help_echo_object, help_echo_pos);
6638 if (emacsframe->mouse_moved && send_appdefined)
6639 ns_send_appdefined (-1);
6643 - (void)mouseDragged: (NSEvent *)e
6645 NSTRACE ("[EmacsView mouseDragged:]");
6646 [self mouseMoved: e];
6650 - (void)rightMouseDragged: (NSEvent *)e
6652 NSTRACE ("[EmacsView rightMouseDragged:]");
6653 [self mouseMoved: e];
6657 - (void)otherMouseDragged: (NSEvent *)e
6659 NSTRACE ("[EmacsView otherMouseDragged:]");
6660 [self mouseMoved: e];
6664 - (BOOL)windowShouldClose: (id)sender
6666 NSEvent *e =[[self window] currentEvent];
6668 NSTRACE ("[EmacsView windowShouldClose:]");
6669 windowClosing = YES;
6672 emacs_event->kind = DELETE_WINDOW_EVENT;
6673 emacs_event->modifiers = 0;
6674 emacs_event->code = 0;
6676 /* Don't close this window, let this be done from lisp code. */
6680 - (void) updateFrameSize: (BOOL) delay
6682 NSWindow *window = [self window];
6683 NSRect wr = [window frame];
6685 int oldc = cols, oldr = rows;
6686 int oldw = FRAME_PIXEL_WIDTH (emacsframe);
6687 int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
6690 NSTRACE ("[EmacsView updateFrameSize:]");
6691 NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
6692 NSTRACE_RECT ("Original frame", wr);
6693 NSTRACE_MSG ("Original columns: %d", cols);
6694 NSTRACE_MSG ("Original rows: %d", rows);
6696 if (! [self isFullscreen])
6698 #ifdef NS_IMPL_GNUSTEP
6699 // GNUstep does not always update the tool bar height. Force it.
6700 if (toolbar && [toolbar isVisible])
6701 update_frame_tool_bar (emacsframe);
6704 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6705 + FRAME_TOOLBAR_HEIGHT (emacsframe);
6708 if (wait_for_tool_bar)
6710 /* The toolbar height is always 0 in fullscreen, so don't wait
6711 for it to become available. */
6712 if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0
6713 && ! [self isFullscreen])
6715 NSTRACE_MSG ("Waiting for toolbar");
6718 wait_for_tool_bar = NO;
6721 neww = (int)wr.size.width - emacsframe->border_width;
6722 newh = (int)wr.size.height - extra;
6724 NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
6725 NSTRACE_MSG ("FRAME_TOOLBAR_HEIGHT: %d", FRAME_TOOLBAR_HEIGHT (emacsframe));
6726 NSTRACE_MSG ("FRAME_NS_TITLEBAR_HEIGHT: %d", FRAME_NS_TITLEBAR_HEIGHT (emacsframe));
6728 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
6729 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
6731 if (cols < MINWIDTH)
6734 if (rows < MINHEIGHT)
6737 NSTRACE_MSG ("New columns: %d", cols);
6738 NSTRACE_MSG ("New rows: %d", rows);
6740 if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
6742 NSView *view = FRAME_NS_VIEW (emacsframe);
6744 change_frame_size (emacsframe,
6745 FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
6746 FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
6748 SET_FRAME_GARBAGED (emacsframe);
6749 cancel_mouse_face (emacsframe);
6751 /* The next two lines appear to be setting the frame to the same
6752 size as it already is. Why are they there? */
6753 // wr = NSMakeRect (0, 0, neww, newh);
6755 // [view setFrame: wr];
6757 // to do: consider using [NSNotificationCenter postNotificationName:].
6758 [self windowDidMove: // Update top/left.
6759 [NSNotification notificationWithName:NSWindowDidMoveNotification
6760 object:[view window]]];
6764 NSTRACE_MSG ("No change");
6768 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
6769 /* normalize frame to gridded text size */
6773 NSTRACE ("[EmacsView windowWillResize:toSize: " NSTRACE_FMT_SIZE "]",
6774 NSTRACE_ARG_SIZE (frameSize));
6775 NSTRACE_RECT ("[sender frame]", [sender frame]);
6776 NSTRACE_FSTYPE ("fs_state", fs_state);
6778 if (fs_state == FULLSCREEN_MAXIMIZED
6779 && (maximized_width != (int)frameSize.width
6780 || maximized_height != (int)frameSize.height))
6781 [self setFSValue: FULLSCREEN_NONE];
6782 else if (fs_state == FULLSCREEN_WIDTH
6783 && maximized_width != (int)frameSize.width)
6784 [self setFSValue: FULLSCREEN_NONE];
6785 else if (fs_state == FULLSCREEN_HEIGHT
6786 && maximized_height != (int)frameSize.height)
6787 [self setFSValue: FULLSCREEN_NONE];
6789 if (fs_state == FULLSCREEN_NONE)
6790 maximized_width = maximized_height = -1;
6792 if (! [self isFullscreen])
6794 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6795 + FRAME_TOOLBAR_HEIGHT (emacsframe);
6798 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
6799 if (cols < MINWIDTH)
6802 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
6803 frameSize.height - extra);
6804 if (rows < MINHEIGHT)
6806 #ifdef NS_IMPL_COCOA
6808 /* this sets window title to have size in it; the wm does this under GS */
6809 NSRect r = [[self window] frame];
6810 if (r.size.height == frameSize.height && r.size.width == frameSize.width)
6818 else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize
6819 && [[self window] title] != NULL)
6822 NSWindow *window = [self window];
6825 char *t = strdup ([[[self window] title] UTF8String]);
6826 char *pos = strstr (t, " — ");
6831 size_title = xmalloc (strlen (old_title) + 40);
6832 esprintf (size_title, "%s — (%d x %d)", old_title, cols, rows);
6833 [window setTitle: [NSString stringWithUTF8String: size_title]];
6838 #endif /* NS_IMPL_COCOA */
6840 NSTRACE_MSG ("cols: %d rows: %d", cols, rows);
6842 /* Restrict the new size to the text gird.
6844 Don't restrict the width if the user only adjusted the height, and
6845 vice versa. (Without this, the frame would shrink, and move
6846 slightly, if the window was resized by dragging one of its
6848 if (!frame_resize_pixelwise)
6850 NSRect r = [[self window] frame];
6852 if (r.size.width != frameSize.width)
6855 FRAME_TEXT_COLS_TO_PIXEL_WIDTH (emacsframe, cols);
6858 if (r.size.height != frameSize.height)
6861 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (emacsframe, rows) + extra;
6865 NSTRACE_RETURN_SIZE (frameSize);
6871 - (void)windowDidResize: (NSNotification *)notification
6873 NSTRACE ("[EmacsView windowDidResize:]");
6874 if (!FRAME_LIVE_P (emacsframe))
6876 NSTRACE_MSG ("Ignored (frame dead)");
6879 if (emacsframe->output_data.ns->in_animation)
6881 NSTRACE_MSG ("Ignored (in animation)");
6885 if (! [self fsIsNative])
6887 NSWindow *theWindow = [notification object];
6888 /* We can get notification on the non-FS window when in
6890 if ([self window] != theWindow) return;
6893 NSTRACE_RECT ("frame", [[notification object] frame]);
6895 #ifdef NS_IMPL_GNUSTEP
6896 NSWindow *theWindow = [notification object];
6898 /* In GNUstep, at least currently, it's possible to get a didResize
6899 without getting a willResize.. therefore we need to act as if we got
6900 the willResize now */
6901 NSSize sz = [theWindow frame].size;
6902 sz = [self windowWillResize: theWindow toSize: sz];
6903 #endif /* NS_IMPL_GNUSTEP */
6905 if (cols > 0 && rows > 0)
6907 [self updateFrameSize: YES];
6910 ns_send_appdefined (-1);
6913 #ifdef NS_IMPL_COCOA
6914 - (void)viewDidEndLiveResize
6916 NSTRACE ("[EmacsView viewDidEndLiveResize]");
6918 [super viewDidEndLiveResize];
6921 [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
6925 maximizing_resize = NO;
6927 #endif /* NS_IMPL_COCOA */
6930 - (void)windowDidBecomeKey: (NSNotification *)notification
6931 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6933 [self windowDidBecomeKey];
6937 - (void)windowDidBecomeKey /* for direct calls */
6939 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6940 struct frame *old_focus = dpyinfo->x_focus_frame;
6942 NSTRACE ("[EmacsView windowDidBecomeKey]");
6944 if (emacsframe != old_focus)
6945 dpyinfo->x_focus_frame = emacsframe;
6947 ns_frame_rehighlight (emacsframe);
6951 emacs_event->kind = FOCUS_IN_EVENT;
6952 EV_TRAILER ((id)nil);
6957 - (void)windowDidResignKey: (NSNotification *)notification
6958 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6960 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6961 BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
6962 NSTRACE ("[EmacsView windowDidResignKey:]");
6965 dpyinfo->x_focus_frame = 0;
6967 emacsframe->mouse_moved = 0;
6968 ns_frame_rehighlight (emacsframe);
6970 /* FIXME: for some reason needed on second and subsequent clicks away
6971 from sole-frame Emacs to get hollow box to show */
6972 if (!windowClosing && [[self window] isVisible] == YES)
6974 x_update_cursor (emacsframe, 1);
6975 x_set_frame_alpha (emacsframe);
6978 if (any_help_event_p)
6981 XSETFRAME (frame, emacsframe);
6982 help_echo_string = Qnil;
6983 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
6986 if (emacs_event && is_focus_frame)
6988 [self deleteWorkingText];
6989 emacs_event->kind = FOCUS_OUT_EVENT;
6990 EV_TRAILER ((id)nil);
6995 - (void)windowWillMiniaturize: sender
6997 NSTRACE ("[EmacsView windowWillMiniaturize:]");
7001 - (void)setFrame:(NSRect)frameRect
7003 NSTRACE ("[EmacsView setFrame:" NSTRACE_FMT_RECT "]",
7004 NSTRACE_ARG_RECT (frameRect));
7006 [super setFrame:(NSRect)frameRect];
7022 - (void)createToolbar: (struct frame *)f
7024 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
7025 NSWindow *window = [view window];
7027 toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
7028 [NSString stringWithFormat: @"Emacs Frame %d",
7030 [toolbar setVisible: NO];
7031 [window setToolbar: toolbar];
7033 /* Don't set frame garbaged until tool bar is up to date?
7034 This avoids an extra clear and redraw (flicker) at frame creation. */
7035 if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
7036 else wait_for_tool_bar = NO;
7039 #ifdef NS_IMPL_COCOA
7041 NSButton *toggleButton;
7042 toggleButton = [window standardWindowButton: NSWindowToolbarButton];
7043 [toggleButton setTarget: self];
7044 [toggleButton setAction: @selector (toggleToolbar: )];
7050 - (instancetype) initFrameFromEmacs: (struct frame *)f
7058 NSTRACE ("[EmacsView initFrameFromEmacs:]");
7059 NSTRACE_MSG ("cols:%d lines:%d", f->text_cols, f->text_lines);
7062 processingCompose = NO;
7063 scrollbarsNeedingUpdate = 0;
7064 fs_state = FULLSCREEN_NONE;
7065 fs_before_fs = next_maximized = -1;
7068 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7069 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7070 if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7072 fs_is_native = ns_use_native_fullscreen;
7075 maximized_width = maximized_height = -1;
7078 ns_userRect = NSMakeRect (0, 0, 0, 0);
7079 r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
7080 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
7081 [self initWithFrame: r];
7082 [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
7084 FRAME_NS_VIEW (f) = self;
7086 #ifdef NS_IMPL_COCOA
7088 maximizing_resize = NO;
7091 win = [[EmacsWindow alloc]
7092 initWithContentRect: r
7093 styleMask: (FRAME_UNDECORATED (f)
7094 ? FRAME_UNDECORATED_FLAGS
7095 : FRAME_DECORATED_FLAGS
7096 #ifdef NS_IMPL_COCOA
7097 | NSWindowStyleMaskResizable
7098 | NSWindowStyleMaskMiniaturizable
7099 | NSWindowStyleMaskClosable
7102 backing: NSBackingStoreBuffered
7105 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7106 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7107 if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7109 [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
7113 bwidth = f->border_width = wr.size.width - r.size.width;
7115 [win setAcceptsMouseMovedEvents: YES];
7116 [win setDelegate: self];
7117 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7118 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7119 if ([win respondsToSelector: @selector(useOptimizedDrawing:)])
7121 [win useOptimizedDrawing: YES];
7124 [[win contentView] addSubview: self];
7127 [self registerForDraggedTypes: ns_drag_types];
7130 name = [NSString stringWithUTF8String:
7131 NILP (tem) ? "Emacs" : SSDATA (tem)];
7132 [win setTitle: name];
7134 /* toolbar support */
7135 if (! FRAME_UNDECORATED (f))
7136 [self createToolbar: f];
7138 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
7139 #ifndef NSAppKitVersionNumber10_9
7140 #define NSAppKitVersionNumber10_9 1265
7143 if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_9
7144 && FRAME_NS_APPEARANCE (f) != ns_appearance_aqua)
7145 win.appearance = [NSAppearance
7146 appearanceNamed: NSAppearanceNameVibrantDark];
7149 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
7150 if ([win respondsToSelector: @selector(titlebarAppearsTransparent)])
7151 win.titlebarAppearsTransparent = FRAME_NS_TRANSPARENT_TITLEBAR (f);
7156 [win setMiniwindowTitle:
7157 [NSString stringWithUTF8String: SSDATA (tem)]];
7159 if (FRAME_PARENT_FRAME (f) != NULL)
7161 NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
7162 [parent addChildWindow: win
7163 ordered: NSWindowAbove];
7166 if (FRAME_Z_GROUP (f) != z_group_none)
7167 win.level = NSNormalWindowLevel
7168 + (FRAME_Z_GROUP_BELOW (f) ? -1 : 1);
7171 NSScreen *screen = [win screen];
7175 NSPoint pt = NSMakePoint
7176 (IN_BOUND (-SCREENMAX, f->left_pos
7177 + NS_PARENT_WINDOW_LEFT_POS (f), SCREENMAX),
7178 IN_BOUND (-SCREENMAX,
7179 NS_PARENT_WINDOW_TOP_POS (f) - f->top_pos,
7182 [win setFrameTopLeftPoint: pt];
7184 NSTRACE_RECT ("new frame", [win frame]);
7188 [win makeFirstResponder: self];
7190 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7191 (FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID)),
7193 [win setBackgroundColor: col];
7194 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7195 [win setOpaque: NO];
7197 #if !defined (NS_IMPL_COCOA) \
7198 || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7199 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7200 if ([self respondsToSelector: @selector(allocateGState)])
7202 [self allocateGState];
7204 [NSApp registerServicesMenuSendTypes: ns_send_types
7205 returnTypes: [NSArray array]];
7207 /* macOS Sierra automatically enables tabbed windows. We can't
7208 allow this to be enabled until it's available on a Free system.
7209 Currently it only happens by accident and is buggy anyway. */
7210 #if defined (NS_IMPL_COCOA) \
7211 && MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
7212 #if MAC_OS_X_VERSION_MIN_REQUIRED < 101200
7213 if ([win respondsToSelector: @selector(setTabbingMode:)])
7215 [win setTabbingMode: NSWindowTabbingModeDisallowed];
7223 - (void)windowDidMove: sender
7225 NSWindow *win = [self window];
7226 NSRect r = [win frame];
7227 NSArray *screens = [NSScreen screens];
7228 NSScreen *screen = [screens objectAtIndex: 0];
7230 NSTRACE ("[EmacsView windowDidMove:]");
7232 if (!emacsframe->output_data.ns)
7236 emacsframe->left_pos = r.origin.x - NS_PARENT_WINDOW_LEFT_POS (emacsframe);
7237 emacsframe->top_pos =
7238 NS_PARENT_WINDOW_TOP_POS (emacsframe) - (r.origin.y + r.size.height);
7242 emacs_event->kind = MOVE_FRAME_EVENT;
7243 EV_TRAILER ((id)nil);
7249 /* Called AFTER method below, but before our windowWillResize call there leads
7250 to windowDidResize -> x_set_window_size. Update emacs' notion of frame
7251 location so set_window_size moves the frame. */
7252 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
7254 NSTRACE (("[EmacsView windowShouldZoom:toFrame:" NSTRACE_FMT_RECT "]"
7255 NSTRACE_FMT_RETURN "YES"),
7256 NSTRACE_ARG_RECT (newFrame));
7258 emacsframe->output_data.ns->zooming = 1;
7263 /* Override to do something slightly nonstandard, but nice. First click on
7264 zoom button will zoom vertically. Second will zoom completely. Third
7265 returns to original. */
7266 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
7267 defaultFrame:(NSRect)defaultFrame
7269 // TODO: Rename to "currentFrame" and assign "result" properly in
7271 NSRect result = [sender frame];
7273 NSTRACE (("[EmacsView windowWillUseStandardFrame:defaultFrame:"
7274 NSTRACE_FMT_RECT "]"),
7275 NSTRACE_ARG_RECT (defaultFrame));
7276 NSTRACE_FSTYPE ("fs_state", fs_state);
7277 NSTRACE_FSTYPE ("fs_before_fs", fs_before_fs);
7278 NSTRACE_FSTYPE ("next_maximized", next_maximized);
7279 NSTRACE_RECT ("ns_userRect", ns_userRect);
7280 NSTRACE_RECT ("[sender frame]", [sender frame]);
7282 if (fs_before_fs != -1) /* Entering fullscreen */
7284 NSTRACE_MSG ("Entering fullscreen");
7285 result = defaultFrame;
7289 // Save the window size and position (frame) before the resize.
7290 if (fs_state != FULLSCREEN_MAXIMIZED
7291 && fs_state != FULLSCREEN_WIDTH)
7293 ns_userRect.size.width = result.size.width;
7294 ns_userRect.origin.x = result.origin.x;
7297 if (fs_state != FULLSCREEN_MAXIMIZED
7298 && fs_state != FULLSCREEN_HEIGHT)
7300 ns_userRect.size.height = result.size.height;
7301 ns_userRect.origin.y = result.origin.y;
7304 NSTRACE_RECT ("ns_userRect (2)", ns_userRect);
7306 if (next_maximized == FULLSCREEN_HEIGHT
7307 || (next_maximized == -1
7308 && abs ((int)(defaultFrame.size.height - result.size.height))
7309 > FRAME_LINE_HEIGHT (emacsframe)))
7312 NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7313 maximized_height = result.size.height = defaultFrame.size.height;
7314 maximized_width = -1;
7315 result.origin.y = defaultFrame.origin.y;
7316 if (ns_userRect.size.height != 0)
7318 result.origin.x = ns_userRect.origin.x;
7319 result.size.width = ns_userRect.size.width;
7321 [self setFSValue: FULLSCREEN_HEIGHT];
7322 #ifdef NS_IMPL_COCOA
7323 maximizing_resize = YES;
7326 else if (next_maximized == FULLSCREEN_WIDTH)
7328 NSTRACE_MSG ("FULLSCREEN_WIDTH");
7329 maximized_width = result.size.width = defaultFrame.size.width;
7330 maximized_height = -1;
7331 result.origin.x = defaultFrame.origin.x;
7332 if (ns_userRect.size.width != 0)
7334 result.origin.y = ns_userRect.origin.y;
7335 result.size.height = ns_userRect.size.height;
7337 [self setFSValue: FULLSCREEN_WIDTH];
7339 else if (next_maximized == FULLSCREEN_MAXIMIZED
7340 || (next_maximized == -1
7341 && abs ((int)(defaultFrame.size.width - result.size.width))
7342 > FRAME_COLUMN_WIDTH (emacsframe)))
7344 NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7346 result = defaultFrame; /* second click */
7347 maximized_width = result.size.width;
7348 maximized_height = result.size.height;
7349 [self setFSValue: FULLSCREEN_MAXIMIZED];
7350 #ifdef NS_IMPL_COCOA
7351 maximizing_resize = YES;
7357 NSTRACE_MSG ("Restore");
7358 result = ns_userRect.size.height ? ns_userRect : result;
7359 NSTRACE_RECT ("restore (2)", result);
7360 ns_userRect = NSMakeRect (0, 0, 0, 0);
7361 #ifdef NS_IMPL_COCOA
7362 maximizing_resize = fs_state != FULLSCREEN_NONE;
7364 [self setFSValue: FULLSCREEN_NONE];
7365 maximized_width = maximized_height = -1;
7369 if (fs_before_fs == -1) next_maximized = -1;
7371 NSTRACE_RECT ("Final ns_userRect", ns_userRect);
7372 NSTRACE_MSG ("Final maximized_width: %d", maximized_width);
7373 NSTRACE_MSG ("Final maximized_height: %d", maximized_height);
7374 NSTRACE_FSTYPE ("Final next_maximized", next_maximized);
7376 [self windowWillResize: sender toSize: result.size];
7378 NSTRACE_RETURN_RECT (result);
7384 - (void)windowDidDeminiaturize: sender
7386 NSTRACE ("[EmacsView windowDidDeminiaturize:]");
7387 if (!emacsframe->output_data.ns)
7390 SET_FRAME_ICONIFIED (emacsframe, 0);
7391 SET_FRAME_VISIBLE (emacsframe, 1);
7392 windows_or_buffers_changed = 63;
7396 emacs_event->kind = DEICONIFY_EVENT;
7397 EV_TRAILER ((id)nil);
7402 - (void)windowDidExpose: sender
7404 NSTRACE ("[EmacsView windowDidExpose:]");
7405 if (!emacsframe->output_data.ns)
7408 SET_FRAME_VISIBLE (emacsframe, 1);
7409 SET_FRAME_GARBAGED (emacsframe);
7411 if (send_appdefined)
7412 ns_send_appdefined (-1);
7416 - (void)windowDidMiniaturize: sender
7418 NSTRACE ("[EmacsView windowDidMiniaturize:]");
7419 if (!emacsframe->output_data.ns)
7422 SET_FRAME_ICONIFIED (emacsframe, 1);
7423 SET_FRAME_VISIBLE (emacsframe, 0);
7427 emacs_event->kind = ICONIFY_EVENT;
7428 EV_TRAILER ((id)nil);
7432 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7433 - (NSApplicationPresentationOptions)window:(NSWindow *)window
7434 willUseFullScreenPresentationOptions:
7435 (NSApplicationPresentationOptions)proposedOptions
7437 return proposedOptions|NSApplicationPresentationAutoHideToolbar;
7441 - (void)windowWillEnterFullScreen:(NSNotification *)notification
7443 NSTRACE ("[EmacsView windowWillEnterFullScreen:]");
7444 [self windowWillEnterFullScreen];
7446 - (void)windowWillEnterFullScreen /* provided for direct calls */
7448 NSTRACE ("[EmacsView windowWillEnterFullScreen]");
7449 fs_before_fs = fs_state;
7452 - (void)windowDidEnterFullScreen:(NSNotification *)notification
7454 NSTRACE ("[EmacsView windowDidEnterFullScreen:]");
7455 [self windowDidEnterFullScreen];
7458 - (void)windowDidEnterFullScreen /* provided for direct calls */
7460 NSTRACE ("[EmacsView windowDidEnterFullScreen]");
7461 [self setFSValue: FULLSCREEN_BOTH];
7462 if (! [self fsIsNative])
7464 [self windowDidBecomeKey];
7465 [nonfs_window orderOut:self];
7469 BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
7470 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 \
7471 && MAC_OS_X_VERSION_MIN_REQUIRED <= 1070
7472 unsigned val = (unsigned)[NSApp presentationOptions];
7474 // Mac OS X 10.7 bug fix, the menu won't appear without this.
7475 // val is non-zero on other macOS versions.
7478 NSApplicationPresentationOptions options
7479 = NSApplicationPresentationAutoHideDock
7480 | NSApplicationPresentationAutoHideMenuBar
7481 | NSApplicationPresentationFullScreen
7482 | NSApplicationPresentationAutoHideToolbar;
7484 [NSApp setPresentationOptions: options];
7487 [toolbar setVisible:tbar_visible];
7491 - (void)windowWillExitFullScreen:(NSNotification *)notification
7493 NSTRACE ("[EmacsView windowWillExitFullScreen:]");
7494 [self windowWillExitFullScreen];
7497 - (void)windowWillExitFullScreen /* provided for direct calls */
7499 NSTRACE ("[EmacsView windowWillExitFullScreen]");
7500 if (!FRAME_LIVE_P (emacsframe))
7502 NSTRACE_MSG ("Ignored (frame dead)");
7505 if (next_maximized != -1)
7506 fs_before_fs = next_maximized;
7509 - (void)windowDidExitFullScreen:(NSNotification *)notification
7511 NSTRACE ("[EmacsView windowDidExitFullScreen:]");
7512 [self windowDidExitFullScreen];
7515 - (void)windowDidExitFullScreen /* provided for direct calls */
7517 NSTRACE ("[EmacsView windowDidExitFullScreen]");
7518 if (!FRAME_LIVE_P (emacsframe))
7520 NSTRACE_MSG ("Ignored (frame dead)");
7523 [self setFSValue: fs_before_fs];
7525 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7526 [self updateCollectionBehavior];
7528 if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
7530 [toolbar setVisible:YES];
7531 update_frame_tool_bar (emacsframe);
7532 [self updateFrameSize:YES];
7533 [[self window] display];
7536 [toolbar setVisible:NO];
7538 if (next_maximized != -1)
7539 [[self window] performZoom:self];
7544 return fs_is_native;
7547 - (BOOL)isFullscreen
7553 res = (nonfs_window != nil);
7557 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7558 res = (([[self window] styleMask] & NSWindowStyleMaskFullScreen) != 0);
7564 NSTRACE ("[EmacsView isFullscreen] " NSTRACE_FMT_RETURN " %d",
7570 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7571 - (void)updateCollectionBehavior
7573 NSTRACE ("[EmacsView updateCollectionBehavior]");
7575 if (! [self isFullscreen])
7577 NSWindow *win = [self window];
7578 NSWindowCollectionBehavior b = [win collectionBehavior];
7579 if (ns_use_native_fullscreen)
7580 b |= NSWindowCollectionBehaviorFullScreenPrimary;
7582 b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
7584 [win setCollectionBehavior: b];
7585 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7586 if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7588 fs_is_native = ns_use_native_fullscreen;
7593 - (void)toggleFullScreen: (id)sender
7601 NSTRACE ("[EmacsView toggleFullScreen:]");
7605 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7606 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7607 if ([[self window] respondsToSelector: @selector(toggleFullScreen:)])
7609 [[self window] toggleFullScreen:sender];
7615 onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
7618 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7619 (FACE_FROM_ID (f, DEFAULT_FACE_ID)),
7622 if (fs_state != FULLSCREEN_BOTH)
7624 NSScreen *screen = [w screen];
7626 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
7627 /* Hide ghost menu bar on secondary monitor? */
7629 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
7630 && [NSScreen respondsToSelector: @selector(screensHaveSeparateSpaces)]
7633 onFirstScreen = [NSScreen screensHaveSeparateSpaces];
7635 /* Hide dock and menubar if we are on the primary screen. */
7638 #ifdef NS_IMPL_COCOA
7639 NSApplicationPresentationOptions options
7640 = NSApplicationPresentationAutoHideDock
7641 | NSApplicationPresentationAutoHideMenuBar;
7643 [NSApp setPresentationOptions: options];
7645 [NSMenu setMenuBarVisible:NO];
7649 fw = [[EmacsFSWindow alloc]
7650 initWithContentRect:[w contentRectForFrameRect:wr]
7651 styleMask:NSWindowStyleMaskBorderless
7652 backing:NSBackingStoreBuffered
7656 [fw setContentView:[w contentView]];
7657 [fw setTitle:[w title]];
7658 [fw setDelegate:self];
7659 [fw setAcceptsMouseMovedEvents: YES];
7660 #if !defined (NS_IMPL_COCOA) \
7661 || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7662 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7663 if ([fw respondsToSelector: @selector(useOptimizedDrawing:)])
7665 [fw useOptimizedDrawing: YES];
7667 [fw setBackgroundColor: col];
7668 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7671 f->border_width = 0;
7675 [self windowWillEnterFullScreen];
7676 [fw makeKeyAndOrderFront:NSApp];
7677 [fw makeFirstResponder:self];
7679 r = [fw frameRectForContentRect:[screen frame]];
7680 [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
7681 [self windowDidEnterFullScreen];
7692 #ifdef NS_IMPL_COCOA
7693 [NSApp setPresentationOptions: NSApplicationPresentationDefault];
7695 [NSMenu setMenuBarVisible:YES];
7699 [w setContentView:[fw contentView]];
7700 [w setBackgroundColor: col];
7701 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7704 f->border_width = bwidth;
7706 // to do: consider using [NSNotificationCenter postNotificationName:] to send notifications.
7708 [self windowWillExitFullScreen];
7709 [fw setFrame: [w frame] display:YES animate:ns_use_fullscreen_animation];
7711 [w makeKeyAndOrderFront:NSApp];
7712 [self windowDidExitFullScreen];
7713 [self updateFrameSize:YES];
7719 NSTRACE ("[EmacsView handleFS]");
7721 if (fs_state != emacsframe->want_fullscreen)
7723 if (fs_state == FULLSCREEN_BOTH)
7725 NSTRACE_MSG ("fs_state == FULLSCREEN_BOTH");
7726 [self toggleFullScreen:self];
7729 switch (emacsframe->want_fullscreen)
7731 case FULLSCREEN_BOTH:
7732 NSTRACE_MSG ("FULLSCREEN_BOTH");
7733 [self toggleFullScreen:self];
7735 case FULLSCREEN_WIDTH:
7736 NSTRACE_MSG ("FULLSCREEN_WIDTH");
7737 next_maximized = FULLSCREEN_WIDTH;
7738 if (fs_state != FULLSCREEN_BOTH)
7739 [[self window] performZoom:self];
7741 case FULLSCREEN_HEIGHT:
7742 NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7743 next_maximized = FULLSCREEN_HEIGHT;
7744 if (fs_state != FULLSCREEN_BOTH)
7745 [[self window] performZoom:self];
7747 case FULLSCREEN_MAXIMIZED:
7748 NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7749 next_maximized = FULLSCREEN_MAXIMIZED;
7750 if (fs_state != FULLSCREEN_BOTH)
7751 [[self window] performZoom:self];
7753 case FULLSCREEN_NONE:
7754 NSTRACE_MSG ("FULLSCREEN_NONE");
7755 if (fs_state != FULLSCREEN_BOTH)
7757 next_maximized = FULLSCREEN_NONE;
7758 [[self window] performZoom:self];
7763 emacsframe->want_fullscreen = FULLSCREEN_NONE;
7768 - (void) setFSValue: (int)value
7770 NSTRACE ("[EmacsView setFSValue:" NSTRACE_FMT_FSTYPE "]",
7771 NSTRACE_ARG_FSTYPE(value));
7773 Lisp_Object lval = Qnil;
7776 case FULLSCREEN_BOTH:
7779 case FULLSCREEN_WIDTH:
7782 case FULLSCREEN_HEIGHT:
7785 case FULLSCREEN_MAXIMIZED:
7789 store_frame_param (emacsframe, Qfullscreen, lval);
7793 - (void)mouseEntered: (NSEvent *)theEvent
7795 NSTRACE ("[EmacsView mouseEntered:]");
7797 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7798 = EV_TIMESTAMP (theEvent);
7802 - (void)mouseExited: (NSEvent *)theEvent
7804 Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
7806 NSTRACE ("[EmacsView mouseExited:]");
7811 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7812 = EV_TIMESTAMP (theEvent);
7814 if (emacsframe == hlinfo->mouse_face_mouse_frame)
7816 clear_mouse_face (hlinfo);
7817 hlinfo->mouse_face_mouse_frame = 0;
7822 - (instancetype)menuDown: sender
7824 NSTRACE ("[EmacsView menuDown:]");
7825 if (context_menu_value == -1)
7826 context_menu_value = [sender tag];
7829 NSInteger tag = [sender tag];
7830 find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
7831 emacsframe->menu_bar_vector,
7835 ns_send_appdefined (-1);
7840 - (EmacsToolbar *)toolbar
7846 /* this gets called on toolbar button click */
7847 - (instancetype)toolbarClicked: (id)item
7850 int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
7852 NSTRACE ("[EmacsView toolbarClicked:]");
7857 /* send first event (for some reason two needed) */
7858 theEvent = [[self window] currentEvent];
7859 emacs_event->kind = TOOL_BAR_EVENT;
7860 XSETFRAME (emacs_event->arg, emacsframe);
7861 EV_TRAILER (theEvent);
7863 emacs_event->kind = TOOL_BAR_EVENT;
7864 /* XSETINT (emacs_event->code, 0); */
7865 emacs_event->arg = AREF (emacsframe->tool_bar_items,
7866 idx + TOOL_BAR_ITEM_KEY);
7867 emacs_event->modifiers = EV_MODIFIERS (theEvent);
7868 EV_TRAILER (theEvent);
7873 - (instancetype)toggleToolbar: (id)sender
7875 NSTRACE ("[EmacsView toggleToolbar:]");
7880 emacs_event->kind = NS_NONKEY_EVENT;
7881 emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
7882 EV_TRAILER ((id)nil);
7887 - (void)drawRect: (NSRect)rect
7889 int x = NSMinX (rect), y = NSMinY (rect);
7890 int width = NSWidth (rect), height = NSHeight (rect);
7892 NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
7893 NSTRACE_ARG_RECT(rect));
7895 if (!emacsframe || !emacsframe->output_data.ns)
7898 ns_clear_frame_area (emacsframe, x, y, width, height);
7900 expose_frame (emacsframe, x, y, width, height);
7904 drawRect: may be called (at least in Mac OS X 10.5) for invisible
7905 views as well for some reason. Thus, do not infer visibility
7908 emacsframe->async_visible = 1;
7909 emacsframe->async_iconified = 0;
7914 /* NSDraggingDestination protocol methods. Actually this is not really a
7915 protocol, but a category of Object. O well... */
7917 -(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
7919 NSTRACE ("[EmacsView draggingEntered:]");
7920 return NSDragOperationGeneric;
7924 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
7930 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
7935 NSEvent *theEvent = [[self window] currentEvent];
7937 NSDragOperation op = [sender draggingSourceOperationMask];
7940 NSTRACE ("[EmacsView performDragOperation:]");
7945 position = [self convertPoint: [sender draggingLocation] fromView: nil];
7946 x = lrint (position.x); y = lrint (position.y);
7948 pb = [sender draggingPasteboard];
7949 type = [pb availableTypeFromArray: ns_drag_types];
7951 if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
7952 // URL drags contain all operations (0xf), don't allow all to be set.
7955 if (op & NSDragOperationLink)
7956 modifiers |= NSEventModifierFlagControl;
7957 if (op & NSDragOperationCopy)
7958 modifiers |= NSEventModifierFlagOption;
7959 if (op & NSDragOperationGeneric)
7960 modifiers |= NSEventModifierFlagCommand;
7963 modifiers = EV_MODIFIERS2 (modifiers);
7968 else if ([type isEqualToString: NSFilenamesPboardType])
7971 NSEnumerator *fenum;
7974 if (!(files = [pb propertyListForType: type]))
7977 fenum = [files objectEnumerator];
7978 while ( (file = [fenum nextObject]) )
7980 emacs_event->kind = DRAG_N_DROP_EVENT;
7981 XSETINT (emacs_event->x, x);
7982 XSETINT (emacs_event->y, y);
7983 ns_input_file = append2 (ns_input_file,
7984 build_string ([file UTF8String]));
7985 emacs_event->modifiers = modifiers;
7986 emacs_event->arg = list2 (Qfile, build_string ([file UTF8String]));
7987 EV_TRAILER (theEvent);
7991 else if ([type isEqualToString: NSURLPboardType])
7993 NSURL *url = [NSURL URLFromPasteboard: pb];
7994 if (url == nil) return NO;
7996 emacs_event->kind = DRAG_N_DROP_EVENT;
7997 XSETINT (emacs_event->x, x);
7998 XSETINT (emacs_event->y, y);
7999 emacs_event->modifiers = modifiers;
8000 emacs_event->arg = list2 (Qurl,
8001 build_string ([[url absoluteString]
8003 EV_TRAILER (theEvent);
8005 if ([url isFileURL] != NO)
8007 NSString *file = [url path];
8008 ns_input_file = append2 (ns_input_file,
8009 build_string ([file UTF8String]));
8013 else if ([type isEqualToString: NSStringPboardType]
8014 || [type isEqualToString: NSTabularTextPboardType])
8018 if (! (data = [pb stringForType: type]))
8021 emacs_event->kind = DRAG_N_DROP_EVENT;
8022 XSETINT (emacs_event->x, x);
8023 XSETINT (emacs_event->y, y);
8024 emacs_event->modifiers = modifiers;
8025 emacs_event->arg = list2 (Qnil, build_string ([data UTF8String]));
8026 EV_TRAILER (theEvent);
8031 fprintf (stderr, "Invalid data type in dragging pasteboard");
8037 - (id) validRequestorForSendType: (NSString *)typeSent
8038 returnType: (NSString *)typeReturned
8040 NSTRACE ("[EmacsView validRequestorForSendType:returnType:]");
8041 if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
8042 && typeReturned == nil)
8044 if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
8048 return [super validRequestorForSendType: typeSent
8049 returnType: typeReturned];
8053 /* The next two methods are part of NSServicesRequests informal protocol,
8054 supposedly called when a services menu item is chosen from this app.
8055 But this should not happen because we override the services menu with our
8056 own entries which call ns-perform-service.
8057 Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
8058 So let's at least stub them out until further investigation can be done. */
8060 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
8062 /* we could call ns_string_from_pasteboard(pboard) here but then it should
8063 be written into the buffer in place of the existing selection..
8064 ordinary service calls go through functions defined in ns-win.el */
8068 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
8070 NSArray *typesDeclared;
8073 NSTRACE ("[EmacsView writeSelectionToPasteboard:types:]");
8075 /* We only support NSStringPboardType */
8076 if ([types containsObject:NSStringPboardType] == NO) {
8080 val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8081 if (CONSP (val) && SYMBOLP (XCAR (val)))
8084 if (CONSP (val) && NILP (XCDR (val)))
8087 if (! STRINGP (val))
8090 typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
8091 [pb declareTypes:typesDeclared owner:nil];
8092 ns_string_to_pasteboard (pb, val);
8097 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
8098 (gives a miniaturized version of the window); currently we use the latter for
8099 frames whose active buffer doesn't correspond to any file
8100 (e.g., '*scratch*') */
8101 - (instancetype)setMiniwindowImage: (BOOL) setMini
8103 id image = [[self window] miniwindowImage];
8104 NSTRACE ("[EmacsView setMiniwindowImage:%d]", setMini);
8106 /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
8107 about "AppleDockIconEnabled" notwithstanding, however the set message
8108 below has its effect nonetheless. */
8109 if (image != emacsframe->output_data.ns->miniimage)
8111 if (image && [image isKindOfClass: [EmacsImage class]])
8113 [[self window] setMiniwindowImage:
8114 setMini ? emacsframe->output_data.ns->miniimage : nil];
8121 - (void) setRows: (int) r andColumns: (int) c
8123 NSTRACE ("[EmacsView setRows:%d andColumns:%d]", r, c);
8128 - (int) fullscreenState
8133 @end /* EmacsView */
8137 /* ==========================================================================
8139 EmacsWindow implementation
8141 ========================================================================== */
8143 @implementation EmacsWindow
8145 #ifdef NS_IMPL_COCOA
8146 - (id)accessibilityAttributeValue:(NSString *)attribute
8148 Lisp_Object str = Qnil;
8149 struct frame *f = SELECTED_FRAME ();
8150 struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
8152 NSTRACE ("[EmacsWindow accessibilityAttributeValue:]");
8154 if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
8155 return NSAccessibilityTextFieldRole;
8157 if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
8158 && curbuf && ! NILP (BVAR (curbuf, mark_active)))
8160 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8162 else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
8164 if (! NILP (BVAR (curbuf, mark_active)))
8165 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8169 ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
8170 ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
8171 ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
8173 if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
8174 str = make_uninit_multibyte_string (range, byte_range);
8176 str = make_uninit_string (range);
8177 /* To check: This returns emacs-utf-8, which is a superset of utf-8.
8178 Is this a problem? */
8179 memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
8186 if (CONSP (str) && SYMBOLP (XCAR (str)))
8189 if (CONSP (str) && NILP (XCDR (str)))
8194 const char *utfStr = SSDATA (str);
8195 NSString *nsStr = [NSString stringWithUTF8String: utfStr];
8200 return [super accessibilityAttributeValue:attribute];
8202 #endif /* NS_IMPL_COCOA */
8204 /* Constrain size and placement of a frame.
8206 By returning the original "frameRect", the frame is not
8207 constrained. This can lead to unwanted situations where, for
8208 example, the menu bar covers the frame.
8210 The default implementation (accessed using "super") constrains the
8211 frame to the visible area of SCREEN, minus the menu bar (if
8212 present) and the Dock. Note that default implementation also calls
8213 windowWillResize, with the frame it thinks should have. (This can
8214 make the frame exit maximized mode.)
8216 Note that this should work in situations where multiple monitors
8217 are present. Common configurations are side-by-side monitors and a
8218 monitor on top of another (e.g. when a laptop is placed under a
8220 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
8222 NSTRACE ("[EmacsWindow constrainFrameRect:" NSTRACE_FMT_RECT " toScreen:]",
8223 NSTRACE_ARG_RECT (frameRect));
8225 #ifdef NS_IMPL_COCOA
8226 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
8227 // If separate spaces is on, it is like each screen is independent. There is
8228 // no spanning of frames across screens.
8230 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
8231 [NSScreen respondsToSelector: @selector(screensHaveSeparateSpaces)] &&
8233 [NSScreen screensHaveSeparateSpaces])
8235 NSTRACE_MSG ("Screens have separate spaces");
8236 frameRect = [super constrainFrameRect:frameRect toScreen:screen];
8237 NSTRACE_RETURN_RECT (frameRect);
8241 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 */
8243 // Check that the proposed frameRect is visible in at least one
8244 // screen. If it is not, ask the system to reposition it (only
8245 // for non-child windows).
8247 if (!FRAME_PARENT_FRAME (((EmacsView *)[self delegate])->emacsframe))
8249 NSArray *screens = [NSScreen screens];
8250 NSUInteger nr_screens = [screens count];
8253 BOOL frame_on_screen = NO;
8255 for (i = 0; i < nr_screens; ++i)
8257 NSScreen *s = [screens objectAtIndex: i];
8258 NSRect scrRect = [s frame];
8260 if (NSIntersectsRect(frameRect, scrRect))
8262 frame_on_screen = YES;
8267 if (!frame_on_screen)
8269 NSTRACE_MSG ("Frame outside screens; constraining");
8270 frameRect = [super constrainFrameRect:frameRect toScreen:screen];
8271 NSTRACE_RETURN_RECT (frameRect);
8277 return constrain_frame_rect(frameRect,
8278 [(EmacsView *)[self delegate] isFullscreen]);
8282 - (void)performZoom:(id)sender
8284 NSTRACE ("[EmacsWindow performZoom:]");
8286 return [super performZoom:sender];
8289 - (void)zoom:(id)sender
8291 NSTRACE ("[EmacsWindow zoom:]");
8293 ns_update_auto_hide_menu_bar();
8295 // Below are three zoom implementations. In the final commit, the
8296 // idea is that the last should be included.
8299 // Native zoom done using the standard zoom animation. Size of the
8300 // resulting frame reduced to accommodate the Dock and, if present,
8302 [super zoom:sender];
8305 // Native zoom done using the standard zoom animation, plus an
8306 // explicit resize to cover the full screen, except the menu-bar and
8307 // dock, if present.
8308 [super zoom:sender];
8310 // After the native zoom, resize the resulting frame to fill the
8311 // entire screen, except the menu-bar.
8313 // This works for all practical purposes. (The only minor oddity is
8314 // when transiting from full-height frame to a maximized, the
8315 // animation reduces the height of the frame slightly (to the 4
8316 // pixels needed to accommodate the Doc) before it snaps back into
8317 // full height. The user would need a very trained eye to spot
8319 NSScreen * screen = [self screen];
8322 int fs_state = [(EmacsView *)[self delegate] fullscreenState];
8324 NSTRACE_FSTYPE ("fullscreenState", fs_state);
8326 NSRect sr = [screen frame];
8327 struct EmacsMargins margins
8328 = ns_screen_margins_ignoring_hidden_dock(screen);
8330 NSRect wr = [self frame];
8331 NSTRACE_RECT ("Rect after zoom", wr);
8335 if (fs_state == FULLSCREEN_MAXIMIZED
8336 || fs_state == FULLSCREEN_HEIGHT)
8338 newWr.origin.y = sr.origin.y + margins.bottom;
8339 newWr.size.height = sr.size.height - margins.top - margins.bottom;
8342 if (fs_state == FULLSCREEN_MAXIMIZED
8343 || fs_state == FULLSCREEN_WIDTH)
8345 newWr.origin.x = sr.origin.x + margins.left;
8346 newWr.size.width = sr.size.width - margins.right - margins.left;
8349 if (newWr.size.width != wr.size.width
8350 || newWr.size.height != wr.size.height
8351 || newWr.origin.x != wr.origin.x
8352 || newWr.origin.y != wr.origin.y)
8354 NSTRACE_MSG ("New frame different");
8355 [self setFrame: newWr display: NO];
8359 // Non-native zoom which is done instantaneously. The resulting
8360 // frame covers the entire screen, except the menu-bar and dock, if
8362 NSScreen * screen = [self screen];
8365 NSRect sr = [screen frame];
8366 struct EmacsMargins margins
8367 = ns_screen_margins_ignoring_hidden_dock(screen);
8369 sr.size.height -= (margins.top + margins.bottom);
8370 sr.size.width -= (margins.left + margins.right);
8371 sr.origin.x += margins.left;
8372 sr.origin.y += margins.bottom;
8374 sr = [[self delegate] windowWillUseStandardFrame:self
8376 [self setFrame: sr display: NO];
8381 - (void)setFrame:(NSRect)windowFrame
8382 display:(BOOL)displayViews
8384 NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT " display:%d]",
8385 NSTRACE_ARG_RECT (windowFrame), displayViews);
8387 [super setFrame:windowFrame display:displayViews];
8390 - (void)setFrame:(NSRect)windowFrame
8391 display:(BOOL)displayViews
8392 animate:(BOOL)performAnimation
8394 NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT
8395 " display:%d performAnimation:%d]",
8396 NSTRACE_ARG_RECT (windowFrame), displayViews, performAnimation);
8398 [super setFrame:windowFrame display:displayViews animate:performAnimation];
8401 - (void)setFrameTopLeftPoint:(NSPoint)point
8403 NSTRACE ("[EmacsWindow setFrameTopLeftPoint:" NSTRACE_FMT_POINT "]",
8404 NSTRACE_ARG_POINT (point));
8406 [super setFrameTopLeftPoint:point];
8409 - (BOOL)canBecomeKeyWindow
8411 return !FRAME_NO_ACCEPT_FOCUS (((EmacsView *)[self delegate])->emacsframe);
8413 @end /* EmacsWindow */
8416 @implementation EmacsFSWindow
8418 - (BOOL)canBecomeKeyWindow
8423 - (BOOL)canBecomeMainWindow
8430 /* ==========================================================================
8432 EmacsScroller implementation
8434 ========================================================================== */
8437 @implementation EmacsScroller
8439 /* for repeat button push */
8440 #define SCROLL_BAR_FIRST_DELAY 0.5
8441 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
8443 + (CGFloat) scrollerWidth
8445 /* TODO: if we want to allow variable widths, this is the place to do it,
8446 however neither GNUstep nor Cocoa support it very well */
8448 #if defined (NS_IMPL_COCOA) \
8449 && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
8450 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
8451 if ([NSScroller respondsToSelector:
8452 @selector(scrollerWidthForControlSize:scrollerStyle:)])
8454 r = [NSScroller scrollerWidthForControlSize: NSControlSizeRegular
8455 scrollerStyle: NSScrollerStyleLegacy];
8456 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
8459 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
8460 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 \
8461 || defined (NS_IMPL_GNUSTEP)
8462 r = [NSScroller scrollerWidth];
8467 - (instancetype)initFrame: (NSRect )r window: (Lisp_Object)nwin
8469 NSTRACE ("[EmacsScroller initFrame: window:]");
8471 if (r.size.width > r.size.height)
8476 [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
8477 [self setContinuous: YES];
8478 [self setEnabled: YES];
8480 /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
8481 locked against the top and bottom edges, and right edge on macOS, where
8482 scrollers are on right. */
8483 #ifdef NS_IMPL_GNUSTEP
8484 [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
8486 [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
8489 window = XWINDOW (nwin);
8492 pixel_length = NSWidth (r);
8494 pixel_length = NSHeight (r);
8495 if (pixel_length == 0) pixel_length = 1;
8496 min_portion = 20 / pixel_length;
8498 frame = XFRAME (window->frame);
8499 if (FRAME_LIVE_P (frame))
8502 EmacsView *view = FRAME_NS_VIEW (frame);
8503 NSView *sview = [[view window] contentView];
8504 NSArray *subs = [sview subviews];
8506 /* disable optimization stopping redraw of other scrollbars */
8507 view->scrollbarsNeedingUpdate = 0;
8508 for (i =[subs count]-1; i >= 0; i--)
8509 if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
8510 view->scrollbarsNeedingUpdate++;
8511 [sview addSubview: self];
8514 /* [self setFrame: r]; */
8520 - (void)setFrame: (NSRect)newRect
8522 NSTRACE ("[EmacsScroller setFrame:]");
8524 /* block_input (); */
8526 pixel_length = NSWidth (newRect);
8528 pixel_length = NSHeight (newRect);
8529 if (pixel_length == 0) pixel_length = 1;
8530 min_portion = 20 / pixel_length;
8531 [super setFrame: newRect];
8532 /* unblock_input (); */
8538 NSTRACE ("[EmacsScroller dealloc]");
8542 wset_horizontal_scroll_bar (window, Qnil);
8544 wset_vertical_scroll_bar (window, Qnil);
8551 - (instancetype)condemn
8553 NSTRACE ("[EmacsScroller condemn]");
8559 - (instancetype)reprieve
8561 NSTRACE ("[EmacsScroller reprieve]");
8569 NSTRACE ("[EmacsScroller judge]");
8570 bool ret = condemned;
8575 /* ensure other scrollbar updates after deletion */
8576 view = (EmacsView *)FRAME_NS_VIEW (frame);
8578 view->scrollbarsNeedingUpdate++;
8582 wset_horizontal_scroll_bar (window, Qnil);
8584 wset_vertical_scroll_bar (window, Qnil);
8587 [self removeFromSuperview];
8595 - (void)resetCursorRects
8597 NSRect visible = [self visibleRect];
8598 NSTRACE ("[EmacsScroller resetCursorRects]");
8600 if (!NSIsEmptyRect (visible))
8601 [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
8602 [[NSCursor arrowCursor] setOnMouseEntered: YES];
8606 - (int) checkSamePosition: (int) position portion: (int) portion
8609 return em_position ==position && em_portion ==portion && em_whole ==whole
8610 && portion != whole; /* needed for resize empty buf */
8614 - (instancetype)setPosition: (int)position portion: (int)portion whole: (int)whole
8616 NSTRACE ("[EmacsScroller setPosition:portion:whole:]");
8618 em_position = position;
8619 em_portion = portion;
8622 if (portion >= whole)
8624 #ifdef NS_IMPL_COCOA
8625 [self setKnobProportion: 1.0];
8626 [self setDoubleValue: 1.0];
8628 [self setFloatValue: 0.0 knobProportion: 1.0];
8635 portion = max ((float)whole*min_portion/pixel_length, portion);
8636 pos = (float)position / (whole - portion);
8637 por = (CGFloat)portion/whole;
8638 #ifdef NS_IMPL_COCOA
8639 [self setKnobProportion: por];
8640 [self setDoubleValue: pos];
8642 [self setFloatValue: pos knobProportion: por];
8649 /* set up emacs_event */
8650 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
8654 NSTRACE ("[EmacsScroller sendScrollEventAtLoc:fromEvent:]");
8659 emacs_event->part = last_hit_part;
8660 emacs_event->code = 0;
8661 emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
8662 XSETWINDOW (win, window);
8663 emacs_event->frame_or_window = win;
8664 emacs_event->timestamp = EV_TIMESTAMP (e);
8665 emacs_event->arg = Qnil;
8669 emacs_event->kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT;
8670 XSETINT (emacs_event->x, em_whole * loc / pixel_length);
8671 XSETINT (emacs_event->y, em_whole);
8675 emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
8676 XSETINT (emacs_event->x, loc);
8677 XSETINT (emacs_event->y, pixel_length-20);
8682 n_emacs_events_pending++;
8683 kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
8686 hold_event (emacs_event);
8687 EVENT_INIT (*emacs_event);
8688 ns_send_appdefined (-1);
8692 /* called manually thru timer to implement repeated button action w/hold-down */
8693 - (instancetype)repeatScroll: (NSTimer *)scrollEntry
8695 NSEvent *e = [[self window] currentEvent];
8696 NSPoint p = [[self window] mouseLocationOutsideOfEventStream];
8697 BOOL inKnob = [self testPart: p] == NSScrollerKnob;
8699 NSTRACE ("[EmacsScroller repeatScroll:]");
8701 /* clear timer if need be */
8702 if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
8704 [scroll_repeat_entry invalidate];
8705 [scroll_repeat_entry release];
8706 scroll_repeat_entry = nil;
8712 = [[NSTimer scheduledTimerWithTimeInterval:
8713 SCROLL_BAR_CONTINUOUS_DELAY
8715 selector: @selector (repeatScroll:)
8721 [self sendScrollEventAtLoc: 0 fromEvent: e];
8726 /* Asynchronous mouse tracking for scroller. This allows us to dispatch
8727 mouseDragged events without going into a modal loop. */
8728 - (void)mouseDown: (NSEvent *)e
8731 /* hitPart is only updated AFTER event is passed on */
8732 NSScrollerPart part = [self testPart: [e locationInWindow]];
8733 CGFloat loc, kloc, pos UNINIT;
8736 NSTRACE ("[EmacsScroller mouseDown:]");
8740 case NSScrollerDecrementPage:
8741 last_hit_part = horizontal ? scroll_bar_before_handle : scroll_bar_above_handle; break;
8742 case NSScrollerIncrementPage:
8743 last_hit_part = horizontal ? scroll_bar_after_handle : scroll_bar_below_handle; break;
8744 case NSScrollerDecrementLine:
8745 last_hit_part = horizontal ? scroll_bar_left_arrow : scroll_bar_up_arrow; break;
8746 case NSScrollerIncrementLine:
8747 last_hit_part = horizontal ? scroll_bar_right_arrow : scroll_bar_down_arrow; break;
8748 case NSScrollerKnob:
8749 last_hit_part = horizontal ? scroll_bar_horizontal_handle : scroll_bar_handle; break;
8750 case NSScrollerKnobSlot: /* GNUstep-only */
8751 last_hit_part = scroll_bar_move_ratio; break;
8752 default: /* NSScrollerNoPart? */
8753 fprintf (stderr, "EmacsScroller-mouseDown: unexpected part %ld\n",
8758 if (part == NSScrollerKnob || part == NSScrollerKnobSlot)
8760 /* handle, or on GNUstep possibly slot */
8761 NSEvent *fake_event;
8764 /* compute float loc in slot and mouse offset on knob */
8765 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8769 length = NSWidth (sr);
8770 loc = ([e locationInWindow].x - NSMinX (sr));
8774 length = NSHeight (sr);
8775 loc = length - ([e locationInWindow].y - NSMinY (sr));
8783 else if (loc >= length)
8793 kr = [self convertRect: [self rectForPart: NSScrollerKnob]
8796 kloc = ([e locationInWindow].x - NSMinX (kr));
8798 kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
8800 last_mouse_offset = kloc;
8802 if (part != NSScrollerKnob)
8803 /* this is a slot click on GNUstep: go straight there */
8806 /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
8807 fake_event = [NSEvent mouseEventWithType: NSEventTypeLeftMouseUp
8808 location: [e locationInWindow]
8809 modifierFlags: [e modifierFlags]
8810 timestamp: [e timestamp]
8811 windowNumber: [e windowNumber]
8813 eventNumber: [e eventNumber]
8814 clickCount: [e clickCount]
8815 pressure: [e pressure]];
8816 [super mouseUp: fake_event];
8820 pos = 0; /* ignored */
8822 /* set a timer to repeat, as we can't let superclass do this modally */
8824 = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
8826 selector: @selector (repeatScroll:)
8832 if (part != NSScrollerKnob)
8833 [self sendScrollEventAtLoc: pos fromEvent: e];
8837 /* Called as we manually track scroller drags, rather than superclass. */
8838 - (void)mouseDragged: (NSEvent *)e
8844 NSTRACE ("[EmacsScroller mouseDragged:]");
8846 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8851 length = NSWidth (sr);
8852 loc = ([e locationInWindow].x - NSMinX (sr));
8856 length = NSHeight (sr);
8857 loc = length - ([e locationInWindow].y - NSMinY (sr));
8864 else if (loc >= length + last_mouse_offset)
8866 loc = length + last_mouse_offset;
8869 pos = (loc - last_mouse_offset);
8870 [self sendScrollEventAtLoc: pos fromEvent: e];
8874 - (void)mouseUp: (NSEvent *)e
8876 NSTRACE ("[EmacsScroller mouseUp:]");
8878 if (scroll_repeat_entry)
8880 [scroll_repeat_entry invalidate];
8881 [scroll_repeat_entry release];
8882 scroll_repeat_entry = nil;
8884 last_hit_part = scroll_bar_above_handle;
8888 /* treat scrollwheel events in the bar as though they were in the main window */
8889 - (void) scrollWheel: (NSEvent *)theEvent
8891 NSTRACE ("[EmacsScroller scrollWheel:]");
8893 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
8894 [view mouseDown: theEvent];
8897 @end /* EmacsScroller */
8900 #ifdef NS_IMPL_GNUSTEP
8901 /* Dummy class to get rid of startup warnings. */
8902 @implementation EmacsDocument
8908 /* ==========================================================================
8910 Font-related functions; these used to be in nsfaces.m
8912 ========================================================================== */
8916 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
8918 struct font *font = XFONT_OBJECT (font_object);
8919 EmacsView *view = FRAME_NS_VIEW (f);
8920 int font_ascent, font_descent;
8923 fontset = fontset_from_font (font_object);
8924 FRAME_FONTSET (f) = fontset;
8926 if (FRAME_FONT (f) == font)
8927 /* This font is already set in frame F. There's nothing more to
8931 FRAME_FONT (f) = font;
8933 FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
8934 FRAME_COLUMN_WIDTH (f) = font->average_width;
8935 get_font_ascent_descent (font, &font_ascent, &font_descent);
8936 FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
8938 /* Compute the scroll bar width in character columns. */
8939 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
8941 int wid = FRAME_COLUMN_WIDTH (f);
8942 FRAME_CONFIG_SCROLL_BAR_COLS (f)
8943 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
8947 int wid = FRAME_COLUMN_WIDTH (f);
8948 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
8951 /* Compute the scroll bar height in character lines. */
8952 if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0)
8954 int height = FRAME_LINE_HEIGHT (f);
8955 FRAME_CONFIG_SCROLL_BAR_LINES (f)
8956 = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
8960 int height = FRAME_LINE_HEIGHT (f);
8961 FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
8964 /* Now make the frame display the given font. */
8965 if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
8966 adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
8967 FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
8974 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
8975 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
8979 ns_xlfd_to_fontname (const char *xlfd)
8980 /* --------------------------------------------------------------------------
8981 Convert an X font name (XLFD) to an NS font name.
8982 Only family is used.
8983 The string returned is temporarily allocated.
8984 -------------------------------------------------------------------------- */
8986 char *name = xmalloc (180);
8990 if (!strncmp (xlfd, "--", 2))
8991 sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
8993 sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
8995 /* stopgap for malformed XLFD input */
8996 if (strlen (name) == 0)
8997 strcpy (name, "Monaco");
8999 /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
9000 also uppercase after '-' or ' ' */
9001 name[0] = c_toupper (name[0]);
9002 for (len =strlen (name), i =0; i<len; i++)
9008 name[i+1] = c_toupper (name[i+1]);
9010 else if (name[i] == '_')
9014 name[i+1] = c_toupper (name[i+1]);
9017 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name); */
9018 ret = [[NSString stringWithUTF8String: name] UTF8String];
9025 syms_of_nsterm (void)
9027 NSTRACE ("syms_of_nsterm");
9029 ns_antialias_threshold = 10.0;
9031 /* from 23+ we need to tell emacs what modifiers there are.. */
9032 DEFSYM (Qmodifier_value, "modifier-value");
9033 DEFSYM (Qalt, "alt");
9034 DEFSYM (Qhyper, "hyper");
9035 DEFSYM (Qmeta, "meta");
9036 DEFSYM (Qsuper, "super");
9037 DEFSYM (Qcontrol, "control");
9038 DEFSYM (QUTF8_STRING, "UTF8_STRING");
9040 DEFSYM (Qfile, "file");
9041 DEFSYM (Qurl, "url");
9043 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
9044 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
9045 Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
9046 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
9047 Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
9049 DEFVAR_LISP ("ns-input-file", ns_input_file,
9050 "The file specified in the last NS event.");
9051 ns_input_file =Qnil;
9053 DEFVAR_LISP ("ns-working-text", ns_working_text,
9054 "String for visualizing working composition sequence.");
9055 ns_working_text =Qnil;
9057 DEFVAR_LISP ("ns-input-font", ns_input_font,
9058 "The font specified in the last NS event.");
9059 ns_input_font =Qnil;
9061 DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
9062 "The fontsize specified in the last NS event.");
9063 ns_input_fontsize =Qnil;
9065 DEFVAR_LISP ("ns-input-line", ns_input_line,
9066 "The line specified in the last NS event.");
9067 ns_input_line =Qnil;
9069 DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
9070 "The service name specified in the last NS event.");
9071 ns_input_spi_name =Qnil;
9073 DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
9074 "The service argument specified in the last NS event.");
9075 ns_input_spi_arg =Qnil;
9077 DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
9078 "This variable describes the behavior of the alternate or option key.\n\
9079 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9081 Set to none means that the alternate / option key is not interpreted by Emacs\n\
9082 at all, allowing it to be used at a lower level for accented character entry.");
9083 ns_alternate_modifier = Qmeta;
9085 DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
9086 "This variable describes the behavior of the right alternate or option key.\n\
9087 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9089 Set to left means be the same key as `ns-alternate-modifier'.\n\
9090 Set to none means that the alternate / option key is not interpreted by Emacs\n\
9091 at all, allowing it to be used at a lower level for accented character entry.");
9092 ns_right_alternate_modifier = Qleft;
9094 DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
9095 "This variable describes the behavior of the command key.\n\
9096 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9098 ns_command_modifier = Qsuper;
9100 DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
9101 "This variable describes the behavior of the right command key.\n\
9102 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9104 Set to left means be the same key as `ns-command-modifier'.\n\
9105 Set to none means that the command / option key is not interpreted by Emacs\n\
9106 at all, allowing it to be used at a lower level for accented character entry.");
9107 ns_right_command_modifier = Qleft;
9109 DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
9110 "This variable describes the behavior of the control key.\n\
9111 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9113 ns_control_modifier = Qcontrol;
9115 DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
9116 "This variable describes the behavior of the right control key.\n\
9117 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9119 Set to left means be the same key as `ns-control-modifier'.\n\
9120 Set to none means that the control / option key is not interpreted by Emacs\n\
9121 at all, allowing it to be used at a lower level for accented character entry.");
9122 ns_right_control_modifier = Qleft;
9124 DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
9125 "This variable describes the behavior of the function key (on laptops).\n\
9126 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9128 Set to none means that the function key is not interpreted by Emacs at all,\n\
9129 allowing it to be used at a lower level for accented character entry.");
9130 ns_function_modifier = Qnone;
9132 DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
9133 "Non-nil (the default) means to render text antialiased.");
9134 ns_antialias_text = Qt;
9136 DEFVAR_LISP ("ns-use-thin-smoothing", ns_use_thin_smoothing,
9137 "Non-nil turns on a font smoothing method that produces thinner strokes.");
9138 ns_use_thin_smoothing = Qnil;
9140 DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
9141 "Whether to confirm application quit using dialog.");
9142 ns_confirm_quit = Qnil;
9144 DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
9145 doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
9146 Only works on Mac OS X 10.6 or later. */);
9147 ns_auto_hide_menu_bar = Qnil;
9149 DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
9150 doc: /*Non-nil means to use native fullscreen on Mac OS X 10.7 and later.
9151 Nil means use fullscreen the old (< 10.7) way. The old way works better with
9152 multiple monitors, but lacks tool bar. This variable is ignored on
9153 Mac OS X < 10.7. Default is t. */);
9154 ns_use_native_fullscreen = YES;
9155 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
9157 DEFVAR_BOOL ("ns-use-fullscreen-animation", ns_use_fullscreen_animation,
9158 doc: /*Non-nil means use animation on non-native fullscreen.
9159 For native fullscreen, this does nothing.
9160 Default is nil. */);
9161 ns_use_fullscreen_animation = NO;
9163 DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
9164 doc: /*Non-nil means to use sRGB colorspace on Mac OS X 10.7 and later.
9165 Note that this does not apply to images.
9166 This variable is ignored on Mac OS X < 10.7 and GNUstep. */);
9167 ns_use_srgb_colorspace = YES;
9169 /* TODO: move to common code */
9170 DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
9171 doc: /* Which toolkit scroll bars Emacs uses, if any.
9172 A value of nil means Emacs doesn't use toolkit scroll bars.
9173 With the X Window system, the value is a symbol describing the
9174 X toolkit. Possible values are: gtk, motif, xaw, or xaw3d.
9175 With MS Windows or Nextstep, the value is t. */);
9176 Vx_toolkit_scroll_bars = Qt;
9178 DEFVAR_BOOL ("x-use-underline-position-properties",
9179 x_use_underline_position_properties,
9180 doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
9181 A value of nil means ignore them. If you encounter fonts with bogus
9182 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
9183 to 4.1, set this to nil. */);
9184 x_use_underline_position_properties = 0;
9186 DEFVAR_BOOL ("x-underline-at-descent-line",
9187 x_underline_at_descent_line,
9188 doc: /* Non-nil means to draw the underline at the same place as the descent line.
9189 A value of nil means to draw the underline according to the value of the
9190 variable `x-use-underline-position-properties', which is usually at the
9191 baseline level. The default value is nil. */);
9192 x_underline_at_descent_line = 0;
9194 /* Tell Emacs about this window system. */
9195 Fprovide (Qns, Qnil);
9197 DEFSYM (Qcocoa, "cocoa");
9198 DEFSYM (Qgnustep, "gnustep");
9200 #ifdef NS_IMPL_COCOA
9201 Fprovide (Qcocoa, Qnil);
9204 Fprovide (Qgnustep, Qnil);