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 <https://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 /* These flags will be OR'd or XOR'd with the NSWindow's styleMask
427 property depending on what we're doing. */
428 #define FRAME_DECORATED_FLAGS (NSWindowStyleMaskTitled \
429 | NSWindowStyleMaskResizable \
430 | NSWindowStyleMaskMiniaturizable \
431 | NSWindowStyleMaskClosable)
432 #define FRAME_UNDECORATED_FLAGS NSWindowStyleMaskBorderless
434 /* TODO: get rid of need for these forward declarations */
435 static void ns_condemn_scroll_bars (struct frame *f);
436 static void ns_judge_scroll_bars (struct frame *f);
439 /* ==========================================================================
443 ========================================================================== */
446 ns_set_represented_filename (NSString *fstr, struct frame *f)
448 represented_filename = [fstr retain];
449 represented_frame = f;
453 ns_init_events (struct input_event *ev)
460 ns_finish_events (void)
466 hold_event (struct input_event *event)
468 if (hold_event_q.nr == hold_event_q.cap)
470 if (hold_event_q.cap == 0) hold_event_q.cap = 10;
471 else hold_event_q.cap *= 2;
473 xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
476 hold_event_q.q[hold_event_q.nr++] = *event;
477 /* Make sure ns_read_socket is called, i.e. we have input. */
479 send_appdefined = YES;
483 append2 (Lisp_Object list, Lisp_Object item)
484 /* --------------------------------------------------------------------------
485 Utility to append to a list
486 -------------------------------------------------------------------------- */
488 return CALLN (Fnconc, list, list1 (item));
493 ns_etc_directory (void)
494 /* If running as a self-contained app bundle, return as a string the
495 filename of the etc directory, if present; else nil. */
497 NSBundle *bundle = [NSBundle mainBundle];
498 NSString *resourceDir = [bundle resourcePath];
499 NSString *resourcePath;
500 NSFileManager *fileManager = [NSFileManager defaultManager];
503 resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
504 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
506 if (isDir) return [resourcePath UTF8String];
514 /* If running as a self-contained app bundle, return as a path string
515 the filenames of the libexec and bin directories, ie libexec:bin.
516 Otherwise, return nil.
517 Normally, Emacs does not add its own bin/ directory to the PATH.
518 However, a self-contained NS build has a different layout, with
519 bin/ and libexec/ subdirectories in the directory that contains
521 We put libexec first, because init_callproc_1 uses the first
522 element to initialize exec-directory. An alternative would be
523 for init_callproc to check for invocation-directory/libexec.
526 NSBundle *bundle = [NSBundle mainBundle];
527 NSString *resourceDir = [bundle resourcePath];
528 NSString *binDir = [bundle bundlePath];
529 NSString *resourcePath, *resourcePaths;
531 NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
532 NSFileManager *fileManager = [NSFileManager defaultManager];
534 NSEnumerator *pathEnum;
537 range = [resourceDir rangeOfString: @"Contents"];
538 if (range.location != NSNotFound)
540 binDir = [binDir stringByAppendingPathComponent: @"Contents"];
542 binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
546 paths = [binDir stringsByAppendingPaths:
547 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
548 pathEnum = [paths objectEnumerator];
551 while ((resourcePath = [pathEnum nextObject]))
553 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
556 if ([resourcePaths length] > 0)
558 = [resourcePaths stringByAppendingString: pathSeparator];
560 = [resourcePaths stringByAppendingString: resourcePath];
563 if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
571 /* If running as a self-contained app bundle, return as a path string
572 the filenames of the site-lisp and lisp directories.
573 Ie, site-lisp:lisp. Otherwise, return nil. */
575 NSBundle *bundle = [NSBundle mainBundle];
576 NSString *resourceDir = [bundle resourcePath];
577 NSString *resourcePath, *resourcePaths;
578 NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
579 NSFileManager *fileManager = [NSFileManager defaultManager];
581 NSArray *paths = [resourceDir stringsByAppendingPaths:
582 [NSArray arrayWithObjects:
583 @"site-lisp", @"lisp", nil]];
584 NSEnumerator *pathEnum = [paths objectEnumerator];
587 /* Hack to skip site-lisp. */
588 if (no_site_lisp) resourcePath = [pathEnum nextObject];
590 while ((resourcePath = [pathEnum nextObject]))
592 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
595 if ([resourcePaths length] > 0)
597 = [resourcePaths stringByAppendingString: pathSeparator];
599 = [resourcePaths stringByAppendingString: resourcePath];
602 if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
609 ns_init_locale (void)
610 /* macOS doesn't set any environment variables for the locale when run
611 from the GUI. Get the locale from the OS and set LANG. */
613 NSLocale *locale = [NSLocale currentLocale];
615 NSTRACE ("ns_init_locale");
619 /* It seems macOS should probably use UTF-8 everywhere.
620 'localeIdentifier' does not specify the encoding, and I can't
621 find any way to get the OS to tell us which encoding to use,
622 so hard-code '.UTF-8'. */
623 NSString *localeID = [NSString stringWithFormat:@"%@.UTF-8",
624 [locale localeIdentifier]];
626 /* Set LANG to locale, but not if LANG is already set. */
627 setenv("LANG", [localeID UTF8String], 0);
629 @catch (NSException *e)
631 NSLog (@"Locale detection failed: %@: %@", [e name], [e reason]);
637 ns_release_object (void *obj)
638 /* --------------------------------------------------------------------------
639 Release an object (callable from C)
640 -------------------------------------------------------------------------- */
647 ns_retain_object (void *obj)
648 /* --------------------------------------------------------------------------
649 Retain an object (callable from C)
650 -------------------------------------------------------------------------- */
657 ns_alloc_autorelease_pool (void)
658 /* --------------------------------------------------------------------------
659 Allocate a pool for temporary objects (callable from C)
660 -------------------------------------------------------------------------- */
662 return [[NSAutoreleasePool alloc] init];
667 ns_release_autorelease_pool (void *pool)
668 /* --------------------------------------------------------------------------
669 Free a pool and temporary objects it refers to (callable from C)
670 -------------------------------------------------------------------------- */
672 ns_release_object (pool);
677 ns_menu_bar_should_be_hidden (void)
678 /* True, if the menu bar should be hidden. */
680 return !NILP (ns_auto_hide_menu_bar)
681 && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
694 static struct EmacsMargins
695 ns_screen_margins (NSScreen *screen)
696 /* The parts of SCREEN used by the operating system. */
698 NSTRACE ("ns_screen_margins");
700 struct EmacsMargins margins;
702 NSRect screenFrame = [screen frame];
703 NSRect screenVisibleFrame = [screen visibleFrame];
705 /* Sometimes, visibleFrame isn't up-to-date with respect to a hidden
706 menu bar, check this explicitly. */
707 if (ns_menu_bar_should_be_hidden())
713 CGFloat frameTop = screenFrame.origin.y + screenFrame.size.height;
714 CGFloat visibleFrameTop = (screenVisibleFrame.origin.y
715 + screenVisibleFrame.size.height);
717 margins.top = frameTop - visibleFrameTop;
721 CGFloat frameRight = screenFrame.origin.x + screenFrame.size.width;
722 CGFloat visibleFrameRight = (screenVisibleFrame.origin.x
723 + screenVisibleFrame.size.width);
724 margins.right = frameRight - visibleFrameRight;
727 margins.bottom = screenVisibleFrame.origin.y - screenFrame.origin.y;
728 margins.left = screenVisibleFrame.origin.x - screenFrame.origin.x;
730 NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
740 /* A screen margin between 1 and DOCK_IGNORE_LIMIT (inclusive) is
741 assumed to contain a hidden dock. macOS currently use 4 pixels for
742 this, however, to be future compatible, a larger value is used. */
743 #define DOCK_IGNORE_LIMIT 6
745 static struct EmacsMargins
746 ns_screen_margins_ignoring_hidden_dock (NSScreen *screen)
747 /* The parts of SCREEN used by the operating system, excluding the parts
748 reserved for an hidden dock. */
750 NSTRACE ("ns_screen_margins_ignoring_hidden_dock");
752 struct EmacsMargins margins = ns_screen_margins(screen);
754 /* macOS (currently) reserved 4 pixels along the edge where a hidden
755 dock is located. Unfortunately, it's not possible to find the
756 location and information about if the dock is hidden. Instead,
757 it is assumed that if the margin of an edge is less than
758 DOCK_IGNORE_LIMIT, it contains a hidden dock. */
759 if (margins.left <= DOCK_IGNORE_LIMIT)
763 if (margins.right <= DOCK_IGNORE_LIMIT)
767 if (margins.top <= DOCK_IGNORE_LIMIT)
771 /* Note: This doesn't occur in current versions of macOS, but
772 included for completeness and future compatibility. */
773 if (margins.bottom <= DOCK_IGNORE_LIMIT)
778 NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
789 ns_menu_bar_height (NSScreen *screen)
790 /* The height of the menu bar, if visible.
792 Note: Don't use this when fullscreen is enabled -- the screen
793 sometimes includes, sometimes excludes the menu bar area. */
795 struct EmacsMargins margins = ns_screen_margins(screen);
797 CGFloat res = margins.top;
799 NSTRACE ("ns_menu_bar_height " NSTRACE_FMT_RETURN " %.0f", res);
805 /* ==========================================================================
807 Focus (clipping) and screen update
809 ========================================================================== */
812 // Window constraining
813 // -------------------
815 // To ensure that the windows are not placed under the menu bar, they
816 // are typically moved by the call-back constrainFrameRect. However,
817 // by overriding it, it's possible to inhibit this, leaving the window
818 // in it's original position.
820 // It's possible to hide the menu bar. However, technically, it's only
821 // possible to hide it when the application is active. To ensure that
822 // this work properly, the menu bar and window constraining are
823 // deferred until the application becomes active.
825 // Even though it's not possible to manually move a window above the
826 // top of the screen, it is allowed if it's done programmatically,
827 // when the menu is hidden. This allows the editable area to cover the
828 // full screen height.
833 // Use the following extra files:
836 // ;; Hide menu and place frame slightly above the top of the screen.
837 // (setq ns-auto-hide-menu-bar t)
838 // (set-frame-position (selected-frame) 0 -20)
842 // emacs -Q -l init.el
844 // Result: No menu bar, and the title bar should be above the screen.
850 // Result: Menu bar visible, frame placed immediately below the menu.
853 static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
855 NSTRACE ("constrain_frame_rect(" NSTRACE_FMT_RECT ")",
856 NSTRACE_ARG_RECT (frameRect));
858 // --------------------
859 // Collect information about the screen the frame is covering.
862 NSArray *screens = [NSScreen screens];
863 NSUInteger nr_screens = [screens count];
867 // The height of the menu bar, if present in any screen the frame is
869 int menu_bar_height = 0;
871 // A rectangle covering all the screen the frame is displayed in.
872 NSRect multiscreenRect = NSMakeRect(0, 0, 0, 0);
873 for (i = 0; i < nr_screens; ++i )
875 NSScreen *s = [screens objectAtIndex: i];
876 NSRect scrRect = [s frame];
878 NSTRACE_MSG ("Screen %d: " NSTRACE_FMT_RECT,
879 i, NSTRACE_ARG_RECT (scrRect));
881 if (NSIntersectionRect (frameRect, scrRect).size.height != 0)
883 multiscreenRect = NSUnionRect (multiscreenRect, scrRect);
887 CGFloat screen_menu_bar_height = ns_menu_bar_height (s);
888 menu_bar_height = max(menu_bar_height, screen_menu_bar_height);
893 NSTRACE_RECT ("multiscreenRect", multiscreenRect);
895 NSTRACE_MSG ("menu_bar_height: %d", menu_bar_height);
897 if (multiscreenRect.size.width == 0
898 || multiscreenRect.size.height == 0)
900 // Failed to find any monitor, give up.
901 NSTRACE_MSG ("multiscreenRect empty");
902 NSTRACE_RETURN_RECT (frameRect);
907 // --------------------
908 // Find a suitable placement.
911 if (ns_menu_bar_should_be_hidden())
913 // When the menu bar is hidden, the user may place part of the
914 // frame above the top of the screen, for example to hide the
917 // Hence, keep the original position.
921 // Ensure that the frame is below the menu bar, or below the top
924 // This assume that the menu bar is placed at the top in the
925 // rectangle that covers the monitors. (It doesn't have to be,
926 // but if it's not it's hard to do anything useful.)
927 CGFloat topOfWorkArea = (multiscreenRect.origin.y
928 + multiscreenRect.size.height
931 CGFloat topOfFrame = frameRect.origin.y + frameRect.size.height;
932 if (topOfFrame > topOfWorkArea)
934 frameRect.origin.y -= topOfFrame - topOfWorkArea;
935 NSTRACE_RECT ("After placement adjust", frameRect);
939 // Include the following section to restrict frame to the screens.
940 // (If so, update it to allow the frame to stretch down below the
943 // --------------------
944 // Ensure frame doesn't stretch below the screens.
947 CGFloat diff = multiscreenRect.origin.y - frameRect.origin.y;
951 frameRect.origin.y = multiscreenRect.origin.y;
952 frameRect.size.height -= diff;
956 NSTRACE_RETURN_RECT (frameRect);
962 ns_constrain_all_frames (void)
963 /* --------------------------------------------------------------------------
964 Ensure that the menu bar doesn't cover any frames.
965 -------------------------------------------------------------------------- */
967 Lisp_Object tail, frame;
969 NSTRACE ("ns_constrain_all_frames");
973 FOR_EACH_FRAME (tail, frame)
975 struct frame *f = XFRAME (frame);
978 EmacsView *view = FRAME_NS_VIEW (f);
980 if (![view isFullscreen])
983 setFrame:constrain_frame_rect([[view window] frame], false)
994 ns_update_auto_hide_menu_bar (void)
995 /* --------------------------------------------------------------------------
996 Show or hide the menu bar, based on user setting.
997 -------------------------------------------------------------------------- */
1000 NSTRACE ("ns_update_auto_hide_menu_bar");
1004 if (NSApp != nil && [NSApp isActive])
1006 // Note, "setPresentationOptions" triggers an error unless the
1007 // application is active.
1008 BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
1010 if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
1012 NSApplicationPresentationOptions options
1013 = NSApplicationPresentationDefault;
1015 if (menu_bar_should_be_hidden)
1016 options |= NSApplicationPresentationAutoHideMenuBar
1017 | NSApplicationPresentationAutoHideDock;
1019 [NSApp setPresentationOptions: options];
1021 ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
1023 if (!ns_menu_bar_is_hidden)
1025 ns_constrain_all_frames ();
1036 ns_update_begin (struct frame *f)
1037 /* --------------------------------------------------------------------------
1038 Prepare for a grouped sequence of drawing calls
1039 external (RIF) call; whole frame, called before update_window_begin
1040 -------------------------------------------------------------------------- */
1042 EmacsView *view = FRAME_NS_VIEW (f);
1043 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_begin");
1045 ns_update_auto_hide_menu_bar ();
1047 #ifdef NS_IMPL_COCOA
1048 if ([view isFullscreen] && [view fsIsNative])
1050 // Fix reappearing tool bar in fullscreen for Mac OS X 10.7
1051 BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
1052 NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
1053 if (! tbar_visible != ! [toolbar isVisible])
1054 [toolbar setVisible: tbar_visible];
1058 ns_updating_frame = f;
1061 /* drawRect may have been called for say the minibuffer, and then clip path
1062 is for the minibuffer. But the display engine may draw more because
1063 we have set the frame as garbaged. So reset clip path to the whole
1065 #ifdef NS_IMPL_COCOA
1068 NSRect r = [view frame];
1069 NSRect cr = [[view window] frame];
1070 /* If a large frame size is set, r may be larger than the window frame
1071 before constrained. In that case don't change the clip path, as we
1072 will clear in to the tool bar and title bar. */
1074 + FRAME_NS_TITLEBAR_HEIGHT (f)
1075 + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
1077 bp = [[NSBezierPath bezierPathWithRect: r] retain];
1084 #ifdef NS_IMPL_GNUSTEP
1085 uRect = NSMakeRect (0, 0, 0, 0);
1091 ns_update_window_begin (struct window *w)
1092 /* --------------------------------------------------------------------------
1093 Prepare for a grouped sequence of drawing calls
1094 external (RIF) call; for one window, called after update_begin
1095 -------------------------------------------------------------------------- */
1097 struct frame *f = XFRAME (WINDOW_FRAME (w));
1098 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1100 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_begin");
1101 w->output_cursor = w->cursor;
1105 if (f == hlinfo->mouse_face_mouse_frame)
1107 /* Don't do highlighting for mouse motion during the update. */
1108 hlinfo->mouse_face_defer = 1;
1110 /* If the frame needs to be redrawn,
1111 simply forget about any prior mouse highlighting. */
1112 if (FRAME_GARBAGED_P (f))
1113 hlinfo->mouse_face_window = Qnil;
1115 /* (further code for mouse faces ifdef'd out in other terms elided) */
1123 ns_update_window_end (struct window *w, bool cursor_on_p,
1124 bool mouse_face_overwritten_p)
1125 /* --------------------------------------------------------------------------
1126 Finished a grouped sequence of drawing calls
1127 external (RIF) call; for one window called before update_end
1128 -------------------------------------------------------------------------- */
1130 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_end");
1132 /* note: this fn is nearly identical in all terms */
1133 if (!w->pseudo_window_p)
1138 display_and_set_cursor (w, 1,
1139 w->output_cursor.hpos, w->output_cursor.vpos,
1140 w->output_cursor.x, w->output_cursor.y);
1142 if (draw_window_fringes (w, 1))
1144 if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
1145 x_draw_right_divider (w);
1147 x_draw_vertical_border (w);
1153 /* If a row with mouse-face was overwritten, arrange for
1154 frame_up_to_date to redisplay the mouse highlight. */
1155 if (mouse_face_overwritten_p)
1156 reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
1161 ns_update_end (struct frame *f)
1162 /* --------------------------------------------------------------------------
1163 Finished a grouped sequence of drawing calls
1164 external (RIF) call; for whole frame, called after update_window_end
1165 -------------------------------------------------------------------------- */
1167 EmacsView *view = FRAME_NS_VIEW (f);
1169 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_end");
1171 /* if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
1172 MOUSE_HL_INFO (f)->mouse_face_defer = 0;
1177 [[view window] flushWindow];
1180 ns_updating_frame = NULL;
1184 ns_focus (struct frame *f, NSRect *r, int n)
1185 /* --------------------------------------------------------------------------
1186 Internal: Focus on given frame. During small local updates this is used to
1187 draw, however during large updates, ns_update_begin and ns_update_end are
1188 called to wrap the whole thing, in which case these calls are stubbed out.
1189 Except, on GNUstep, we accumulate the rectangle being drawn into, because
1190 the back end won't do this automatically, and will just end up flushing
1192 -------------------------------------------------------------------------- */
1194 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_focus");
1197 NSTRACE_RECT ("r", *r);
1200 if (f != ns_updating_frame)
1202 NSView *view = FRAME_NS_VIEW (f);
1203 if (view != focus_view)
1205 if (focus_view != NULL)
1207 [focus_view unlockFocus];
1208 [[focus_view window] flushWindow];
1215 /*if (view) debug_lock++; */
1222 [[NSGraphicsContext currentContext] saveGraphicsState];
1224 NSRectClipList (r, 2);
1233 ns_unfocus (struct frame *f)
1234 /* --------------------------------------------------------------------------
1235 Internal: Remove focus on given frame
1236 -------------------------------------------------------------------------- */
1238 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_unfocus");
1242 [[NSGraphicsContext currentContext] restoreGraphicsState];
1246 if (f != ns_updating_frame)
1248 if (focus_view != NULL)
1250 [focus_view unlockFocus];
1251 [[focus_view window] flushWindow];
1260 ns_clip_to_row (struct window *w, struct glyph_row *row,
1261 enum glyph_row_area area, BOOL gc)
1262 /* --------------------------------------------------------------------------
1263 Internal (but parallels other terms): Focus drawing on given row
1264 -------------------------------------------------------------------------- */
1266 struct frame *f = XFRAME (WINDOW_FRAME (w));
1268 int window_x, window_y, window_width;
1270 window_box (w, area, &window_x, &window_y, &window_width, 0);
1272 clip_rect.origin.x = window_x;
1273 clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
1274 clip_rect.origin.y = max (clip_rect.origin.y, window_y);
1275 clip_rect.size.width = window_width;
1276 clip_rect.size.height = row->visible_height;
1278 ns_focus (f, &clip_rect, 1);
1282 /* ==========================================================================
1284 Visible bell and beep.
1286 ========================================================================== */
1289 // This bell implementation shows the visual bell image asynchronously
1290 // from the rest of Emacs. This is done by adding a NSView to the
1291 // superview of the Emacs window and removing it using a timer.
1293 // Unfortunately, some Emacs operations, like scrolling, is done using
1294 // low-level primitives that copy the content of the window, including
1295 // the bell image. To some extent, this is handled by removing the
1296 // image prior to scrolling and marking that the window is in need for
1299 // To test this code, make sure that there is no artifacts of the bell
1300 // image in the following situations. Use a non-empty buffer (like the
1301 // tutorial) to ensure that a scroll is performed:
1303 // * Single-window: C-g C-v
1305 // * Side-by-windows: C-x 3 C-g C-v
1307 // * Windows above each other: C-x 2 C-g C-v
1309 @interface EmacsBell : NSImageView
1311 // Number of currently active bell:s.
1312 unsigned int nestCount;
1316 - (void)show:(NSView *)view;
1321 @implementation EmacsBell
1325 NSTRACE ("[EmacsBell init]");
1326 if ((self = [super init]))
1330 #ifdef NS_IMPL_GNUSTEP
1331 // GNUstep doesn't provide named images. This was reported in
1332 // 2011, see https://savannah.gnu.org/bugs/?33396
1334 // As a drop in replacement, a semitransparent gray square is used.
1335 self.image = [[NSImage alloc] initWithSize:NSMakeSize(32 * 5, 32 * 5)];
1336 [self.image lockFocus];
1337 [[NSColor colorForEmacsRed:0.5 green:0.5 blue:0.5 alpha:0.5] set];
1338 NSRectFill(NSMakeRect(0, 0, 32, 32));
1339 [self.image unlockFocus];
1341 self.image = [NSImage imageNamed:NSImageNameCaution];
1342 [self.image setSize:NSMakeSize(self.image.size.width * 5,
1343 self.image.size.height * 5)];
1349 - (void)show:(NSView *)view
1351 NSTRACE ("[EmacsBell show:]");
1352 NSTRACE_MSG ("nestCount: %u", nestCount);
1354 // Show the image, unless it's already shown.
1357 NSRect rect = [view bounds];
1359 pos.x = rect.origin.x + (rect.size.width - self.image.size.width )/2;
1360 pos.y = rect.origin.y + (rect.size.height - self.image.size.height)/2;
1362 [self setFrameOrigin:pos];
1363 [self setFrameSize:self.image.size];
1367 [[[view window] contentView] addSubview:self
1368 positioned:NSWindowAbove
1374 [self performSelector:@selector(hide) withObject:self afterDelay:0.5];
1380 // Note: Trace output from this method isn't shown, reason unknown.
1381 // NSTRACE ("[EmacsBell hide]");
1386 // Remove the image once the last bell became inactive.
1396 NSTRACE ("[EmacsBell remove]");
1399 NSTRACE_MSG ("removeFromSuperview");
1400 [self removeFromSuperview];
1401 mView.needsDisplay = YES;
1409 static EmacsBell * bell_view = nil;
1412 ns_ring_bell (struct frame *f)
1413 /* --------------------------------------------------------------------------
1415 -------------------------------------------------------------------------- */
1417 NSTRACE ("ns_ring_bell");
1420 struct frame *frame = SELECTED_FRAME ();
1423 if (bell_view == nil)
1425 bell_view = [[EmacsBell alloc] init];
1431 view = FRAME_NS_VIEW (frame);
1434 [bell_view show:view];
1448 /* --------------------------------------------------------------------------
1449 Ensure the bell is hidden.
1450 -------------------------------------------------------------------------- */
1452 NSTRACE ("hide_bell");
1454 if (bell_view != nil)
1461 /* ==========================================================================
1463 Frame / window manager related functions
1465 ========================================================================== */
1469 ns_raise_frame (struct frame *f, BOOL make_key)
1470 /* --------------------------------------------------------------------------
1471 Bring window to foreground and if make_key is YES, give it focus.
1472 -------------------------------------------------------------------------- */
1476 check_window_system (f);
1477 view = FRAME_NS_VIEW (f);
1479 if (FRAME_VISIBLE_P (f))
1482 [[view window] makeKeyAndOrderFront: NSApp];
1484 [[view window] orderFront: NSApp];
1491 ns_lower_frame (struct frame *f)
1492 /* --------------------------------------------------------------------------
1494 -------------------------------------------------------------------------- */
1498 check_window_system (f);
1499 view = FRAME_NS_VIEW (f);
1501 [[view window] orderBack: NSApp];
1507 ns_frame_raise_lower (struct frame *f, bool raise)
1508 /* --------------------------------------------------------------------------
1510 -------------------------------------------------------------------------- */
1512 NSTRACE ("ns_frame_raise_lower");
1515 ns_raise_frame (f, YES);
1522 ns_frame_rehighlight (struct frame *frame)
1523 /* --------------------------------------------------------------------------
1524 External (hook): called on things like window switching within frame
1525 -------------------------------------------------------------------------- */
1527 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1528 struct frame *old_highlight = dpyinfo->x_highlight_frame;
1530 NSTRACE ("ns_frame_rehighlight");
1531 if (dpyinfo->x_focus_frame)
1533 dpyinfo->x_highlight_frame
1534 = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1535 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1536 : dpyinfo->x_focus_frame);
1537 if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1539 fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1540 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1544 dpyinfo->x_highlight_frame = 0;
1546 if (dpyinfo->x_highlight_frame &&
1547 dpyinfo->x_highlight_frame != old_highlight)
1551 x_update_cursor (old_highlight, 1);
1552 x_set_frame_alpha (old_highlight);
1554 if (dpyinfo->x_highlight_frame)
1556 x_update_cursor (dpyinfo->x_highlight_frame, 1);
1557 x_set_frame_alpha (dpyinfo->x_highlight_frame);
1564 x_make_frame_visible (struct frame *f)
1565 /* --------------------------------------------------------------------------
1566 External: Show the window (X11 semantics)
1567 -------------------------------------------------------------------------- */
1569 NSTRACE ("x_make_frame_visible");
1570 /* XXX: at some points in past this was not needed, as the only place that
1571 called this (frame.c:Fraise_frame ()) also called raise_lower;
1572 if this ends up the case again, comment this out again. */
1573 if (!FRAME_VISIBLE_P (f))
1575 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1576 NSWindow *window = [view window];
1578 SET_FRAME_VISIBLE (f, 1);
1579 ns_raise_frame (f, ! FRAME_NO_FOCUS_ON_MAP (f));
1581 /* Making a new frame from a fullscreen frame will make the new frame
1582 fullscreen also. So skip handleFS as this will print an error. */
1583 if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1584 && [view isFullscreen])
1587 if (f->want_fullscreen != FULLSCREEN_NONE)
1594 /* Making a frame invisible seems to break the parent->child
1595 relationship, so reinstate it. */
1596 if ([window parentWindow] == nil && FRAME_PARENT_FRAME (f) != NULL)
1598 NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
1601 [parent addChildWindow: window
1602 ordered: NSWindowAbove];
1605 /* If the parent frame moved while the child frame was
1606 invisible, the child frame's position won't have been
1607 updated. Make sure it's in the right place now. */
1608 x_set_offset(f, f->left_pos, f->top_pos, 0);
1615 x_make_frame_invisible (struct frame *f)
1616 /* --------------------------------------------------------------------------
1617 External: Hide the window (X11 semantics)
1618 -------------------------------------------------------------------------- */
1621 NSTRACE ("x_make_frame_invisible");
1622 check_window_system (f);
1623 view = FRAME_NS_VIEW (f);
1624 [[view window] orderOut: NSApp];
1625 SET_FRAME_VISIBLE (f, 0);
1626 SET_FRAME_ICONIFIED (f, 0);
1631 x_iconify_frame (struct frame *f)
1632 /* --------------------------------------------------------------------------
1633 External: Iconify window
1634 -------------------------------------------------------------------------- */
1637 struct ns_display_info *dpyinfo;
1639 NSTRACE ("x_iconify_frame");
1640 check_window_system (f);
1641 view = FRAME_NS_VIEW (f);
1642 dpyinfo = FRAME_DISPLAY_INFO (f);
1644 if (dpyinfo->x_highlight_frame == f)
1645 dpyinfo->x_highlight_frame = 0;
1647 if ([[view window] windowNumber] <= 0)
1649 /* the window is still deferred. Make it very small, bring it
1650 on screen and order it out. */
1651 NSRect s = { { 100, 100}, {0, 0} };
1653 t = [[view window] frame];
1654 [[view window] setFrame: s display: NO];
1655 [[view window] orderBack: NSApp];
1656 [[view window] orderOut: NSApp];
1657 [[view window] setFrame: t display: NO];
1660 /* Processing input while Emacs is being minimized can cause a
1661 crash, so block it for the duration. */
1663 [[view window] miniaturize: NSApp];
1667 /* Free X resources of frame F. */
1670 x_free_frame_resources (struct frame *f)
1673 struct ns_display_info *dpyinfo;
1674 Mouse_HLInfo *hlinfo;
1676 NSTRACE ("x_free_frame_resources");
1677 check_window_system (f);
1678 view = FRAME_NS_VIEW (f);
1679 dpyinfo = FRAME_DISPLAY_INFO (f);
1680 hlinfo = MOUSE_HL_INFO (f);
1682 [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1686 free_frame_menubar (f);
1687 free_frame_faces (f);
1689 if (f == dpyinfo->x_focus_frame)
1690 dpyinfo->x_focus_frame = 0;
1691 if (f == dpyinfo->x_highlight_frame)
1692 dpyinfo->x_highlight_frame = 0;
1693 if (f == hlinfo->mouse_face_mouse_frame)
1694 reset_mouse_highlight (hlinfo);
1696 if (f->output_data.ns->miniimage != nil)
1697 [f->output_data.ns->miniimage release];
1699 [[view window] close];
1702 xfree (f->output_data.ns);
1708 x_destroy_window (struct frame *f)
1709 /* --------------------------------------------------------------------------
1710 External: Delete the window
1711 -------------------------------------------------------------------------- */
1713 NSTRACE ("x_destroy_window");
1715 /* If this frame has a parent window, detach it as not doing so can
1716 cause a crash in GNUStep. */
1717 if (FRAME_PARENT_FRAME (f) != NULL)
1719 NSWindow *child = [FRAME_NS_VIEW (f) window];
1720 NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
1722 [parent removeChildWindow: child];
1725 check_window_system (f);
1726 x_free_frame_resources (f);
1732 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1733 /* --------------------------------------------------------------------------
1734 External: Position the window
1735 -------------------------------------------------------------------------- */
1737 NSView *view = FRAME_NS_VIEW (f);
1738 NSArray *screens = [NSScreen screens];
1739 NSScreen *fscreen = [screens objectAtIndex: 0];
1740 NSScreen *screen = [[view window] screen];
1742 NSTRACE ("x_set_offset");
1749 if (view != nil && screen && fscreen)
1751 f->left_pos = f->size_hint_flags & XNegative
1752 ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1754 /* We use visibleFrame here to take menu bar into account.
1755 Ideally we should also adjust left/top with visibleFrame.origin. */
1757 f->top_pos = f->size_hint_flags & YNegative
1758 ? ([screen visibleFrame].size.height + f->top_pos
1759 - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1760 - FRAME_TOOLBAR_HEIGHT (f))
1762 #ifdef NS_IMPL_GNUSTEP
1763 if (FRAME_PARENT_FRAME (f) == NULL)
1765 if (f->left_pos < 100)
1766 f->left_pos = 100; /* don't overlap menu */
1769 /* Constrain the setFrameTopLeftPoint so we don't move behind the
1771 NSPoint pt = NSMakePoint (SCREENMAXBOUND (f->left_pos
1772 + NS_PARENT_WINDOW_LEFT_POS (f)),
1773 SCREENMAXBOUND (NS_PARENT_WINDOW_TOP_POS (f)
1775 NSTRACE_POINT ("setFrameTopLeftPoint", pt);
1776 [[view window] setFrameTopLeftPoint: pt];
1777 f->size_hint_flags &= ~(XNegative|YNegative);
1785 x_set_window_size (struct frame *f,
1786 bool change_gravity,
1790 /* --------------------------------------------------------------------------
1791 Adjust window pixel size based on given character grid size
1792 Impl is a bit more complex than other terms, need to do some
1794 -------------------------------------------------------------------------- */
1796 EmacsView *view = FRAME_NS_VIEW (f);
1797 NSWindow *window = [view window];
1798 NSRect wr = [window frame];
1799 int pixelwidth, pixelheight;
1800 int orig_height = wr.size.height;
1802 NSTRACE ("x_set_window_size");
1807 NSTRACE_RECT ("current", wr);
1808 NSTRACE_MSG ("Width:%d Height:%d Pixelwise:%d", width, height, pixelwise);
1809 NSTRACE_MSG ("Font %d x %d", FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f));
1815 pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1816 pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1820 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, width);
1821 pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1824 wr.size.width = pixelwidth + f->border_width;
1825 wr.size.height = pixelheight;
1826 if (! [view isFullscreen])
1827 wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1828 + FRAME_TOOLBAR_HEIGHT (f);
1830 /* Do not try to constrain to this screen. We may have multiple
1831 screens, and want Emacs to span those. Constraining to screen
1832 prevents that, and that is not nice to the user. */
1833 if (f->output_data.ns->zooming)
1834 f->output_data.ns->zooming = 0;
1836 wr.origin.y += orig_height - wr.size.height;
1838 frame_size_history_add
1839 (f, Qx_set_window_size_1, width, height,
1840 list5 (Fcons (make_number (pixelwidth), make_number (pixelheight)),
1841 Fcons (make_number (wr.size.width), make_number (wr.size.height)),
1842 make_number (f->border_width),
1843 make_number (FRAME_NS_TITLEBAR_HEIGHT (f)),
1844 make_number (FRAME_TOOLBAR_HEIGHT (f))));
1846 [window setFrame: wr display: YES];
1848 [view updateFrameSize: NO];
1852 #ifdef NS_IMPL_COCOA
1854 x_set_undecorated (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1855 /* --------------------------------------------------------------------------
1856 Set frame F's `undecorated' parameter. If non-nil, F's window-system
1857 window is drawn without decorations, title, minimize/maximize boxes
1858 and external borders. This usually means that the window cannot be
1859 dragged, resized, iconified, maximized or deleted with the mouse. If
1860 nil, draw the frame with all the elements listed above unless these
1861 have been suspended via window manager settings.
1863 GNUStep cannot change an existing window's style.
1864 -------------------------------------------------------------------------- */
1866 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1867 NSWindow *window = [view window];
1869 NSTRACE ("x_set_undecorated");
1871 if (!EQ (new_value, old_value))
1875 if (NILP (new_value))
1877 FRAME_UNDECORATED (f) = false;
1878 [window setStyleMask: ((window.styleMask | FRAME_DECORATED_FLAGS)
1879 ^ FRAME_UNDECORATED_FLAGS)];
1881 [view createToolbar: f];
1885 [window setToolbar: nil];
1886 /* Do I need to release the toolbar here? */
1888 FRAME_UNDECORATED (f) = true;
1889 [window setStyleMask: ((window.styleMask | FRAME_UNDECORATED_FLAGS)
1890 ^ FRAME_DECORATED_FLAGS)];
1893 /* At this point it seems we don't have an active NSResponder,
1894 so some key presses (TAB) are swallowed by the system. */
1895 [window makeFirstResponder: view];
1897 [view updateFrameSize: NO];
1901 #endif /* NS_IMPL_COCOA */
1904 x_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1905 /* --------------------------------------------------------------------------
1906 Set frame F's `parent-frame' parameter. If non-nil, make F a child
1907 frame of the frame specified by that parameter. Technically, this
1908 makes F's window-system window a child window of the parent frame's
1909 window-system window. If nil, make F's window-system window a
1910 top-level window--a child of its display's root window.
1912 A child frame's `left' and `top' parameters specify positions
1913 relative to the top-left corner of its parent frame's native
1914 rectangle. On macOS moving a parent frame moves all its child
1915 frames too, keeping their position relative to the parent
1916 unaltered. When a parent frame is iconified or made invisible, its
1917 child frames are made invisible. When a parent frame is deleted,
1918 its child frames are deleted too.
1920 Whether a child frame has a tool bar may be window-system or window
1921 manager dependent. It's advisable to disable it via the frame
1924 Some window managers may not honor this parameter.
1925 -------------------------------------------------------------------------- */
1927 struct frame *p = NULL;
1928 NSWindow *parent, *child;
1930 NSTRACE ("x_set_parent_frame");
1932 if (!NILP (new_value)
1933 && (!FRAMEP (new_value)
1934 || !FRAME_LIVE_P (p = XFRAME (new_value))
1937 store_frame_param (f, Qparent_frame, old_value);
1938 error ("Invalid specification of `parent-frame'");
1941 if (p != FRAME_PARENT_FRAME (f))
1943 parent = [FRAME_NS_VIEW (p) window];
1944 child = [FRAME_NS_VIEW (f) window];
1947 [parent addChildWindow: child
1948 ordered: NSWindowAbove];
1951 fset_parent_frame (f, new_value);
1956 x_set_no_focus_on_map (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1957 /* Set frame F's `no-focus-on-map' parameter which, if non-nil, means
1958 * that F's window-system window does not want to receive input focus
1959 * when it is mapped. (A frame's window is mapped when the frame is
1960 * displayed for the first time and when the frame changes its state
1961 * from `iconified' or `invisible' to `visible'.)
1963 * Some window managers may not honor this parameter. */
1965 NSTRACE ("x_set_no_focus_on_map");
1967 if (!EQ (new_value, old_value))
1969 FRAME_NO_FOCUS_ON_MAP (f) = !NILP (new_value);
1974 x_set_no_accept_focus (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1975 /* Set frame F's `no-accept-focus' parameter which, if non-nil, hints
1976 * that F's window-system window does not want to receive input focus
1977 * via mouse clicks or by moving the mouse into it.
1979 * If non-nil, this may have the unwanted side-effect that a user cannot
1980 * scroll a non-selected frame with the mouse.
1982 * Some window managers may not honor this parameter. */
1984 NSTRACE ("x_set_no_accept_focus");
1986 if (!EQ (new_value, old_value))
1987 FRAME_NO_ACCEPT_FOCUS (f) = !NILP (new_value);
1991 x_set_z_group (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1992 /* Set frame F's `z-group' parameter. If `above', F's window-system
1993 window is displayed above all windows that do not have the `above'
1994 property set. If nil, F's window is shown below all windows that
1995 have the `above' property set and above all windows that have the
1996 `below' property set. If `below', F's window is displayed below
1997 all windows that do.
1999 Some window managers may not honor this parameter. */
2001 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2002 NSWindow *window = [view window];
2004 NSTRACE ("x_set_z_group");
2006 if (NILP (new_value))
2008 window.level = NSNormalWindowLevel;
2009 FRAME_Z_GROUP (f) = z_group_none;
2011 else if (EQ (new_value, Qabove))
2013 window.level = NSNormalWindowLevel + 1;
2014 FRAME_Z_GROUP (f) = z_group_above;
2016 else if (EQ (new_value, Qabove_suspended))
2018 /* Not sure what level this should be. */
2019 window.level = NSNormalWindowLevel + 1;
2020 FRAME_Z_GROUP (f) = z_group_above_suspended;
2022 else if (EQ (new_value, Qbelow))
2024 window.level = NSNormalWindowLevel - 1;
2025 FRAME_Z_GROUP (f) = z_group_below;
2028 error ("Invalid z-group specification");
2031 #ifdef NS_IMPL_COCOA
2033 ns_set_appearance (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
2035 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
2036 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2037 NSWindow *window = [view window];
2039 NSTRACE ("ns_set_appearance");
2041 #ifndef NSAppKitVersionNumber10_10
2042 #define NSAppKitVersionNumber10_10 1343
2045 if (NSAppKitVersionNumber < NSAppKitVersionNumber10_10)
2048 if (EQ (new_value, Qdark))
2050 window.appearance = [NSAppearance
2051 appearanceNamed: NSAppearanceNameVibrantDark];
2052 FRAME_NS_APPEARANCE (f) = ns_appearance_vibrant_dark;
2056 window.appearance = [NSAppearance
2057 appearanceNamed: NSAppearanceNameAqua];
2058 FRAME_NS_APPEARANCE (f) = ns_appearance_aqua;
2060 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 */
2064 ns_set_transparent_titlebar (struct frame *f, Lisp_Object new_value,
2065 Lisp_Object old_value)
2067 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
2068 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2069 NSWindow *window = [view window];
2071 NSTRACE ("ns_set_transparent_titlebar");
2073 if ([window respondsToSelector: @selector(titlebarAppearsTransparent)]
2074 && !EQ (new_value, old_value))
2076 window.titlebarAppearsTransparent = !NILP (new_value);
2077 FRAME_NS_TRANSPARENT_TITLEBAR (f) = !NILP (new_value);
2079 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 */
2081 #endif /* NS_IMPL_COCOA */
2084 ns_fullscreen_hook (struct frame *f)
2086 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2088 NSTRACE ("ns_fullscreen_hook");
2090 if (!FRAME_VISIBLE_P (f))
2093 if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
2095 /* Old style fs don't initiate correctly if created from
2096 init/default-frame alist, so use a timer (not nice...).
2098 [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
2099 selector: @selector (handleFS)
2100 userInfo: nil repeats: NO];
2109 /* ==========================================================================
2113 ========================================================================== */
2117 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
2119 struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
2120 if (idx < 1 || idx >= color_table->avail)
2122 return color_table->colors[idx];
2127 ns_index_color (NSColor *color, struct frame *f)
2129 struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
2133 if (!color_table->colors)
2135 color_table->size = NS_COLOR_CAPACITY;
2136 color_table->avail = 1; /* skip idx=0 as marker */
2137 color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
2138 color_table->colors[0] = nil;
2139 color_table->empty_indices = [[NSMutableSet alloc] init];
2142 /* Do we already have this color? */
2143 for (i = 1; i < color_table->avail; i++)
2144 if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
2147 if ([color_table->empty_indices count] > 0)
2149 NSNumber *index = [color_table->empty_indices anyObject];
2150 [color_table->empty_indices removeObject: index];
2151 idx = [index unsignedLongValue];
2155 if (color_table->avail == color_table->size)
2156 color_table->colors =
2157 xpalloc (color_table->colors, &color_table->size, 1,
2158 min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
2159 idx = color_table->avail++;
2162 color_table->colors[idx] = color;
2164 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
2170 ns_get_color (const char *name, NSColor **col)
2171 /* --------------------------------------------------------------------------
2173 -------------------------------------------------------------------------- */
2174 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
2175 X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
2176 See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
2179 static char hex[20];
2181 float r = -1.0, g, b;
2182 NSString *nsname = [NSString stringWithUTF8String: name];
2184 NSTRACE ("ns_get_color(%s, **)", name);
2188 if ([nsname isEqualToString: @"ns_selection_bg_color"])
2190 #ifdef NS_IMPL_COCOA
2191 NSString *defname = [[NSUserDefaults standardUserDefaults]
2192 stringForKey: @"AppleHighlightColor"];
2197 if ((new = [NSColor selectedTextBackgroundColor]) != nil)
2199 *col = [new colorUsingDefaultColorSpace];
2204 nsname = NS_SELECTION_BG_COLOR_DEFAULT;
2206 name = [nsname UTF8String];
2208 else if ([nsname isEqualToString: @"ns_selection_fg_color"])
2210 /* NOTE: macOS applications normally don't set foreground
2211 selection, but text may be unreadable if we don't.
2213 if ((new = [NSColor selectedTextColor]) != nil)
2215 *col = [new colorUsingDefaultColorSpace];
2220 nsname = NS_SELECTION_FG_COLOR_DEFAULT;
2221 name = [nsname UTF8String];
2224 /* First, check for some sort of numeric specification. */
2227 if (name[0] == '0' || name[0] == '1' || name[0] == '.') /* RGB decimal */
2229 NSScanner *scanner = [NSScanner scannerWithString: nsname];
2230 [scanner scanFloat: &r];
2231 [scanner scanFloat: &g];
2232 [scanner scanFloat: &b];
2234 else if (!strncmp(name, "rgb:", 4)) /* A newer X11 format -- rgb:r/g/b */
2235 scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
2236 else if (name[0] == '#') /* An old X11 format; convert to newer */
2238 int len = (strlen(name) - 1);
2239 int start = (len % 3 == 0) ? 1 : len / 4 + 1;
2241 scaling = strlen(name+start) / 3;
2242 for (i = 0; i < 3; i++)
2243 sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
2244 name + start + i * scaling);
2245 hex[3 * (scaling + 1) - 1] = '\0';
2250 unsigned int rr, gg, bb;
2251 float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
2252 if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
2262 *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
2267 /* Otherwise, color is expected to be from a list */
2269 NSEnumerator *lenum, *cenum;
2273 #ifdef NS_IMPL_GNUSTEP
2274 /* XXX: who is wrong, the requestor or the implementation? */
2275 if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
2277 nsname = @"highlightColor";
2280 lenum = [[NSColorList availableColorLists] objectEnumerator];
2281 while ( (clist = [lenum nextObject]) && new == nil)
2283 cenum = [[clist allKeys] objectEnumerator];
2284 while ( (name = [cenum nextObject]) && new == nil )
2286 if ([name compare: nsname
2287 options: NSCaseInsensitiveSearch] == NSOrderedSame )
2288 new = [clist colorWithKey: name];
2294 *col = [new colorUsingDefaultColorSpace];
2301 ns_lisp_to_color (Lisp_Object color, NSColor **col)
2302 /* --------------------------------------------------------------------------
2303 Convert a Lisp string object to a NS color
2304 -------------------------------------------------------------------------- */
2306 NSTRACE ("ns_lisp_to_color");
2307 if (STRINGP (color))
2308 return ns_get_color (SSDATA (color), col);
2309 else if (SYMBOLP (color))
2310 return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
2316 ns_query_color(void *col, XColor *color_def, int setPixel)
2317 /* --------------------------------------------------------------------------
2318 Get ARGB values out of NSColor col and put them into color_def.
2319 If setPixel, set the pixel to a concatenated version.
2320 and set color_def pixel to the resulting index.
2321 -------------------------------------------------------------------------- */
2323 EmacsCGFloat r, g, b, a;
2325 [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
2326 color_def->red = r * 65535;
2327 color_def->green = g * 65535;
2328 color_def->blue = b * 65535;
2330 if (setPixel == YES)
2332 = ARGB_TO_ULONG((int)(a*255),
2333 (int)(r*255), (int)(g*255), (int)(b*255));
2338 ns_defined_color (struct frame *f,
2343 /* --------------------------------------------------------------------------
2344 Return true if named color found, and set color_def rgb accordingly.
2345 If makeIndex and alloc are nonzero put the color in the color_table,
2346 and set color_def pixel to the resulting index.
2347 If makeIndex is zero, set color_def pixel to ARGB.
2348 Return false if not found
2349 -------------------------------------------------------------------------- */
2352 NSTRACE_WHEN (NSTRACE_GROUP_COLOR, "ns_defined_color");
2355 if (ns_get_color (name, &col) != 0) /* Color not found */
2360 if (makeIndex && alloc)
2361 color_def->pixel = ns_index_color (col, f);
2362 ns_query_color (col, color_def, !makeIndex);
2369 x_set_frame_alpha (struct frame *f)
2370 /* --------------------------------------------------------------------------
2371 change the entire-frame transparency
2372 -------------------------------------------------------------------------- */
2374 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2376 double alpha_min = 1.0;
2378 NSTRACE ("x_set_frame_alpha");
2380 if (dpyinfo->x_highlight_frame == f)
2381 alpha = f->alpha[0];
2383 alpha = f->alpha[1];
2385 if (FLOATP (Vframe_alpha_lower_limit))
2386 alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
2387 else if (INTEGERP (Vframe_alpha_lower_limit))
2388 alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
2392 else if (1.0 < alpha)
2394 else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
2397 #ifdef NS_IMPL_COCOA
2399 EmacsView *view = FRAME_NS_VIEW (f);
2400 [[view window] setAlphaValue: alpha];
2406 /* ==========================================================================
2410 ========================================================================== */
2414 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
2415 /* --------------------------------------------------------------------------
2416 Programmatically reposition mouse pointer in pixel coordinates
2417 -------------------------------------------------------------------------- */
2419 NSTRACE ("frame_set_mouse_pixel_position");
2421 /* FIXME: what about GNUstep? */
2422 #ifdef NS_IMPL_COCOA
2424 CGPointMake(f->left_pos + pix_x,
2425 f->top_pos + pix_y +
2426 FRAME_NS_TITLEBAR_HEIGHT(f) + FRAME_TOOLBAR_HEIGHT(f));
2427 CGWarpMouseCursorPosition (mouse_pos);
2432 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
2433 /* ------------------------------------------------------------------------
2434 Called by EmacsView on mouseMovement events. Passes on
2435 to emacs mainstream code if we moved off of a rect of interest
2436 known as last_mouse_glyph.
2437 ------------------------------------------------------------------------ */
2439 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
2442 // NSTRACE ("note_mouse_movement");
2444 dpyinfo->last_mouse_motion_frame = frame;
2445 r = &dpyinfo->last_mouse_glyph;
2447 /* Note, this doesn't get called for enter/leave, since we don't have a
2448 position. Those are taken care of in the corresponding NSView methods. */
2450 /* has movement gone beyond last rect we were tracking? */
2451 if (x < r->origin.x || x >= r->origin.x + r->size.width
2452 || y < r->origin.y || y >= r->origin.y + r->size.height)
2454 ns_update_begin (frame);
2455 frame->mouse_moved = 1;
2456 note_mouse_highlight (frame, x, y);
2457 remember_mouse_glyph (frame, x, y, r);
2458 ns_update_end (frame);
2467 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
2468 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
2470 /* --------------------------------------------------------------------------
2471 External (hook): inform emacs about mouse position and hit parts.
2472 If a scrollbar is being dragged, set bar_window, part, x, y, time.
2473 x & y should be position in the scrollbar (the whole bar, not the handle)
2474 and length of scrollbar respectively
2475 -------------------------------------------------------------------------- */
2479 Lisp_Object frame, tail;
2481 struct ns_display_info *dpyinfo;
2483 NSTRACE ("ns_mouse_position");
2487 fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
2491 dpyinfo = FRAME_DISPLAY_INFO (*fp);
2495 /* Clear the mouse-moved flag for every frame on this display. */
2496 FOR_EACH_FRAME (tail, frame)
2497 if (FRAME_NS_P (XFRAME (frame))
2498 && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
2499 XFRAME (frame)->mouse_moved = 0;
2501 dpyinfo->last_mouse_scroll_bar = nil;
2502 if (dpyinfo->last_mouse_frame
2503 && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
2504 f = dpyinfo->last_mouse_frame;
2506 f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame : SELECTED_FRAME ();
2508 if (f && FRAME_NS_P (f))
2510 view = FRAME_NS_VIEW (*fp);
2512 position = [[view window] mouseLocationOutsideOfEventStream];
2513 position = [view convertPoint: position fromView: nil];
2514 remember_mouse_glyph (f, position.x, position.y,
2515 &dpyinfo->last_mouse_glyph);
2516 NSTRACE_POINT ("position", position);
2518 if (bar_window) *bar_window = Qnil;
2519 if (part) *part = scroll_bar_above_handle;
2521 if (x) XSETINT (*x, lrint (position.x));
2522 if (y) XSETINT (*y, lrint (position.y));
2524 *time = dpyinfo->last_mouse_movement_time;
2533 ns_frame_up_to_date (struct frame *f)
2534 /* --------------------------------------------------------------------------
2535 External (hook): Fix up mouse highlighting right after a full update.
2536 Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
2537 -------------------------------------------------------------------------- */
2539 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_frame_up_to_date");
2543 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
2544 if (f == hlinfo->mouse_face_mouse_frame)
2548 note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
2549 hlinfo->mouse_face_mouse_x,
2550 hlinfo->mouse_face_mouse_y);
2559 ns_define_frame_cursor (struct frame *f, Cursor cursor)
2560 /* --------------------------------------------------------------------------
2561 External (RIF): set frame mouse pointer type.
2562 -------------------------------------------------------------------------- */
2564 NSTRACE ("ns_define_frame_cursor");
2565 if (FRAME_POINTER_TYPE (f) != cursor)
2567 EmacsView *view = FRAME_NS_VIEW (f);
2568 FRAME_POINTER_TYPE (f) = cursor;
2569 [[view window] invalidateCursorRectsForView: view];
2570 /* Redisplay assumes this function also draws the changed frame
2571 cursor, but this function doesn't, so do it explicitly. */
2572 x_update_cursor (f, 1);
2578 /* ==========================================================================
2582 ========================================================================== */
2586 ns_convert_key (unsigned code)
2587 /* --------------------------------------------------------------------------
2588 Internal call used by NSView-keyDown.
2589 -------------------------------------------------------------------------- */
2591 const unsigned last_keysym = ARRAYELTS (convert_ns_to_X_keysym);
2593 /* An array would be faster, but less easy to read. */
2594 for (keysym = 0; keysym < last_keysym; keysym += 2)
2595 if (code == convert_ns_to_X_keysym[keysym])
2596 return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
2598 /* if decide to use keyCode and Carbon table, use this line:
2599 return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
2604 x_get_keysym_name (int keysym)
2605 /* --------------------------------------------------------------------------
2606 Called by keyboard.c. Not sure if the return val is important, except
2608 -------------------------------------------------------------------------- */
2610 static char value[16];
2611 NSTRACE ("x_get_keysym_name");
2612 sprintf (value, "%d", keysym);
2618 /* ==========================================================================
2620 Block drawing operations
2622 ========================================================================== */
2626 ns_redraw_scroll_bars (struct frame *f)
2630 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2631 NSTRACE ("ns_redraw_scroll_bars");
2632 for (i =[subviews count]-1; i >= 0; i--)
2634 view = [subviews objectAtIndex: i];
2635 if (![view isKindOfClass: [EmacsScroller class]]) continue;
2642 ns_clear_frame (struct frame *f)
2643 /* --------------------------------------------------------------------------
2644 External (hook): Erase the entire frame
2645 -------------------------------------------------------------------------- */
2647 NSView *view = FRAME_NS_VIEW (f);
2650 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame");
2652 /* comes on initial frame because we have
2653 after-make-frame-functions = select-frame */
2654 if (!FRAME_DEFAULT_FACE (f))
2657 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2662 ns_focus (f, &r, 1);
2663 [ns_lookup_indexed_color (NS_FACE_BACKGROUND
2664 (FACE_FROM_ID (f, DEFAULT_FACE_ID)), f) set];
2668 /* as of 2006/11 or so this is now needed */
2669 ns_redraw_scroll_bars (f);
2675 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2676 /* --------------------------------------------------------------------------
2677 External (RIF): Clear section of frame
2678 -------------------------------------------------------------------------- */
2680 NSRect r = NSMakeRect (x, y, width, height);
2681 NSView *view = FRAME_NS_VIEW (f);
2682 struct face *face = FRAME_DEFAULT_FACE (f);
2687 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame_area");
2689 r = NSIntersectionRect (r, [view frame]);
2690 ns_focus (f, &r, 1);
2691 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2700 ns_copy_bits (struct frame *f, NSRect src, NSRect dest)
2702 NSTRACE ("ns_copy_bits");
2704 if (FRAME_NS_VIEW (f))
2706 hide_bell(); // Ensure the bell image isn't scrolled.
2708 ns_focus (f, &dest, 1);
2709 [FRAME_NS_VIEW (f) scrollRect: src
2710 by: NSMakeSize (dest.origin.x - src.origin.x,
2711 dest.origin.y - src.origin.y)];
2717 ns_scroll_run (struct window *w, struct run *run)
2718 /* --------------------------------------------------------------------------
2719 External (RIF): Insert or delete n lines at line vpos
2720 -------------------------------------------------------------------------- */
2722 struct frame *f = XFRAME (w->frame);
2723 int x, y, width, height, from_y, to_y, bottom_y;
2725 NSTRACE ("ns_scroll_run");
2727 /* begin copy from other terms */
2728 /* Get frame-relative bounding box of the text display area of W,
2729 without mode lines. Include in this box the left and right
2731 window_box (w, ANY_AREA, &x, &y, &width, &height);
2733 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2734 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2735 bottom_y = y + height;
2739 /* Scrolling up. Make sure we don't copy part of the mode
2740 line at the bottom. */
2741 if (from_y + run->height > bottom_y)
2742 height = bottom_y - from_y;
2744 height = run->height;
2748 /* Scrolling down. Make sure we don't copy over the mode line.
2750 if (to_y + run->height > bottom_y)
2751 height = bottom_y - to_y;
2753 height = run->height;
2755 /* end copy from other terms */
2765 NSRect srcRect = NSMakeRect (x, from_y, width, height);
2766 NSRect dstRect = NSMakeRect (x, to_y, width, height);
2768 ns_copy_bits (f, srcRect , dstRect);
2776 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2777 /* --------------------------------------------------------------------------
2778 External (RIF): preparatory to fringe update after text was updated
2779 -------------------------------------------------------------------------- */
2784 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_after_update_window_line");
2786 /* begin copy from other terms */
2789 if (!desired_row->mode_line_p && !w->pseudo_window_p)
2790 desired_row->redraw_fringe_bitmaps_p = 1;
2792 /* When a window has disappeared, make sure that no rest of
2793 full-width rows stays visible in the internal border. */
2794 if (windows_or_buffers_changed
2795 && desired_row->full_width_p
2796 && (f = XFRAME (w->frame),
2797 width = FRAME_INTERNAL_BORDER_WIDTH (f),
2799 && (height = desired_row->visible_height,
2802 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2805 ns_clear_frame_area (f, 0, y, width, height);
2806 ns_clear_frame_area (f,
2807 FRAME_PIXEL_WIDTH (f) - width,
2815 ns_shift_glyphs_for_insert (struct frame *f,
2816 int x, int y, int width, int height,
2818 /* --------------------------------------------------------------------------
2819 External (RIF): copy an area horizontally, don't worry about clearing src
2820 -------------------------------------------------------------------------- */
2822 NSRect srcRect = NSMakeRect (x, y, width, height);
2823 NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2825 NSTRACE ("ns_shift_glyphs_for_insert");
2827 ns_copy_bits (f, srcRect, dstRect);
2832 /* ==========================================================================
2834 Character encoding and metrics
2836 ========================================================================== */
2840 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2841 /* --------------------------------------------------------------------------
2842 External (RIF); compute left/right overhang of whole string and set in s
2843 -------------------------------------------------------------------------- */
2845 struct font *font = s->font;
2849 struct font_metrics metrics;
2850 unsigned int codes[2];
2851 codes[0] = *(s->char2b);
2852 codes[1] = *(s->char2b + s->nchars - 1);
2854 font->driver->text_extents (font, codes, 2, &metrics);
2855 s->left_overhang = -metrics.lbearing;
2857 = metrics.rbearing > metrics.width
2858 ? metrics.rbearing - metrics.width : 0;
2862 s->left_overhang = 0;
2863 if (EQ (font->driver->type, Qns))
2864 s->right_overhang = ((struct nsfont_info *)font)->ital ?
2865 FONT_HEIGHT (font) * 0.2 : 0;
2867 s->right_overhang = 0;
2873 /* ==========================================================================
2875 Fringe and cursor drawing
2877 ========================================================================== */
2880 extern int max_used_fringe_bitmap;
2882 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2883 struct draw_fringe_bitmap_params *p)
2884 /* --------------------------------------------------------------------------
2885 External (RIF); fringe-related
2886 -------------------------------------------------------------------------- */
2888 /* Fringe bitmaps comes in two variants, normal and periodic. A
2889 periodic bitmap is used to create a continuous pattern. Since a
2890 bitmap is rendered one text line at a time, the start offset (dh)
2891 of the bitmap varies. Concretely, this is used for the empty
2894 For a bitmap, "h + dh" is the full height and is always
2895 invariant. For a normal bitmap "dh" is zero.
2897 For example, when the period is three and the full height is 72
2898 the following combinations exists:
2904 struct frame *f = XFRAME (WINDOW_FRAME (w));
2905 struct face *face = p->face;
2906 static EmacsImage **bimgs = NULL;
2907 static int nBimgs = 0;
2909 NSTRACE_WHEN (NSTRACE_GROUP_FRINGE, "ns_draw_fringe_bitmap");
2910 NSTRACE_MSG ("which:%d cursor:%d overlay:%d width:%d height:%d period:%d",
2911 p->which, p->cursor_p, p->overlay_p, p->wd, p->h, p->dh);
2913 /* grow bimgs if needed */
2914 if (nBimgs < max_used_fringe_bitmap)
2916 bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2917 memset (bimgs + nBimgs, 0,
2918 (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2919 nBimgs = max_used_fringe_bitmap;
2922 /* Must clip because of partially visible lines. */
2923 ns_clip_to_row (w, row, ANY_AREA, YES);
2927 int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2929 if (bx >= 0 && nx > 0)
2931 NSRect r = NSMakeRect (bx, by, nx, ny);
2933 [ns_lookup_indexed_color (face->background, f) set];
2940 NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2941 EmacsImage *img = bimgs[p->which - 1];
2945 // Note: For "periodic" images, allocate one EmacsImage for
2946 // the base image, and use it for all dh:s.
2947 unsigned short *bits = p->bits;
2948 int full_height = p->h + p->dh;
2950 unsigned char *cbits = xmalloc (full_height);
2952 for (i = 0; i < full_height; i++)
2954 img = [[EmacsImage alloc] initFromXBM: cbits width: 8
2957 bimgs[p->which - 1] = img;
2961 NSTRACE_RECT ("r", r);
2964 /* Since we composite the bitmap instead of just blitting it, we need
2965 to erase the whole background. */
2966 [ns_lookup_indexed_color(face->background, f) set];
2972 bm_color = ns_lookup_indexed_color(face->foreground, f);
2973 else if (p->overlay_p)
2974 bm_color = ns_lookup_indexed_color(face->background, f);
2976 bm_color = f->output_data.ns->cursor_color;
2977 [img setXBMColor: bm_color];
2980 #ifdef NS_IMPL_COCOA
2981 // Note: For periodic images, the full image height is "h + hd".
2982 // By using the height h, a suitable part of the image is used.
2983 NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h);
2985 NSTRACE_RECT ("fromRect", fromRect);
2989 operation: NSCompositingOperationSourceOver
2995 NSPoint pt = r.origin;
2997 [img compositeToPoint: pt operation: NSCompositingOperationSourceOver];
3006 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
3007 int x, int y, enum text_cursor_kinds cursor_type,
3008 int cursor_width, bool on_p, bool active_p)
3009 /* --------------------------------------------------------------------------
3010 External call (RIF): draw cursor.
3011 Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
3012 -------------------------------------------------------------------------- */
3015 int fx, fy, h, cursor_height;
3016 struct frame *f = WINDOW_XFRAME (w);
3017 struct glyph *phys_cursor_glyph;
3018 struct glyph *cursor_glyph;
3020 NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
3022 /* If cursor is out of bounds, don't draw garbage. This can happen
3023 in mini-buffer windows when switching between echo area glyphs
3026 NSTRACE ("ns_draw_window_cursor");
3031 w->phys_cursor_type = cursor_type;
3032 w->phys_cursor_on_p = on_p;
3034 if (cursor_type == NO_CURSOR)
3036 w->phys_cursor_width = 0;
3040 if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
3042 if (glyph_row->exact_window_width_line_p
3043 && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
3045 glyph_row->cursor_in_fringe_p = 1;
3046 draw_fringe_bitmap (w, glyph_row, 0);
3051 /* We draw the cursor (with NSRectFill), then draw the glyph on top
3052 (other terminals do it the other way round). We must set
3053 w->phys_cursor_width to the cursor width. For bar cursors, that
3054 is CURSOR_WIDTH; for box cursors, it is the glyph width. */
3055 get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
3057 /* The above get_phys_cursor_geometry call set w->phys_cursor_width
3058 to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
3059 if (cursor_type == BAR_CURSOR)
3061 if (cursor_width < 1)
3062 cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
3064 /* The bar cursor should never be wider than the glyph. */
3065 if (cursor_width < w->phys_cursor_width)
3066 w->phys_cursor_width = cursor_width;
3068 /* If we have an HBAR, "cursor_width" MAY specify height. */
3069 else if (cursor_type == HBAR_CURSOR)
3071 cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
3072 if (cursor_height > glyph_row->height)
3073 cursor_height = glyph_row->height;
3074 if (h > cursor_height) // Cursor smaller than line height, move down
3075 fy += h - cursor_height;
3079 r.origin.x = fx, r.origin.y = fy;
3081 r.size.width = w->phys_cursor_width;
3083 /* Prevent the cursor from being drawn outside the text area. */
3084 ns_clip_to_row (w, glyph_row, TEXT_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
3087 face = FACE_FROM_ID_OR_NULL (f, phys_cursor_glyph->face_id);
3088 if (face && NS_FACE_BACKGROUND (face)
3089 == ns_index_color (FRAME_CURSOR_COLOR (f), f))
3091 [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
3092 hollow_color = FRAME_CURSOR_COLOR (f);
3095 [FRAME_CURSOR_COLOR (f) set];
3097 #ifdef NS_IMPL_COCOA
3098 /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
3099 atomic. Cleaner ways of doing this should be investigated.
3100 One way would be to set a global variable DRAWING_CURSOR
3101 when making the call to draw_phys..(), don't focus in that
3102 case, then move the ns_unfocus() here after that call. */
3103 NSDisableScreenUpdates ();
3106 switch (cursor_type)
3108 case DEFAULT_CURSOR:
3111 case FILLED_BOX_CURSOR:
3114 case HOLLOW_BOX_CURSOR:
3117 NSRectFill (NSInsetRect (r, 1, 1));
3118 [FRAME_CURSOR_COLOR (f) set];
3125 /* If the character under cursor is R2L, draw the bar cursor
3126 on the right of its glyph, rather than on the left. */
3127 cursor_glyph = get_phys_cursor_glyph (w);
3128 if ((cursor_glyph->resolved_level & 1) != 0)
3129 s.origin.x += cursor_glyph->pixel_width - s.size.width;
3136 /* draw the character under the cursor */
3137 if (cursor_type != NO_CURSOR)
3138 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
3140 #ifdef NS_IMPL_COCOA
3141 NSEnableScreenUpdates ();
3148 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
3149 /* --------------------------------------------------------------------------
3150 External (RIF): Draw a vertical line.
3151 -------------------------------------------------------------------------- */
3153 struct frame *f = XFRAME (WINDOW_FRAME (w));
3155 NSRect r = NSMakeRect (x, y0, 1, y1-y0);
3157 NSTRACE ("ns_draw_vertical_window_border");
3159 face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID);
3161 ns_focus (f, &r, 1);
3163 [ns_lookup_indexed_color(face->foreground, f) set];
3171 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
3172 /* --------------------------------------------------------------------------
3173 External (RIF): Draw a window divider.
3174 -------------------------------------------------------------------------- */
3176 struct frame *f = XFRAME (WINDOW_FRAME (w));
3178 NSRect r = NSMakeRect (x0, y0, x1-x0, y1-y0);
3180 NSTRACE ("ns_draw_window_divider");
3182 face = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FACE_ID);
3184 ns_focus (f, &r, 1);
3186 [ns_lookup_indexed_color(face->foreground, f) set];
3193 ns_show_hourglass (struct frame *f)
3195 /* TODO: add NSProgressIndicator to all frames. */
3199 ns_hide_hourglass (struct frame *f)
3201 /* TODO: remove NSProgressIndicator from all frames. */
3204 /* ==========================================================================
3206 Glyph drawing operations
3208 ========================================================================== */
3211 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
3212 /* --------------------------------------------------------------------------
3213 Wrapper utility to account for internal border width on full-width lines,
3214 and allow top full-width rows to hit the frame top. nr should be pointer
3215 to two successive NSRects. Number of rects actually used is returned.
3216 -------------------------------------------------------------------------- */
3218 int n = get_glyph_string_clip_rects (s, nr, 2);
3222 /* --------------------------------------------------------------------
3223 Draw a wavy line under glyph string s. The wave fills wave_height
3230 wave_height = 3 | * * * *
3231 --------------------------------------------------------------------- */
3234 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
3236 int wave_height = 3, wave_length = 2;
3237 int y, dx, dy, odd, xmax;
3242 dy = wave_height - 1;
3243 y = s->ybase - wave_height + 3;
3246 /* Find and set clipping rectangle */
3247 waveClip = NSMakeRect (x, y, width, wave_height);
3248 [[NSGraphicsContext currentContext] saveGraphicsState];
3249 NSRectClip (waveClip);
3251 /* Draw the waves */
3252 a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
3254 odd = (int)(a.x/dx) % 2;
3255 a.y = b.y = y + 0.5;
3264 [NSBezierPath strokeLineFromPoint:a toPoint:b];
3265 a.x = b.x, a.y = b.y;
3266 b.x += dx, b.y = y + 0.5 + odd*dy;
3270 /* Restore previous clipping rectangle(s) */
3271 [[NSGraphicsContext currentContext] restoreGraphicsState];
3277 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
3278 NSColor *defaultCol, CGFloat width, CGFloat x)
3279 /* --------------------------------------------------------------------------
3280 Draw underline, overline, and strike-through on glyph string s.
3281 -------------------------------------------------------------------------- */
3283 if (s->for_overlaps)
3287 if (face->underline_p)
3289 if (s->face->underline_type == FACE_UNDER_WAVE)
3291 if (face->underline_defaulted_p)
3294 [ns_lookup_indexed_color (face->underline_color, s->f) set];
3296 ns_draw_underwave (s, width, x);
3298 else if (s->face->underline_type == FACE_UNDER_LINE)
3302 unsigned long thickness, position;
3304 /* If the prev was underlined, match its appearance. */
3305 if (s->prev && s->prev->face->underline_p
3306 && s->prev->face->underline_type == FACE_UNDER_LINE
3307 && s->prev->underline_thickness > 0)
3309 thickness = s->prev->underline_thickness;
3310 position = s->prev->underline_position;
3314 struct font *font = font_for_underline_metrics (s);
3315 unsigned long descent = s->y + s->height - s->ybase;
3317 /* Use underline thickness of font, defaulting to 1. */
3318 thickness = (font && font->underline_thickness > 0)
3319 ? font->underline_thickness : 1;
3321 /* Determine the offset of underlining from the baseline. */
3322 if (x_underline_at_descent_line)
3323 position = descent - thickness;
3324 else if (x_use_underline_position_properties
3325 && font && font->underline_position >= 0)
3326 position = font->underline_position;
3328 position = lround (font->descent / 2);
3330 position = underline_minimum_offset;
3332 position = max (position, underline_minimum_offset);
3334 /* Ensure underlining is not cropped. */
3335 if (descent <= position)
3337 position = descent - 1;
3340 else if (descent < position + thickness)
3344 s->underline_thickness = thickness;
3345 s->underline_position = position;
3347 r = NSMakeRect (x, s->ybase + position, width, thickness);
3349 if (face->underline_defaulted_p)
3352 [ns_lookup_indexed_color (face->underline_color, s->f) set];
3356 /* Do overline. We follow other terms in using a thickness of 1
3357 and ignoring overline_margin. */
3358 if (face->overline_p)
3361 r = NSMakeRect (x, s->y, width, 1);
3363 if (face->overline_color_defaulted_p)
3366 [ns_lookup_indexed_color (face->overline_color, s->f) set];
3370 /* Do strike-through. We follow other terms for thickness and
3371 vertical position.*/
3372 if (face->strike_through_p)
3375 /* Y-coordinate and height of the glyph string's first glyph.
3376 We cannot use s->y and s->height because those could be
3377 larger if there are taller display elements (e.g., characters
3378 displayed with a larger font) in the same glyph row. */
3379 int glyph_y = s->ybase - s->first_glyph->ascent;
3380 int glyph_height = s->first_glyph->ascent + s->first_glyph->descent;
3381 /* Strike-through width and offset from the glyph string's
3383 unsigned long h = 1;
3386 dy = lrint ((glyph_height - h) / 2);
3387 r = NSMakeRect (x, glyph_y + dy, width, 1);
3389 if (face->strike_through_color_defaulted_p)
3392 [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
3398 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
3399 char left_p, char right_p)
3400 /* --------------------------------------------------------------------------
3401 Draw an unfilled rect inside r, optionally leaving left and/or right open.
3402 Note we can't just use an NSDrawRect command, because of the possibility
3403 of some sides not being drawn, and because the rect will be filled.
3404 -------------------------------------------------------------------------- */
3410 s.size.height = thickness;
3412 s.origin.y += r.size.height - thickness;
3415 s.size.height = r.size.height;
3416 s.origin.y = r.origin.y;
3418 /* left, right (optional) */
3419 s.size.width = thickness;
3424 s.origin.x += r.size.width - thickness;
3431 ns_draw_relief (NSRect r, int thickness, char raised_p,
3432 char top_p, char bottom_p, char left_p, char right_p,
3433 struct glyph_string *s)
3434 /* --------------------------------------------------------------------------
3435 Draw a relief rect inside r, optionally leaving some sides open.
3436 Note we can't just use an NSDrawBezel command, because of the possibility
3437 of some sides not being drawn, and because the rect will be filled.
3438 -------------------------------------------------------------------------- */
3440 static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
3441 NSColor *newBaseCol = nil;
3444 NSTRACE ("ns_draw_relief");
3448 if (s->face->use_box_color_for_shadows_p)
3450 newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
3452 /* else if (s->first_glyph->type == IMAGE_GLYPH
3454 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3456 newBaseCol = IMAGE_BACKGROUND (s->img, s->f, 0);
3460 newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
3463 if (newBaseCol == nil)
3464 newBaseCol = [NSColor grayColor];
3466 if (newBaseCol != baseCol) /* TODO: better check */
3469 baseCol = [newBaseCol retain];
3471 lightCol = [[baseCol highlightWithLevel: 0.2] retain];
3473 darkCol = [[baseCol shadowWithLevel: 0.3] retain];
3476 [(raised_p ? lightCol : darkCol) set];
3478 /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
3481 sr.size.height = thickness;
3482 if (top_p) NSRectFill (sr);
3485 sr.size.height = r.size.height;
3486 sr.size.width = thickness;
3487 if (left_p) NSRectFill (sr);
3489 [(raised_p ? darkCol : lightCol) set];
3492 sr.size.width = r.size.width;
3493 sr.size.height = thickness;
3494 sr.origin.y += r.size.height - thickness;
3495 if (bottom_p) NSRectFill (sr);
3498 sr.size.height = r.size.height;
3499 sr.origin.y = r.origin.y;
3500 sr.size.width = thickness;
3501 sr.origin.x += r.size.width - thickness;
3502 if (right_p) NSRectFill (sr);
3507 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
3508 /* --------------------------------------------------------------------------
3509 Function modeled after x_draw_glyph_string_box ().
3510 Sets up parameters for drawing.
3511 -------------------------------------------------------------------------- */
3513 int right_x, last_x;
3514 char left_p, right_p;
3515 struct glyph *last_glyph;
3520 if (s->hl == DRAW_MOUSE_FACE)
3522 face = FACE_FROM_ID_OR_NULL (s->f,
3523 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3525 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3530 thickness = face->box_line_width;
3532 NSTRACE ("ns_dumpglyphs_box_or_relief");
3534 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
3535 ? WINDOW_RIGHT_EDGE_X (s->w)
3536 : window_box_right (s->w, s->area));
3537 last_glyph = (s->cmp || s->img
3538 ? s->first_glyph : s->first_glyph + s->nchars-1);
3540 right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
3541 ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
3543 left_p = (s->first_glyph->left_box_line_p
3544 || (s->hl == DRAW_MOUSE_FACE
3545 && (s->prev == NULL || s->prev->hl != s->hl)));
3546 right_p = (last_glyph->right_box_line_p
3547 || (s->hl == DRAW_MOUSE_FACE
3548 && (s->next == NULL || s->next->hl != s->hl)));
3550 r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
3552 /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
3553 if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
3555 ns_draw_box (r, abs (thickness),
3556 ns_lookup_indexed_color (face->box_color, s->f),
3561 ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
3562 1, 1, left_p, right_p, s);
3568 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
3569 /* --------------------------------------------------------------------------
3570 Modeled after x_draw_glyph_string_background, which draws BG in
3571 certain cases. Others are left to the text rendering routine.
3572 -------------------------------------------------------------------------- */
3574 NSTRACE ("ns_maybe_dumpglyphs_background");
3576 if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
3578 int box_line_width = max (s->face->box_line_width, 0);
3579 if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
3580 /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font
3581 dimensions, since the actual glyphs might be much
3582 smaller. So in that case we always clear the rectangle
3583 with background color. */
3584 || FONT_TOO_HIGH (s->font)
3585 || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
3588 if (s->hl == DRAW_MOUSE_FACE)
3591 = FACE_FROM_ID_OR_NULL (s->f,
3592 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3594 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3597 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3599 [(NS_FACE_BACKGROUND (face) != 0
3600 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
3601 : FRAME_BACKGROUND_COLOR (s->f)) set];
3604 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
3605 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
3608 if (s->hl != DRAW_CURSOR)
3610 NSRect r = NSMakeRect (s->x, s->y + box_line_width,
3611 s->background_width,
3612 s->height-2*box_line_width);
3616 s->background_filled_p = 1;
3623 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3624 /* --------------------------------------------------------------------------
3625 Renders an image and associated borders.
3626 -------------------------------------------------------------------------- */
3628 EmacsImage *img = s->img->pixmap;
3629 int box_line_vwidth = max (s->face->box_line_width, 0);
3630 int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3631 int bg_x, bg_y, bg_height;
3638 NSTRACE ("ns_dumpglyphs_image");
3640 if (s->face->box != FACE_NO_BOX
3641 && s->first_glyph->left_box_line_p && s->slice.x == 0)
3642 x += abs (s->face->box_line_width);
3645 bg_y = s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
3646 bg_height = s->height;
3647 /* other terms have this, but was causing problems w/tabbar mode */
3648 /* - 2 * box_line_vwidth; */
3650 if (s->slice.x == 0) x += s->img->hmargin;
3651 if (s->slice.y == 0) y += s->img->vmargin;
3653 /* Draw BG: if we need larger area than image itself cleared, do that,
3654 otherwise, since we composite the image under NS (instead of mucking
3655 with its background color), we must clear just the image area. */
3656 if (s->hl == DRAW_MOUSE_FACE)
3658 face = FACE_FROM_ID_OR_NULL (s->f,
3659 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3661 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3664 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3666 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3668 if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3669 || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3671 br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3672 s->background_filled_p = 1;
3676 br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3681 /* Draw the image.. do we need to draw placeholder if img ==nil? */
3684 #ifdef NS_IMPL_COCOA
3685 NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3686 NSRect ir = NSMakeRect (s->slice.x,
3687 s->img->height - s->slice.y - s->slice.height,
3688 s->slice.width, s->slice.height);
3691 operation: NSCompositingOperationSourceOver
3696 [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3697 operation: NSCompositingOperationSourceOver];
3701 if (s->hl == DRAW_CURSOR)
3703 [FRAME_CURSOR_COLOR (s->f) set];
3704 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3705 tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3707 /* Currently on NS img->mask is always 0. Since
3708 get_window_cursor_type specifies a hollow box cursor when on
3709 a non-masked image we never reach this clause. But we put it
3710 in, in anticipation of better support for image masks on
3712 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3716 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3719 /* Draw underline, overline, strike-through. */
3720 ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3722 /* Draw relief, if requested */
3723 if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3725 if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3727 th = tool_bar_button_relief >= 0 ?
3728 tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3729 raised_p = (s->hl == DRAW_IMAGE_RAISED);
3733 th = abs (s->img->relief);
3734 raised_p = (s->img->relief > 0);
3737 r.origin.x = x - th;
3738 r.origin.y = y - th;
3739 r.size.width = s->slice.width + 2*th-1;
3740 r.size.height = s->slice.height + 2*th-1;
3741 ns_draw_relief (r, th, raised_p,
3743 s->slice.y + s->slice.height == s->img->height,
3745 s->slice.x + s->slice.width == s->img->width, s);
3748 /* If there is no mask, the background won't be seen,
3749 so draw a rectangle on the image for the cursor.
3750 Do this for all images, getting transparency right is not reliable. */
3751 if (s->hl == DRAW_CURSOR)
3753 int thickness = abs (s->img->relief);
3754 if (thickness == 0) thickness = 1;
3755 ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3761 ns_dumpglyphs_stretch (struct glyph_string *s)
3766 NSColor *fgCol, *bgCol;
3768 if (!s->background_filled_p)
3770 n = ns_get_glyph_string_clip_rect (s, r);
3771 *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3773 ns_focus (s->f, r, n);
3775 if (s->hl == DRAW_MOUSE_FACE)
3777 face = FACE_FROM_ID_OR_NULL (s->f,
3778 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3780 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3783 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3785 bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3786 fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3788 for (i = 0; i < n; ++i)
3790 if (!s->row->full_width_p)
3792 int overrun, leftoverrun;
3794 /* truncate to avoid overwriting fringe and/or scrollbar */
3795 overrun = max (0, (s->x + s->background_width)
3796 - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3797 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3798 r[i].size.width -= overrun;
3800 /* truncate to avoid overwriting to left of the window box */
3801 leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3802 + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3804 if (leftoverrun > 0)
3806 r[i].origin.x += leftoverrun;
3807 r[i].size.width -= leftoverrun;
3810 /* XXX: Try to work between problem where a stretch glyph on
3811 a partially-visible bottom row will clear part of the
3812 modeline, and another where list-buffers headers and similar
3813 rows erroneously have visible_height set to 0. Not sure
3814 where this is coming from as other terms seem not to show. */
3815 r[i].size.height = min (s->height, s->row->visible_height);
3820 /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3821 overwriting cursor (usually when cursor on a tab) */
3822 if (s->hl == DRAW_CURSOR)
3827 width = s->w->phys_cursor_width;
3828 r[i].size.width -= width;
3829 r[i].origin.x += width;
3833 /* Draw overlining, etc. on the cursor. */
3834 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3835 ns_draw_text_decoration (s, face, bgCol, width, x);
3837 ns_draw_text_decoration (s, face, fgCol, width, x);
3844 /* Draw overlining, etc. on the stretch glyph (or the part
3845 of the stretch glyph after the cursor). */
3846 ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3850 s->background_filled_p = 1;
3856 ns_draw_glyph_string_foreground (struct glyph_string *s)
3859 struct font *font = s->font;
3861 /* If first glyph of S has a left box line, start drawing the text
3862 of S to the right of that box line. */
3863 if (s->face && s->face->box != FACE_NO_BOX
3864 && s->first_glyph->left_box_line_p)
3865 x = s->x + eabs (s->face->box_line_width);
3869 flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3870 (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3871 (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3872 NS_DUMPGLYPH_NORMAL));
3875 (s, s->cmp_from, s->nchars, x, s->ybase,
3876 (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3877 || flags == NS_DUMPGLYPH_MOUSEFACE);
3882 ns_draw_composite_glyph_string_foreground (struct glyph_string *s)
3885 struct font *font = s->font;
3887 /* If first glyph of S has a left box line, start drawing the text
3888 of S to the right of that box line. */
3889 if (s->face && s->face->box != FACE_NO_BOX
3890 && s->first_glyph->left_box_line_p)
3891 x = s->x + eabs (s->face->box_line_width);
3895 /* S is a glyph string for a composition. S->cmp_from is the index
3896 of the first character drawn for glyphs of this composition.
3897 S->cmp_from == 0 means we are drawing the very first character of
3898 this composition. */
3900 /* Draw a rectangle for the composition if the font for the very
3901 first character of the composition could not be loaded. */
3902 if (s->font_not_found_p)
3904 if (s->cmp_from == 0)
3906 NSRect r = NSMakeRect (s->x, s->y, s->width-1, s->height -1);
3907 ns_draw_box (r, 1, FRAME_CURSOR_COLOR (s->f), 1, 1);
3910 else if (! s->first_glyph->u.cmp.automatic)
3914 for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
3915 /* TAB in a composition means display glyphs with padding
3916 space on the left or right. */
3917 if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
3919 int xx = x + s->cmp->offsets[j * 2];
3920 int yy = y - s->cmp->offsets[j * 2 + 1];
3922 font->driver->draw (s, j, j + 1, xx, yy, false);
3923 if (s->face->overstrike)
3924 font->driver->draw (s, j, j + 1, xx + 1, yy, false);
3929 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
3934 for (i = j = s->cmp_from; i < s->cmp_to; i++)
3936 glyph = LGSTRING_GLYPH (gstring, i);
3937 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
3938 width += LGLYPH_WIDTH (glyph);
3941 int xoff, yoff, wadjust;
3945 font->driver->draw (s, j, i, x, y, false);
3946 if (s->face->overstrike)
3947 font->driver->draw (s, j, i, x + 1, y, false);
3950 xoff = LGLYPH_XOFF (glyph);
3951 yoff = LGLYPH_YOFF (glyph);
3952 wadjust = LGLYPH_WADJUST (glyph);
3953 font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
3954 if (s->face->overstrike)
3955 font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
3964 font->driver->draw (s, j, i, x, y, false);
3965 if (s->face->overstrike)
3966 font->driver->draw (s, j, i, x + 1, y, false);
3972 ns_draw_glyph_string (struct glyph_string *s)
3973 /* --------------------------------------------------------------------------
3974 External (RIF): Main draw-text call.
3975 -------------------------------------------------------------------------- */
3977 /* TODO (optimize): focus for box and contents draw */
3980 char box_drawn_p = 0;
3981 struct font *font = s->face->font;
3982 if (! font) font = FRAME_FONT (s->f);
3984 NSTRACE_WHEN (NSTRACE_GROUP_GLYPHS, "ns_draw_glyph_string");
3986 if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3989 struct glyph_string *next;
3991 for (width = 0, next = s->next;
3992 next && width < s->right_overhang;
3993 width += next->width, next = next->next)
3994 if (next->first_glyph->type != IMAGE_GLYPH)
3996 if (next->first_glyph->type != STRETCH_GLYPH)
3998 n = ns_get_glyph_string_clip_rect (s->next, r);
3999 ns_focus (s->f, r, n);
4000 ns_maybe_dumpglyphs_background (s->next, 1);
4005 ns_dumpglyphs_stretch (s->next);
4007 next->num_clips = 0;
4011 if (!s->for_overlaps && s->face->box != FACE_NO_BOX
4012 && (s->first_glyph->type == CHAR_GLYPH
4013 || s->first_glyph->type == COMPOSITE_GLYPH))
4015 n = ns_get_glyph_string_clip_rect (s, r);
4016 ns_focus (s->f, r, n);
4017 ns_maybe_dumpglyphs_background (s, 1);
4018 ns_dumpglyphs_box_or_relief (s);
4023 switch (s->first_glyph->type)
4027 n = ns_get_glyph_string_clip_rect (s, r);
4028 ns_focus (s->f, r, n);
4029 ns_dumpglyphs_image (s, r[0]);
4034 ns_dumpglyphs_stretch (s);
4038 case COMPOSITE_GLYPH:
4039 n = ns_get_glyph_string_clip_rect (s, r);
4040 ns_focus (s->f, r, n);
4042 if (s->for_overlaps || (s->cmp_from > 0
4043 && ! s->first_glyph->u.cmp.automatic))
4044 s->background_filled_p = 1;
4046 ns_maybe_dumpglyphs_background
4047 (s, s->first_glyph->type == COMPOSITE_GLYPH);
4049 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
4051 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
4052 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
4053 NS_FACE_FOREGROUND (s->face) = tmp;
4057 BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
4060 ns_draw_composite_glyph_string_foreground (s);
4062 ns_draw_glyph_string_foreground (s);
4066 NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
4067 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
4069 : FRAME_FOREGROUND_COLOR (s->f));
4072 /* Draw underline, overline, strike-through. */
4073 ns_draw_text_decoration (s, s->face, col, s->width, s->x);
4076 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
4078 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
4079 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
4080 NS_FACE_FOREGROUND (s->face) = tmp;
4086 case GLYPHLESS_GLYPH:
4087 n = ns_get_glyph_string_clip_rect (s, r);
4088 ns_focus (s->f, r, n);
4090 if (s->for_overlaps || (s->cmp_from > 0
4091 && ! s->first_glyph->u.cmp.automatic))
4092 s->background_filled_p = 1;
4094 ns_maybe_dumpglyphs_background
4095 (s, s->first_glyph->type == COMPOSITE_GLYPH);
4097 /* Not yet implemented. */
4106 /* Draw box if not done already. */
4107 if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
4109 n = ns_get_glyph_string_clip_rect (s, r);
4110 ns_focus (s->f, r, n);
4111 ns_dumpglyphs_box_or_relief (s);
4120 /* ==========================================================================
4124 ========================================================================== */
4128 ns_send_appdefined (int value)
4129 /* --------------------------------------------------------------------------
4130 Internal: post an appdefined event which EmacsApp-sendEvent will
4131 recognize and take as a command to halt the event loop.
4132 -------------------------------------------------------------------------- */
4134 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_send_appdefined(%d)", value);
4136 // GNUstep needs postEvent to happen on the main thread.
4137 // Cocoa needs nextEventMatchingMask to happen on the main thread too.
4138 if (! [[NSThread currentThread] isMainThread])
4140 EmacsApp *app = (EmacsApp *)NSApp;
4141 app->nextappdefined = value;
4142 [app performSelectorOnMainThread:@selector (sendFromMainThread:)
4148 /* Only post this event if we haven't already posted one. This will end
4149 the [NXApp run] main loop after having processed all events queued at
4152 #ifdef NS_IMPL_COCOA
4153 if (! send_appdefined)
4155 /* OS X 10.10.1 swallows the AppDefined event we are sending ourselves
4156 in certain situations (rapid incoming events).
4157 So check if we have one, if not add one. */
4158 NSEvent *appev = [NSApp nextEventMatchingMask:NSEventMaskApplicationDefined
4159 untilDate:[NSDate distantPast]
4160 inMode:NSDefaultRunLoopMode
4162 if (! appev) send_appdefined = YES;
4166 if (send_appdefined)
4170 /* We only need one NX_APPDEFINED event to stop NXApp from running. */
4171 send_appdefined = NO;
4173 /* Don't need wakeup timer any more */
4176 [timed_entry invalidate];
4177 [timed_entry release];
4181 nxev = [NSEvent otherEventWithType: NSEventTypeApplicationDefined
4182 location: NSMakePoint (0, 0)
4185 windowNumber: [[NSApp mainWindow] windowNumber]
4186 context: [NSApp context]
4191 /* Post an application defined event on the event queue. When this is
4192 received the [NXApp run] will return, thus having processed all
4193 events which are currently queued. */
4194 [NSApp postEvent: nxev atStart: NO];
4198 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
4202 Lisp_Object frame, tail;
4204 if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
4207 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
4209 FOR_EACH_FRAME (tail, frame)
4211 struct frame *f = XFRAME (frame);
4214 EmacsView *view = FRAME_NS_VIEW (f);
4215 [view updateCollectionBehavior];
4221 /* GNUstep does not have cancelTracking. */
4222 #ifdef NS_IMPL_COCOA
4223 /* Check if menu open should be canceled or continued as normal. */
4225 ns_check_menu_open (NSMenu *menu)
4227 /* Click in menu bar? */
4228 NSArray *a = [[NSApp mainMenu] itemArray];
4232 if (menu == nil) // Menu tracking ended.
4234 if (menu_will_open_state == MENU_OPENING)
4235 menu_will_open_state = MENU_NONE;
4239 for (i = 0; ! found && i < [a count]; i++)
4240 found = menu == [[a objectAtIndex:i] submenu];
4243 if (menu_will_open_state == MENU_NONE && emacs_event)
4245 NSEvent *theEvent = [NSApp currentEvent];
4246 struct frame *emacsframe = SELECTED_FRAME ();
4248 [menu cancelTracking];
4249 menu_will_open_state = MENU_PENDING;
4250 emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
4251 EV_TRAILER (theEvent);
4253 CGEventRef ourEvent = CGEventCreate (NULL);
4254 menu_mouse_point = CGEventGetLocation (ourEvent);
4255 CFRelease (ourEvent);
4257 else if (menu_will_open_state == MENU_OPENING)
4259 menu_will_open_state = MENU_NONE;
4264 /* Redo saved menu click if state is MENU_PENDING. */
4266 ns_check_pending_open_menu ()
4268 if (menu_will_open_state == MENU_PENDING)
4270 CGEventSourceRef source
4271 = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
4273 CGEventRef event = CGEventCreateMouseEvent (source,
4274 kCGEventLeftMouseDown,
4276 kCGMouseButtonLeft);
4277 CGEventSetType (event, kCGEventLeftMouseDown);
4278 CGEventPost (kCGHIDEventTap, event);
4282 menu_will_open_state = MENU_OPENING;
4285 #endif /* NS_IMPL_COCOA */
4288 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
4289 /* --------------------------------------------------------------------------
4290 External (hook): Post an event to ourself and keep reading events until
4291 we read it back again. In effect process all events which were waiting.
4292 From 21+ we have to manage the event buffer ourselves.
4293 -------------------------------------------------------------------------- */
4295 struct input_event ev;
4298 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_read_socket");
4300 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
4304 if ([NSApp modalWindow] != nil)
4307 if (hold_event_q.nr > 0)
4310 for (i = 0; i < hold_event_q.nr; ++i)
4311 kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
4312 hold_event_q.nr = 0;
4316 if ([NSThread isMainThread])
4319 n_emacs_events_pending = 0;
4320 ns_init_events (&ev);
4321 q_event_ptr = hold_quit;
4323 /* we manage autorelease pools by allocate/reallocate each time around
4324 the loop; strict nesting is occasionally violated but seems not to
4325 matter.. earlier methods using full nesting caused major memory leaks */
4326 [outerpool release];
4327 outerpool = [[NSAutoreleasePool alloc] init];
4329 /* If have pending open-file requests, attend to the next one of those. */
4330 if (ns_pending_files && [ns_pending_files count] != 0
4331 && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
4333 [ns_pending_files removeObjectAtIndex: 0];
4335 /* Deal with pending service requests. */
4336 else if (ns_pending_service_names && [ns_pending_service_names count] != 0
4338 NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
4339 withArg: [ns_pending_service_args objectAtIndex: 0]])
4341 [ns_pending_service_names removeObjectAtIndex: 0];
4342 [ns_pending_service_args removeObjectAtIndex: 0];
4346 /* Run and wait for events. We must always send one NX_APPDEFINED event
4347 to ourself, otherwise [NXApp run] will never exit. */
4348 send_appdefined = YES;
4349 ns_send_appdefined (-1);
4354 nevents = n_emacs_events_pending;
4355 n_emacs_events_pending = 0;
4356 ns_finish_events ();
4368 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
4369 fd_set *exceptfds, struct timespec *timeout,
4371 /* --------------------------------------------------------------------------
4372 Replacement for select, checking for events
4373 -------------------------------------------------------------------------- */
4377 struct input_event event;
4380 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_select");
4382 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
4386 if (hold_event_q.nr > 0)
4388 /* We already have events pending. */
4394 for (k = 0; k < nfds+1; k++)
4396 if (readfds && FD_ISSET(k, readfds)) ++nr;
4397 if (writefds && FD_ISSET(k, writefds)) ++nr;
4401 || ![NSThread isMainThread]
4402 || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
4403 return thread_select(pselect, nfds, readfds, writefds,
4404 exceptfds, timeout, sigmask);
4407 struct timespec t = {0, 0};
4408 thread_select(pselect, 0, NULL, NULL, NULL, &t, sigmask);
4411 [outerpool release];
4412 outerpool = [[NSAutoreleasePool alloc] init];
4415 send_appdefined = YES;
4418 pthread_mutex_lock (&select_mutex);
4423 select_readfds = *readfds;
4424 select_valid += SELECT_HAVE_READ;
4428 select_writefds = *writefds;
4429 select_valid += SELECT_HAVE_WRITE;
4434 select_timeout = *timeout;
4435 select_valid += SELECT_HAVE_TMO;
4438 pthread_mutex_unlock (&select_mutex);
4440 /* Inform fd_handler that select should be called */
4442 emacs_write_sig (selfds[1], &c, 1);
4444 else if (nr == 0 && timeout)
4446 /* No file descriptor, just a timeout, no need to wake fd_handler */
4447 double time = timespectod (*timeout);
4448 timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
4451 @selector (timeout_handler:)
4456 else /* No timeout and no file descriptors, can this happen? */
4458 /* Send appdefined so we exit from the loop */
4459 ns_send_appdefined (-1);
4463 ns_init_events (&event);
4467 ns_finish_events ();
4468 if (nr > 0 && readfds)
4471 emacs_write_sig (selfds[1], &c, 1);
4475 t = last_appdefined_event_data;
4477 if (t != NO_APPDEFINED_DATA)
4479 last_appdefined_event_data = NO_APPDEFINED_DATA;
4483 /* The NX_APPDEFINED event we received was a timeout. */
4488 /* The NX_APPDEFINED event we received was the result of
4489 at least one real input event arriving. */
4495 /* Received back from select () in fd_handler; copy the results */
4496 pthread_mutex_lock (&select_mutex);
4497 if (readfds) *readfds = select_readfds;
4498 if (writefds) *writefds = select_writefds;
4499 pthread_mutex_unlock (&select_mutex);
4514 ns_run_loop_break ()
4515 /* Break out of the NS run loop in ns_select or ns_read_socket. */
4517 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_run_loop_break");
4519 /* If we don't have a GUI, don't send the event. */
4521 ns_send_appdefined(-1);
4526 /* ==========================================================================
4530 ========================================================================== */
4534 ns_set_vertical_scroll_bar (struct window *window,
4535 int portion, int whole, int position)
4536 /* --------------------------------------------------------------------------
4537 External (hook): Update or add scrollbar
4538 -------------------------------------------------------------------------- */
4542 struct frame *f = XFRAME (WINDOW_FRAME (window));
4543 EmacsView *view = FRAME_NS_VIEW (f);
4545 int window_y, window_height;
4546 int top, left, height, width;
4547 BOOL update_p = YES;
4549 /* optimization; display engine sends WAY too many of these.. */
4550 if (!NILP (window->vertical_scroll_bar))
4552 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4553 if ([bar checkSamePosition: position portion: portion whole: whole])
4555 if (view->scrollbarsNeedingUpdate == 0)
4557 if (!windows_or_buffers_changed)
4561 view->scrollbarsNeedingUpdate--;
4566 NSTRACE ("ns_set_vertical_scroll_bar");
4568 /* Get dimensions. */
4569 window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
4571 height = window_height;
4572 width = NS_SCROLL_BAR_WIDTH (f);
4573 left = WINDOW_SCROLL_BAR_AREA_X (window);
4575 r = NSMakeRect (left, top, width, height);
4576 /* the parent view is flipped, so we need to flip y value */
4578 r.origin.y = (v.size.height - r.size.height - r.origin.y);
4580 XSETWINDOW (win, window);
4583 /* we want at least 5 lines to display a scrollbar */
4584 if (WINDOW_TOTAL_LINES (window) < 5)
4586 if (!NILP (window->vertical_scroll_bar))
4588 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4589 [bar removeFromSuperview];
4590 wset_vertical_scroll_bar (window, Qnil);
4593 ns_clear_frame_area (f, left, top, width, height);
4598 if (NILP (window->vertical_scroll_bar))
4600 if (width > 0 && height > 0)
4601 ns_clear_frame_area (f, left, top, width, height);
4603 bar = [[EmacsScroller alloc] initFrame: r window: win];
4604 wset_vertical_scroll_bar (window, make_save_ptr (bar));
4610 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4611 oldRect = [bar frame];
4612 r.size.width = oldRect.size.width;
4613 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4615 if (oldRect.origin.x != r.origin.x)
4616 ns_clear_frame_area (f, left, top, width, height);
4622 [bar setPosition: position portion: portion whole: whole];
4628 ns_set_horizontal_scroll_bar (struct window *window,
4629 int portion, int whole, int position)
4630 /* --------------------------------------------------------------------------
4631 External (hook): Update or add scrollbar
4632 -------------------------------------------------------------------------- */
4636 struct frame *f = XFRAME (WINDOW_FRAME (window));
4637 EmacsView *view = FRAME_NS_VIEW (f);
4639 int top, height, left, width;
4640 int window_x, window_width;
4641 BOOL update_p = YES;
4643 /* optimization; display engine sends WAY too many of these.. */
4644 if (!NILP (window->horizontal_scroll_bar))
4646 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4647 if ([bar checkSamePosition: position portion: portion whole: whole])
4649 if (view->scrollbarsNeedingUpdate == 0)
4651 if (!windows_or_buffers_changed)
4655 view->scrollbarsNeedingUpdate--;
4660 NSTRACE ("ns_set_horizontal_scroll_bar");
4662 /* Get dimensions. */
4663 window_box (window, ANY_AREA, &window_x, 0, &window_width, 0);
4665 width = window_width;
4666 height = NS_SCROLL_BAR_HEIGHT (f);
4667 top = WINDOW_SCROLL_BAR_AREA_Y (window);
4669 r = NSMakeRect (left, top, width, height);
4670 /* the parent view is flipped, so we need to flip y value */
4672 r.origin.y = (v.size.height - r.size.height - r.origin.y);
4674 XSETWINDOW (win, window);
4677 if (NILP (window->horizontal_scroll_bar))
4679 if (width > 0 && height > 0)
4680 ns_clear_frame_area (f, left, top, width, height);
4682 bar = [[EmacsScroller alloc] initFrame: r window: win];
4683 wset_horizontal_scroll_bar (window, make_save_ptr (bar));
4689 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4690 oldRect = [bar frame];
4691 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4693 if (oldRect.origin.y != r.origin.y)
4694 ns_clear_frame_area (f, left, top, width, height);
4700 /* If there are both horizontal and vertical scroll-bars they leave
4701 a square that belongs to neither. We need to clear it otherwise
4702 it fills with junk. */
4703 if (!NILP (window->vertical_scroll_bar))
4704 ns_clear_frame_area (f, WINDOW_SCROLL_BAR_AREA_X (window), top,
4705 NS_SCROLL_BAR_HEIGHT (f), height);
4708 [bar setPosition: position portion: portion whole: whole];
4714 ns_condemn_scroll_bars (struct frame *f)
4715 /* --------------------------------------------------------------------------
4716 External (hook): arrange for all frame's scrollbars to be removed
4717 at next call to judge_scroll_bars, except for those redeemed.
4718 -------------------------------------------------------------------------- */
4722 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
4724 NSTRACE ("ns_condemn_scroll_bars");
4726 for (i =[subviews count]-1; i >= 0; i--)
4728 view = [subviews objectAtIndex: i];
4729 if ([view isKindOfClass: [EmacsScroller class]])
4736 ns_redeem_scroll_bar (struct window *window)
4737 /* --------------------------------------------------------------------------
4738 External (hook): arrange to spare this window's scrollbar
4739 at next call to judge_scroll_bars.
4740 -------------------------------------------------------------------------- */
4743 NSTRACE ("ns_redeem_scroll_bar");
4744 if (!NILP (window->vertical_scroll_bar)
4745 && WINDOW_HAS_VERTICAL_SCROLL_BAR (window))
4747 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4751 if (!NILP (window->horizontal_scroll_bar)
4752 && WINDOW_HAS_HORIZONTAL_SCROLL_BAR (window))
4754 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4761 ns_judge_scroll_bars (struct frame *f)
4762 /* --------------------------------------------------------------------------
4763 External (hook): destroy all scrollbars on frame that weren't
4764 redeemed after call to condemn_scroll_bars.
4765 -------------------------------------------------------------------------- */
4769 EmacsView *eview = FRAME_NS_VIEW (f);
4770 NSArray *subviews = [[eview superview] subviews];
4773 NSTRACE ("ns_judge_scroll_bars");
4774 for (i = [subviews count]-1; i >= 0; --i)
4776 view = [subviews objectAtIndex: i];
4777 if (![view isKindOfClass: [EmacsScroller class]]) continue;
4783 [eview updateFrameSize: NO];
4786 /* ==========================================================================
4790 ========================================================================== */
4793 x_display_pixel_height (struct ns_display_info *dpyinfo)
4795 NSArray *screens = [NSScreen screens];
4796 NSEnumerator *enumerator = [screens objectEnumerator];
4801 while ((screen = [enumerator nextObject]) != nil)
4802 frame = NSUnionRect (frame, [screen frame]);
4804 return NSHeight (frame);
4808 x_display_pixel_width (struct ns_display_info *dpyinfo)
4810 NSArray *screens = [NSScreen screens];
4811 NSEnumerator *enumerator = [screens objectEnumerator];
4816 while ((screen = [enumerator nextObject]) != nil)
4817 frame = NSUnionRect (frame, [screen frame]);
4819 return NSWidth (frame);
4823 static Lisp_Object ns_string_to_lispmod (const char *s)
4824 /* --------------------------------------------------------------------------
4825 Convert modifier name to lisp symbol
4826 -------------------------------------------------------------------------- */
4828 if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
4830 else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
4832 else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
4834 else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
4836 else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
4838 else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
4846 ns_default (const char *parameter, Lisp_Object *result,
4847 Lisp_Object yesval, Lisp_Object noval,
4848 BOOL is_float, BOOL is_modstring)
4849 /* --------------------------------------------------------------------------
4850 Check a parameter value in user's preferences
4851 -------------------------------------------------------------------------- */
4853 const char *value = ns_get_defaults_value (parameter);
4859 if (c_strcasecmp (value, "YES") == 0)
4861 else if (c_strcasecmp (value, "NO") == 0)
4863 else if (is_float && (f = strtod (value, &pos), pos != value))
4864 *result = make_float (f);
4865 else if (is_modstring && value)
4866 *result = ns_string_to_lispmod (value);
4867 else fprintf (stderr,
4868 "Bad value for default \"%s\": \"%s\"\n", parameter, value);
4874 ns_initialize_display_info (struct ns_display_info *dpyinfo)
4875 /* --------------------------------------------------------------------------
4876 Initialize global info and storage for display.
4877 -------------------------------------------------------------------------- */
4879 NSScreen *screen = [NSScreen mainScreen];
4880 NSWindowDepth depth = [screen depth];
4882 dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
4883 dpyinfo->resy = 72.27;
4884 dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4885 NSColorSpaceFromDepth (depth)]
4886 && ![NSCalibratedWhiteColorSpace isEqualToString:
4887 NSColorSpaceFromDepth (depth)];
4888 dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4889 dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
4890 dpyinfo->color_table->colors = NULL;
4891 dpyinfo->root_window = 42; /* a placeholder.. */
4892 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4893 dpyinfo->n_fonts = 0;
4894 dpyinfo->smallest_font_height = 1;
4895 dpyinfo->smallest_char_width = 1;
4897 reset_mouse_highlight (&dpyinfo->mouse_highlight);
4901 /* This and next define (many of the) public functions in this file. */
4902 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4903 with using despite presence in the "system dependent" redisplay
4904 interface. In addition, many of the ns_ methods have code that is
4905 shared with all terms, indicating need for further refactoring. */
4906 extern frame_parm_handler ns_frame_parm_handlers[];
4907 static struct redisplay_interface ns_redisplay_interface =
4909 ns_frame_parm_handlers,
4913 x_clear_end_of_line,
4915 ns_after_update_window_line,
4916 ns_update_window_begin,
4917 ns_update_window_end,
4918 0, /* flush_display */
4919 x_clear_window_mouse_face,
4920 x_get_glyph_overhangs,
4921 x_fix_overlapping_area,
4922 ns_draw_fringe_bitmap,
4923 0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4924 0, /* destroy_fringe_bitmap */
4925 ns_compute_glyph_string_overhangs,
4926 ns_draw_glyph_string,
4927 ns_define_frame_cursor,
4928 ns_clear_frame_area,
4929 ns_draw_window_cursor,
4930 ns_draw_vertical_window_border,
4931 ns_draw_window_divider,
4932 ns_shift_glyphs_for_insert,
4939 ns_delete_display (struct ns_display_info *dpyinfo)
4945 /* This function is called when the last frame on a display is deleted. */
4947 ns_delete_terminal (struct terminal *terminal)
4949 struct ns_display_info *dpyinfo = terminal->display_info.ns;
4951 NSTRACE ("ns_delete_terminal");
4953 /* Protect against recursive calls. delete_frame in
4954 delete_terminal calls us back when it deletes our last frame. */
4955 if (!terminal->name)
4960 x_destroy_all_bitmaps (dpyinfo);
4961 ns_delete_display (dpyinfo);
4966 static struct terminal *
4967 ns_create_terminal (struct ns_display_info *dpyinfo)
4968 /* --------------------------------------------------------------------------
4969 Set up use of NS before we make the first connection.
4970 -------------------------------------------------------------------------- */
4972 struct terminal *terminal;
4974 NSTRACE ("ns_create_terminal");
4976 terminal = create_terminal (output_ns, &ns_redisplay_interface);
4978 terminal->display_info.ns = dpyinfo;
4979 dpyinfo->terminal = terminal;
4981 terminal->clear_frame_hook = ns_clear_frame;
4982 terminal->ring_bell_hook = ns_ring_bell;
4983 terminal->update_begin_hook = ns_update_begin;
4984 terminal->update_end_hook = ns_update_end;
4985 terminal->read_socket_hook = ns_read_socket;
4986 terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4987 terminal->mouse_position_hook = ns_mouse_position;
4988 terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4989 terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4990 terminal->fullscreen_hook = ns_fullscreen_hook;
4991 terminal->menu_show_hook = ns_menu_show;
4992 terminal->popup_dialog_hook = ns_popup_dialog;
4993 terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4994 terminal->set_horizontal_scroll_bar_hook = ns_set_horizontal_scroll_bar;
4995 terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4996 terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4997 terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4998 terminal->delete_frame_hook = x_destroy_window;
4999 terminal->delete_terminal_hook = ns_delete_terminal;
5000 /* Other hooks are NULL by default. */
5006 struct ns_display_info *
5007 ns_term_init (Lisp_Object display_name)
5008 /* --------------------------------------------------------------------------
5009 Start the Application and get things rolling.
5010 -------------------------------------------------------------------------- */
5012 struct terminal *terminal;
5013 struct ns_display_info *dpyinfo;
5014 static int ns_initialized = 0;
5017 if (ns_initialized) return x_display_list;
5022 NSTRACE ("ns_term_init");
5024 [outerpool release];
5025 outerpool = [[NSAutoreleasePool alloc] init];
5027 /* count object allocs (About, click icon); on macOS use ObjectAlloc tool */
5028 /*GSDebugAllocationActive (YES); */
5032 Fset_input_interrupt_mode (Qnil);
5034 if (selfds[0] == -1)
5036 if (emacs_pipe (selfds) != 0)
5038 fprintf (stderr, "Failed to create pipe: %s\n",
5039 emacs_strerror (errno));
5043 fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
5044 FD_ZERO (&select_readfds);
5045 FD_ZERO (&select_writefds);
5046 pthread_mutex_init (&select_mutex, NULL);
5049 ns_pending_files = [[NSMutableArray alloc] init];
5050 ns_pending_service_names = [[NSMutableArray alloc] init];
5051 ns_pending_service_args = [[NSMutableArray alloc] init];
5053 /* Start app and create the main menu, window, view.
5054 Needs to be here because ns_initialize_display_info () uses AppKit classes.
5055 The view will then ask the NSApp to stop and return to Emacs. */
5056 [EmacsApp sharedApplication];
5059 [NSApp setDelegate: NSApp];
5061 /* Start the select thread. */
5062 [NSThread detachNewThreadSelector:@selector (fd_handler:)
5066 /* debugging: log all notifications */
5067 /* [[NSNotificationCenter defaultCenter] addObserver: NSApp
5068 selector: @selector (logNotification:)
5069 name: nil object: nil]; */
5071 dpyinfo = xzalloc (sizeof *dpyinfo);
5073 ns_initialize_display_info (dpyinfo);
5074 terminal = ns_create_terminal (dpyinfo);
5076 terminal->kboard = allocate_kboard (Qns);
5077 /* Don't let the initial kboard remain current longer than necessary.
5078 That would cause problems if a file loaded on startup tries to
5079 prompt in the mini-buffer. */
5080 if (current_kboard == initial_kboard)
5081 current_kboard = terminal->kboard;
5082 terminal->kboard->reference_count++;
5084 dpyinfo->next = x_display_list;
5085 x_display_list = dpyinfo;
5087 dpyinfo->name_list_element = Fcons (display_name, Qnil);
5089 terminal->name = xlispstrdup (display_name);
5093 if (!inhibit_x_resources)
5095 ns_default ("GSFontAntiAlias", &ns_antialias_text,
5098 /* this is a standard variable */
5099 ns_default ("AppleAntiAliasingThreshold", &tmp,
5100 make_float (10.0), make_float (6.0), YES, NO);
5101 ns_antialias_threshold = NILP (tmp) ? 10.0 : extract_float (tmp);
5104 NSTRACE_MSG ("Colors");
5107 NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
5111 Lisp_Object color_file, color_map, color;
5115 color_file = Fexpand_file_name (build_string ("rgb.txt"),
5116 Fsymbol_value (intern ("data-directory")));
5118 color_map = Fx_load_color_file (color_file);
5119 if (NILP (color_map))
5120 fatal ("Could not read %s.\n", SDATA (color_file));
5122 cl = [[NSColorList alloc] initWithName: @"Emacs"];
5123 for ( ; CONSP (color_map); color_map = XCDR (color_map))
5125 color = XCAR (color_map);
5126 name = SSDATA (XCAR (color));
5127 c = XINT (XCDR (color));
5129 [NSColor colorForEmacsRed: RED_FROM_ULONG (c) / 255.0
5130 green: GREEN_FROM_ULONG (c) / 255.0
5131 blue: BLUE_FROM_ULONG (c) / 255.0
5133 forKey: [NSString stringWithUTF8String: name]];
5135 [cl writeToFile: nil];
5139 NSTRACE_MSG ("Versions");
5142 #ifdef NS_IMPL_GNUSTEP
5143 Vwindow_system_version = build_string (gnustep_base_version);
5145 /*PSnextrelease (128, c); */
5146 char c[DBL_BUFSIZE_BOUND];
5147 int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
5148 Vwindow_system_version = make_unibyte_string (c, len);
5152 delete_keyboard_wait_descriptor (0);
5154 ns_app_name = [[NSProcessInfo processInfo] processName];
5156 /* Set up macOS app menu */
5158 NSTRACE_MSG ("Menu init");
5160 #ifdef NS_IMPL_COCOA
5164 /* set up the application menu */
5165 svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
5166 [svcsMenu setAutoenablesItems: NO];
5167 appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
5168 [appMenu setAutoenablesItems: NO];
5169 mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
5170 dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
5172 [appMenu insertItemWithTitle: @"About Emacs"
5173 action: @selector (orderFrontStandardAboutPanel:)
5176 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
5177 [appMenu insertItemWithTitle: @"Preferences..."
5178 action: @selector (showPreferencesWindow:)
5181 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
5182 item = [appMenu insertItemWithTitle: @"Services"
5183 action: @selector (menuDown:)
5186 [appMenu setSubmenu: svcsMenu forItem: item];
5187 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
5188 [appMenu insertItemWithTitle: @"Hide Emacs"
5189 action: @selector (hide:)
5192 item = [appMenu insertItemWithTitle: @"Hide Others"
5193 action: @selector (hideOtherApplications:)
5196 [item setKeyEquivalentModifierMask: NSEventModifierFlagCommand | NSEventModifierFlagOption];
5197 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
5198 [appMenu insertItemWithTitle: @"Quit Emacs"
5199 action: @selector (terminate:)
5203 item = [mainMenu insertItemWithTitle: ns_app_name
5204 action: @selector (menuDown:)
5207 [mainMenu setSubmenu: appMenu forItem: item];
5208 [dockMenu insertItemWithTitle: @"New Frame"
5209 action: @selector (newFrame:)
5213 [NSApp setMainMenu: mainMenu];
5214 [NSApp setAppleMenu: appMenu];
5215 [NSApp setServicesMenu: svcsMenu];
5216 /* Needed at least on Cocoa, to get dock menu to show windows */
5217 [NSApp setWindowsMenu: [[NSMenu alloc] init]];
5219 [[NSNotificationCenter defaultCenter]
5220 addObserver: mainMenu
5221 selector: @selector (trackingNotification:)
5222 name: NSMenuDidBeginTrackingNotification object: mainMenu];
5223 [[NSNotificationCenter defaultCenter]
5224 addObserver: mainMenu
5225 selector: @selector (trackingNotification:)
5226 name: NSMenuDidEndTrackingNotification object: mainMenu];
5228 #endif /* macOS menu setup */
5230 /* Register our external input/output types, used for determining
5231 applicable services and also drag/drop eligibility. */
5233 NSTRACE_MSG ("Input/output types");
5235 ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
5236 ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
5238 ns_drag_types = [[NSArray arrayWithObjects:
5240 NSTabularTextPboardType,
5241 NSFilenamesPboardType,
5242 NSURLPboardType, nil] retain];
5244 /* If fullscreen is in init/default-frame-alist, focus isn't set
5245 right for fullscreen windows, so set this. */
5246 [NSApp activateIgnoringOtherApps:YES];
5248 NSTRACE_MSG ("Call NSApp run");
5251 ns_do_open_file = YES;
5253 #ifdef NS_IMPL_GNUSTEP
5254 /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
5255 We must re-catch it so subprocess works. */
5256 catch_child_signal ();
5259 NSTRACE_MSG ("ns_term_init done");
5268 ns_term_shutdown (int sig)
5270 [[NSUserDefaults standardUserDefaults] synchronize];
5272 /* code not reached in emacs.c after this is called by shut_down_emacs: */
5273 if (STRINGP (Vauto_save_list_file_name))
5274 unlink (SSDATA (Vauto_save_list_file_name));
5276 if (sig == 0 || sig == SIGTERM)
5278 [NSApp terminate: NSApp];
5280 else // force a stack trace to happen
5287 /* ==========================================================================
5289 EmacsApp implementation
5291 ========================================================================== */
5294 @implementation EmacsApp
5298 NSTRACE ("[EmacsApp init]");
5300 if ((self = [super init]))
5302 #ifdef NS_IMPL_COCOA
5303 self->isFirst = YES;
5305 #ifdef NS_IMPL_GNUSTEP
5306 self->applicationDidFinishLaunchingCalled = NO;
5313 #ifdef NS_IMPL_COCOA
5316 NSTRACE ("[EmacsApp run]");
5318 #ifndef NSAppKitVersionNumber10_9
5319 #define NSAppKitVersionNumber10_9 1265
5322 if ((int)NSAppKitVersionNumber != NSAppKitVersionNumber10_9)
5328 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5330 if (isFirst) [self finishLaunching];
5333 shouldKeepRunning = YES;
5337 pool = [[NSAutoreleasePool alloc] init];
5340 [self nextEventMatchingMask:NSEventMaskAny
5341 untilDate:[NSDate distantFuture]
5342 inMode:NSDefaultRunLoopMode
5345 [self sendEvent:event];
5346 [self updateWindows];
5347 } while (shouldKeepRunning);
5352 - (void)stop: (id)sender
5354 NSTRACE ("[EmacsApp stop:]");
5356 shouldKeepRunning = NO;
5357 // Stop possible dialog also. Noop if no dialog present.
5358 // The file dialog still leaks 7k - 10k on 10.9 though.
5359 [super stop:sender];
5361 #endif /* NS_IMPL_COCOA */
5363 - (void)logNotification: (NSNotification *)notification
5365 NSTRACE ("[EmacsApp logNotification:]");
5367 const char *name = [[notification name] UTF8String];
5368 if (!strstr (name, "Update") && !strstr (name, "NSMenu")
5369 && !strstr (name, "WindowNumber"))
5370 NSLog (@"notification: '%@'", [notification name]);
5374 - (void)sendEvent: (NSEvent *)theEvent
5375 /* --------------------------------------------------------------------------
5376 Called when NSApp is running for each event received. Used to stop
5377 the loop when we choose, since there's no way to just run one iteration.
5378 -------------------------------------------------------------------------- */
5380 int type = [theEvent type];
5381 NSWindow *window = [theEvent window];
5383 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsApp sendEvent:]");
5384 NSTRACE_MSG ("Type: %d", type);
5386 #ifdef NS_IMPL_GNUSTEP
5387 // Keyboard events aren't propagated to file dialogs for some reason.
5388 if ([NSApp modalWindow] != nil &&
5389 (type == NSEventTypeKeyDown || type == NSEventTypeKeyUp || type == NSEventTypeFlagsChanged))
5391 [[NSApp modalWindow] sendEvent: theEvent];
5396 if (represented_filename != nil && represented_frame)
5398 NSString *fstr = represented_filename;
5399 NSView *view = FRAME_NS_VIEW (represented_frame);
5400 #ifdef NS_IMPL_COCOA
5401 /* work around a bug observed on 10.3 and later where
5402 setTitleWithRepresentedFilename does not clear out previous state
5403 if given filename does not exist */
5404 if (! [[NSFileManager defaultManager] fileExistsAtPath: fstr])
5405 [[view window] setRepresentedFilename: @""];
5407 [[view window] setRepresentedFilename: fstr];
5408 [represented_filename release];
5409 represented_filename = nil;
5410 represented_frame = NULL;
5413 if (type == NSEventTypeApplicationDefined)
5415 switch ([theEvent data2])
5417 #ifdef NS_IMPL_COCOA
5418 case NSAPP_DATA2_RUNASSCRIPT:
5423 case NSAPP_DATA2_RUNFILEDIALOG:
5424 ns_run_file_dialog ();
5430 if (type == NSEventTypeCursorUpdate && window == nil)
5432 fprintf (stderr, "Dropping external cursor update event.\n");
5436 if (type == NSEventTypeApplicationDefined)
5438 /* Events posted by ns_send_appdefined interrupt the run loop here.
5439 But, if a modal window is up, an appdefined can still come through,
5440 (e.g., from a makeKeyWindow event) but stopping self also stops the
5441 modal loop. Just defer it until later. */
5442 if ([NSApp modalWindow] == nil)
5444 last_appdefined_event_data = [theEvent data1];
5449 send_appdefined = YES;
5454 #ifdef NS_IMPL_COCOA
5455 /* If no dialog and none of our frames have focus and it is a move, skip it.
5456 It is a mouse move in an auxiliary menu, i.e. on the top right on macOS,
5457 such as Wifi, sound, date or similar.
5458 This prevents "spooky" highlighting in the frame under the menu. */
5459 if (type == NSEventTypeMouseMoved && [NSApp modalWindow] == nil)
5461 struct ns_display_info *di;
5462 BOOL has_focus = NO;
5463 for (di = x_display_list; ! has_focus && di; di = di->next)
5464 has_focus = di->x_focus_frame != 0;
5470 NSTRACE_UNSILENCE();
5472 [super sendEvent: theEvent];
5476 - (void)showPreferencesWindow: (id)sender
5478 struct frame *emacsframe = SELECTED_FRAME ();
5479 NSEvent *theEvent = [NSApp currentEvent];
5483 emacs_event->kind = NS_NONKEY_EVENT;
5484 emacs_event->code = KEY_NS_SHOW_PREFS;
5485 emacs_event->modifiers = 0;
5486 EV_TRAILER (theEvent);
5490 - (void)newFrame: (id)sender
5492 NSTRACE ("[EmacsApp newFrame:]");
5494 struct frame *emacsframe = SELECTED_FRAME ();
5495 NSEvent *theEvent = [NSApp currentEvent];
5499 emacs_event->kind = NS_NONKEY_EVENT;
5500 emacs_event->code = KEY_NS_NEW_FRAME;
5501 emacs_event->modifiers = 0;
5502 EV_TRAILER (theEvent);
5506 /* Open a file (used by below, after going into queue read by ns_read_socket) */
5507 - (BOOL) openFile: (NSString *)fileName
5509 NSTRACE ("[EmacsApp openFile:]");
5511 struct frame *emacsframe = SELECTED_FRAME ();
5512 NSEvent *theEvent = [NSApp currentEvent];
5517 emacs_event->kind = NS_NONKEY_EVENT;
5518 emacs_event->code = KEY_NS_OPEN_FILE_LINE;
5519 ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
5520 ns_input_line = Qnil; /* can be start or cons start,end */
5521 emacs_event->modifiers =0;
5522 EV_TRAILER (theEvent);
5528 /* **************************************************************************
5530 EmacsApp delegate implementation
5532 ************************************************************************** */
5534 - (void)applicationDidFinishLaunching: (NSNotification *)notification
5535 /* --------------------------------------------------------------------------
5536 When application is loaded, terminate event loop in ns_term_init
5537 -------------------------------------------------------------------------- */
5539 NSTRACE ("[EmacsApp applicationDidFinishLaunching:]");
5541 #ifdef NS_IMPL_GNUSTEP
5542 ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
5544 [NSApp setServicesProvider: NSApp];
5546 [self antialiasThresholdDidChange:nil];
5547 #ifdef NS_IMPL_COCOA
5548 [[NSNotificationCenter defaultCenter]
5550 selector:@selector(antialiasThresholdDidChange:)
5551 name:NSAntialiasThresholdChangedNotification
5555 #ifdef NS_IMPL_COCOA
5556 if ([NSApp activationPolicy] == NSApplicationActivationPolicyProhibited) {
5557 /* Set the app's activation policy to regular when we run outside
5558 of a bundle. This is already done for us by Info.plist when we
5559 run inside a bundle. */
5560 [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
5561 [NSApp setApplicationIconImage:
5564 build_string("icons/hicolor/128x128/apps/emacs.png")]];
5568 ns_send_appdefined (-2);
5571 - (void)antialiasThresholdDidChange:(NSNotification *)notification
5573 #ifdef NS_IMPL_COCOA
5574 macfont_update_antialias_threshold ();
5579 /* Termination sequences:
5582 MenuBar | File | Exit:
5583 Select Quit from App menubar:
5585 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5588 Select Quit from Dock menu:
5591 Cancel -> Nothing else
5595 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5600 - (void) terminate: (id)sender
5602 NSTRACE ("[EmacsApp terminate:]");
5604 struct frame *emacsframe = SELECTED_FRAME ();
5609 emacs_event->kind = NS_NONKEY_EVENT;
5610 emacs_event->code = KEY_NS_POWER_OFF;
5611 emacs_event->arg = Qt; /* mark as non-key event */
5612 EV_TRAILER ((id)nil);
5616 runAlertPanel(NSString *title,
5617 NSString *msgFormat,
5618 NSString *defaultButton,
5619 NSString *alternateButton)
5621 #ifdef NS_IMPL_GNUSTEP
5622 return NSRunAlertPanel(title, msgFormat, defaultButton, alternateButton, nil)
5623 == NSAlertDefaultReturn;
5625 NSAlert *alert = [[NSAlert alloc] init];
5626 [alert setAlertStyle: NSAlertStyleCritical];
5627 [alert setMessageText: msgFormat];
5628 [alert addButtonWithTitle: defaultButton];
5629 [alert addButtonWithTitle: alternateButton];
5630 NSInteger ret = [alert runModal];
5632 return ret == NSAlertFirstButtonReturn;
5637 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
5639 NSTRACE ("[EmacsApp applicationShouldTerminate:]");
5643 if (NILP (ns_confirm_quit)) // || ns_shutdown_properly --> TO DO
5644 return NSTerminateNow;
5646 ret = runAlertPanel(ns_app_name,
5647 @"Exit requested. Would you like to Save Buffers and Exit, or Cancel the request?",
5648 @"Save Buffers and Exit", @"Cancel");
5650 return ret ? NSTerminateNow : NSTerminateCancel;
5654 not_in_argv (NSString *arg)
5657 const char *a = [arg UTF8String];
5658 for (k = 1; k < initial_argc; ++k)
5659 if (strcmp (a, initial_argv[k]) == 0) return 0;
5663 /* Notification from the Workspace to open a file */
5664 - (BOOL)application: sender openFile: (NSString *)file
5666 if (ns_do_open_file || not_in_argv (file))
5667 [ns_pending_files addObject: file];
5672 /* Open a file as a temporary file */
5673 - (BOOL)application: sender openTempFile: (NSString *)file
5675 if (ns_do_open_file || not_in_argv (file))
5676 [ns_pending_files addObject: file];
5681 /* Notification from the Workspace to open a file noninteractively (?) */
5682 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
5684 if (ns_do_open_file || not_in_argv (file))
5685 [ns_pending_files addObject: file];
5689 /* Notification from the Workspace to open multiple files */
5690 - (void)application: sender openFiles: (NSArray *)fileList
5692 NSEnumerator *files = [fileList objectEnumerator];
5694 /* Don't open files from the command line unconditionally,
5695 Cocoa parses the command line wrong, --option value tries to open value
5696 if --option is the last option. */
5697 while ((file = [files nextObject]) != nil)
5698 if (ns_do_open_file || not_in_argv (file))
5699 [ns_pending_files addObject: file];
5701 [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
5706 /* Handle dock menu requests. */
5707 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
5713 /* TODO: these may help w/IO switching btwn terminal and NSApp */
5714 - (void)applicationWillBecomeActive: (NSNotification *)notification
5716 NSTRACE ("[EmacsApp applicationWillBecomeActive:]");
5717 //ns_app_active=YES;
5720 - (void)applicationDidBecomeActive: (NSNotification *)notification
5722 NSTRACE ("[EmacsApp applicationDidBecomeActive:]");
5724 #ifdef NS_IMPL_GNUSTEP
5725 if (! applicationDidFinishLaunchingCalled)
5726 [self applicationDidFinishLaunching:notification];
5728 //ns_app_active=YES;
5730 ns_update_auto_hide_menu_bar ();
5731 // No constraining takes place when the application is not active.
5732 ns_constrain_all_frames ();
5734 - (void)applicationDidResignActive: (NSNotification *)notification
5736 NSTRACE ("[EmacsApp applicationDidResignActive:]");
5739 ns_send_appdefined (-1);
5744 /* ==========================================================================
5746 EmacsApp aux handlers for managing event loop
5748 ========================================================================== */
5751 - (void)timeout_handler: (NSTimer *)timedEntry
5752 /* --------------------------------------------------------------------------
5753 The timeout specified to ns_select has passed.
5754 -------------------------------------------------------------------------- */
5756 /*NSTRACE ("timeout_handler"); */
5757 ns_send_appdefined (-2);
5760 - (void)sendFromMainThread:(id)unused
5762 ns_send_appdefined (nextappdefined);
5765 - (void)fd_handler:(id)unused
5766 /* --------------------------------------------------------------------------
5767 Check data waiting on file descriptors and terminate if so
5768 -------------------------------------------------------------------------- */
5771 int waiting = 1, nfds;
5774 fd_set readfds, writefds, *wfds;
5775 struct timespec timeout, *tmo;
5776 NSAutoreleasePool *pool = nil;
5778 /* NSTRACE ("fd_handler"); */
5783 pool = [[NSAutoreleasePool alloc] init];
5789 FD_SET (selfds[0], &fds);
5790 result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
5791 if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
5796 pthread_mutex_lock (&select_mutex);
5799 if (select_valid & SELECT_HAVE_READ)
5800 readfds = select_readfds;
5804 if (select_valid & SELECT_HAVE_WRITE)
5806 writefds = select_writefds;
5811 if (select_valid & SELECT_HAVE_TMO)
5813 timeout = select_timeout;
5819 pthread_mutex_unlock (&select_mutex);
5821 FD_SET (selfds[0], &readfds);
5822 if (selfds[0] >= nfds) nfds = selfds[0]+1;
5824 result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
5827 ns_send_appdefined (-2);
5828 else if (result > 0)
5830 if (FD_ISSET (selfds[0], &readfds))
5832 if (read (selfds[0], &c, 1) == 1 && c == 's')
5837 pthread_mutex_lock (&select_mutex);
5838 if (select_valid & SELECT_HAVE_READ)
5839 select_readfds = readfds;
5840 if (select_valid & SELECT_HAVE_WRITE)
5841 select_writefds = writefds;
5842 if (select_valid & SELECT_HAVE_TMO)
5843 select_timeout = timeout;
5844 pthread_mutex_unlock (&select_mutex);
5846 ns_send_appdefined (result);
5856 /* ==========================================================================
5860 ========================================================================== */
5862 /* called from system: queue for next pass through event loop */
5863 - (void)requestService: (NSPasteboard *)pboard
5864 userData: (NSString *)userData
5865 error: (NSString **)error
5867 [ns_pending_service_names addObject: userData];
5868 [ns_pending_service_args addObject: [NSString stringWithUTF8String:
5869 SSDATA (ns_string_from_pasteboard (pboard))]];
5873 /* called from ns_read_socket to clear queue */
5874 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
5876 struct frame *emacsframe = SELECTED_FRAME ();
5877 NSEvent *theEvent = [NSApp currentEvent];
5879 NSTRACE ("[EmacsApp fulfillService:withArg:]");
5884 emacs_event->kind = NS_NONKEY_EVENT;
5885 emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
5886 ns_input_spi_name = build_string ([name UTF8String]);
5887 ns_input_spi_arg = build_string ([arg UTF8String]);
5888 emacs_event->modifiers = EV_MODIFIERS (theEvent);
5889 EV_TRAILER (theEvent);
5899 /* ==========================================================================
5901 EmacsView implementation
5903 ========================================================================== */
5906 @implementation EmacsView
5908 /* needed to inform when window closed from LISP */
5909 - (void) setWindowClosing: (BOOL)closing
5911 NSTRACE ("[EmacsView setWindowClosing:%d]", closing);
5913 windowClosing = closing;
5919 NSTRACE ("[EmacsView dealloc]");
5921 if (fs_state == FULLSCREEN_BOTH)
5922 [nonfs_window release];
5927 /* called on font panel selection */
5928 - (void)changeFont: (id)sender
5930 NSEvent *e = [[self window] currentEvent];
5931 struct face *face = FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID);
5932 struct font *font = face->font;
5937 NSTRACE ("[EmacsView changeFont:]");
5942 #ifdef NS_IMPL_GNUSTEP
5943 nsfont = ((struct nsfont_info *)font)->nsfont;
5945 #ifdef NS_IMPL_COCOA
5946 nsfont = (NSFont *) macfont_get_nsctfont (font);
5949 if ((newFont = [sender convertFont: nsfont]))
5951 SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
5953 emacs_event->kind = NS_NONKEY_EVENT;
5954 emacs_event->modifiers = 0;
5955 emacs_event->code = KEY_NS_CHANGE_FONT;
5957 size = [newFont pointSize];
5958 ns_input_fontsize = make_number (lrint (size));
5959 ns_input_font = build_string ([[newFont familyName] UTF8String]);
5965 - (BOOL)acceptsFirstResponder
5967 NSTRACE ("[EmacsView acceptsFirstResponder]");
5972 - (void)resetCursorRects
5974 NSRect visible = [self visibleRect];
5975 NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
5976 NSTRACE ("[EmacsView resetCursorRects]");
5978 if (currentCursor == nil)
5979 currentCursor = [NSCursor arrowCursor];
5981 if (!NSIsEmptyRect (visible))
5982 [self addCursorRect: visible cursor: currentCursor];
5983 [currentCursor setOnMouseEntered: YES];
5988 /*****************************************************************************/
5989 /* Keyboard handling. */
5992 - (void)keyDown: (NSEvent *)theEvent
5994 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5996 unsigned fnKeysym = 0;
5997 static NSMutableArray *nsEvArray;
5999 unsigned int flags = [theEvent modifierFlags];
6001 NSTRACE ("[EmacsView keyDown:]");
6003 /* Rhapsody and macOS give up and down events for the arrow keys */
6004 if (ns_fake_keydown == YES)
6005 ns_fake_keydown = NO;
6006 else if ([theEvent type] != NSEventTypeKeyDown)
6012 if (![[self window] isKeyWindow]
6013 && [[theEvent window] isKindOfClass: [EmacsWindow class]]
6014 /* we must avoid an infinite loop here. */
6015 && (EmacsView *)[[theEvent window] delegate] != self)
6017 /* XXX: There is an occasional condition in which, when Emacs display
6018 updates a different frame from the current one, and temporarily
6019 selects it, then processes some interrupt-driven input
6020 (dispnew.c:3878), OS will send the event to the correct NSWindow, but
6021 for some reason that window has its first responder set to the NSView
6022 most recently updated (I guess), which is not the correct one. */
6023 [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
6027 if (nsEvArray == nil)
6028 nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
6030 [NSCursor setHiddenUntilMouseMoves: YES];
6032 if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
6034 clear_mouse_face (hlinfo);
6035 hlinfo->mouse_face_hidden = 1;
6038 if (!processingCompose)
6040 /* When using screen sharing, no left or right information is sent,
6041 so use Left key in those cases. */
6042 int is_left_key, is_right_key;
6044 code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
6045 0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
6047 /* (Carbon way: [theEvent keyCode]) */
6049 /* is it a "function key"? */
6050 /* Note: Sometimes a plain key will have the NSEventModifierFlagNumericPad
6051 flag set (this is probably a bug in the OS).
6053 if (code < 0x00ff && (flags&NSEventModifierFlagNumericPad))
6055 fnKeysym = ns_convert_key ([theEvent keyCode] | NSEventModifierFlagNumericPad);
6059 fnKeysym = ns_convert_key (code);
6064 /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
6065 because Emacs treats Delete and KP-Delete same (in simple.el). */
6066 if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
6067 #ifdef NS_IMPL_GNUSTEP
6068 /* GNUstep uses incompatible keycodes, even for those that are
6069 supposed to be hardware independent. Just check for delete.
6070 Keypad delete does not have keysym 0xFFFF.
6071 See https://savannah.gnu.org/bugs/?25395
6073 || (fnKeysym == 0xFFFF && code == 127)
6076 code = 0xFF08; /* backspace */
6081 /* are there modifiers? */
6082 emacs_event->modifiers = 0;
6084 if (flags & NSEventModifierFlagHelp)
6085 emacs_event->modifiers |= hyper_modifier;
6087 if (flags & NSEventModifierFlagShift)
6088 emacs_event->modifiers |= shift_modifier;
6090 is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
6091 is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
6092 || (! is_right_key && (flags & NSEventModifierFlagCommand) == NSEventModifierFlagCommand);
6095 emacs_event->modifiers |= parse_solitary_modifier
6096 (EQ (ns_right_command_modifier, Qleft)
6097 ? ns_command_modifier
6098 : ns_right_command_modifier);
6102 emacs_event->modifiers |= parse_solitary_modifier
6103 (ns_command_modifier);
6105 /* if super (default), take input manager's word so things like
6106 dvorak / qwerty layout work */
6107 if (EQ (ns_command_modifier, Qsuper)
6109 && [[theEvent characters] length] != 0)
6111 /* XXX: the code we get will be unshifted, so if we have
6112 a shift modifier, must convert ourselves */
6113 if (!(flags & NSEventModifierFlagShift))
6114 code = [[theEvent characters] characterAtIndex: 0];
6116 /* this is ugly and also requires linking w/Carbon framework
6117 (for LMGetKbdType) so for now leave this rare (?) case
6118 undealt with.. in future look into CGEvent methods */
6121 long smv = GetScriptManagerVariable (smKeyScript);
6122 Handle uchrHandle = GetResource
6123 ('uchr', GetScriptVariable (smv, smScriptKeys));
6125 UCKeyTranslate ((UCKeyboardLayout *) *uchrHandle,
6126 [[theEvent characters] characterAtIndex: 0],
6127 kUCKeyActionDisplay,
6128 (flags & ~NSEventModifierFlagCommand) >> 8,
6129 LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
6130 &dummy, 1, &dummy, &code);
6137 is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
6138 is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
6139 || (! is_right_key && (flags & NSEventModifierFlagControl) == NSEventModifierFlagControl);
6142 emacs_event->modifiers |= parse_solitary_modifier
6143 (EQ (ns_right_control_modifier, Qleft)
6144 ? ns_control_modifier
6145 : ns_right_control_modifier);
6148 emacs_event->modifiers |= parse_solitary_modifier
6149 (ns_control_modifier);
6151 if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
6152 emacs_event->modifiers |=
6153 parse_solitary_modifier (ns_function_modifier);
6155 left_is_none = NILP (ns_alternate_modifier)
6156 || EQ (ns_alternate_modifier, Qnone);
6158 is_right_key = (flags & NSRightAlternateKeyMask)
6159 == NSRightAlternateKeyMask;
6160 is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
6162 && (flags & NSEventModifierFlagOption) == NSEventModifierFlagOption);
6166 if ((NILP (ns_right_alternate_modifier)
6167 || EQ (ns_right_alternate_modifier, Qnone)
6168 || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
6170 { /* accept pre-interp alt comb */
6171 if ([[theEvent characters] length] > 0)
6172 code = [[theEvent characters] characterAtIndex: 0];
6173 /*HACK: clear lone shift modifier to stop next if from firing */
6174 if (emacs_event->modifiers == shift_modifier)
6175 emacs_event->modifiers = 0;
6178 emacs_event->modifiers |= parse_solitary_modifier
6179 (EQ (ns_right_alternate_modifier, Qleft)
6180 ? ns_alternate_modifier
6181 : ns_right_alternate_modifier);
6184 if (is_left_key) /* default = meta */
6186 if (left_is_none && !fnKeysym)
6187 { /* accept pre-interp alt comb */
6188 if ([[theEvent characters] length] > 0)
6189 code = [[theEvent characters] characterAtIndex: 0];
6190 /*HACK: clear lone shift modifier to stop next if from firing */
6191 if (emacs_event->modifiers == shift_modifier)
6192 emacs_event->modifiers = 0;
6195 emacs_event->modifiers |=
6196 parse_solitary_modifier (ns_alternate_modifier);
6200 fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
6201 (unsigned) code, fnKeysym, flags, emacs_event->modifiers);
6203 /* if it was a function key or had modifiers, pass it directly to emacs */
6204 if (fnKeysym || (emacs_event->modifiers
6205 && (emacs_event->modifiers != shift_modifier)
6206 && [[theEvent charactersIgnoringModifiers] length] > 0))
6207 /*[[theEvent characters] length] */
6209 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6211 code |= (1<<28)|(3<<16);
6212 else if (code == 0x7f)
6213 code |= (1<<28)|(3<<16);
6215 emacs_event->kind = code > 0xFF
6216 ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6218 emacs_event->code = code;
6219 EV_TRAILER (theEvent);
6220 processingCompose = NO;
6226 if (NS_KEYLOG && !processingCompose)
6227 fprintf (stderr, "keyDown: Begin compose sequence.\n");
6229 processingCompose = YES;
6230 [nsEvArray addObject: theEvent];
6231 [self interpretKeyEvents: nsEvArray];
6232 [nsEvArray removeObject: theEvent];
6236 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
6239 /* <NSTextInput>: called when done composing;
6240 NOTE: also called when we delete over working text, followed immed.
6241 by doCommandBySelector: deleteBackward: */
6242 - (void)insertText: (id)aString
6245 int len = [(NSString *)aString length];
6248 NSTRACE ("[EmacsView insertText:]");
6251 NSLog (@"insertText '%@'\tlen = %d", aString, len);
6252 processingCompose = NO;
6257 /* first, clear any working text */
6258 if (workingText != nil)
6259 [self deleteWorkingText];
6261 /* now insert the string as keystrokes */
6262 for (i =0; i<len; i++)
6264 code = [aString characterAtIndex: i];
6265 /* TODO: still need this? */
6267 code = '~'; /* 0x7E */
6268 if (code != 32) /* Space */
6269 emacs_event->modifiers = 0;
6271 = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6272 emacs_event->code = code;
6273 EV_TRAILER ((id)nil);
6278 /* <NSTextInput>: inserts display of composing characters */
6279 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
6281 NSString *str = [aString respondsToSelector: @selector (string)] ?
6282 [aString string] : aString;
6284 NSTRACE ("[EmacsView setMarkedText:selectedRange:]");
6287 NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
6288 str, (unsigned long)[str length],
6289 (unsigned long)selRange.length,
6290 (unsigned long)selRange.location);
6292 if (workingText != nil)
6293 [self deleteWorkingText];
6294 if ([str length] == 0)
6300 processingCompose = YES;
6301 workingText = [str copy];
6302 ns_working_text = build_string ([workingText UTF8String]);
6304 emacs_event->kind = NS_TEXT_EVENT;
6305 emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
6306 EV_TRAILER ((id)nil);
6310 /* delete display of composing characters [not in <NSTextInput>] */
6311 - (void)deleteWorkingText
6313 NSTRACE ("[EmacsView deleteWorkingText]");
6315 if (workingText == nil)
6318 NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
6319 [workingText release];
6321 processingCompose = NO;
6326 emacs_event->kind = NS_TEXT_EVENT;
6327 emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
6328 EV_TRAILER ((id)nil);
6332 - (BOOL)hasMarkedText
6334 NSTRACE ("[EmacsView hasMarkedText]");
6336 return workingText != nil;
6340 - (NSRange)markedRange
6342 NSTRACE ("[EmacsView markedRange]");
6344 NSRange rng = workingText != nil
6345 ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
6347 NSLog (@"markedRange request");
6354 NSTRACE ("[EmacsView unmarkText]");
6357 NSLog (@"unmark (accept) text");
6358 [self deleteWorkingText];
6359 processingCompose = NO;
6363 /* used to position char selection windows, etc. */
6364 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
6368 struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
6370 NSTRACE ("[EmacsView firstRectForCharacterRange:]");
6373 NSLog (@"firstRectForCharRange request");
6375 rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
6376 rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
6377 pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
6378 pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
6379 +FRAME_LINE_HEIGHT (emacsframe));
6381 pt = [self convertPoint: pt toView: nil];
6383 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
6384 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6385 if ([[self window] respondsToSelector: @selector(convertRectToScreen:)])
6389 rect = [(EmacsWindow *) [self window] convertRectToScreen: rect];
6390 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6394 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
6395 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 \
6396 || defined (NS_IMPL_GNUSTEP)
6398 pt = [[self window] convertBaseToScreen: pt];
6407 - (NSInteger)conversationIdentifier
6409 return (NSInteger)self;
6413 - (void)doCommandBySelector: (SEL)aSelector
6415 NSTRACE ("[EmacsView doCommandBySelector:]");
6418 NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
6420 processingCompose = NO;
6421 if (aSelector == @selector (deleteBackward:))
6423 /* happens when user backspaces over an ongoing composition:
6424 throw a 'delete' into the event queue */
6427 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6428 emacs_event->code = 0xFF08;
6429 EV_TRAILER ((id)nil);
6433 - (NSArray *)validAttributesForMarkedText
6435 static NSArray *arr = nil;
6436 if (arr == nil) arr = [NSArray new];
6437 /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
6441 - (NSRange)selectedRange
6444 NSLog (@"selectedRange request");
6445 return NSMakeRange (NSNotFound, 0);
6448 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
6449 GNUSTEP_GUI_MINOR_VERSION > 22
6450 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
6452 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
6456 NSLog (@"characterIndexForPoint request");
6460 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
6462 static NSAttributedString *str = nil;
6463 if (str == nil) str = [NSAttributedString new];
6465 NSLog (@"attributedSubstringFromRange request");
6469 /* End <NSTextInput> impl. */
6470 /*****************************************************************************/
6473 /* This is what happens when the user presses a mouse button. */
6474 - (void)mouseDown: (NSEvent *)theEvent
6476 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6477 NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
6479 NSTRACE ("[EmacsView mouseDown:]");
6481 [self deleteWorkingText];
6486 dpyinfo->last_mouse_frame = emacsframe;
6487 /* appears to be needed to prevent spurious movement events generated on
6489 emacsframe->mouse_moved = 0;
6491 if ([theEvent type] == NSEventTypeScrollWheel)
6493 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
6494 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6495 if ([theEvent respondsToSelector:@selector(hasPreciseScrollingDeltas)])
6498 /* If the input device is a touchpad or similar, use precise
6499 * scrolling deltas. These are measured in pixels, so we
6500 * have to add them up until they exceed one line height,
6501 * then we can send a scroll wheel event.
6503 * If the device only has coarse scrolling deltas, like a
6504 * real mousewheel, the deltas represent a ratio of whole
6505 * lines, so round up the number of lines. This means we
6506 * always send one scroll event per click, but can still
6507 * scroll more than one line if the OS tells us to.
6513 /* FIXME: At the top or bottom of the buffer we should
6514 * ignore momentum-phase events. */
6515 if (! ns_use_mwheel_momentum
6516 && [theEvent momentumPhase] != NSEventPhaseNone)
6519 if ([theEvent hasPreciseScrollingDeltas])
6521 static int totalDeltaX, totalDeltaY;
6524 if (NUMBERP (ns_mwheel_line_height))
6525 lineHeight = XINT (ns_mwheel_line_height);
6528 /* FIXME: Use actual line height instead of the default. */
6529 lineHeight = default_line_pixel_height
6530 (XWINDOW (FRAME_SELECTED_WINDOW (emacsframe)));
6533 if ([theEvent phase] == NSEventPhaseBegan)
6539 totalDeltaX += [theEvent scrollingDeltaX];
6540 totalDeltaY += [theEvent scrollingDeltaY];
6542 /* Calculate the number of lines, if any, to scroll, and
6543 * reset the total delta for the direction we're NOT
6544 * scrolling so that small movements don't add up. */
6545 if (abs (totalDeltaX) > abs (totalDeltaY)
6546 && abs (totalDeltaX) > lineHeight)
6549 scrollUp = totalDeltaX > 0;
6551 lines = abs (totalDeltaX / lineHeight);
6552 totalDeltaX = totalDeltaX % lineHeight;
6555 else if (abs (totalDeltaY) >= abs (totalDeltaX)
6556 && abs (totalDeltaY) > lineHeight)
6559 scrollUp = totalDeltaY > 0;
6561 lines = abs (totalDeltaY / lineHeight);
6562 totalDeltaY = totalDeltaY % lineHeight;
6566 if (lines > 1 && ! ns_use_mwheel_acceleration)
6573 if ([theEvent scrollingDeltaY] == 0)
6576 delta = [theEvent scrollingDeltaX];
6581 delta = [theEvent scrollingDeltaY];
6584 lines = (ns_use_mwheel_acceleration)
6585 ? ceil (fabs (delta)) : 1;
6587 scrollUp = delta > 0;
6593 emacs_event->kind = horizontal ? HORIZ_WHEEL_EVENT : WHEEL_EVENT;
6594 emacs_event->arg = (make_number (lines));
6596 emacs_event->code = 0;
6597 emacs_event->modifiers = EV_MODIFIERS (theEvent) |
6598 (scrollUp ? up_modifier : down_modifier);
6599 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6603 #endif /* defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
6604 #if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6606 CGFloat delta = [theEvent deltaY];
6607 /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
6610 delta = [theEvent deltaX];
6613 NSTRACE_MSG ("deltaIsZero");
6616 emacs_event->kind = HORIZ_WHEEL_EVENT;
6619 emacs_event->kind = WHEEL_EVENT;
6621 emacs_event->code = 0;
6622 emacs_event->modifiers = EV_MODIFIERS (theEvent) |
6623 ((delta > 0) ? up_modifier : down_modifier);
6629 emacs_event->kind = MOUSE_CLICK_EVENT;
6630 emacs_event->code = EV_BUTTON (theEvent);
6631 emacs_event->modifiers = EV_MODIFIERS (theEvent)
6632 | EV_UDMODIFIERS (theEvent);
6635 XSETINT (emacs_event->x, lrint (p.x));
6636 XSETINT (emacs_event->y, lrint (p.y));
6637 EV_TRAILER (theEvent);
6642 - (void)rightMouseDown: (NSEvent *)theEvent
6644 NSTRACE ("[EmacsView rightMouseDown:]");
6645 [self mouseDown: theEvent];
6649 - (void)otherMouseDown: (NSEvent *)theEvent
6651 NSTRACE ("[EmacsView otherMouseDown:]");
6652 [self mouseDown: theEvent];
6656 - (void)mouseUp: (NSEvent *)theEvent
6658 NSTRACE ("[EmacsView mouseUp:]");
6659 [self mouseDown: theEvent];
6663 - (void)rightMouseUp: (NSEvent *)theEvent
6665 NSTRACE ("[EmacsView rightMouseUp:]");
6666 [self mouseDown: theEvent];
6670 - (void)otherMouseUp: (NSEvent *)theEvent
6672 NSTRACE ("[EmacsView otherMouseUp:]");
6673 [self mouseDown: theEvent];
6677 - (void) scrollWheel: (NSEvent *)theEvent
6679 NSTRACE ("[EmacsView scrollWheel:]");
6680 [self mouseDown: theEvent];
6684 /* Tell emacs the mouse has moved. */
6685 - (void)mouseMoved: (NSEvent *)e
6687 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
6688 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6692 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsView mouseMoved:]");
6694 dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
6695 pt = [self convertPoint: [e locationInWindow] fromView: nil];
6696 dpyinfo->last_mouse_motion_x = pt.x;
6697 dpyinfo->last_mouse_motion_y = pt.y;
6699 /* update any mouse face */
6700 if (hlinfo->mouse_face_hidden)
6702 hlinfo->mouse_face_hidden = 0;
6703 clear_mouse_face (hlinfo);
6706 /* tooltip handling */
6707 previous_help_echo_string = help_echo_string;
6708 help_echo_string = Qnil;
6710 if (!NILP (Vmouse_autoselect_window))
6712 NSTRACE_MSG ("mouse_autoselect_window");
6713 static Lisp_Object last_mouse_window;
6715 = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
6717 if (WINDOWP (window)
6718 && !EQ (window, last_mouse_window)
6719 && !EQ (window, selected_window)
6720 && (!NILP (focus_follows_mouse)
6721 || (EQ (XWINDOW (window)->frame,
6722 XWINDOW (selected_window)->frame))))
6724 NSTRACE_MSG ("in_window");
6725 emacs_event->kind = SELECT_WINDOW_EVENT;
6726 emacs_event->frame_or_window = window;
6729 /* Remember the last window where we saw the mouse. */
6730 last_mouse_window = window;
6733 if (!note_mouse_movement (emacsframe, pt.x, pt.y))
6734 help_echo_string = previous_help_echo_string;
6736 XSETFRAME (frame, emacsframe);
6737 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
6739 /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
6740 (note_mouse_highlight), which is called through the
6741 note_mouse_movement () call above */
6742 any_help_event_p = YES;
6743 gen_help_event (help_echo_string, frame, help_echo_window,
6744 help_echo_object, help_echo_pos);
6747 if (emacsframe->mouse_moved && send_appdefined)
6748 ns_send_appdefined (-1);
6752 - (void)mouseDragged: (NSEvent *)e
6754 NSTRACE ("[EmacsView mouseDragged:]");
6755 [self mouseMoved: e];
6759 - (void)rightMouseDragged: (NSEvent *)e
6761 NSTRACE ("[EmacsView rightMouseDragged:]");
6762 [self mouseMoved: e];
6766 - (void)otherMouseDragged: (NSEvent *)e
6768 NSTRACE ("[EmacsView otherMouseDragged:]");
6769 [self mouseMoved: e];
6773 - (BOOL)windowShouldClose: (id)sender
6775 NSEvent *e =[[self window] currentEvent];
6777 NSTRACE ("[EmacsView windowShouldClose:]");
6778 windowClosing = YES;
6781 emacs_event->kind = DELETE_WINDOW_EVENT;
6782 emacs_event->modifiers = 0;
6783 emacs_event->code = 0;
6785 /* Don't close this window, let this be done from lisp code. */
6789 - (void) updateFrameSize: (BOOL) delay
6791 NSWindow *window = [self window];
6792 NSRect wr = [window frame];
6794 int oldc = cols, oldr = rows;
6795 int oldw = FRAME_PIXEL_WIDTH (emacsframe);
6796 int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
6799 NSTRACE ("[EmacsView updateFrameSize:]");
6800 NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
6801 NSTRACE_RECT ("Original frame", wr);
6802 NSTRACE_MSG ("Original columns: %d", cols);
6803 NSTRACE_MSG ("Original rows: %d", rows);
6805 if (! [self isFullscreen])
6807 #ifdef NS_IMPL_GNUSTEP
6808 // GNUstep does not always update the tool bar height. Force it.
6809 if (toolbar && [toolbar isVisible])
6810 update_frame_tool_bar (emacsframe);
6813 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6814 + FRAME_TOOLBAR_HEIGHT (emacsframe);
6817 if (wait_for_tool_bar)
6819 /* The toolbar height is always 0 in fullscreen and undecorated
6820 frames, so don't wait for it to become available. */
6821 if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0
6822 && FRAME_UNDECORATED (emacsframe) == false
6823 && ! [self isFullscreen])
6825 NSTRACE_MSG ("Waiting for toolbar");
6828 wait_for_tool_bar = NO;
6831 neww = (int)wr.size.width - emacsframe->border_width;
6832 newh = (int)wr.size.height - extra;
6834 NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
6835 NSTRACE_MSG ("FRAME_TOOLBAR_HEIGHT: %d", FRAME_TOOLBAR_HEIGHT (emacsframe));
6836 NSTRACE_MSG ("FRAME_NS_TITLEBAR_HEIGHT: %d", FRAME_NS_TITLEBAR_HEIGHT (emacsframe));
6838 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
6839 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
6841 if (cols < MINWIDTH)
6844 if (rows < MINHEIGHT)
6847 NSTRACE_MSG ("New columns: %d", cols);
6848 NSTRACE_MSG ("New rows: %d", rows);
6850 if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
6852 NSView *view = FRAME_NS_VIEW (emacsframe);
6854 change_frame_size (emacsframe,
6855 FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
6856 FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
6858 SET_FRAME_GARBAGED (emacsframe);
6859 cancel_mouse_face (emacsframe);
6861 /* The next two lines appear to be setting the frame to the same
6862 size as it already is. Why are they there? */
6863 // wr = NSMakeRect (0, 0, neww, newh);
6865 // [view setFrame: wr];
6867 // to do: consider using [NSNotificationCenter postNotificationName:].
6868 [self windowDidMove: // Update top/left.
6869 [NSNotification notificationWithName:NSWindowDidMoveNotification
6870 object:[view window]]];
6874 NSTRACE_MSG ("No change");
6878 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
6879 /* normalize frame to gridded text size */
6883 NSTRACE ("[EmacsView windowWillResize:toSize: " NSTRACE_FMT_SIZE "]",
6884 NSTRACE_ARG_SIZE (frameSize));
6885 NSTRACE_RECT ("[sender frame]", [sender frame]);
6886 NSTRACE_FSTYPE ("fs_state", fs_state);
6888 if (!FRAME_LIVE_P (emacsframe))
6891 if (fs_state == FULLSCREEN_MAXIMIZED
6892 && (maximized_width != (int)frameSize.width
6893 || maximized_height != (int)frameSize.height))
6894 [self setFSValue: FULLSCREEN_NONE];
6895 else if (fs_state == FULLSCREEN_WIDTH
6896 && maximized_width != (int)frameSize.width)
6897 [self setFSValue: FULLSCREEN_NONE];
6898 else if (fs_state == FULLSCREEN_HEIGHT
6899 && maximized_height != (int)frameSize.height)
6900 [self setFSValue: FULLSCREEN_NONE];
6902 if (fs_state == FULLSCREEN_NONE)
6903 maximized_width = maximized_height = -1;
6905 if (! [self isFullscreen])
6907 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6908 + FRAME_TOOLBAR_HEIGHT (emacsframe);
6911 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
6912 if (cols < MINWIDTH)
6915 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
6916 frameSize.height - extra);
6917 if (rows < MINHEIGHT)
6919 #ifdef NS_IMPL_COCOA
6921 /* this sets window title to have size in it; the wm does this under GS */
6922 NSRect r = [[self window] frame];
6923 if (r.size.height == frameSize.height && r.size.width == frameSize.width)
6931 else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize
6932 && [[self window] title] != NULL)
6935 NSWindow *window = [self window];
6938 char *t = strdup ([[[self window] title] UTF8String]);
6939 char *pos = strstr (t, " — ");
6944 size_title = xmalloc (strlen (old_title) + 40);
6945 esprintf (size_title, "%s — (%d x %d)", old_title, cols, rows);
6946 [window setTitle: [NSString stringWithUTF8String: size_title]];
6951 #endif /* NS_IMPL_COCOA */
6953 NSTRACE_MSG ("cols: %d rows: %d", cols, rows);
6955 /* Restrict the new size to the text gird.
6957 Don't restrict the width if the user only adjusted the height, and
6958 vice versa. (Without this, the frame would shrink, and move
6959 slightly, if the window was resized by dragging one of its
6961 if (!frame_resize_pixelwise)
6963 NSRect r = [[self window] frame];
6965 if (r.size.width != frameSize.width)
6968 FRAME_TEXT_COLS_TO_PIXEL_WIDTH (emacsframe, cols);
6971 if (r.size.height != frameSize.height)
6974 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (emacsframe, rows) + extra;
6978 NSTRACE_RETURN_SIZE (frameSize);
6984 - (void)windowDidResize: (NSNotification *)notification
6986 NSTRACE ("[EmacsView windowDidResize:]");
6987 if (!FRAME_LIVE_P (emacsframe))
6989 NSTRACE_MSG ("Ignored (frame dead)");
6992 if (emacsframe->output_data.ns->in_animation)
6994 NSTRACE_MSG ("Ignored (in animation)");
6998 if (! [self fsIsNative])
7000 NSWindow *theWindow = [notification object];
7001 /* We can get notification on the non-FS window when in
7003 if ([self window] != theWindow) return;
7006 NSTRACE_RECT ("frame", [[notification object] frame]);
7008 #ifdef NS_IMPL_GNUSTEP
7009 NSWindow *theWindow = [notification object];
7011 /* In GNUstep, at least currently, it's possible to get a didResize
7012 without getting a willResize.. therefore we need to act as if we got
7013 the willResize now */
7014 NSSize sz = [theWindow frame].size;
7015 sz = [self windowWillResize: theWindow toSize: sz];
7016 #endif /* NS_IMPL_GNUSTEP */
7018 if (cols > 0 && rows > 0)
7020 [self updateFrameSize: YES];
7023 ns_send_appdefined (-1);
7026 #ifdef NS_IMPL_COCOA
7027 - (void)viewDidEndLiveResize
7029 NSTRACE ("[EmacsView viewDidEndLiveResize]");
7031 [super viewDidEndLiveResize];
7034 [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
7038 maximizing_resize = NO;
7040 #endif /* NS_IMPL_COCOA */
7043 - (void)windowDidBecomeKey: (NSNotification *)notification
7044 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
7046 [self windowDidBecomeKey];
7050 - (void)windowDidBecomeKey /* for direct calls */
7052 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
7053 struct frame *old_focus = dpyinfo->x_focus_frame;
7055 NSTRACE ("[EmacsView windowDidBecomeKey]");
7057 if (emacsframe != old_focus)
7058 dpyinfo->x_focus_frame = emacsframe;
7060 ns_frame_rehighlight (emacsframe);
7064 emacs_event->kind = FOCUS_IN_EVENT;
7065 EV_TRAILER ((id)nil);
7070 - (void)windowDidResignKey: (NSNotification *)notification
7071 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
7073 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
7074 BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
7075 NSTRACE ("[EmacsView windowDidResignKey:]");
7078 dpyinfo->x_focus_frame = 0;
7080 emacsframe->mouse_moved = 0;
7081 ns_frame_rehighlight (emacsframe);
7083 /* FIXME: for some reason needed on second and subsequent clicks away
7084 from sole-frame Emacs to get hollow box to show */
7085 if (!windowClosing && [[self window] isVisible] == YES)
7087 x_update_cursor (emacsframe, 1);
7088 x_set_frame_alpha (emacsframe);
7091 if (any_help_event_p)
7094 XSETFRAME (frame, emacsframe);
7095 help_echo_string = Qnil;
7096 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
7099 if (emacs_event && is_focus_frame)
7101 [self deleteWorkingText];
7102 emacs_event->kind = FOCUS_OUT_EVENT;
7103 EV_TRAILER ((id)nil);
7108 - (void)windowWillMiniaturize: sender
7110 NSTRACE ("[EmacsView windowWillMiniaturize:]");
7114 - (void)setFrame:(NSRect)frameRect
7116 NSTRACE ("[EmacsView setFrame:" NSTRACE_FMT_RECT "]",
7117 NSTRACE_ARG_RECT (frameRect));
7119 [super setFrame:(NSRect)frameRect];
7135 - (void)createToolbar: (struct frame *)f
7137 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
7138 NSWindow *window = [view window];
7140 toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
7141 [NSString stringWithFormat: @"Emacs Frame %d",
7143 [toolbar setVisible: NO];
7144 [window setToolbar: toolbar];
7146 /* Don't set frame garbaged until tool bar is up to date?
7147 This avoids an extra clear and redraw (flicker) at frame creation. */
7148 if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
7149 else wait_for_tool_bar = NO;
7152 #ifdef NS_IMPL_COCOA
7154 NSButton *toggleButton;
7155 toggleButton = [window standardWindowButton: NSWindowToolbarButton];
7156 [toggleButton setTarget: self];
7157 [toggleButton setAction: @selector (toggleToolbar: )];
7163 - (instancetype) initFrameFromEmacs: (struct frame *)f
7171 NSTRACE ("[EmacsView initFrameFromEmacs:]");
7172 NSTRACE_MSG ("cols:%d lines:%d", f->text_cols, f->text_lines);
7175 processingCompose = NO;
7176 scrollbarsNeedingUpdate = 0;
7177 fs_state = FULLSCREEN_NONE;
7178 fs_before_fs = next_maximized = -1;
7181 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7182 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7183 if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7185 fs_is_native = ns_use_native_fullscreen;
7188 maximized_width = maximized_height = -1;
7191 ns_userRect = NSMakeRect (0, 0, 0, 0);
7192 r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
7193 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
7194 [self initWithFrame: r];
7195 [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
7197 FRAME_NS_VIEW (f) = self;
7199 #ifdef NS_IMPL_COCOA
7201 maximizing_resize = NO;
7204 win = [[EmacsWindow alloc]
7205 initWithContentRect: r
7206 styleMask: (FRAME_UNDECORATED (f)
7207 ? FRAME_UNDECORATED_FLAGS
7208 : FRAME_DECORATED_FLAGS)
7209 backing: NSBackingStoreBuffered
7212 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7213 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7214 if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7216 [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
7220 bwidth = f->border_width = wr.size.width - r.size.width;
7222 [win setAcceptsMouseMovedEvents: YES];
7223 [win setDelegate: self];
7224 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7225 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7226 if ([win respondsToSelector: @selector(useOptimizedDrawing:)])
7228 [win useOptimizedDrawing: YES];
7231 [[win contentView] addSubview: self];
7234 [self registerForDraggedTypes: ns_drag_types];
7237 name = [NSString stringWithUTF8String:
7238 NILP (tem) ? "Emacs" : SSDATA (tem)];
7239 [win setTitle: name];
7241 /* toolbar support */
7242 if (! FRAME_UNDECORATED (f))
7243 [self createToolbar: f];
7245 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
7246 #ifndef NSAppKitVersionNumber10_10
7247 #define NSAppKitVersionNumber10_10 1343
7250 if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_10
7251 && FRAME_NS_APPEARANCE (f) != ns_appearance_aqua)
7252 win.appearance = [NSAppearance
7253 appearanceNamed: NSAppearanceNameVibrantDark];
7256 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
7257 if ([win respondsToSelector: @selector(titlebarAppearsTransparent)])
7258 win.titlebarAppearsTransparent = FRAME_NS_TRANSPARENT_TITLEBAR (f);
7263 [win setMiniwindowTitle:
7264 [NSString stringWithUTF8String: SSDATA (tem)]];
7266 if (FRAME_PARENT_FRAME (f) != NULL)
7268 NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
7269 [parent addChildWindow: win
7270 ordered: NSWindowAbove];
7273 if (FRAME_Z_GROUP (f) != z_group_none)
7274 win.level = NSNormalWindowLevel
7275 + (FRAME_Z_GROUP_BELOW (f) ? -1 : 1);
7278 NSScreen *screen = [win screen];
7282 NSPoint pt = NSMakePoint
7283 (IN_BOUND (-SCREENMAX, f->left_pos
7284 + NS_PARENT_WINDOW_LEFT_POS (f), SCREENMAX),
7285 IN_BOUND (-SCREENMAX,
7286 NS_PARENT_WINDOW_TOP_POS (f) - f->top_pos,
7289 [win setFrameTopLeftPoint: pt];
7291 NSTRACE_RECT ("new frame", [win frame]);
7295 [win makeFirstResponder: self];
7297 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7298 (FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID)),
7300 [win setBackgroundColor: col];
7301 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7302 [win setOpaque: NO];
7304 #if !defined (NS_IMPL_COCOA) \
7305 || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7306 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7307 if ([self respondsToSelector: @selector(allocateGState)])
7309 [self allocateGState];
7311 [NSApp registerServicesMenuSendTypes: ns_send_types
7312 returnTypes: [NSArray array]];
7314 /* macOS Sierra automatically enables tabbed windows. We can't
7315 allow this to be enabled until it's available on a Free system.
7316 Currently it only happens by accident and is buggy anyway. */
7317 #if defined (NS_IMPL_COCOA) \
7318 && MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
7319 #if MAC_OS_X_VERSION_MIN_REQUIRED < 101200
7320 if ([win respondsToSelector: @selector(setTabbingMode:)])
7322 [win setTabbingMode: NSWindowTabbingModeDisallowed];
7330 - (void)windowDidMove: sender
7332 NSWindow *win = [self window];
7333 NSRect r = [win frame];
7334 NSArray *screens = [NSScreen screens];
7335 NSScreen *screen = [screens objectAtIndex: 0];
7337 NSTRACE ("[EmacsView windowDidMove:]");
7339 if (!emacsframe->output_data.ns)
7343 emacsframe->left_pos = r.origin.x - NS_PARENT_WINDOW_LEFT_POS (emacsframe);
7344 emacsframe->top_pos =
7345 NS_PARENT_WINDOW_TOP_POS (emacsframe) - (r.origin.y + r.size.height);
7349 emacs_event->kind = MOVE_FRAME_EVENT;
7350 EV_TRAILER ((id)nil);
7356 /* Called AFTER method below, but before our windowWillResize call there leads
7357 to windowDidResize -> x_set_window_size. Update emacs' notion of frame
7358 location so set_window_size moves the frame. */
7359 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
7361 NSTRACE (("[EmacsView windowShouldZoom:toFrame:" NSTRACE_FMT_RECT "]"
7362 NSTRACE_FMT_RETURN "YES"),
7363 NSTRACE_ARG_RECT (newFrame));
7365 emacsframe->output_data.ns->zooming = 1;
7370 /* Override to do something slightly nonstandard, but nice. First click on
7371 zoom button will zoom vertically. Second will zoom completely. Third
7372 returns to original. */
7373 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
7374 defaultFrame:(NSRect)defaultFrame
7376 // TODO: Rename to "currentFrame" and assign "result" properly in
7378 NSRect result = [sender frame];
7380 NSTRACE (("[EmacsView windowWillUseStandardFrame:defaultFrame:"
7381 NSTRACE_FMT_RECT "]"),
7382 NSTRACE_ARG_RECT (defaultFrame));
7383 NSTRACE_FSTYPE ("fs_state", fs_state);
7384 NSTRACE_FSTYPE ("fs_before_fs", fs_before_fs);
7385 NSTRACE_FSTYPE ("next_maximized", next_maximized);
7386 NSTRACE_RECT ("ns_userRect", ns_userRect);
7387 NSTRACE_RECT ("[sender frame]", [sender frame]);
7389 if (fs_before_fs != -1) /* Entering fullscreen */
7391 NSTRACE_MSG ("Entering fullscreen");
7392 result = defaultFrame;
7396 // Save the window size and position (frame) before the resize.
7397 if (fs_state != FULLSCREEN_MAXIMIZED
7398 && fs_state != FULLSCREEN_WIDTH)
7400 ns_userRect.size.width = result.size.width;
7401 ns_userRect.origin.x = result.origin.x;
7404 if (fs_state != FULLSCREEN_MAXIMIZED
7405 && fs_state != FULLSCREEN_HEIGHT)
7407 ns_userRect.size.height = result.size.height;
7408 ns_userRect.origin.y = result.origin.y;
7411 NSTRACE_RECT ("ns_userRect (2)", ns_userRect);
7413 if (next_maximized == FULLSCREEN_HEIGHT
7414 || (next_maximized == -1
7415 && abs ((int)(defaultFrame.size.height - result.size.height))
7416 > FRAME_LINE_HEIGHT (emacsframe)))
7419 NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7420 maximized_height = result.size.height = defaultFrame.size.height;
7421 maximized_width = -1;
7422 result.origin.y = defaultFrame.origin.y;
7423 if (ns_userRect.size.height != 0)
7425 result.origin.x = ns_userRect.origin.x;
7426 result.size.width = ns_userRect.size.width;
7428 [self setFSValue: FULLSCREEN_HEIGHT];
7429 #ifdef NS_IMPL_COCOA
7430 maximizing_resize = YES;
7433 else if (next_maximized == FULLSCREEN_WIDTH)
7435 NSTRACE_MSG ("FULLSCREEN_WIDTH");
7436 maximized_width = result.size.width = defaultFrame.size.width;
7437 maximized_height = -1;
7438 result.origin.x = defaultFrame.origin.x;
7439 if (ns_userRect.size.width != 0)
7441 result.origin.y = ns_userRect.origin.y;
7442 result.size.height = ns_userRect.size.height;
7444 [self setFSValue: FULLSCREEN_WIDTH];
7446 else if (next_maximized == FULLSCREEN_MAXIMIZED
7447 || (next_maximized == -1
7448 && abs ((int)(defaultFrame.size.width - result.size.width))
7449 > FRAME_COLUMN_WIDTH (emacsframe)))
7451 NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7453 result = defaultFrame; /* second click */
7454 maximized_width = result.size.width;
7455 maximized_height = result.size.height;
7456 [self setFSValue: FULLSCREEN_MAXIMIZED];
7457 #ifdef NS_IMPL_COCOA
7458 maximizing_resize = YES;
7464 NSTRACE_MSG ("Restore");
7465 result = ns_userRect.size.height ? ns_userRect : result;
7466 NSTRACE_RECT ("restore (2)", result);
7467 ns_userRect = NSMakeRect (0, 0, 0, 0);
7468 #ifdef NS_IMPL_COCOA
7469 maximizing_resize = fs_state != FULLSCREEN_NONE;
7471 [self setFSValue: FULLSCREEN_NONE];
7472 maximized_width = maximized_height = -1;
7476 if (fs_before_fs == -1) next_maximized = -1;
7478 NSTRACE_RECT ("Final ns_userRect", ns_userRect);
7479 NSTRACE_MSG ("Final maximized_width: %d", maximized_width);
7480 NSTRACE_MSG ("Final maximized_height: %d", maximized_height);
7481 NSTRACE_FSTYPE ("Final next_maximized", next_maximized);
7483 [self windowWillResize: sender toSize: result.size];
7485 NSTRACE_RETURN_RECT (result);
7491 - (void)windowDidDeminiaturize: sender
7493 NSTRACE ("[EmacsView windowDidDeminiaturize:]");
7494 if (!emacsframe->output_data.ns)
7497 SET_FRAME_ICONIFIED (emacsframe, 0);
7498 SET_FRAME_VISIBLE (emacsframe, 1);
7499 windows_or_buffers_changed = 63;
7503 emacs_event->kind = DEICONIFY_EVENT;
7504 EV_TRAILER ((id)nil);
7509 - (void)windowDidExpose: sender
7511 NSTRACE ("[EmacsView windowDidExpose:]");
7512 if (!emacsframe->output_data.ns)
7515 SET_FRAME_VISIBLE (emacsframe, 1);
7516 SET_FRAME_GARBAGED (emacsframe);
7518 if (send_appdefined)
7519 ns_send_appdefined (-1);
7523 - (void)windowDidMiniaturize: sender
7525 NSTRACE ("[EmacsView windowDidMiniaturize:]");
7526 if (!emacsframe->output_data.ns)
7529 SET_FRAME_ICONIFIED (emacsframe, 1);
7530 SET_FRAME_VISIBLE (emacsframe, 0);
7534 emacs_event->kind = ICONIFY_EVENT;
7535 EV_TRAILER ((id)nil);
7539 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7540 - (NSApplicationPresentationOptions)window:(NSWindow *)window
7541 willUseFullScreenPresentationOptions:
7542 (NSApplicationPresentationOptions)proposedOptions
7544 return proposedOptions|NSApplicationPresentationAutoHideToolbar;
7548 - (void)windowWillEnterFullScreen:(NSNotification *)notification
7550 NSTRACE ("[EmacsView windowWillEnterFullScreen:]");
7551 [self windowWillEnterFullScreen];
7553 - (void)windowWillEnterFullScreen /* provided for direct calls */
7555 NSTRACE ("[EmacsView windowWillEnterFullScreen]");
7556 fs_before_fs = fs_state;
7559 - (void)windowDidEnterFullScreen:(NSNotification *)notification
7561 NSTRACE ("[EmacsView windowDidEnterFullScreen:]");
7562 [self windowDidEnterFullScreen];
7565 - (void)windowDidEnterFullScreen /* provided for direct calls */
7567 NSTRACE ("[EmacsView windowDidEnterFullScreen]");
7568 [self setFSValue: FULLSCREEN_BOTH];
7569 if (! [self fsIsNative])
7571 [self windowDidBecomeKey];
7572 [nonfs_window orderOut:self];
7576 BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
7577 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 \
7578 && MAC_OS_X_VERSION_MIN_REQUIRED <= 1070
7579 unsigned val = (unsigned)[NSApp presentationOptions];
7581 // Mac OS X 10.7 bug fix, the menu won't appear without this.
7582 // val is non-zero on other macOS versions.
7585 NSApplicationPresentationOptions options
7586 = NSApplicationPresentationAutoHideDock
7587 | NSApplicationPresentationAutoHideMenuBar
7588 | NSApplicationPresentationFullScreen
7589 | NSApplicationPresentationAutoHideToolbar;
7591 [NSApp setPresentationOptions: options];
7594 [toolbar setVisible:tbar_visible];
7598 - (void)windowWillExitFullScreen:(NSNotification *)notification
7600 NSTRACE ("[EmacsView windowWillExitFullScreen:]");
7601 [self windowWillExitFullScreen];
7604 - (void)windowWillExitFullScreen /* provided for direct calls */
7606 NSTRACE ("[EmacsView windowWillExitFullScreen]");
7607 if (!FRAME_LIVE_P (emacsframe))
7609 NSTRACE_MSG ("Ignored (frame dead)");
7612 if (next_maximized != -1)
7613 fs_before_fs = next_maximized;
7616 - (void)windowDidExitFullScreen:(NSNotification *)notification
7618 NSTRACE ("[EmacsView windowDidExitFullScreen:]");
7619 [self windowDidExitFullScreen];
7622 - (void)windowDidExitFullScreen /* provided for direct calls */
7624 NSTRACE ("[EmacsView windowDidExitFullScreen]");
7625 if (!FRAME_LIVE_P (emacsframe))
7627 NSTRACE_MSG ("Ignored (frame dead)");
7630 [self setFSValue: fs_before_fs];
7632 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7633 [self updateCollectionBehavior];
7635 if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
7637 [toolbar setVisible:YES];
7638 update_frame_tool_bar (emacsframe);
7639 [self updateFrameSize:YES];
7640 [[self window] display];
7643 [toolbar setVisible:NO];
7645 if (next_maximized != -1)
7646 [[self window] performZoom:self];
7651 return fs_is_native;
7654 - (BOOL)isFullscreen
7660 res = (nonfs_window != nil);
7664 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7665 res = (([[self window] styleMask] & NSWindowStyleMaskFullScreen) != 0);
7671 NSTRACE ("[EmacsView isFullscreen] " NSTRACE_FMT_RETURN " %d",
7677 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7678 - (void)updateCollectionBehavior
7680 NSTRACE ("[EmacsView updateCollectionBehavior]");
7682 if (! [self isFullscreen])
7684 NSWindow *win = [self window];
7685 NSWindowCollectionBehavior b = [win collectionBehavior];
7686 if (ns_use_native_fullscreen)
7687 b |= NSWindowCollectionBehaviorFullScreenPrimary;
7689 b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
7691 [win setCollectionBehavior: b];
7692 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7693 if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7695 fs_is_native = ns_use_native_fullscreen;
7700 - (void)toggleFullScreen: (id)sender
7708 NSTRACE ("[EmacsView toggleFullScreen:]");
7712 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7713 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7714 if ([[self window] respondsToSelector: @selector(toggleFullScreen:)])
7716 [[self window] toggleFullScreen:sender];
7722 onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
7725 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7726 (FACE_FROM_ID (f, DEFAULT_FACE_ID)),
7729 if (fs_state != FULLSCREEN_BOTH)
7731 NSScreen *screen = [w screen];
7733 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
7734 /* Hide ghost menu bar on secondary monitor? */
7736 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
7737 && [NSScreen respondsToSelector: @selector(screensHaveSeparateSpaces)]
7740 onFirstScreen = [NSScreen screensHaveSeparateSpaces];
7742 /* Hide dock and menubar if we are on the primary screen. */
7745 #ifdef NS_IMPL_COCOA
7746 NSApplicationPresentationOptions options
7747 = NSApplicationPresentationAutoHideDock
7748 | NSApplicationPresentationAutoHideMenuBar;
7750 [NSApp setPresentationOptions: options];
7752 [NSMenu setMenuBarVisible:NO];
7756 fw = [[EmacsFSWindow alloc]
7757 initWithContentRect:[w contentRectForFrameRect:wr]
7758 styleMask:NSWindowStyleMaskBorderless
7759 backing:NSBackingStoreBuffered
7763 [fw setContentView:[w contentView]];
7764 [fw setTitle:[w title]];
7765 [fw setDelegate:self];
7766 [fw setAcceptsMouseMovedEvents: YES];
7767 #if !defined (NS_IMPL_COCOA) \
7768 || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7769 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7770 if ([fw respondsToSelector: @selector(useOptimizedDrawing:)])
7772 [fw useOptimizedDrawing: YES];
7774 [fw setBackgroundColor: col];
7775 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7778 f->border_width = 0;
7782 [self windowWillEnterFullScreen];
7783 [fw makeKeyAndOrderFront:NSApp];
7784 [fw makeFirstResponder:self];
7786 r = [fw frameRectForContentRect:[screen frame]];
7787 [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
7788 [self windowDidEnterFullScreen];
7799 #ifdef NS_IMPL_COCOA
7800 [NSApp setPresentationOptions: NSApplicationPresentationDefault];
7802 [NSMenu setMenuBarVisible:YES];
7806 [w setContentView:[fw contentView]];
7807 [w setBackgroundColor: col];
7808 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7811 f->border_width = bwidth;
7813 // to do: consider using [NSNotificationCenter postNotificationName:] to send notifications.
7815 [self windowWillExitFullScreen];
7816 [fw setFrame: [w frame] display:YES animate:ns_use_fullscreen_animation];
7818 [w makeKeyAndOrderFront:NSApp];
7819 [self windowDidExitFullScreen];
7820 [self updateFrameSize:YES];
7826 NSTRACE ("[EmacsView handleFS]");
7828 if (fs_state != emacsframe->want_fullscreen)
7830 if (fs_state == FULLSCREEN_BOTH)
7832 NSTRACE_MSG ("fs_state == FULLSCREEN_BOTH");
7833 [self toggleFullScreen:self];
7836 switch (emacsframe->want_fullscreen)
7838 case FULLSCREEN_BOTH:
7839 NSTRACE_MSG ("FULLSCREEN_BOTH");
7840 [self toggleFullScreen:self];
7842 case FULLSCREEN_WIDTH:
7843 NSTRACE_MSG ("FULLSCREEN_WIDTH");
7844 next_maximized = FULLSCREEN_WIDTH;
7845 if (fs_state != FULLSCREEN_BOTH)
7846 [[self window] performZoom:self];
7848 case FULLSCREEN_HEIGHT:
7849 NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7850 next_maximized = FULLSCREEN_HEIGHT;
7851 if (fs_state != FULLSCREEN_BOTH)
7852 [[self window] performZoom:self];
7854 case FULLSCREEN_MAXIMIZED:
7855 NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7856 next_maximized = FULLSCREEN_MAXIMIZED;
7857 if (fs_state != FULLSCREEN_BOTH)
7858 [[self window] performZoom:self];
7860 case FULLSCREEN_NONE:
7861 NSTRACE_MSG ("FULLSCREEN_NONE");
7862 if (fs_state != FULLSCREEN_BOTH)
7864 next_maximized = FULLSCREEN_NONE;
7865 [[self window] performZoom:self];
7870 emacsframe->want_fullscreen = FULLSCREEN_NONE;
7875 - (void) setFSValue: (int)value
7877 NSTRACE ("[EmacsView setFSValue:" NSTRACE_FMT_FSTYPE "]",
7878 NSTRACE_ARG_FSTYPE(value));
7880 Lisp_Object lval = Qnil;
7883 case FULLSCREEN_BOTH:
7886 case FULLSCREEN_WIDTH:
7889 case FULLSCREEN_HEIGHT:
7892 case FULLSCREEN_MAXIMIZED:
7896 store_frame_param (emacsframe, Qfullscreen, lval);
7900 - (void)mouseEntered: (NSEvent *)theEvent
7902 NSTRACE ("[EmacsView mouseEntered:]");
7904 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7905 = EV_TIMESTAMP (theEvent);
7909 - (void)mouseExited: (NSEvent *)theEvent
7911 Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
7913 NSTRACE ("[EmacsView mouseExited:]");
7918 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7919 = EV_TIMESTAMP (theEvent);
7921 if (emacsframe == hlinfo->mouse_face_mouse_frame)
7923 clear_mouse_face (hlinfo);
7924 hlinfo->mouse_face_mouse_frame = 0;
7929 - (instancetype)menuDown: sender
7931 NSTRACE ("[EmacsView menuDown:]");
7932 if (context_menu_value == -1)
7933 context_menu_value = [sender tag];
7936 NSInteger tag = [sender tag];
7937 find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
7938 emacsframe->menu_bar_vector,
7942 ns_send_appdefined (-1);
7947 - (EmacsToolbar *)toolbar
7953 /* this gets called on toolbar button click */
7954 - (instancetype)toolbarClicked: (id)item
7957 int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
7959 NSTRACE ("[EmacsView toolbarClicked:]");
7964 /* send first event (for some reason two needed) */
7965 theEvent = [[self window] currentEvent];
7966 emacs_event->kind = TOOL_BAR_EVENT;
7967 XSETFRAME (emacs_event->arg, emacsframe);
7968 EV_TRAILER (theEvent);
7970 emacs_event->kind = TOOL_BAR_EVENT;
7971 /* XSETINT (emacs_event->code, 0); */
7972 emacs_event->arg = AREF (emacsframe->tool_bar_items,
7973 idx + TOOL_BAR_ITEM_KEY);
7974 emacs_event->modifiers = EV_MODIFIERS (theEvent);
7975 EV_TRAILER (theEvent);
7980 - (instancetype)toggleToolbar: (id)sender
7982 NSTRACE ("[EmacsView toggleToolbar:]");
7987 emacs_event->kind = NS_NONKEY_EVENT;
7988 emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
7989 EV_TRAILER ((id)nil);
7994 - (void)drawRect: (NSRect)rect
7996 int x = NSMinX (rect), y = NSMinY (rect);
7997 int width = NSWidth (rect), height = NSHeight (rect);
7999 NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
8000 NSTRACE_ARG_RECT(rect));
8002 if (!emacsframe || !emacsframe->output_data.ns)
8005 ns_clear_frame_area (emacsframe, x, y, width, height);
8007 expose_frame (emacsframe, x, y, width, height);
8011 drawRect: may be called (at least in Mac OS X 10.5) for invisible
8012 views as well for some reason. Thus, do not infer visibility
8015 emacsframe->async_visible = 1;
8016 emacsframe->async_iconified = 0;
8021 /* NSDraggingDestination protocol methods. Actually this is not really a
8022 protocol, but a category of Object. O well... */
8024 -(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
8026 NSTRACE ("[EmacsView draggingEntered:]");
8027 return NSDragOperationGeneric;
8031 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
8037 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
8042 NSEvent *theEvent = [[self window] currentEvent];
8044 NSDragOperation op = [sender draggingSourceOperationMask];
8047 NSTRACE ("[EmacsView performDragOperation:]");
8052 position = [self convertPoint: [sender draggingLocation] fromView: nil];
8053 x = lrint (position.x); y = lrint (position.y);
8055 pb = [sender draggingPasteboard];
8056 type = [pb availableTypeFromArray: ns_drag_types];
8058 if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
8059 // URL drags contain all operations (0xf), don't allow all to be set.
8062 if (op & NSDragOperationLink)
8063 modifiers |= NSEventModifierFlagControl;
8064 if (op & NSDragOperationCopy)
8065 modifiers |= NSEventModifierFlagOption;
8066 if (op & NSDragOperationGeneric)
8067 modifiers |= NSEventModifierFlagCommand;
8070 modifiers = EV_MODIFIERS2 (modifiers);
8075 else if ([type isEqualToString: NSFilenamesPboardType])
8078 NSEnumerator *fenum;
8081 if (!(files = [pb propertyListForType: type]))
8084 fenum = [files objectEnumerator];
8085 while ( (file = [fenum nextObject]) )
8087 emacs_event->kind = DRAG_N_DROP_EVENT;
8088 XSETINT (emacs_event->x, x);
8089 XSETINT (emacs_event->y, y);
8090 ns_input_file = append2 (ns_input_file,
8091 build_string ([file UTF8String]));
8092 emacs_event->modifiers = modifiers;
8093 emacs_event->arg = list2 (Qfile, build_string ([file UTF8String]));
8094 EV_TRAILER (theEvent);
8098 else if ([type isEqualToString: NSURLPboardType])
8100 NSURL *url = [NSURL URLFromPasteboard: pb];
8101 if (url == nil) return NO;
8103 emacs_event->kind = DRAG_N_DROP_EVENT;
8104 XSETINT (emacs_event->x, x);
8105 XSETINT (emacs_event->y, y);
8106 emacs_event->modifiers = modifiers;
8107 emacs_event->arg = list2 (Qurl,
8108 build_string ([[url absoluteString]
8110 EV_TRAILER (theEvent);
8112 if ([url isFileURL] != NO)
8114 NSString *file = [url path];
8115 ns_input_file = append2 (ns_input_file,
8116 build_string ([file UTF8String]));
8120 else if ([type isEqualToString: NSStringPboardType]
8121 || [type isEqualToString: NSTabularTextPboardType])
8125 if (! (data = [pb stringForType: type]))
8128 emacs_event->kind = DRAG_N_DROP_EVENT;
8129 XSETINT (emacs_event->x, x);
8130 XSETINT (emacs_event->y, y);
8131 emacs_event->modifiers = modifiers;
8132 emacs_event->arg = list2 (Qnil, build_string ([data UTF8String]));
8133 EV_TRAILER (theEvent);
8138 fprintf (stderr, "Invalid data type in dragging pasteboard");
8144 - (id) validRequestorForSendType: (NSString *)typeSent
8145 returnType: (NSString *)typeReturned
8147 NSTRACE ("[EmacsView validRequestorForSendType:returnType:]");
8148 if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
8149 && typeReturned == nil)
8151 if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
8155 return [super validRequestorForSendType: typeSent
8156 returnType: typeReturned];
8160 /* The next two methods are part of NSServicesRequests informal protocol,
8161 supposedly called when a services menu item is chosen from this app.
8162 But this should not happen because we override the services menu with our
8163 own entries which call ns-perform-service.
8164 Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
8165 So let's at least stub them out until further investigation can be done. */
8167 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
8169 /* we could call ns_string_from_pasteboard(pboard) here but then it should
8170 be written into the buffer in place of the existing selection..
8171 ordinary service calls go through functions defined in ns-win.el */
8175 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
8177 NSArray *typesDeclared;
8180 NSTRACE ("[EmacsView writeSelectionToPasteboard:types:]");
8182 /* We only support NSStringPboardType */
8183 if ([types containsObject:NSStringPboardType] == NO) {
8187 val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8188 if (CONSP (val) && SYMBOLP (XCAR (val)))
8191 if (CONSP (val) && NILP (XCDR (val)))
8194 if (! STRINGP (val))
8197 typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
8198 [pb declareTypes:typesDeclared owner:nil];
8199 ns_string_to_pasteboard (pb, val);
8204 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
8205 (gives a miniaturized version of the window); currently we use the latter for
8206 frames whose active buffer doesn't correspond to any file
8207 (e.g., '*scratch*') */
8208 - (instancetype)setMiniwindowImage: (BOOL) setMini
8210 id image = [[self window] miniwindowImage];
8211 NSTRACE ("[EmacsView setMiniwindowImage:%d]", setMini);
8213 /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
8214 about "AppleDockIconEnabled" notwithstanding, however the set message
8215 below has its effect nonetheless. */
8216 if (image != emacsframe->output_data.ns->miniimage)
8218 if (image && [image isKindOfClass: [EmacsImage class]])
8220 [[self window] setMiniwindowImage:
8221 setMini ? emacsframe->output_data.ns->miniimage : nil];
8228 - (void) setRows: (int) r andColumns: (int) c
8230 NSTRACE ("[EmacsView setRows:%d andColumns:%d]", r, c);
8235 - (int) fullscreenState
8240 @end /* EmacsView */
8244 /* ==========================================================================
8246 EmacsWindow implementation
8248 ========================================================================== */
8250 @implementation EmacsWindow
8252 #ifdef NS_IMPL_COCOA
8253 - (id)accessibilityAttributeValue:(NSString *)attribute
8255 Lisp_Object str = Qnil;
8256 struct frame *f = SELECTED_FRAME ();
8257 struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
8259 NSTRACE ("[EmacsWindow accessibilityAttributeValue:]");
8261 if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
8262 return NSAccessibilityTextFieldRole;
8264 if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
8265 && curbuf && ! NILP (BVAR (curbuf, mark_active)))
8267 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8269 else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
8271 if (! NILP (BVAR (curbuf, mark_active)))
8272 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8276 ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
8277 ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
8278 ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
8280 if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
8281 str = make_uninit_multibyte_string (range, byte_range);
8283 str = make_uninit_string (range);
8284 /* To check: This returns emacs-utf-8, which is a superset of utf-8.
8285 Is this a problem? */
8286 memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
8293 if (CONSP (str) && SYMBOLP (XCAR (str)))
8296 if (CONSP (str) && NILP (XCDR (str)))
8301 const char *utfStr = SSDATA (str);
8302 NSString *nsStr = [NSString stringWithUTF8String: utfStr];
8307 return [super accessibilityAttributeValue:attribute];
8309 #endif /* NS_IMPL_COCOA */
8311 /* Constrain size and placement of a frame.
8313 By returning the original "frameRect", the frame is not
8314 constrained. This can lead to unwanted situations where, for
8315 example, the menu bar covers the frame.
8317 The default implementation (accessed using "super") constrains the
8318 frame to the visible area of SCREEN, minus the menu bar (if
8319 present) and the Dock. Note that default implementation also calls
8320 windowWillResize, with the frame it thinks should have. (This can
8321 make the frame exit maximized mode.)
8323 Note that this should work in situations where multiple monitors
8324 are present. Common configurations are side-by-side monitors and a
8325 monitor on top of another (e.g. when a laptop is placed under a
8327 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
8329 NSTRACE ("[EmacsWindow constrainFrameRect:" NSTRACE_FMT_RECT " toScreen:]",
8330 NSTRACE_ARG_RECT (frameRect));
8332 #ifdef NS_IMPL_COCOA
8333 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
8334 // If separate spaces is on, it is like each screen is independent. There is
8335 // no spanning of frames across screens.
8337 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
8338 [NSScreen respondsToSelector: @selector(screensHaveSeparateSpaces)] &&
8340 [NSScreen screensHaveSeparateSpaces])
8342 NSTRACE_MSG ("Screens have separate spaces");
8343 frameRect = [super constrainFrameRect:frameRect toScreen:screen];
8344 NSTRACE_RETURN_RECT (frameRect);
8348 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 */
8350 // Check that the proposed frameRect is visible in at least one
8351 // screen. If it is not, ask the system to reposition it (only
8352 // for non-child windows).
8354 if (!FRAME_PARENT_FRAME (((EmacsView *)[self delegate])->emacsframe))
8356 NSArray *screens = [NSScreen screens];
8357 NSUInteger nr_screens = [screens count];
8360 BOOL frame_on_screen = NO;
8362 for (i = 0; i < nr_screens; ++i)
8364 NSScreen *s = [screens objectAtIndex: i];
8365 NSRect scrRect = [s frame];
8367 if (NSIntersectsRect(frameRect, scrRect))
8369 frame_on_screen = YES;
8374 if (!frame_on_screen)
8376 NSTRACE_MSG ("Frame outside screens; constraining");
8377 frameRect = [super constrainFrameRect:frameRect toScreen:screen];
8378 NSTRACE_RETURN_RECT (frameRect);
8384 return constrain_frame_rect(frameRect,
8385 [(EmacsView *)[self delegate] isFullscreen]);
8389 - (void)performZoom:(id)sender
8391 NSTRACE ("[EmacsWindow performZoom:]");
8393 return [super performZoom:sender];
8396 - (void)zoom:(id)sender
8398 NSTRACE ("[EmacsWindow zoom:]");
8400 ns_update_auto_hide_menu_bar();
8402 // Below are three zoom implementations. In the final commit, the
8403 // idea is that the last should be included.
8406 // Native zoom done using the standard zoom animation. Size of the
8407 // resulting frame reduced to accommodate the Dock and, if present,
8409 [super zoom:sender];
8412 // Native zoom done using the standard zoom animation, plus an
8413 // explicit resize to cover the full screen, except the menu-bar and
8414 // dock, if present.
8415 [super zoom:sender];
8417 // After the native zoom, resize the resulting frame to fill the
8418 // entire screen, except the menu-bar.
8420 // This works for all practical purposes. (The only minor oddity is
8421 // when transiting from full-height frame to a maximized, the
8422 // animation reduces the height of the frame slightly (to the 4
8423 // pixels needed to accommodate the Doc) before it snaps back into
8424 // full height. The user would need a very trained eye to spot
8426 NSScreen * screen = [self screen];
8429 int fs_state = [(EmacsView *)[self delegate] fullscreenState];
8431 NSTRACE_FSTYPE ("fullscreenState", fs_state);
8433 NSRect sr = [screen frame];
8434 struct EmacsMargins margins
8435 = ns_screen_margins_ignoring_hidden_dock(screen);
8437 NSRect wr = [self frame];
8438 NSTRACE_RECT ("Rect after zoom", wr);
8442 if (fs_state == FULLSCREEN_MAXIMIZED
8443 || fs_state == FULLSCREEN_HEIGHT)
8445 newWr.origin.y = sr.origin.y + margins.bottom;
8446 newWr.size.height = sr.size.height - margins.top - margins.bottom;
8449 if (fs_state == FULLSCREEN_MAXIMIZED
8450 || fs_state == FULLSCREEN_WIDTH)
8452 newWr.origin.x = sr.origin.x + margins.left;
8453 newWr.size.width = sr.size.width - margins.right - margins.left;
8456 if (newWr.size.width != wr.size.width
8457 || newWr.size.height != wr.size.height
8458 || newWr.origin.x != wr.origin.x
8459 || newWr.origin.y != wr.origin.y)
8461 NSTRACE_MSG ("New frame different");
8462 [self setFrame: newWr display: NO];
8466 // Non-native zoom which is done instantaneously. The resulting
8467 // frame covers the entire screen, except the menu-bar and dock, if
8469 NSScreen * screen = [self screen];
8472 NSRect sr = [screen frame];
8473 struct EmacsMargins margins
8474 = ns_screen_margins_ignoring_hidden_dock(screen);
8476 sr.size.height -= (margins.top + margins.bottom);
8477 sr.size.width -= (margins.left + margins.right);
8478 sr.origin.x += margins.left;
8479 sr.origin.y += margins.bottom;
8481 sr = [[self delegate] windowWillUseStandardFrame:self
8483 [self setFrame: sr display: NO];
8488 - (void)setFrame:(NSRect)windowFrame
8489 display:(BOOL)displayViews
8491 NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT " display:%d]",
8492 NSTRACE_ARG_RECT (windowFrame), displayViews);
8494 [super setFrame:windowFrame display:displayViews];
8497 - (void)setFrame:(NSRect)windowFrame
8498 display:(BOOL)displayViews
8499 animate:(BOOL)performAnimation
8501 NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT
8502 " display:%d performAnimation:%d]",
8503 NSTRACE_ARG_RECT (windowFrame), displayViews, performAnimation);
8505 [super setFrame:windowFrame display:displayViews animate:performAnimation];
8508 - (void)setFrameTopLeftPoint:(NSPoint)point
8510 NSTRACE ("[EmacsWindow setFrameTopLeftPoint:" NSTRACE_FMT_POINT "]",
8511 NSTRACE_ARG_POINT (point));
8513 [super setFrameTopLeftPoint:point];
8516 - (BOOL)canBecomeKeyWindow
8518 return !FRAME_NO_ACCEPT_FOCUS (((EmacsView *)[self delegate])->emacsframe);
8520 @end /* EmacsWindow */
8523 @implementation EmacsFSWindow
8525 - (BOOL)canBecomeKeyWindow
8530 - (BOOL)canBecomeMainWindow
8537 /* ==========================================================================
8539 EmacsScroller implementation
8541 ========================================================================== */
8544 @implementation EmacsScroller
8546 /* for repeat button push */
8547 #define SCROLL_BAR_FIRST_DELAY 0.5
8548 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
8550 + (CGFloat) scrollerWidth
8552 /* TODO: if we want to allow variable widths, this is the place to do it,
8553 however neither GNUstep nor Cocoa support it very well */
8555 #if defined (NS_IMPL_COCOA) \
8556 && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
8557 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
8558 if ([NSScroller respondsToSelector:
8559 @selector(scrollerWidthForControlSize:scrollerStyle:)])
8561 r = [NSScroller scrollerWidthForControlSize: NSControlSizeRegular
8562 scrollerStyle: NSScrollerStyleLegacy];
8563 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
8566 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
8567 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 \
8568 || defined (NS_IMPL_GNUSTEP)
8569 r = [NSScroller scrollerWidth];
8574 - (instancetype)initFrame: (NSRect )r window: (Lisp_Object)nwin
8576 NSTRACE ("[EmacsScroller initFrame: window:]");
8578 if (r.size.width > r.size.height)
8583 [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
8584 [self setContinuous: YES];
8585 [self setEnabled: YES];
8587 /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
8588 locked against the top and bottom edges, and right edge on macOS, where
8589 scrollers are on right. */
8590 #ifdef NS_IMPL_GNUSTEP
8591 [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
8593 [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
8596 window = XWINDOW (nwin);
8599 pixel_length = NSWidth (r);
8601 pixel_length = NSHeight (r);
8602 if (pixel_length == 0) pixel_length = 1;
8603 min_portion = 20 / pixel_length;
8605 frame = XFRAME (window->frame);
8606 if (FRAME_LIVE_P (frame))
8609 EmacsView *view = FRAME_NS_VIEW (frame);
8610 NSView *sview = [[view window] contentView];
8611 NSArray *subs = [sview subviews];
8613 /* disable optimization stopping redraw of other scrollbars */
8614 view->scrollbarsNeedingUpdate = 0;
8615 for (i =[subs count]-1; i >= 0; i--)
8616 if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
8617 view->scrollbarsNeedingUpdate++;
8618 [sview addSubview: self];
8621 /* [self setFrame: r]; */
8627 - (void)setFrame: (NSRect)newRect
8629 NSTRACE ("[EmacsScroller setFrame:]");
8631 /* block_input (); */
8633 pixel_length = NSWidth (newRect);
8635 pixel_length = NSHeight (newRect);
8636 if (pixel_length == 0) pixel_length = 1;
8637 min_portion = 20 / pixel_length;
8638 [super setFrame: newRect];
8639 /* unblock_input (); */
8645 NSTRACE ("[EmacsScroller dealloc]");
8649 wset_horizontal_scroll_bar (window, Qnil);
8651 wset_vertical_scroll_bar (window, Qnil);
8658 - (instancetype)condemn
8660 NSTRACE ("[EmacsScroller condemn]");
8666 - (instancetype)reprieve
8668 NSTRACE ("[EmacsScroller reprieve]");
8676 NSTRACE ("[EmacsScroller judge]");
8677 bool ret = condemned;
8682 /* ensure other scrollbar updates after deletion */
8683 view = (EmacsView *)FRAME_NS_VIEW (frame);
8685 view->scrollbarsNeedingUpdate++;
8689 wset_horizontal_scroll_bar (window, Qnil);
8691 wset_vertical_scroll_bar (window, Qnil);
8694 [self removeFromSuperview];
8702 - (void)resetCursorRects
8704 NSRect visible = [self visibleRect];
8705 NSTRACE ("[EmacsScroller resetCursorRects]");
8707 if (!NSIsEmptyRect (visible))
8708 [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
8709 [[NSCursor arrowCursor] setOnMouseEntered: YES];
8713 - (int) checkSamePosition: (int) position portion: (int) portion
8716 return em_position ==position && em_portion ==portion && em_whole ==whole
8717 && portion != whole; /* needed for resize empty buf */
8721 - (instancetype)setPosition: (int)position portion: (int)portion whole: (int)whole
8723 NSTRACE ("[EmacsScroller setPosition:portion:whole:]");
8725 em_position = position;
8726 em_portion = portion;
8729 if (portion >= whole)
8731 #ifdef NS_IMPL_COCOA
8732 [self setKnobProportion: 1.0];
8733 [self setDoubleValue: 1.0];
8735 [self setFloatValue: 0.0 knobProportion: 1.0];
8742 portion = max ((float)whole*min_portion/pixel_length, portion);
8743 pos = (float)position / (whole - portion);
8744 por = (CGFloat)portion/whole;
8745 #ifdef NS_IMPL_COCOA
8746 [self setKnobProportion: por];
8747 [self setDoubleValue: pos];
8749 [self setFloatValue: pos knobProportion: por];
8756 /* set up emacs_event */
8757 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
8761 NSTRACE ("[EmacsScroller sendScrollEventAtLoc:fromEvent:]");
8766 emacs_event->part = last_hit_part;
8767 emacs_event->code = 0;
8768 emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
8769 XSETWINDOW (win, window);
8770 emacs_event->frame_or_window = win;
8771 emacs_event->timestamp = EV_TIMESTAMP (e);
8772 emacs_event->arg = Qnil;
8776 emacs_event->kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT;
8777 XSETINT (emacs_event->x, em_whole * loc / pixel_length);
8778 XSETINT (emacs_event->y, em_whole);
8782 emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
8783 XSETINT (emacs_event->x, loc);
8784 XSETINT (emacs_event->y, pixel_length-20);
8789 n_emacs_events_pending++;
8790 kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
8793 hold_event (emacs_event);
8794 EVENT_INIT (*emacs_event);
8795 ns_send_appdefined (-1);
8799 /* called manually thru timer to implement repeated button action w/hold-down */
8800 - (instancetype)repeatScroll: (NSTimer *)scrollEntry
8802 NSEvent *e = [[self window] currentEvent];
8803 NSPoint p = [[self window] mouseLocationOutsideOfEventStream];
8804 BOOL inKnob = [self testPart: p] == NSScrollerKnob;
8806 NSTRACE ("[EmacsScroller repeatScroll:]");
8808 /* clear timer if need be */
8809 if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
8811 [scroll_repeat_entry invalidate];
8812 [scroll_repeat_entry release];
8813 scroll_repeat_entry = nil;
8819 = [[NSTimer scheduledTimerWithTimeInterval:
8820 SCROLL_BAR_CONTINUOUS_DELAY
8822 selector: @selector (repeatScroll:)
8828 [self sendScrollEventAtLoc: 0 fromEvent: e];
8833 /* Asynchronous mouse tracking for scroller. This allows us to dispatch
8834 mouseDragged events without going into a modal loop. */
8835 - (void)mouseDown: (NSEvent *)e
8838 /* hitPart is only updated AFTER event is passed on */
8839 NSScrollerPart part = [self testPart: [e locationInWindow]];
8840 CGFloat loc, kloc, pos UNINIT;
8843 NSTRACE ("[EmacsScroller mouseDown:]");
8847 case NSScrollerDecrementPage:
8848 last_hit_part = horizontal ? scroll_bar_before_handle : scroll_bar_above_handle; break;
8849 case NSScrollerIncrementPage:
8850 last_hit_part = horizontal ? scroll_bar_after_handle : scroll_bar_below_handle; break;
8851 case NSScrollerDecrementLine:
8852 last_hit_part = horizontal ? scroll_bar_left_arrow : scroll_bar_up_arrow; break;
8853 case NSScrollerIncrementLine:
8854 last_hit_part = horizontal ? scroll_bar_right_arrow : scroll_bar_down_arrow; break;
8855 case NSScrollerKnob:
8856 last_hit_part = horizontal ? scroll_bar_horizontal_handle : scroll_bar_handle; break;
8857 case NSScrollerKnobSlot: /* GNUstep-only */
8858 last_hit_part = scroll_bar_move_ratio; break;
8859 default: /* NSScrollerNoPart? */
8860 fprintf (stderr, "EmacsScroller-mouseDown: unexpected part %ld\n",
8865 if (part == NSScrollerKnob || part == NSScrollerKnobSlot)
8867 /* handle, or on GNUstep possibly slot */
8868 NSEvent *fake_event;
8871 /* compute float loc in slot and mouse offset on knob */
8872 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8876 length = NSWidth (sr);
8877 loc = ([e locationInWindow].x - NSMinX (sr));
8881 length = NSHeight (sr);
8882 loc = length - ([e locationInWindow].y - NSMinY (sr));
8890 else if (loc >= length)
8900 kr = [self convertRect: [self rectForPart: NSScrollerKnob]
8903 kloc = ([e locationInWindow].x - NSMinX (kr));
8905 kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
8907 last_mouse_offset = kloc;
8909 if (part != NSScrollerKnob)
8910 /* this is a slot click on GNUstep: go straight there */
8913 /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
8914 fake_event = [NSEvent mouseEventWithType: NSEventTypeLeftMouseUp
8915 location: [e locationInWindow]
8916 modifierFlags: [e modifierFlags]
8917 timestamp: [e timestamp]
8918 windowNumber: [e windowNumber]
8920 eventNumber: [e eventNumber]
8921 clickCount: [e clickCount]
8922 pressure: [e pressure]];
8923 [super mouseUp: fake_event];
8927 pos = 0; /* ignored */
8929 /* set a timer to repeat, as we can't let superclass do this modally */
8931 = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
8933 selector: @selector (repeatScroll:)
8939 if (part != NSScrollerKnob)
8940 [self sendScrollEventAtLoc: pos fromEvent: e];
8944 /* Called as we manually track scroller drags, rather than superclass. */
8945 - (void)mouseDragged: (NSEvent *)e
8951 NSTRACE ("[EmacsScroller mouseDragged:]");
8953 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8958 length = NSWidth (sr);
8959 loc = ([e locationInWindow].x - NSMinX (sr));
8963 length = NSHeight (sr);
8964 loc = length - ([e locationInWindow].y - NSMinY (sr));
8971 else if (loc >= length + last_mouse_offset)
8973 loc = length + last_mouse_offset;
8976 pos = (loc - last_mouse_offset);
8977 [self sendScrollEventAtLoc: pos fromEvent: e];
8981 - (void)mouseUp: (NSEvent *)e
8983 NSTRACE ("[EmacsScroller mouseUp:]");
8985 if (scroll_repeat_entry)
8987 [scroll_repeat_entry invalidate];
8988 [scroll_repeat_entry release];
8989 scroll_repeat_entry = nil;
8991 last_hit_part = scroll_bar_above_handle;
8995 /* treat scrollwheel events in the bar as though they were in the main window */
8996 - (void) scrollWheel: (NSEvent *)theEvent
8998 NSTRACE ("[EmacsScroller scrollWheel:]");
9000 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
9001 [view mouseDown: theEvent];
9004 @end /* EmacsScroller */
9007 #ifdef NS_IMPL_GNUSTEP
9008 /* Dummy class to get rid of startup warnings. */
9009 @implementation EmacsDocument
9015 /* ==========================================================================
9017 Font-related functions; these used to be in nsfaces.m
9019 ========================================================================== */
9023 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
9025 struct font *font = XFONT_OBJECT (font_object);
9026 EmacsView *view = FRAME_NS_VIEW (f);
9027 int font_ascent, font_descent;
9030 fontset = fontset_from_font (font_object);
9031 FRAME_FONTSET (f) = fontset;
9033 if (FRAME_FONT (f) == font)
9034 /* This font is already set in frame F. There's nothing more to
9038 FRAME_FONT (f) = font;
9040 FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
9041 FRAME_COLUMN_WIDTH (f) = font->average_width;
9042 get_font_ascent_descent (font, &font_ascent, &font_descent);
9043 FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
9045 /* Compute the scroll bar width in character columns. */
9046 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
9048 int wid = FRAME_COLUMN_WIDTH (f);
9049 FRAME_CONFIG_SCROLL_BAR_COLS (f)
9050 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
9054 int wid = FRAME_COLUMN_WIDTH (f);
9055 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
9058 /* Compute the scroll bar height in character lines. */
9059 if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0)
9061 int height = FRAME_LINE_HEIGHT (f);
9062 FRAME_CONFIG_SCROLL_BAR_LINES (f)
9063 = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
9067 int height = FRAME_LINE_HEIGHT (f);
9068 FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
9071 /* Now make the frame display the given font. */
9072 if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
9073 adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
9074 FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
9081 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
9082 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
9086 ns_xlfd_to_fontname (const char *xlfd)
9087 /* --------------------------------------------------------------------------
9088 Convert an X font name (XLFD) to an NS font name.
9089 Only family is used.
9090 The string returned is temporarily allocated.
9091 -------------------------------------------------------------------------- */
9093 char *name = xmalloc (180);
9097 if (!strncmp (xlfd, "--", 2))
9098 sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
9100 sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
9102 /* stopgap for malformed XLFD input */
9103 if (strlen (name) == 0)
9104 strcpy (name, "Monaco");
9106 /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
9107 also uppercase after '-' or ' ' */
9108 name[0] = c_toupper (name[0]);
9109 for (len =strlen (name), i =0; i<len; i++)
9115 name[i+1] = c_toupper (name[i+1]);
9117 else if (name[i] == '_')
9121 name[i+1] = c_toupper (name[i+1]);
9124 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name); */
9125 ret = [[NSString stringWithUTF8String: name] UTF8String];
9132 syms_of_nsterm (void)
9134 NSTRACE ("syms_of_nsterm");
9136 ns_antialias_threshold = 10.0;
9138 /* from 23+ we need to tell emacs what modifiers there are.. */
9139 DEFSYM (Qmodifier_value, "modifier-value");
9140 DEFSYM (Qalt, "alt");
9141 DEFSYM (Qhyper, "hyper");
9142 DEFSYM (Qmeta, "meta");
9143 DEFSYM (Qsuper, "super");
9144 DEFSYM (Qcontrol, "control");
9145 DEFSYM (QUTF8_STRING, "UTF8_STRING");
9147 DEFSYM (Qfile, "file");
9148 DEFSYM (Qurl, "url");
9150 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
9151 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
9152 Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
9153 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
9154 Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
9156 DEFVAR_LISP ("ns-input-file", ns_input_file,
9157 "The file specified in the last NS event.");
9158 ns_input_file =Qnil;
9160 DEFVAR_LISP ("ns-working-text", ns_working_text,
9161 "String for visualizing working composition sequence.");
9162 ns_working_text =Qnil;
9164 DEFVAR_LISP ("ns-input-font", ns_input_font,
9165 "The font specified in the last NS event.");
9166 ns_input_font =Qnil;
9168 DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
9169 "The fontsize specified in the last NS event.");
9170 ns_input_fontsize =Qnil;
9172 DEFVAR_LISP ("ns-input-line", ns_input_line,
9173 "The line specified in the last NS event.");
9174 ns_input_line =Qnil;
9176 DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
9177 "The service name specified in the last NS event.");
9178 ns_input_spi_name =Qnil;
9180 DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
9181 "The service argument specified in the last NS event.");
9182 ns_input_spi_arg =Qnil;
9184 DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
9185 "This variable describes the behavior of the alternate or option key.\n\
9186 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9188 Set to none means that the alternate / option key is not interpreted by Emacs\n\
9189 at all, allowing it to be used at a lower level for accented character entry.");
9190 ns_alternate_modifier = Qmeta;
9192 DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
9193 "This variable describes the behavior of the right alternate or option key.\n\
9194 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9196 Set to left means be the same key as `ns-alternate-modifier'.\n\
9197 Set to none means that the alternate / option key is not interpreted by Emacs\n\
9198 at all, allowing it to be used at a lower level for accented character entry.");
9199 ns_right_alternate_modifier = Qleft;
9201 DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
9202 "This variable describes the behavior of the command key.\n\
9203 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9205 ns_command_modifier = Qsuper;
9207 DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
9208 "This variable describes the behavior of the right command key.\n\
9209 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9211 Set to left means be the same key as `ns-command-modifier'.\n\
9212 Set to none means that the command / option key is not interpreted by Emacs\n\
9213 at all, allowing it to be used at a lower level for accented character entry.");
9214 ns_right_command_modifier = Qleft;
9216 DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
9217 "This variable describes the behavior of the control key.\n\
9218 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9220 ns_control_modifier = Qcontrol;
9222 DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
9223 "This variable describes the behavior of the right control key.\n\
9224 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9226 Set to left means be the same key as `ns-control-modifier'.\n\
9227 Set to none means that the control / option key is not interpreted by Emacs\n\
9228 at all, allowing it to be used at a lower level for accented character entry.");
9229 ns_right_control_modifier = Qleft;
9231 DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
9232 "This variable describes the behavior of the function key (on laptops).\n\
9233 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9235 Set to none means that the function key is not interpreted by Emacs at all,\n\
9236 allowing it to be used at a lower level for accented character entry.");
9237 ns_function_modifier = Qnone;
9239 DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
9240 "Non-nil (the default) means to render text antialiased.");
9241 ns_antialias_text = Qt;
9243 DEFVAR_LISP ("ns-use-thin-smoothing", ns_use_thin_smoothing,
9244 "Non-nil turns on a font smoothing method that produces thinner strokes.");
9245 ns_use_thin_smoothing = Qnil;
9247 DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
9248 "Whether to confirm application quit using dialog.");
9249 ns_confirm_quit = Qnil;
9251 DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
9252 doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
9253 Only works on Mac OS X 10.6 or later. */);
9254 ns_auto_hide_menu_bar = Qnil;
9256 DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
9257 doc: /*Non-nil means to use native fullscreen on Mac OS X 10.7 and later.
9258 Nil means use fullscreen the old (< 10.7) way. The old way works better with
9259 multiple monitors, but lacks tool bar. This variable is ignored on
9260 Mac OS X < 10.7. Default is t. */);
9261 ns_use_native_fullscreen = YES;
9262 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
9264 DEFVAR_BOOL ("ns-use-fullscreen-animation", ns_use_fullscreen_animation,
9265 doc: /*Non-nil means use animation on non-native fullscreen.
9266 For native fullscreen, this does nothing.
9267 Default is nil. */);
9268 ns_use_fullscreen_animation = NO;
9270 DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
9271 doc: /*Non-nil means to use sRGB colorspace on Mac OS X 10.7 and later.
9272 Note that this does not apply to images.
9273 This variable is ignored on Mac OS X < 10.7 and GNUstep. */);
9274 ns_use_srgb_colorspace = YES;
9276 DEFVAR_BOOL ("ns-use-mwheel-acceleration",
9277 ns_use_mwheel_acceleration,
9278 doc: /*Non-nil means use macOS's standard mouse wheel acceleration.
9279 This variable is ignored on macOS < 10.7 and GNUstep. Default is t. */);
9280 ns_use_mwheel_acceleration = YES;
9282 DEFVAR_LISP ("ns-mwheel-line-height", ns_mwheel_line_height,
9283 doc: /*The number of pixels touchpad scrolling considers one line.
9284 Nil or a non-number means use the default frame line height.
9285 This variable is ignored on macOS < 10.7 and GNUstep. Default is nil. */);
9286 ns_mwheel_line_height = Qnil;
9288 DEFVAR_BOOL ("ns-use-mwheel-momentum", ns_use_mwheel_momentum,
9289 doc: /*Non-nil means mouse wheel scrolling uses momentum.
9290 This variable is ignored on macOS < 10.7 and GNUstep. Default is t. */);
9291 ns_use_mwheel_momentum = YES;
9293 /* TODO: move to common code */
9294 DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
9295 doc: /* Which toolkit scroll bars Emacs uses, if any.
9296 A value of nil means Emacs doesn't use toolkit scroll bars.
9297 With the X Window system, the value is a symbol describing the
9298 X toolkit. Possible values are: gtk, motif, xaw, or xaw3d.
9299 With MS Windows or Nextstep, the value is t. */);
9300 Vx_toolkit_scroll_bars = Qt;
9302 DEFVAR_BOOL ("x-use-underline-position-properties",
9303 x_use_underline_position_properties,
9304 doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
9305 A value of nil means ignore them. If you encounter fonts with bogus
9306 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
9307 to 4.1, set this to nil. */);
9308 x_use_underline_position_properties = 0;
9310 DEFVAR_BOOL ("x-underline-at-descent-line",
9311 x_underline_at_descent_line,
9312 doc: /* Non-nil means to draw the underline at the same place as the descent line.
9313 A value of nil means to draw the underline according to the value of the
9314 variable `x-use-underline-position-properties', which is usually at the
9315 baseline level. The default value is nil. */);
9316 x_underline_at_descent_line = 0;
9318 /* Tell Emacs about this window system. */
9319 Fprovide (Qns, Qnil);
9321 DEFSYM (Qcocoa, "cocoa");
9322 DEFSYM (Qgnustep, "gnustep");
9324 #ifdef NS_IMPL_COCOA
9325 Fprovide (Qcocoa, Qnil);
9328 Fprovide (Qgnustep, Qnil);