1 /* NeXT/Open/GNUstep / macOS communication module. -*- coding: utf-8 -*-
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2017 Free Software
6 This file is part of GNU Emacs.
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or (at
11 your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
22 Originally by Carl Edman
23 Updated by Christian Limpach (chris@nice.ch)
24 OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
25 macOS/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
26 GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
29 /* This should be the first include, as it may set up #defines affecting
30 interpretation of even the system includes. */
36 #include <sys/types.h>
42 #include <c-strcase.h>
46 #include "blockinput.h"
47 #include "sysselect.h"
50 #include "character.h"
52 #include "composite.h"
55 #include "termhooks.h"
63 #ifdef NS_IMPL_GNUSTEP
71 static EmacsMenu *dockMenu;
73 static EmacsMenu *mainMenu;
76 /* ==========================================================================
78 NSTRACE, Trace support.
80 ========================================================================== */
84 /* The following use "volatile" since they can be accessed from
86 volatile int nstrace_num = 0;
87 volatile int nstrace_depth = 0;
89 /* When 0, no trace is emitted. This is used by NSTRACE_WHEN and
90 NSTRACE_UNLESS to silence functions called.
92 TODO: This should really be a thread-local variable, to avoid that
93 a function with disabled trace thread silence trace output in
94 another. However, in practice this seldom is a problem. */
95 volatile int nstrace_enabled_global = 1;
97 /* Called when nstrace_enabled goes out of scope. */
98 void nstrace_leave(int * pointer_to_nstrace_enabled)
100 if (*pointer_to_nstrace_enabled)
107 /* Called when nstrace_saved_enabled_global goes out of scope. */
108 void nstrace_restore_global_trace_state(int * pointer_to_saved_enabled_global)
110 nstrace_enabled_global = *pointer_to_saved_enabled_global;
114 char const * nstrace_fullscreen_type_name (int fs_type)
118 case -1: return "-1";
119 case FULLSCREEN_NONE: return "FULLSCREEN_NONE";
120 case FULLSCREEN_WIDTH: return "FULLSCREEN_WIDTH";
121 case FULLSCREEN_HEIGHT: return "FULLSCREEN_HEIGHT";
122 case FULLSCREEN_BOTH: return "FULLSCREEN_BOTH";
123 case FULLSCREEN_MAXIMIZED: return "FULLSCREEN_MAXIMIZED";
124 default: return "FULLSCREEN_?????";
130 /* ==========================================================================
132 NSColor, EmacsColor category.
134 ========================================================================== */
135 @implementation NSColor (EmacsColor)
136 + (NSColor *)colorForEmacsRed:(CGFloat)red green:(CGFloat)green
137 blue:(CGFloat)blue alpha:(CGFloat)alpha
139 #if defined (NS_IMPL_COCOA) \
140 && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
141 if (ns_use_srgb_colorspace
142 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
143 && [NSColor respondsToSelector:
144 @selector(colorWithSRGBRed:green:blue:alpha:)]
147 return [NSColor colorWithSRGBRed: red
152 return [NSColor colorWithCalibratedRed: red
158 - (NSColor *)colorUsingDefaultColorSpace
160 /* FIXMES: We're checking for colorWithSRGBRed here so this will
161 only work in the same place as in the method above. It should
162 really be a check whether we're on macOS 10.7 or above. */
163 #if defined (NS_IMPL_COCOA) \
164 && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
165 if (ns_use_srgb_colorspace
166 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
167 && [NSColor respondsToSelector:
168 @selector(colorWithSRGBRed:green:blue:alpha:)]
171 return [self colorUsingColorSpace: [NSColorSpace sRGBColorSpace]];
173 return [self colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
178 /* ==========================================================================
182 ========================================================================== */
184 /* Convert a symbol indexed with an NSxxx value to a value as defined
185 in keyboard.c (lispy_function_key). I hope this is a correct way
186 of doing things... */
187 static unsigned convert_ns_to_X_keysym[] =
189 NSHomeFunctionKey, 0x50,
190 NSLeftArrowFunctionKey, 0x51,
191 NSUpArrowFunctionKey, 0x52,
192 NSRightArrowFunctionKey, 0x53,
193 NSDownArrowFunctionKey, 0x54,
194 NSPageUpFunctionKey, 0x55,
195 NSPageDownFunctionKey, 0x56,
196 NSEndFunctionKey, 0x57,
197 NSBeginFunctionKey, 0x58,
198 NSSelectFunctionKey, 0x60,
199 NSPrintFunctionKey, 0x61,
200 NSClearLineFunctionKey, 0x0B,
201 NSExecuteFunctionKey, 0x62,
202 NSInsertFunctionKey, 0x63,
203 NSUndoFunctionKey, 0x65,
204 NSRedoFunctionKey, 0x66,
205 NSMenuFunctionKey, 0x67,
206 NSFindFunctionKey, 0x68,
207 NSHelpFunctionKey, 0x6A,
208 NSBreakFunctionKey, 0x6B,
210 NSF1FunctionKey, 0xBE,
211 NSF2FunctionKey, 0xBF,
212 NSF3FunctionKey, 0xC0,
213 NSF4FunctionKey, 0xC1,
214 NSF5FunctionKey, 0xC2,
215 NSF6FunctionKey, 0xC3,
216 NSF7FunctionKey, 0xC4,
217 NSF8FunctionKey, 0xC5,
218 NSF9FunctionKey, 0xC6,
219 NSF10FunctionKey, 0xC7,
220 NSF11FunctionKey, 0xC8,
221 NSF12FunctionKey, 0xC9,
222 NSF13FunctionKey, 0xCA,
223 NSF14FunctionKey, 0xCB,
224 NSF15FunctionKey, 0xCC,
225 NSF16FunctionKey, 0xCD,
226 NSF17FunctionKey, 0xCE,
227 NSF18FunctionKey, 0xCF,
228 NSF19FunctionKey, 0xD0,
229 NSF20FunctionKey, 0xD1,
230 NSF21FunctionKey, 0xD2,
231 NSF22FunctionKey, 0xD3,
232 NSF23FunctionKey, 0xD4,
233 NSF24FunctionKey, 0xD5,
235 NSBackspaceCharacter, 0x08, /* 8: Not on some KBs. */
236 NSDeleteCharacter, 0xFF, /* 127: Big 'delete' key upper right. */
237 NSDeleteFunctionKey, 0x9F, /* 63272: Del forw key off main array. */
239 NSTabCharacter, 0x09,
240 0x19, 0x09, /* left tab->regular since pass shift */
241 NSCarriageReturnCharacter, 0x0D,
242 NSNewlineCharacter, 0x0D,
243 NSEnterCharacter, 0x8D,
245 0x41|NSEventModifierFlagNumericPad, 0xAE, /* KP_Decimal */
246 0x43|NSEventModifierFlagNumericPad, 0xAA, /* KP_Multiply */
247 0x45|NSEventModifierFlagNumericPad, 0xAB, /* KP_Add */
248 0x4B|NSEventModifierFlagNumericPad, 0xAF, /* KP_Divide */
249 0x4E|NSEventModifierFlagNumericPad, 0xAD, /* KP_Subtract */
250 0x51|NSEventModifierFlagNumericPad, 0xBD, /* KP_Equal */
251 0x52|NSEventModifierFlagNumericPad, 0xB0, /* KP_0 */
252 0x53|NSEventModifierFlagNumericPad, 0xB1, /* KP_1 */
253 0x54|NSEventModifierFlagNumericPad, 0xB2, /* KP_2 */
254 0x55|NSEventModifierFlagNumericPad, 0xB3, /* KP_3 */
255 0x56|NSEventModifierFlagNumericPad, 0xB4, /* KP_4 */
256 0x57|NSEventModifierFlagNumericPad, 0xB5, /* KP_5 */
257 0x58|NSEventModifierFlagNumericPad, 0xB6, /* KP_6 */
258 0x59|NSEventModifierFlagNumericPad, 0xB7, /* KP_7 */
259 0x5B|NSEventModifierFlagNumericPad, 0xB8, /* KP_8 */
260 0x5C|NSEventModifierFlagNumericPad, 0xB9, /* KP_9 */
262 0x1B, 0x1B /* escape */
265 /* On macOS picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
266 the maximum font size to NOT antialias. On GNUstep there is currently
267 no way to control this behavior. */
268 float ns_antialias_threshold;
270 NSArray *ns_send_types = 0, *ns_return_types = 0;
271 static NSArray *ns_drag_types = 0;
272 NSString *ns_app_name = @"Emacs"; /* default changed later */
274 /* Display variables */
275 struct ns_display_info *x_display_list; /* Chain of existing displays */
276 long context_menu_value = 0;
279 static struct frame *ns_updating_frame;
280 static NSView *focus_view = NULL;
281 static int ns_window_num = 0;
282 #ifdef NS_IMPL_GNUSTEP
283 static NSRect uRect; // TODO: This is dead, remove it?
285 static BOOL gsaved = NO;
286 static BOOL ns_fake_keydown = NO;
288 static BOOL ns_menu_bar_is_hidden = NO;
290 /*static int debug_lock = 0; */
293 static BOOL send_appdefined = YES;
294 #define NO_APPDEFINED_DATA (-8)
295 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
296 static NSTimer *timed_entry = 0;
297 static NSTimer *scroll_repeat_entry = nil;
298 static fd_set select_readfds, select_writefds;
299 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
300 static int select_nfds = 0, select_valid = 0;
301 static struct timespec select_timeout = { 0, 0 };
302 static int selfds[2] = { -1, -1 };
303 static pthread_mutex_t select_mutex;
304 static NSAutoreleasePool *outerpool;
305 static struct input_event *emacs_event = NULL;
306 static struct input_event *q_event_ptr = NULL;
307 static int n_emacs_events_pending = 0;
308 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
309 *ns_pending_service_args;
310 static BOOL ns_do_open_file = NO;
311 static BOOL ns_last_use_native_fullscreen;
313 /* Non-zero means that a HELP_EVENT has been generated since Emacs
316 static BOOL any_help_event_p = NO;
319 struct input_event *q;
325 static NSString *represented_filename = nil;
326 static struct frame *represented_frame = 0;
330 * State for pending menu activation:
331 * MENU_NONE Normal state
332 * MENU_PENDING A menu has been clicked on, but has been canceled so we can
333 * run lisp to update the menu.
334 * MENU_OPENING Menu is up to date, and the click event is redone so the menu
338 #define MENU_PENDING 1
339 #define MENU_OPENING 2
340 static int menu_will_open_state = MENU_NONE;
342 /* Saved position for menu click. */
343 static CGPoint menu_mouse_point;
346 /* Convert modifiers in a NeXTstep event to emacs style modifiers. */
347 #define NS_FUNCTION_KEY_MASK 0x800000
348 #define NSLeftControlKeyMask (0x000001 | NSEventModifierFlagControl)
349 #define NSRightControlKeyMask (0x002000 | NSEventModifierFlagControl)
350 #define NSLeftCommandKeyMask (0x000008 | NSEventModifierFlagCommand)
351 #define NSRightCommandKeyMask (0x000010 | NSEventModifierFlagCommand)
352 #define NSLeftAlternateKeyMask (0x000020 | NSEventModifierFlagOption)
353 #define NSRightAlternateKeyMask (0x000040 | NSEventModifierFlagOption)
354 #define EV_MODIFIERS2(flags) \
355 (((flags & NSEventModifierFlagHelp) ? \
356 hyper_modifier : 0) \
357 | (!EQ (ns_right_alternate_modifier, Qleft) && \
358 ((flags & NSRightAlternateKeyMask) \
359 == NSRightAlternateKeyMask) ? \
360 parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
361 | ((flags & NSEventModifierFlagOption) ? \
362 parse_solitary_modifier (ns_alternate_modifier) : 0) \
363 | ((flags & NSEventModifierFlagShift) ? \
364 shift_modifier : 0) \
365 | (!EQ (ns_right_control_modifier, Qleft) && \
366 ((flags & NSRightControlKeyMask) \
367 == NSRightControlKeyMask) ? \
368 parse_solitary_modifier (ns_right_control_modifier) : 0) \
369 | ((flags & NSEventModifierFlagControl) ? \
370 parse_solitary_modifier (ns_control_modifier) : 0) \
371 | ((flags & NS_FUNCTION_KEY_MASK) ? \
372 parse_solitary_modifier (ns_function_modifier) : 0) \
373 | (!EQ (ns_right_command_modifier, Qleft) && \
374 ((flags & NSRightCommandKeyMask) \
375 == NSRightCommandKeyMask) ? \
376 parse_solitary_modifier (ns_right_command_modifier) : 0) \
377 | ((flags & NSEventModifierFlagCommand) ? \
378 parse_solitary_modifier (ns_command_modifier):0))
379 #define EV_MODIFIERS(e) EV_MODIFIERS2 ([e modifierFlags])
381 #define EV_UDMODIFIERS(e) \
382 ((([e type] == NSEventTypeLeftMouseDown) ? down_modifier : 0) \
383 | (([e type] == NSEventTypeRightMouseDown) ? down_modifier : 0) \
384 | (([e type] == NSEventTypeOtherMouseDown) ? down_modifier : 0) \
385 | (([e type] == NSEventTypeLeftMouseDragged) ? down_modifier : 0) \
386 | (([e type] == NSEventTypeRightMouseDragged) ? down_modifier : 0) \
387 | (([e type] == NSEventTypeOtherMouseDragged) ? down_modifier : 0) \
388 | (([e type] == NSEventTypeLeftMouseUp) ? up_modifier : 0) \
389 | (([e type] == NSEventTypeRightMouseUp) ? up_modifier : 0) \
390 | (([e type] == NSEventTypeOtherMouseUp) ? up_modifier : 0))
392 #define EV_BUTTON(e) \
393 ((([e type] == NSEventTypeLeftMouseDown) || ([e type] == NSEventTypeLeftMouseUp)) ? 0 : \
394 (([e type] == NSEventTypeRightMouseDown) || ([e type] == NSEventTypeRightMouseUp)) ? 2 : \
395 [e buttonNumber] - 1)
397 /* Convert the time field to a timestamp in milliseconds. */
398 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
400 /* This is a piece of code which is common to all the event handling
401 methods. Maybe it should even be a function. */
402 #define EV_TRAILER(e) \
404 XSETFRAME (emacs_event->frame_or_window, emacsframe); \
408 #define EV_TRAILER2(e) \
410 if (e) emacs_event->timestamp = EV_TIMESTAMP (e); \
413 Lisp_Object tem = Vinhibit_quit; \
414 Vinhibit_quit = Qt; \
415 n_emacs_events_pending++; \
416 kbd_buffer_store_event_hold (emacs_event, q_event_ptr); \
417 Vinhibit_quit = tem; \
420 hold_event (emacs_event); \
421 EVENT_INIT (*emacs_event); \
422 ns_send_appdefined (-1); \
426 /* GNUstep always shows decorations if the window is resizable,
427 miniaturizable or closable, but Cocoa does strange things in native
428 fullscreen mode if you don't have at least resizable enabled.
430 These flags will be OR'd or XOR'd with the NSWindow's styleMask
431 property depending on what we're doing. */
433 #define FRAME_DECORATED_FLAGS NSWindowStyleMaskTitled
435 #define FRAME_DECORATED_FLAGS (NSWindowStyleMaskTitled \
436 | NSWindowStyleMaskResizable \
437 | NSWindowStyleMaskMiniaturizable \
438 | NSWindowStyleMaskClosable)
440 #define FRAME_UNDECORATED_FLAGS NSWindowStyleMaskBorderless
442 /* TODO: get rid of need for these forward declarations */
443 static void ns_condemn_scroll_bars (struct frame *f);
444 static void ns_judge_scroll_bars (struct frame *f);
447 /* ==========================================================================
451 ========================================================================== */
454 ns_set_represented_filename (NSString *fstr, struct frame *f)
456 represented_filename = [fstr retain];
457 represented_frame = f;
461 ns_init_events (struct input_event *ev)
468 ns_finish_events (void)
474 hold_event (struct input_event *event)
476 if (hold_event_q.nr == hold_event_q.cap)
478 if (hold_event_q.cap == 0) hold_event_q.cap = 10;
479 else hold_event_q.cap *= 2;
481 xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
484 hold_event_q.q[hold_event_q.nr++] = *event;
485 /* Make sure ns_read_socket is called, i.e. we have input. */
487 send_appdefined = YES;
491 append2 (Lisp_Object list, Lisp_Object item)
492 /* --------------------------------------------------------------------------
493 Utility to append to a list
494 -------------------------------------------------------------------------- */
496 return CALLN (Fnconc, list, list1 (item));
501 ns_etc_directory (void)
502 /* If running as a self-contained app bundle, return as a string the
503 filename of the etc directory, if present; else nil. */
505 NSBundle *bundle = [NSBundle mainBundle];
506 NSString *resourceDir = [bundle resourcePath];
507 NSString *resourcePath;
508 NSFileManager *fileManager = [NSFileManager defaultManager];
511 resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
512 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
514 if (isDir) return [resourcePath UTF8String];
522 /* If running as a self-contained app bundle, return as a path string
523 the filenames of the libexec and bin directories, ie libexec:bin.
524 Otherwise, return nil.
525 Normally, Emacs does not add its own bin/ directory to the PATH.
526 However, a self-contained NS build has a different layout, with
527 bin/ and libexec/ subdirectories in the directory that contains
529 We put libexec first, because init_callproc_1 uses the first
530 element to initialize exec-directory. An alternative would be
531 for init_callproc to check for invocation-directory/libexec.
534 NSBundle *bundle = [NSBundle mainBundle];
535 NSString *resourceDir = [bundle resourcePath];
536 NSString *binDir = [bundle bundlePath];
537 NSString *resourcePath, *resourcePaths;
539 NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
540 NSFileManager *fileManager = [NSFileManager defaultManager];
542 NSEnumerator *pathEnum;
545 range = [resourceDir rangeOfString: @"Contents"];
546 if (range.location != NSNotFound)
548 binDir = [binDir stringByAppendingPathComponent: @"Contents"];
550 binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
554 paths = [binDir stringsByAppendingPaths:
555 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
556 pathEnum = [paths objectEnumerator];
559 while ((resourcePath = [pathEnum nextObject]))
561 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
564 if ([resourcePaths length] > 0)
566 = [resourcePaths stringByAppendingString: pathSeparator];
568 = [resourcePaths stringByAppendingString: resourcePath];
571 if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
579 /* If running as a self-contained app bundle, return as a path string
580 the filenames of the site-lisp and lisp directories.
581 Ie, site-lisp:lisp. Otherwise, return nil. */
583 NSBundle *bundle = [NSBundle mainBundle];
584 NSString *resourceDir = [bundle resourcePath];
585 NSString *resourcePath, *resourcePaths;
586 NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
587 NSFileManager *fileManager = [NSFileManager defaultManager];
589 NSArray *paths = [resourceDir stringsByAppendingPaths:
590 [NSArray arrayWithObjects:
591 @"site-lisp", @"lisp", nil]];
592 NSEnumerator *pathEnum = [paths objectEnumerator];
595 /* Hack to skip site-lisp. */
596 if (no_site_lisp) resourcePath = [pathEnum nextObject];
598 while ((resourcePath = [pathEnum nextObject]))
600 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
603 if ([resourcePaths length] > 0)
605 = [resourcePaths stringByAppendingString: pathSeparator];
607 = [resourcePaths stringByAppendingString: resourcePath];
610 if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
617 ns_init_locale (void)
618 /* macOS doesn't set any environment variables for the locale when run
619 from the GUI. Get the locale from the OS and set LANG. */
621 NSLocale *locale = [NSLocale currentLocale];
623 NSTRACE ("ns_init_locale");
627 /* It seems macOS should probably use UTF-8 everywhere.
628 'localeIdentifier' does not specify the encoding, and I can't
629 find any way to get the OS to tell us which encoding to use,
630 so hard-code '.UTF-8'. */
631 NSString *localeID = [NSString stringWithFormat:@"%@.UTF-8",
632 [locale localeIdentifier]];
634 /* Set LANG to locale, but not if LANG is already set. */
635 setenv("LANG", [localeID UTF8String], 0);
637 @catch (NSException *e)
639 NSLog (@"Locale detection failed: %@: %@", [e name], [e reason]);
645 ns_release_object (void *obj)
646 /* --------------------------------------------------------------------------
647 Release an object (callable from C)
648 -------------------------------------------------------------------------- */
655 ns_retain_object (void *obj)
656 /* --------------------------------------------------------------------------
657 Retain an object (callable from C)
658 -------------------------------------------------------------------------- */
665 ns_alloc_autorelease_pool (void)
666 /* --------------------------------------------------------------------------
667 Allocate a pool for temporary objects (callable from C)
668 -------------------------------------------------------------------------- */
670 return [[NSAutoreleasePool alloc] init];
675 ns_release_autorelease_pool (void *pool)
676 /* --------------------------------------------------------------------------
677 Free a pool and temporary objects it refers to (callable from C)
678 -------------------------------------------------------------------------- */
680 ns_release_object (pool);
685 ns_menu_bar_should_be_hidden (void)
686 /* True, if the menu bar should be hidden. */
688 return !NILP (ns_auto_hide_menu_bar)
689 && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
702 static struct EmacsMargins
703 ns_screen_margins (NSScreen *screen)
704 /* The parts of SCREEN used by the operating system. */
706 NSTRACE ("ns_screen_margins");
708 struct EmacsMargins margins;
710 NSRect screenFrame = [screen frame];
711 NSRect screenVisibleFrame = [screen visibleFrame];
713 /* Sometimes, visibleFrame isn't up-to-date with respect to a hidden
714 menu bar, check this explicitly. */
715 if (ns_menu_bar_should_be_hidden())
721 CGFloat frameTop = screenFrame.origin.y + screenFrame.size.height;
722 CGFloat visibleFrameTop = (screenVisibleFrame.origin.y
723 + screenVisibleFrame.size.height);
725 margins.top = frameTop - visibleFrameTop;
729 CGFloat frameRight = screenFrame.origin.x + screenFrame.size.width;
730 CGFloat visibleFrameRight = (screenVisibleFrame.origin.x
731 + screenVisibleFrame.size.width);
732 margins.right = frameRight - visibleFrameRight;
735 margins.bottom = screenVisibleFrame.origin.y - screenFrame.origin.y;
736 margins.left = screenVisibleFrame.origin.x - screenFrame.origin.x;
738 NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
748 /* A screen margin between 1 and DOCK_IGNORE_LIMIT (inclusive) is
749 assumed to contain a hidden dock. macOS currently use 4 pixels for
750 this, however, to be future compatible, a larger value is used. */
751 #define DOCK_IGNORE_LIMIT 6
753 static struct EmacsMargins
754 ns_screen_margins_ignoring_hidden_dock (NSScreen *screen)
755 /* The parts of SCREEN used by the operating system, excluding the parts
756 reserved for an hidden dock. */
758 NSTRACE ("ns_screen_margins_ignoring_hidden_dock");
760 struct EmacsMargins margins = ns_screen_margins(screen);
762 /* macOS (currently) reserved 4 pixels along the edge where a hidden
763 dock is located. Unfortunately, it's not possible to find the
764 location and information about if the dock is hidden. Instead,
765 it is assumed that if the margin of an edge is less than
766 DOCK_IGNORE_LIMIT, it contains a hidden dock. */
767 if (margins.left <= DOCK_IGNORE_LIMIT)
771 if (margins.right <= DOCK_IGNORE_LIMIT)
775 if (margins.top <= DOCK_IGNORE_LIMIT)
779 /* Note: This doesn't occur in current versions of macOS, but
780 included for completeness and future compatibility. */
781 if (margins.bottom <= DOCK_IGNORE_LIMIT)
786 NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
797 ns_menu_bar_height (NSScreen *screen)
798 /* The height of the menu bar, if visible.
800 Note: Don't use this when fullscreen is enabled -- the screen
801 sometimes includes, sometimes excludes the menu bar area. */
803 struct EmacsMargins margins = ns_screen_margins(screen);
805 CGFloat res = margins.top;
807 NSTRACE ("ns_menu_bar_height " NSTRACE_FMT_RETURN " %.0f", res);
813 /* ==========================================================================
815 Focus (clipping) and screen update
817 ========================================================================== */
820 // Window constraining
821 // -------------------
823 // To ensure that the windows are not placed under the menu bar, they
824 // are typically moved by the call-back constrainFrameRect. However,
825 // by overriding it, it's possible to inhibit this, leaving the window
826 // in it's original position.
828 // It's possible to hide the menu bar. However, technically, it's only
829 // possible to hide it when the application is active. To ensure that
830 // this work properly, the menu bar and window constraining are
831 // deferred until the application becomes active.
833 // Even though it's not possible to manually move a window above the
834 // top of the screen, it is allowed if it's done programmatically,
835 // when the menu is hidden. This allows the editable area to cover the
836 // full screen height.
841 // Use the following extra files:
844 // ;; Hide menu and place frame slightly above the top of the screen.
845 // (setq ns-auto-hide-menu-bar t)
846 // (set-frame-position (selected-frame) 0 -20)
850 // emacs -Q -l init.el
852 // Result: No menu bar, and the title bar should be above the screen.
858 // Result: Menu bar visible, frame placed immediately below the menu.
861 static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
863 NSTRACE ("constrain_frame_rect(" NSTRACE_FMT_RECT ")",
864 NSTRACE_ARG_RECT (frameRect));
866 // --------------------
867 // Collect information about the screen the frame is covering.
870 NSArray *screens = [NSScreen screens];
871 NSUInteger nr_screens = [screens count];
875 // The height of the menu bar, if present in any screen the frame is
877 int menu_bar_height = 0;
879 // A rectangle covering all the screen the frame is displayed in.
880 NSRect multiscreenRect = NSMakeRect(0, 0, 0, 0);
881 for (i = 0; i < nr_screens; ++i )
883 NSScreen *s = [screens objectAtIndex: i];
884 NSRect scrRect = [s frame];
886 NSTRACE_MSG ("Screen %d: " NSTRACE_FMT_RECT,
887 i, NSTRACE_ARG_RECT (scrRect));
889 if (NSIntersectionRect (frameRect, scrRect).size.height != 0)
891 multiscreenRect = NSUnionRect (multiscreenRect, scrRect);
895 CGFloat screen_menu_bar_height = ns_menu_bar_height (s);
896 menu_bar_height = max(menu_bar_height, screen_menu_bar_height);
901 NSTRACE_RECT ("multiscreenRect", multiscreenRect);
903 NSTRACE_MSG ("menu_bar_height: %d", menu_bar_height);
905 if (multiscreenRect.size.width == 0
906 || multiscreenRect.size.height == 0)
908 // Failed to find any monitor, give up.
909 NSTRACE_MSG ("multiscreenRect empty");
910 NSTRACE_RETURN_RECT (frameRect);
915 // --------------------
916 // Find a suitable placement.
919 if (ns_menu_bar_should_be_hidden())
921 // When the menu bar is hidden, the user may place part of the
922 // frame above the top of the screen, for example to hide the
925 // Hence, keep the original position.
929 // Ensure that the frame is below the menu bar, or below the top
932 // This assume that the menu bar is placed at the top in the
933 // rectangle that covers the monitors. (It doesn't have to be,
934 // but if it's not it's hard to do anything useful.)
935 CGFloat topOfWorkArea = (multiscreenRect.origin.y
936 + multiscreenRect.size.height
939 CGFloat topOfFrame = frameRect.origin.y + frameRect.size.height;
940 if (topOfFrame > topOfWorkArea)
942 frameRect.origin.y -= topOfFrame - topOfWorkArea;
943 NSTRACE_RECT ("After placement adjust", frameRect);
947 // Include the following section to restrict frame to the screens.
948 // (If so, update it to allow the frame to stretch down below the
951 // --------------------
952 // Ensure frame doesn't stretch below the screens.
955 CGFloat diff = multiscreenRect.origin.y - frameRect.origin.y;
959 frameRect.origin.y = multiscreenRect.origin.y;
960 frameRect.size.height -= diff;
964 NSTRACE_RETURN_RECT (frameRect);
970 ns_constrain_all_frames (void)
971 /* --------------------------------------------------------------------------
972 Ensure that the menu bar doesn't cover any frames.
973 -------------------------------------------------------------------------- */
975 Lisp_Object tail, frame;
977 NSTRACE ("ns_constrain_all_frames");
981 FOR_EACH_FRAME (tail, frame)
983 struct frame *f = XFRAME (frame);
986 EmacsView *view = FRAME_NS_VIEW (f);
988 if (![view isFullscreen])
991 setFrame:constrain_frame_rect([[view window] frame], false)
1002 ns_update_auto_hide_menu_bar (void)
1003 /* --------------------------------------------------------------------------
1004 Show or hide the menu bar, based on user setting.
1005 -------------------------------------------------------------------------- */
1007 #ifdef NS_IMPL_COCOA
1008 NSTRACE ("ns_update_auto_hide_menu_bar");
1012 if (NSApp != nil && [NSApp isActive])
1014 // Note, "setPresentationOptions" triggers an error unless the
1015 // application is active.
1016 BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
1018 if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
1020 NSApplicationPresentationOptions options
1021 = NSApplicationPresentationDefault;
1023 if (menu_bar_should_be_hidden)
1024 options |= NSApplicationPresentationAutoHideMenuBar
1025 | NSApplicationPresentationAutoHideDock;
1027 [NSApp setPresentationOptions: options];
1029 ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
1031 if (!ns_menu_bar_is_hidden)
1033 ns_constrain_all_frames ();
1044 ns_update_begin (struct frame *f)
1045 /* --------------------------------------------------------------------------
1046 Prepare for a grouped sequence of drawing calls
1047 external (RIF) call; whole frame, called before update_window_begin
1048 -------------------------------------------------------------------------- */
1050 EmacsView *view = FRAME_NS_VIEW (f);
1051 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_begin");
1053 ns_update_auto_hide_menu_bar ();
1055 #ifdef NS_IMPL_COCOA
1056 if ([view isFullscreen] && [view fsIsNative])
1058 // Fix reappearing tool bar in fullscreen for Mac OS X 10.7
1059 BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
1060 NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
1061 if (! tbar_visible != ! [toolbar isVisible])
1062 [toolbar setVisible: tbar_visible];
1066 ns_updating_frame = f;
1069 /* drawRect may have been called for say the minibuffer, and then clip path
1070 is for the minibuffer. But the display engine may draw more because
1071 we have set the frame as garbaged. So reset clip path to the whole
1073 #ifdef NS_IMPL_COCOA
1076 NSRect r = [view frame];
1077 NSRect cr = [[view window] frame];
1078 /* If a large frame size is set, r may be larger than the window frame
1079 before constrained. In that case don't change the clip path, as we
1080 will clear in to the tool bar and title bar. */
1082 + FRAME_NS_TITLEBAR_HEIGHT (f)
1083 + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
1085 bp = [[NSBezierPath bezierPathWithRect: r] retain];
1092 #ifdef NS_IMPL_GNUSTEP
1093 uRect = NSMakeRect (0, 0, 0, 0);
1099 ns_update_window_begin (struct window *w)
1100 /* --------------------------------------------------------------------------
1101 Prepare for a grouped sequence of drawing calls
1102 external (RIF) call; for one window, called after update_begin
1103 -------------------------------------------------------------------------- */
1105 struct frame *f = XFRAME (WINDOW_FRAME (w));
1106 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1108 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_begin");
1109 w->output_cursor = w->cursor;
1113 if (f == hlinfo->mouse_face_mouse_frame)
1115 /* Don't do highlighting for mouse motion during the update. */
1116 hlinfo->mouse_face_defer = 1;
1118 /* If the frame needs to be redrawn,
1119 simply forget about any prior mouse highlighting. */
1120 if (FRAME_GARBAGED_P (f))
1121 hlinfo->mouse_face_window = Qnil;
1123 /* (further code for mouse faces ifdef'd out in other terms elided) */
1131 ns_update_window_end (struct window *w, bool cursor_on_p,
1132 bool mouse_face_overwritten_p)
1133 /* --------------------------------------------------------------------------
1134 Finished a grouped sequence of drawing calls
1135 external (RIF) call; for one window called before update_end
1136 -------------------------------------------------------------------------- */
1138 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_end");
1140 /* note: this fn is nearly identical in all terms */
1141 if (!w->pseudo_window_p)
1146 display_and_set_cursor (w, 1,
1147 w->output_cursor.hpos, w->output_cursor.vpos,
1148 w->output_cursor.x, w->output_cursor.y);
1150 if (draw_window_fringes (w, 1))
1152 if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
1153 x_draw_right_divider (w);
1155 x_draw_vertical_border (w);
1161 /* If a row with mouse-face was overwritten, arrange for
1162 frame_up_to_date to redisplay the mouse highlight. */
1163 if (mouse_face_overwritten_p)
1164 reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
1169 ns_update_end (struct frame *f)
1170 /* --------------------------------------------------------------------------
1171 Finished a grouped sequence of drawing calls
1172 external (RIF) call; for whole frame, called after update_window_end
1173 -------------------------------------------------------------------------- */
1175 EmacsView *view = FRAME_NS_VIEW (f);
1177 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_end");
1179 /* if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
1180 MOUSE_HL_INFO (f)->mouse_face_defer = 0;
1185 [[view window] flushWindow];
1188 ns_updating_frame = NULL;
1192 ns_focus (struct frame *f, NSRect *r, int n)
1193 /* --------------------------------------------------------------------------
1194 Internal: Focus on given frame. During small local updates this is used to
1195 draw, however during large updates, ns_update_begin and ns_update_end are
1196 called to wrap the whole thing, in which case these calls are stubbed out.
1197 Except, on GNUstep, we accumulate the rectangle being drawn into, because
1198 the back end won't do this automatically, and will just end up flushing
1200 -------------------------------------------------------------------------- */
1202 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_focus");
1205 NSTRACE_RECT ("r", *r);
1208 if (f != ns_updating_frame)
1210 NSView *view = FRAME_NS_VIEW (f);
1211 if (view != focus_view)
1213 if (focus_view != NULL)
1215 [focus_view unlockFocus];
1216 [[focus_view window] flushWindow];
1223 /*if (view) debug_lock++; */
1230 [[NSGraphicsContext currentContext] saveGraphicsState];
1232 NSRectClipList (r, 2);
1241 ns_unfocus (struct frame *f)
1242 /* --------------------------------------------------------------------------
1243 Internal: Remove focus on given frame
1244 -------------------------------------------------------------------------- */
1246 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_unfocus");
1250 [[NSGraphicsContext currentContext] restoreGraphicsState];
1254 if (f != ns_updating_frame)
1256 if (focus_view != NULL)
1258 [focus_view unlockFocus];
1259 [[focus_view window] flushWindow];
1268 ns_clip_to_row (struct window *w, struct glyph_row *row,
1269 enum glyph_row_area area, BOOL gc)
1270 /* --------------------------------------------------------------------------
1271 Internal (but parallels other terms): Focus drawing on given row
1272 -------------------------------------------------------------------------- */
1274 struct frame *f = XFRAME (WINDOW_FRAME (w));
1276 int window_x, window_y, window_width;
1278 window_box (w, area, &window_x, &window_y, &window_width, 0);
1280 clip_rect.origin.x = window_x;
1281 clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
1282 clip_rect.origin.y = max (clip_rect.origin.y, window_y);
1283 clip_rect.size.width = window_width;
1284 clip_rect.size.height = row->visible_height;
1286 ns_focus (f, &clip_rect, 1);
1290 /* ==========================================================================
1292 Visible bell and beep.
1294 ========================================================================== */
1297 // This bell implementation shows the visual bell image asynchronously
1298 // from the rest of Emacs. This is done by adding a NSView to the
1299 // superview of the Emacs window and removing it using a timer.
1301 // Unfortunately, some Emacs operations, like scrolling, is done using
1302 // low-level primitives that copy the content of the window, including
1303 // the bell image. To some extent, this is handled by removing the
1304 // image prior to scrolling and marking that the window is in need for
1307 // To test this code, make sure that there is no artifacts of the bell
1308 // image in the following situations. Use a non-empty buffer (like the
1309 // tutorial) to ensure that a scroll is performed:
1311 // * Single-window: C-g C-v
1313 // * Side-by-windows: C-x 3 C-g C-v
1315 // * Windows above each other: C-x 2 C-g C-v
1317 @interface EmacsBell : NSImageView
1319 // Number of currently active bell:s.
1320 unsigned int nestCount;
1324 - (void)show:(NSView *)view;
1329 @implementation EmacsBell
1333 NSTRACE ("[EmacsBell init]");
1334 if ((self = [super init]))
1338 #ifdef NS_IMPL_GNUSTEP
1339 // GNUstep doesn't provide named images. This was reported in
1340 // 2011, see https://savannah.gnu.org/bugs/?33396
1342 // As a drop in replacement, a semitransparent gray square is used.
1343 self.image = [[NSImage alloc] initWithSize:NSMakeSize(32 * 5, 32 * 5)];
1344 [self.image lockFocus];
1345 [[NSColor colorForEmacsRed:0.5 green:0.5 blue:0.5 alpha:0.5] set];
1346 NSRectFill(NSMakeRect(0, 0, 32, 32));
1347 [self.image unlockFocus];
1349 self.image = [NSImage imageNamed:NSImageNameCaution];
1350 [self.image setSize:NSMakeSize(self.image.size.width * 5,
1351 self.image.size.height * 5)];
1357 - (void)show:(NSView *)view
1359 NSTRACE ("[EmacsBell show:]");
1360 NSTRACE_MSG ("nestCount: %u", nestCount);
1362 // Show the image, unless it's already shown.
1365 NSRect rect = [view bounds];
1367 pos.x = rect.origin.x + (rect.size.width - self.image.size.width )/2;
1368 pos.y = rect.origin.y + (rect.size.height - self.image.size.height)/2;
1370 [self setFrameOrigin:pos];
1371 [self setFrameSize:self.image.size];
1375 [[[view window] contentView] addSubview:self
1376 positioned:NSWindowAbove
1382 [self performSelector:@selector(hide) withObject:self afterDelay:0.5];
1388 // Note: Trace output from this method isn't shown, reason unknown.
1389 // NSTRACE ("[EmacsBell hide]");
1394 // Remove the image once the last bell became inactive.
1404 NSTRACE ("[EmacsBell remove]");
1407 NSTRACE_MSG ("removeFromSuperview");
1408 [self removeFromSuperview];
1409 mView.needsDisplay = YES;
1417 static EmacsBell * bell_view = nil;
1420 ns_ring_bell (struct frame *f)
1421 /* --------------------------------------------------------------------------
1423 -------------------------------------------------------------------------- */
1425 NSTRACE ("ns_ring_bell");
1428 struct frame *frame = SELECTED_FRAME ();
1431 if (bell_view == nil)
1433 bell_view = [[EmacsBell alloc] init];
1439 view = FRAME_NS_VIEW (frame);
1442 [bell_view show:view];
1456 /* --------------------------------------------------------------------------
1457 Ensure the bell is hidden.
1458 -------------------------------------------------------------------------- */
1460 NSTRACE ("hide_bell");
1462 if (bell_view != nil)
1469 /* ==========================================================================
1471 Frame / window manager related functions
1473 ========================================================================== */
1477 ns_raise_frame (struct frame *f, BOOL make_key)
1478 /* --------------------------------------------------------------------------
1479 Bring window to foreground and if make_key is YES, give it focus.
1480 -------------------------------------------------------------------------- */
1484 check_window_system (f);
1485 view = FRAME_NS_VIEW (f);
1487 if (FRAME_VISIBLE_P (f))
1490 [[view window] makeKeyAndOrderFront: NSApp];
1492 [[view window] orderFront: NSApp];
1499 ns_lower_frame (struct frame *f)
1500 /* --------------------------------------------------------------------------
1502 -------------------------------------------------------------------------- */
1506 check_window_system (f);
1507 view = FRAME_NS_VIEW (f);
1509 [[view window] orderBack: NSApp];
1515 ns_frame_raise_lower (struct frame *f, bool raise)
1516 /* --------------------------------------------------------------------------
1518 -------------------------------------------------------------------------- */
1520 NSTRACE ("ns_frame_raise_lower");
1523 ns_raise_frame (f, YES);
1530 ns_frame_rehighlight (struct frame *frame)
1531 /* --------------------------------------------------------------------------
1532 External (hook): called on things like window switching within frame
1533 -------------------------------------------------------------------------- */
1535 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1536 struct frame *old_highlight = dpyinfo->x_highlight_frame;
1538 NSTRACE ("ns_frame_rehighlight");
1539 if (dpyinfo->x_focus_frame)
1541 dpyinfo->x_highlight_frame
1542 = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1543 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1544 : dpyinfo->x_focus_frame);
1545 if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1547 fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1548 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1552 dpyinfo->x_highlight_frame = 0;
1554 if (dpyinfo->x_highlight_frame &&
1555 dpyinfo->x_highlight_frame != old_highlight)
1559 x_update_cursor (old_highlight, 1);
1560 x_set_frame_alpha (old_highlight);
1562 if (dpyinfo->x_highlight_frame)
1564 x_update_cursor (dpyinfo->x_highlight_frame, 1);
1565 x_set_frame_alpha (dpyinfo->x_highlight_frame);
1572 x_make_frame_visible (struct frame *f)
1573 /* --------------------------------------------------------------------------
1574 External: Show the window (X11 semantics)
1575 -------------------------------------------------------------------------- */
1577 NSTRACE ("x_make_frame_visible");
1578 /* XXX: at some points in past this was not needed, as the only place that
1579 called this (frame.c:Fraise_frame ()) also called raise_lower;
1580 if this ends up the case again, comment this out again. */
1581 if (!FRAME_VISIBLE_P (f))
1583 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1584 NSWindow *window = [view window];
1586 SET_FRAME_VISIBLE (f, 1);
1587 ns_raise_frame (f, ! FRAME_NO_FOCUS_ON_MAP (f));
1589 /* Making a new frame from a fullscreen frame will make the new frame
1590 fullscreen also. So skip handleFS as this will print an error. */
1591 if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1592 && [view isFullscreen])
1595 if (f->want_fullscreen != FULLSCREEN_NONE)
1602 /* Making a frame invisible seems to break the parent->child
1603 relationship, so reinstate it. */
1604 if ([window parentWindow] == nil && FRAME_PARENT_FRAME (f) != NULL)
1606 NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
1609 [parent addChildWindow: window
1610 ordered: NSWindowAbove];
1613 /* If the parent frame moved while the child frame was
1614 invisible, the child frame's position won't have been
1615 updated. Make sure it's in the right place now. */
1616 x_set_offset(f, f->left_pos, f->top_pos, 0);
1623 x_make_frame_invisible (struct frame *f)
1624 /* --------------------------------------------------------------------------
1625 External: Hide the window (X11 semantics)
1626 -------------------------------------------------------------------------- */
1629 NSTRACE ("x_make_frame_invisible");
1630 check_window_system (f);
1631 view = FRAME_NS_VIEW (f);
1632 [[view window] orderOut: NSApp];
1633 SET_FRAME_VISIBLE (f, 0);
1634 SET_FRAME_ICONIFIED (f, 0);
1639 x_iconify_frame (struct frame *f)
1640 /* --------------------------------------------------------------------------
1641 External: Iconify window
1642 -------------------------------------------------------------------------- */
1645 struct ns_display_info *dpyinfo;
1647 NSTRACE ("x_iconify_frame");
1648 check_window_system (f);
1649 view = FRAME_NS_VIEW (f);
1650 dpyinfo = FRAME_DISPLAY_INFO (f);
1652 if (dpyinfo->x_highlight_frame == f)
1653 dpyinfo->x_highlight_frame = 0;
1655 if ([[view window] windowNumber] <= 0)
1657 /* the window is still deferred. Make it very small, bring it
1658 on screen and order it out. */
1659 NSRect s = { { 100, 100}, {0, 0} };
1661 t = [[view window] frame];
1662 [[view window] setFrame: s display: NO];
1663 [[view window] orderBack: NSApp];
1664 [[view window] orderOut: NSApp];
1665 [[view window] setFrame: t display: NO];
1668 /* Processing input while Emacs is being minimized can cause a
1669 crash, so block it for the duration. */
1671 [[view window] miniaturize: NSApp];
1675 /* Free X resources of frame F. */
1678 x_free_frame_resources (struct frame *f)
1681 struct ns_display_info *dpyinfo;
1682 Mouse_HLInfo *hlinfo;
1684 NSTRACE ("x_free_frame_resources");
1685 check_window_system (f);
1686 view = FRAME_NS_VIEW (f);
1687 dpyinfo = FRAME_DISPLAY_INFO (f);
1688 hlinfo = MOUSE_HL_INFO (f);
1690 [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1694 free_frame_menubar (f);
1695 free_frame_faces (f);
1697 if (f == dpyinfo->x_focus_frame)
1698 dpyinfo->x_focus_frame = 0;
1699 if (f == dpyinfo->x_highlight_frame)
1700 dpyinfo->x_highlight_frame = 0;
1701 if (f == hlinfo->mouse_face_mouse_frame)
1702 reset_mouse_highlight (hlinfo);
1704 if (f->output_data.ns->miniimage != nil)
1705 [f->output_data.ns->miniimage release];
1707 [[view window] close];
1710 xfree (f->output_data.ns);
1716 x_destroy_window (struct frame *f)
1717 /* --------------------------------------------------------------------------
1718 External: Delete the window
1719 -------------------------------------------------------------------------- */
1721 NSTRACE ("x_destroy_window");
1723 /* If this frame has a parent window, detach it as not doing so can
1724 cause a crash in GNUStep. */
1725 if (FRAME_PARENT_FRAME (f) != NULL)
1727 NSWindow *child = [FRAME_NS_VIEW (f) window];
1728 NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
1730 [parent removeChildWindow: child];
1733 check_window_system (f);
1734 x_free_frame_resources (f);
1740 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1741 /* --------------------------------------------------------------------------
1742 External: Position the window
1743 -------------------------------------------------------------------------- */
1745 NSView *view = FRAME_NS_VIEW (f);
1746 NSArray *screens = [NSScreen screens];
1747 NSScreen *fscreen = [screens objectAtIndex: 0];
1748 NSScreen *screen = [[view window] screen];
1750 NSTRACE ("x_set_offset");
1757 if (view != nil && screen && fscreen)
1759 f->left_pos = f->size_hint_flags & XNegative
1760 ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1762 /* We use visibleFrame here to take menu bar into account.
1763 Ideally we should also adjust left/top with visibleFrame.origin. */
1765 f->top_pos = f->size_hint_flags & YNegative
1766 ? ([screen visibleFrame].size.height + f->top_pos
1767 - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1768 - FRAME_TOOLBAR_HEIGHT (f))
1770 #ifdef NS_IMPL_GNUSTEP
1771 if (FRAME_PARENT_FRAME (f) == NULL)
1773 if (f->left_pos < 100)
1774 f->left_pos = 100; /* don't overlap menu */
1777 /* Constrain the setFrameTopLeftPoint so we don't move behind the
1779 NSPoint pt = NSMakePoint (SCREENMAXBOUND (f->left_pos
1780 + NS_PARENT_WINDOW_LEFT_POS (f)),
1781 SCREENMAXBOUND (NS_PARENT_WINDOW_TOP_POS (f)
1783 NSTRACE_POINT ("setFrameTopLeftPoint", pt);
1784 [[view window] setFrameTopLeftPoint: pt];
1785 f->size_hint_flags &= ~(XNegative|YNegative);
1793 x_set_window_size (struct frame *f,
1794 bool change_gravity,
1798 /* --------------------------------------------------------------------------
1799 Adjust window pixel size based on given character grid size
1800 Impl is a bit more complex than other terms, need to do some
1802 -------------------------------------------------------------------------- */
1804 EmacsView *view = FRAME_NS_VIEW (f);
1805 NSWindow *window = [view window];
1806 NSRect wr = [window frame];
1807 int pixelwidth, pixelheight;
1808 int orig_height = wr.size.height;
1810 NSTRACE ("x_set_window_size");
1815 NSTRACE_RECT ("current", wr);
1816 NSTRACE_MSG ("Width:%d Height:%d Pixelwise:%d", width, height, pixelwise);
1817 NSTRACE_MSG ("Font %d x %d", FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f));
1823 pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1824 pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1828 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, width);
1829 pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1832 wr.size.width = pixelwidth + f->border_width;
1833 wr.size.height = pixelheight;
1834 if (! [view isFullscreen])
1835 wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1836 + FRAME_TOOLBAR_HEIGHT (f);
1838 /* Do not try to constrain to this screen. We may have multiple
1839 screens, and want Emacs to span those. Constraining to screen
1840 prevents that, and that is not nice to the user. */
1841 if (f->output_data.ns->zooming)
1842 f->output_data.ns->zooming = 0;
1844 wr.origin.y += orig_height - wr.size.height;
1846 frame_size_history_add
1847 (f, Qx_set_window_size_1, width, height,
1848 list5 (Fcons (make_number (pixelwidth), make_number (pixelheight)),
1849 Fcons (make_number (wr.size.width), make_number (wr.size.height)),
1850 make_number (f->border_width),
1851 make_number (FRAME_NS_TITLEBAR_HEIGHT (f)),
1852 make_number (FRAME_TOOLBAR_HEIGHT (f))));
1854 [window setFrame: wr display: YES];
1856 [view updateFrameSize: NO];
1860 #ifdef NS_IMPL_COCOA
1862 x_set_undecorated (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1863 /* --------------------------------------------------------------------------
1864 Set frame F's `undecorated' parameter. If non-nil, F's window-system
1865 window is drawn without decorations, title, minimize/maximize boxes
1866 and external borders. This usually means that the window cannot be
1867 dragged, resized, iconified, maximized or deleted with the mouse. If
1868 nil, draw the frame with all the elements listed above unless these
1869 have been suspended via window manager settings.
1871 GNUStep cannot change an existing window's style.
1872 -------------------------------------------------------------------------- */
1874 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1875 NSWindow *window = [view window];
1877 NSTRACE ("x_set_undecorated");
1879 if (!EQ (new_value, old_value))
1883 if (NILP (new_value))
1885 FRAME_UNDECORATED (f) = false;
1886 [window setStyleMask: ((window.styleMask | FRAME_DECORATED_FLAGS)
1887 ^ FRAME_UNDECORATED_FLAGS)];
1889 [view createToolbar: f];
1893 [window setToolbar: nil];
1894 /* Do I need to release the toolbar here? */
1896 FRAME_UNDECORATED (f) = true;
1897 [window setStyleMask: ((window.styleMask | FRAME_UNDECORATED_FLAGS)
1898 ^ FRAME_DECORATED_FLAGS)];
1901 /* At this point it seems we don't have an active NSResponder,
1902 so some key presses (TAB) are swallowed by the system. */
1903 [window makeFirstResponder: view];
1905 [view updateFrameSize: NO];
1909 #endif /* NS_IMPL_COCOA */
1912 x_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1913 /* --------------------------------------------------------------------------
1914 Set frame F's `parent-frame' parameter. If non-nil, make F a child
1915 frame of the frame specified by that parameter. Technically, this
1916 makes F's window-system window a child window of the parent frame's
1917 window-system window. If nil, make F's window-system window a
1918 top-level window--a child of its display's root window.
1920 A child frame's `left' and `top' parameters specify positions
1921 relative to the top-left corner of its parent frame's native
1922 rectangle. On macOS moving a parent frame moves all its child
1923 frames too, keeping their position relative to the parent
1924 unaltered. When a parent frame is iconified or made invisible, its
1925 child frames are made invisible. When a parent frame is deleted,
1926 its child frames are deleted too.
1928 Whether a child frame has a tool bar may be window-system or window
1929 manager dependent. It's advisable to disable it via the frame
1932 Some window managers may not honor this parameter.
1933 -------------------------------------------------------------------------- */
1935 struct frame *p = NULL;
1936 NSWindow *parent, *child;
1938 NSTRACE ("x_set_parent_frame");
1940 if (!NILP (new_value)
1941 && (!FRAMEP (new_value)
1942 || !FRAME_LIVE_P (p = XFRAME (new_value))
1945 store_frame_param (f, Qparent_frame, old_value);
1946 error ("Invalid specification of `parent-frame'");
1949 if (p != FRAME_PARENT_FRAME (f))
1951 parent = [FRAME_NS_VIEW (p) window];
1952 child = [FRAME_NS_VIEW (f) window];
1955 [parent addChildWindow: child
1956 ordered: NSWindowAbove];
1959 fset_parent_frame (f, new_value);
1964 x_set_no_focus_on_map (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1965 /* Set frame F's `no-focus-on-map' parameter which, if non-nil, means
1966 * that F's window-system window does not want to receive input focus
1967 * when it is mapped. (A frame's window is mapped when the frame is
1968 * displayed for the first time and when the frame changes its state
1969 * from `iconified' or `invisible' to `visible'.)
1971 * Some window managers may not honor this parameter. */
1973 NSTRACE ("x_set_no_focus_on_map");
1975 if (!EQ (new_value, old_value))
1977 FRAME_NO_FOCUS_ON_MAP (f) = !NILP (new_value);
1982 x_set_no_accept_focus (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1983 /* Set frame F's `no-accept-focus' parameter which, if non-nil, hints
1984 * that F's window-system window does not want to receive input focus
1985 * via mouse clicks or by moving the mouse into it.
1987 * If non-nil, this may have the unwanted side-effect that a user cannot
1988 * scroll a non-selected frame with the mouse.
1990 * Some window managers may not honor this parameter. */
1992 NSTRACE ("x_set_no_accept_focus");
1994 if (!EQ (new_value, old_value))
1995 FRAME_NO_ACCEPT_FOCUS (f) = !NILP (new_value);
1999 x_set_z_group (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
2000 /* Set frame F's `z-group' parameter. If `above', F's window-system
2001 window is displayed above all windows that do not have the `above'
2002 property set. If nil, F's window is shown below all windows that
2003 have the `above' property set and above all windows that have the
2004 `below' property set. If `below', F's window is displayed below
2005 all windows that do.
2007 Some window managers may not honor this parameter. */
2009 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2010 NSWindow *window = [view window];
2012 NSTRACE ("x_set_z_group");
2014 if (NILP (new_value))
2016 window.level = NSNormalWindowLevel;
2017 FRAME_Z_GROUP (f) = z_group_none;
2019 else if (EQ (new_value, Qabove))
2021 window.level = NSNormalWindowLevel + 1;
2022 FRAME_Z_GROUP (f) = z_group_above;
2024 else if (EQ (new_value, Qabove_suspended))
2026 /* Not sure what level this should be. */
2027 window.level = NSNormalWindowLevel + 1;
2028 FRAME_Z_GROUP (f) = z_group_above_suspended;
2030 else if (EQ (new_value, Qbelow))
2032 window.level = NSNormalWindowLevel - 1;
2033 FRAME_Z_GROUP (f) = z_group_below;
2036 error ("Invalid z-group specification");
2040 ns_fullscreen_hook (struct frame *f)
2042 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2044 NSTRACE ("ns_fullscreen_hook");
2046 if (!FRAME_VISIBLE_P (f))
2049 if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
2051 /* Old style fs don't initiate correctly if created from
2052 init/default-frame alist, so use a timer (not nice...).
2054 [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
2055 selector: @selector (handleFS)
2056 userInfo: nil repeats: NO];
2065 /* ==========================================================================
2069 ========================================================================== */
2073 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
2075 struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
2076 if (idx < 1 || idx >= color_table->avail)
2078 return color_table->colors[idx];
2083 ns_index_color (NSColor *color, struct frame *f)
2085 struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
2089 if (!color_table->colors)
2091 color_table->size = NS_COLOR_CAPACITY;
2092 color_table->avail = 1; /* skip idx=0 as marker */
2093 color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
2094 color_table->colors[0] = nil;
2095 color_table->empty_indices = [[NSMutableSet alloc] init];
2098 /* Do we already have this color? */
2099 for (i = 1; i < color_table->avail; i++)
2100 if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
2103 if ([color_table->empty_indices count] > 0)
2105 NSNumber *index = [color_table->empty_indices anyObject];
2106 [color_table->empty_indices removeObject: index];
2107 idx = [index unsignedLongValue];
2111 if (color_table->avail == color_table->size)
2112 color_table->colors =
2113 xpalloc (color_table->colors, &color_table->size, 1,
2114 min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
2115 idx = color_table->avail++;
2118 color_table->colors[idx] = color;
2120 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
2126 ns_get_color (const char *name, NSColor **col)
2127 /* --------------------------------------------------------------------------
2129 -------------------------------------------------------------------------- */
2130 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
2131 X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
2132 See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
2135 static char hex[20];
2137 float r = -1.0, g, b;
2138 NSString *nsname = [NSString stringWithUTF8String: name];
2140 NSTRACE ("ns_get_color(%s, **)", name);
2144 if ([nsname isEqualToString: @"ns_selection_bg_color"])
2146 #ifdef NS_IMPL_COCOA
2147 NSString *defname = [[NSUserDefaults standardUserDefaults]
2148 stringForKey: @"AppleHighlightColor"];
2153 if ((new = [NSColor selectedTextBackgroundColor]) != nil)
2155 *col = [new colorUsingDefaultColorSpace];
2160 nsname = NS_SELECTION_BG_COLOR_DEFAULT;
2162 name = [nsname UTF8String];
2164 else if ([nsname isEqualToString: @"ns_selection_fg_color"])
2166 /* NOTE: macOS applications normally don't set foreground
2167 selection, but text may be unreadable if we don't.
2169 if ((new = [NSColor selectedTextColor]) != nil)
2171 *col = [new colorUsingDefaultColorSpace];
2176 nsname = NS_SELECTION_FG_COLOR_DEFAULT;
2177 name = [nsname UTF8String];
2180 /* First, check for some sort of numeric specification. */
2183 if (name[0] == '0' || name[0] == '1' || name[0] == '.') /* RGB decimal */
2185 NSScanner *scanner = [NSScanner scannerWithString: nsname];
2186 [scanner scanFloat: &r];
2187 [scanner scanFloat: &g];
2188 [scanner scanFloat: &b];
2190 else if (!strncmp(name, "rgb:", 4)) /* A newer X11 format -- rgb:r/g/b */
2191 scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
2192 else if (name[0] == '#') /* An old X11 format; convert to newer */
2194 int len = (strlen(name) - 1);
2195 int start = (len % 3 == 0) ? 1 : len / 4 + 1;
2197 scaling = strlen(name+start) / 3;
2198 for (i = 0; i < 3; i++)
2199 sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
2200 name + start + i * scaling);
2201 hex[3 * (scaling + 1) - 1] = '\0';
2206 unsigned int rr, gg, bb;
2207 float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
2208 if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
2218 *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
2223 /* Otherwise, color is expected to be from a list */
2225 NSEnumerator *lenum, *cenum;
2229 #ifdef NS_IMPL_GNUSTEP
2230 /* XXX: who is wrong, the requestor or the implementation? */
2231 if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
2233 nsname = @"highlightColor";
2236 lenum = [[NSColorList availableColorLists] objectEnumerator];
2237 while ( (clist = [lenum nextObject]) && new == nil)
2239 cenum = [[clist allKeys] objectEnumerator];
2240 while ( (name = [cenum nextObject]) && new == nil )
2242 if ([name compare: nsname
2243 options: NSCaseInsensitiveSearch] == NSOrderedSame )
2244 new = [clist colorWithKey: name];
2250 *col = [new colorUsingDefaultColorSpace];
2257 ns_lisp_to_color (Lisp_Object color, NSColor **col)
2258 /* --------------------------------------------------------------------------
2259 Convert a Lisp string object to a NS color
2260 -------------------------------------------------------------------------- */
2262 NSTRACE ("ns_lisp_to_color");
2263 if (STRINGP (color))
2264 return ns_get_color (SSDATA (color), col);
2265 else if (SYMBOLP (color))
2266 return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
2272 ns_query_color(void *col, XColor *color_def, int setPixel)
2273 /* --------------------------------------------------------------------------
2274 Get ARGB values out of NSColor col and put them into color_def.
2275 If setPixel, set the pixel to a concatenated version.
2276 and set color_def pixel to the resulting index.
2277 -------------------------------------------------------------------------- */
2279 EmacsCGFloat r, g, b, a;
2281 [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
2282 color_def->red = r * 65535;
2283 color_def->green = g * 65535;
2284 color_def->blue = b * 65535;
2286 if (setPixel == YES)
2288 = ARGB_TO_ULONG((int)(a*255),
2289 (int)(r*255), (int)(g*255), (int)(b*255));
2294 ns_defined_color (struct frame *f,
2299 /* --------------------------------------------------------------------------
2300 Return true if named color found, and set color_def rgb accordingly.
2301 If makeIndex and alloc are nonzero put the color in the color_table,
2302 and set color_def pixel to the resulting index.
2303 If makeIndex is zero, set color_def pixel to ARGB.
2304 Return false if not found
2305 -------------------------------------------------------------------------- */
2308 NSTRACE_WHEN (NSTRACE_GROUP_COLOR, "ns_defined_color");
2311 if (ns_get_color (name, &col) != 0) /* Color not found */
2316 if (makeIndex && alloc)
2317 color_def->pixel = ns_index_color (col, f);
2318 ns_query_color (col, color_def, !makeIndex);
2325 x_set_frame_alpha (struct frame *f)
2326 /* --------------------------------------------------------------------------
2327 change the entire-frame transparency
2328 -------------------------------------------------------------------------- */
2330 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2332 double alpha_min = 1.0;
2334 NSTRACE ("x_set_frame_alpha");
2336 if (dpyinfo->x_highlight_frame == f)
2337 alpha = f->alpha[0];
2339 alpha = f->alpha[1];
2341 if (FLOATP (Vframe_alpha_lower_limit))
2342 alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
2343 else if (INTEGERP (Vframe_alpha_lower_limit))
2344 alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
2348 else if (1.0 < alpha)
2350 else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
2353 #ifdef NS_IMPL_COCOA
2355 EmacsView *view = FRAME_NS_VIEW (f);
2356 [[view window] setAlphaValue: alpha];
2362 /* ==========================================================================
2366 ========================================================================== */
2370 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
2371 /* --------------------------------------------------------------------------
2372 Programmatically reposition mouse pointer in pixel coordinates
2373 -------------------------------------------------------------------------- */
2375 NSTRACE ("frame_set_mouse_pixel_position");
2377 /* FIXME: what about GNUstep? */
2378 #ifdef NS_IMPL_COCOA
2380 CGPointMake(f->left_pos + pix_x,
2381 f->top_pos + pix_y +
2382 FRAME_NS_TITLEBAR_HEIGHT(f) + FRAME_TOOLBAR_HEIGHT(f));
2383 CGWarpMouseCursorPosition (mouse_pos);
2388 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
2389 /* ------------------------------------------------------------------------
2390 Called by EmacsView on mouseMovement events. Passes on
2391 to emacs mainstream code if we moved off of a rect of interest
2392 known as last_mouse_glyph.
2393 ------------------------------------------------------------------------ */
2395 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
2398 // NSTRACE ("note_mouse_movement");
2400 dpyinfo->last_mouse_motion_frame = frame;
2401 r = &dpyinfo->last_mouse_glyph;
2403 /* Note, this doesn't get called for enter/leave, since we don't have a
2404 position. Those are taken care of in the corresponding NSView methods. */
2406 /* has movement gone beyond last rect we were tracking? */
2407 if (x < r->origin.x || x >= r->origin.x + r->size.width
2408 || y < r->origin.y || y >= r->origin.y + r->size.height)
2410 ns_update_begin (frame);
2411 frame->mouse_moved = 1;
2412 note_mouse_highlight (frame, x, y);
2413 remember_mouse_glyph (frame, x, y, r);
2414 ns_update_end (frame);
2423 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
2424 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
2426 /* --------------------------------------------------------------------------
2427 External (hook): inform emacs about mouse position and hit parts.
2428 If a scrollbar is being dragged, set bar_window, part, x, y, time.
2429 x & y should be position in the scrollbar (the whole bar, not the handle)
2430 and length of scrollbar respectively
2431 -------------------------------------------------------------------------- */
2435 Lisp_Object frame, tail;
2437 struct ns_display_info *dpyinfo;
2439 NSTRACE ("ns_mouse_position");
2443 fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
2447 dpyinfo = FRAME_DISPLAY_INFO (*fp);
2451 /* Clear the mouse-moved flag for every frame on this display. */
2452 FOR_EACH_FRAME (tail, frame)
2453 if (FRAME_NS_P (XFRAME (frame))
2454 && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
2455 XFRAME (frame)->mouse_moved = 0;
2457 dpyinfo->last_mouse_scroll_bar = nil;
2458 if (dpyinfo->last_mouse_frame
2459 && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
2460 f = dpyinfo->last_mouse_frame;
2462 f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame : SELECTED_FRAME ();
2464 if (f && FRAME_NS_P (f))
2466 view = FRAME_NS_VIEW (*fp);
2468 position = [[view window] mouseLocationOutsideOfEventStream];
2469 position = [view convertPoint: position fromView: nil];
2470 remember_mouse_glyph (f, position.x, position.y,
2471 &dpyinfo->last_mouse_glyph);
2472 NSTRACE_POINT ("position", position);
2474 if (bar_window) *bar_window = Qnil;
2475 if (part) *part = scroll_bar_above_handle;
2477 if (x) XSETINT (*x, lrint (position.x));
2478 if (y) XSETINT (*y, lrint (position.y));
2480 *time = dpyinfo->last_mouse_movement_time;
2489 ns_frame_up_to_date (struct frame *f)
2490 /* --------------------------------------------------------------------------
2491 External (hook): Fix up mouse highlighting right after a full update.
2492 Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
2493 -------------------------------------------------------------------------- */
2495 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_frame_up_to_date");
2499 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
2500 if (f == hlinfo->mouse_face_mouse_frame)
2504 note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
2505 hlinfo->mouse_face_mouse_x,
2506 hlinfo->mouse_face_mouse_y);
2515 ns_define_frame_cursor (struct frame *f, Cursor cursor)
2516 /* --------------------------------------------------------------------------
2517 External (RIF): set frame mouse pointer type.
2518 -------------------------------------------------------------------------- */
2520 NSTRACE ("ns_define_frame_cursor");
2521 if (FRAME_POINTER_TYPE (f) != cursor)
2523 EmacsView *view = FRAME_NS_VIEW (f);
2524 FRAME_POINTER_TYPE (f) = cursor;
2525 [[view window] invalidateCursorRectsForView: view];
2526 /* Redisplay assumes this function also draws the changed frame
2527 cursor, but this function doesn't, so do it explicitly. */
2528 x_update_cursor (f, 1);
2534 /* ==========================================================================
2538 ========================================================================== */
2542 ns_convert_key (unsigned code)
2543 /* --------------------------------------------------------------------------
2544 Internal call used by NSView-keyDown.
2545 -------------------------------------------------------------------------- */
2547 const unsigned last_keysym = ARRAYELTS (convert_ns_to_X_keysym);
2549 /* An array would be faster, but less easy to read. */
2550 for (keysym = 0; keysym < last_keysym; keysym += 2)
2551 if (code == convert_ns_to_X_keysym[keysym])
2552 return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
2554 /* if decide to use keyCode and Carbon table, use this line:
2555 return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
2560 x_get_keysym_name (int keysym)
2561 /* --------------------------------------------------------------------------
2562 Called by keyboard.c. Not sure if the return val is important, except
2564 -------------------------------------------------------------------------- */
2566 static char value[16];
2567 NSTRACE ("x_get_keysym_name");
2568 sprintf (value, "%d", keysym);
2574 /* ==========================================================================
2576 Block drawing operations
2578 ========================================================================== */
2582 ns_redraw_scroll_bars (struct frame *f)
2586 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2587 NSTRACE ("ns_redraw_scroll_bars");
2588 for (i =[subviews count]-1; i >= 0; i--)
2590 view = [subviews objectAtIndex: i];
2591 if (![view isKindOfClass: [EmacsScroller class]]) continue;
2598 ns_clear_frame (struct frame *f)
2599 /* --------------------------------------------------------------------------
2600 External (hook): Erase the entire frame
2601 -------------------------------------------------------------------------- */
2603 NSView *view = FRAME_NS_VIEW (f);
2606 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame");
2608 /* comes on initial frame because we have
2609 after-make-frame-functions = select-frame */
2610 if (!FRAME_DEFAULT_FACE (f))
2613 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2618 ns_focus (f, &r, 1);
2619 [ns_lookup_indexed_color (NS_FACE_BACKGROUND
2620 (FACE_FROM_ID (f, DEFAULT_FACE_ID)), f) set];
2624 /* as of 2006/11 or so this is now needed */
2625 ns_redraw_scroll_bars (f);
2631 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2632 /* --------------------------------------------------------------------------
2633 External (RIF): Clear section of frame
2634 -------------------------------------------------------------------------- */
2636 NSRect r = NSMakeRect (x, y, width, height);
2637 NSView *view = FRAME_NS_VIEW (f);
2638 struct face *face = FRAME_DEFAULT_FACE (f);
2643 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame_area");
2645 r = NSIntersectionRect (r, [view frame]);
2646 ns_focus (f, &r, 1);
2647 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2656 ns_copy_bits (struct frame *f, NSRect src, NSRect dest)
2658 NSTRACE ("ns_copy_bits");
2660 if (FRAME_NS_VIEW (f))
2662 hide_bell(); // Ensure the bell image isn't scrolled.
2664 ns_focus (f, &dest, 1);
2665 [FRAME_NS_VIEW (f) scrollRect: src
2666 by: NSMakeSize (dest.origin.x - src.origin.x,
2667 dest.origin.y - src.origin.y)];
2673 ns_scroll_run (struct window *w, struct run *run)
2674 /* --------------------------------------------------------------------------
2675 External (RIF): Insert or delete n lines at line vpos
2676 -------------------------------------------------------------------------- */
2678 struct frame *f = XFRAME (w->frame);
2679 int x, y, width, height, from_y, to_y, bottom_y;
2681 NSTRACE ("ns_scroll_run");
2683 /* begin copy from other terms */
2684 /* Get frame-relative bounding box of the text display area of W,
2685 without mode lines. Include in this box the left and right
2687 window_box (w, ANY_AREA, &x, &y, &width, &height);
2689 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2690 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2691 bottom_y = y + height;
2695 /* Scrolling up. Make sure we don't copy part of the mode
2696 line at the bottom. */
2697 if (from_y + run->height > bottom_y)
2698 height = bottom_y - from_y;
2700 height = run->height;
2704 /* Scrolling down. Make sure we don't copy over the mode line.
2706 if (to_y + run->height > bottom_y)
2707 height = bottom_y - to_y;
2709 height = run->height;
2711 /* end copy from other terms */
2721 NSRect srcRect = NSMakeRect (x, from_y, width, height);
2722 NSRect dstRect = NSMakeRect (x, to_y, width, height);
2724 ns_copy_bits (f, srcRect , dstRect);
2732 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2733 /* --------------------------------------------------------------------------
2734 External (RIF): preparatory to fringe update after text was updated
2735 -------------------------------------------------------------------------- */
2740 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_after_update_window_line");
2742 /* begin copy from other terms */
2745 if (!desired_row->mode_line_p && !w->pseudo_window_p)
2746 desired_row->redraw_fringe_bitmaps_p = 1;
2748 /* When a window has disappeared, make sure that no rest of
2749 full-width rows stays visible in the internal border. */
2750 if (windows_or_buffers_changed
2751 && desired_row->full_width_p
2752 && (f = XFRAME (w->frame),
2753 width = FRAME_INTERNAL_BORDER_WIDTH (f),
2755 && (height = desired_row->visible_height,
2758 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2761 ns_clear_frame_area (f, 0, y, width, height);
2762 ns_clear_frame_area (f,
2763 FRAME_PIXEL_WIDTH (f) - width,
2771 ns_shift_glyphs_for_insert (struct frame *f,
2772 int x, int y, int width, int height,
2774 /* --------------------------------------------------------------------------
2775 External (RIF): copy an area horizontally, don't worry about clearing src
2776 -------------------------------------------------------------------------- */
2778 NSRect srcRect = NSMakeRect (x, y, width, height);
2779 NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2781 NSTRACE ("ns_shift_glyphs_for_insert");
2783 ns_copy_bits (f, srcRect, dstRect);
2788 /* ==========================================================================
2790 Character encoding and metrics
2792 ========================================================================== */
2796 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2797 /* --------------------------------------------------------------------------
2798 External (RIF); compute left/right overhang of whole string and set in s
2799 -------------------------------------------------------------------------- */
2801 struct font *font = s->font;
2805 struct font_metrics metrics;
2806 unsigned int codes[2];
2807 codes[0] = *(s->char2b);
2808 codes[1] = *(s->char2b + s->nchars - 1);
2810 font->driver->text_extents (font, codes, 2, &metrics);
2811 s->left_overhang = -metrics.lbearing;
2813 = metrics.rbearing > metrics.width
2814 ? metrics.rbearing - metrics.width : 0;
2818 s->left_overhang = 0;
2819 if (EQ (font->driver->type, Qns))
2820 s->right_overhang = ((struct nsfont_info *)font)->ital ?
2821 FONT_HEIGHT (font) * 0.2 : 0;
2823 s->right_overhang = 0;
2829 /* ==========================================================================
2831 Fringe and cursor drawing
2833 ========================================================================== */
2836 extern int max_used_fringe_bitmap;
2838 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2839 struct draw_fringe_bitmap_params *p)
2840 /* --------------------------------------------------------------------------
2841 External (RIF); fringe-related
2842 -------------------------------------------------------------------------- */
2844 /* Fringe bitmaps comes in two variants, normal and periodic. A
2845 periodic bitmap is used to create a continuous pattern. Since a
2846 bitmap is rendered one text line at a time, the start offset (dh)
2847 of the bitmap varies. Concretely, this is used for the empty
2850 For a bitmap, "h + dh" is the full height and is always
2851 invariant. For a normal bitmap "dh" is zero.
2853 For example, when the period is three and the full height is 72
2854 the following combinations exists:
2860 struct frame *f = XFRAME (WINDOW_FRAME (w));
2861 struct face *face = p->face;
2862 static EmacsImage **bimgs = NULL;
2863 static int nBimgs = 0;
2865 NSTRACE_WHEN (NSTRACE_GROUP_FRINGE, "ns_draw_fringe_bitmap");
2866 NSTRACE_MSG ("which:%d cursor:%d overlay:%d width:%d height:%d period:%d",
2867 p->which, p->cursor_p, p->overlay_p, p->wd, p->h, p->dh);
2869 /* grow bimgs if needed */
2870 if (nBimgs < max_used_fringe_bitmap)
2872 bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2873 memset (bimgs + nBimgs, 0,
2874 (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2875 nBimgs = max_used_fringe_bitmap;
2878 /* Must clip because of partially visible lines. */
2879 ns_clip_to_row (w, row, ANY_AREA, YES);
2883 int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2885 if (bx >= 0 && nx > 0)
2887 NSRect r = NSMakeRect (bx, by, nx, ny);
2889 [ns_lookup_indexed_color (face->background, f) set];
2896 NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2897 EmacsImage *img = bimgs[p->which - 1];
2901 // Note: For "periodic" images, allocate one EmacsImage for
2902 // the base image, and use it for all dh:s.
2903 unsigned short *bits = p->bits;
2904 int full_height = p->h + p->dh;
2906 unsigned char *cbits = xmalloc (full_height);
2908 for (i = 0; i < full_height; i++)
2910 img = [[EmacsImage alloc] initFromXBM: cbits width: 8
2913 bimgs[p->which - 1] = img;
2917 NSTRACE_RECT ("r", r);
2920 /* Since we composite the bitmap instead of just blitting it, we need
2921 to erase the whole background. */
2922 [ns_lookup_indexed_color(face->background, f) set];
2928 bm_color = ns_lookup_indexed_color(face->foreground, f);
2929 else if (p->overlay_p)
2930 bm_color = ns_lookup_indexed_color(face->background, f);
2932 bm_color = f->output_data.ns->cursor_color;
2933 [img setXBMColor: bm_color];
2936 #ifdef NS_IMPL_COCOA
2937 // Note: For periodic images, the full image height is "h + hd".
2938 // By using the height h, a suitable part of the image is used.
2939 NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h);
2941 NSTRACE_RECT ("fromRect", fromRect);
2945 operation: NSCompositingOperationSourceOver
2951 NSPoint pt = r.origin;
2953 [img compositeToPoint: pt operation: NSCompositingOperationSourceOver];
2962 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2963 int x, int y, enum text_cursor_kinds cursor_type,
2964 int cursor_width, bool on_p, bool active_p)
2965 /* --------------------------------------------------------------------------
2966 External call (RIF): draw cursor.
2967 Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2968 -------------------------------------------------------------------------- */
2971 int fx, fy, h, cursor_height;
2972 struct frame *f = WINDOW_XFRAME (w);
2973 struct glyph *phys_cursor_glyph;
2974 struct glyph *cursor_glyph;
2976 NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2978 /* If cursor is out of bounds, don't draw garbage. This can happen
2979 in mini-buffer windows when switching between echo area glyphs
2982 NSTRACE ("ns_draw_window_cursor");
2987 w->phys_cursor_type = cursor_type;
2988 w->phys_cursor_on_p = on_p;
2990 if (cursor_type == NO_CURSOR)
2992 w->phys_cursor_width = 0;
2996 if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2998 if (glyph_row->exact_window_width_line_p
2999 && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
3001 glyph_row->cursor_in_fringe_p = 1;
3002 draw_fringe_bitmap (w, glyph_row, 0);
3007 /* We draw the cursor (with NSRectFill), then draw the glyph on top
3008 (other terminals do it the other way round). We must set
3009 w->phys_cursor_width to the cursor width. For bar cursors, that
3010 is CURSOR_WIDTH; for box cursors, it is the glyph width. */
3011 get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
3013 /* The above get_phys_cursor_geometry call set w->phys_cursor_width
3014 to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
3015 if (cursor_type == BAR_CURSOR)
3017 if (cursor_width < 1)
3018 cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
3020 /* The bar cursor should never be wider than the glyph. */
3021 if (cursor_width < w->phys_cursor_width)
3022 w->phys_cursor_width = cursor_width;
3024 /* If we have an HBAR, "cursor_width" MAY specify height. */
3025 else if (cursor_type == HBAR_CURSOR)
3027 cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
3028 if (cursor_height > glyph_row->height)
3029 cursor_height = glyph_row->height;
3030 if (h > cursor_height) // Cursor smaller than line height, move down
3031 fy += h - cursor_height;
3035 r.origin.x = fx, r.origin.y = fy;
3037 r.size.width = w->phys_cursor_width;
3039 /* Prevent the cursor from being drawn outside the text area. */
3040 ns_clip_to_row (w, glyph_row, TEXT_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
3043 face = FACE_FROM_ID_OR_NULL (f, phys_cursor_glyph->face_id);
3044 if (face && NS_FACE_BACKGROUND (face)
3045 == ns_index_color (FRAME_CURSOR_COLOR (f), f))
3047 [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
3048 hollow_color = FRAME_CURSOR_COLOR (f);
3051 [FRAME_CURSOR_COLOR (f) set];
3053 #ifdef NS_IMPL_COCOA
3054 /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
3055 atomic. Cleaner ways of doing this should be investigated.
3056 One way would be to set a global variable DRAWING_CURSOR
3057 when making the call to draw_phys..(), don't focus in that
3058 case, then move the ns_unfocus() here after that call. */
3059 NSDisableScreenUpdates ();
3062 switch (cursor_type)
3064 case DEFAULT_CURSOR:
3067 case FILLED_BOX_CURSOR:
3070 case HOLLOW_BOX_CURSOR:
3073 NSRectFill (NSInsetRect (r, 1, 1));
3074 [FRAME_CURSOR_COLOR (f) set];
3081 /* If the character under cursor is R2L, draw the bar cursor
3082 on the right of its glyph, rather than on the left. */
3083 cursor_glyph = get_phys_cursor_glyph (w);
3084 if ((cursor_glyph->resolved_level & 1) != 0)
3085 s.origin.x += cursor_glyph->pixel_width - s.size.width;
3092 /* draw the character under the cursor */
3093 if (cursor_type != NO_CURSOR)
3094 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
3096 #ifdef NS_IMPL_COCOA
3097 NSEnableScreenUpdates ();
3104 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
3105 /* --------------------------------------------------------------------------
3106 External (RIF): Draw a vertical line.
3107 -------------------------------------------------------------------------- */
3109 struct frame *f = XFRAME (WINDOW_FRAME (w));
3111 NSRect r = NSMakeRect (x, y0, 1, y1-y0);
3113 NSTRACE ("ns_draw_vertical_window_border");
3115 face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID);
3117 ns_focus (f, &r, 1);
3119 [ns_lookup_indexed_color(face->foreground, f) set];
3127 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
3128 /* --------------------------------------------------------------------------
3129 External (RIF): Draw a window divider.
3130 -------------------------------------------------------------------------- */
3132 struct frame *f = XFRAME (WINDOW_FRAME (w));
3134 NSRect r = NSMakeRect (x0, y0, x1-x0, y1-y0);
3136 NSTRACE ("ns_draw_window_divider");
3138 face = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FACE_ID);
3140 ns_focus (f, &r, 1);
3142 [ns_lookup_indexed_color(face->foreground, f) set];
3149 ns_show_hourglass (struct frame *f)
3151 /* TODO: add NSProgressIndicator to all frames. */
3155 ns_hide_hourglass (struct frame *f)
3157 /* TODO: remove NSProgressIndicator from all frames. */
3160 /* ==========================================================================
3162 Glyph drawing operations
3164 ========================================================================== */
3167 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
3168 /* --------------------------------------------------------------------------
3169 Wrapper utility to account for internal border width on full-width lines,
3170 and allow top full-width rows to hit the frame top. nr should be pointer
3171 to two successive NSRects. Number of rects actually used is returned.
3172 -------------------------------------------------------------------------- */
3174 int n = get_glyph_string_clip_rects (s, nr, 2);
3178 /* --------------------------------------------------------------------
3179 Draw a wavy line under glyph string s. The wave fills wave_height
3186 wave_height = 3 | * * * *
3187 --------------------------------------------------------------------- */
3190 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
3192 int wave_height = 3, wave_length = 2;
3193 int y, dx, dy, odd, xmax;
3198 dy = wave_height - 1;
3199 y = s->ybase - wave_height + 3;
3202 /* Find and set clipping rectangle */
3203 waveClip = NSMakeRect (x, y, width, wave_height);
3204 [[NSGraphicsContext currentContext] saveGraphicsState];
3205 NSRectClip (waveClip);
3207 /* Draw the waves */
3208 a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
3210 odd = (int)(a.x/dx) % 2;
3211 a.y = b.y = y + 0.5;
3220 [NSBezierPath strokeLineFromPoint:a toPoint:b];
3221 a.x = b.x, a.y = b.y;
3222 b.x += dx, b.y = y + 0.5 + odd*dy;
3226 /* Restore previous clipping rectangle(s) */
3227 [[NSGraphicsContext currentContext] restoreGraphicsState];
3233 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
3234 NSColor *defaultCol, CGFloat width, CGFloat x)
3235 /* --------------------------------------------------------------------------
3236 Draw underline, overline, and strike-through on glyph string s.
3237 -------------------------------------------------------------------------- */
3239 if (s->for_overlaps)
3243 if (face->underline_p)
3245 if (s->face->underline_type == FACE_UNDER_WAVE)
3247 if (face->underline_defaulted_p)
3250 [ns_lookup_indexed_color (face->underline_color, s->f) set];
3252 ns_draw_underwave (s, width, x);
3254 else if (s->face->underline_type == FACE_UNDER_LINE)
3258 unsigned long thickness, position;
3260 /* If the prev was underlined, match its appearance. */
3261 if (s->prev && s->prev->face->underline_p
3262 && s->prev->face->underline_type == FACE_UNDER_LINE
3263 && s->prev->underline_thickness > 0)
3265 thickness = s->prev->underline_thickness;
3266 position = s->prev->underline_position;
3270 struct font *font = font_for_underline_metrics (s);
3271 unsigned long descent = s->y + s->height - s->ybase;
3273 /* Use underline thickness of font, defaulting to 1. */
3274 thickness = (font && font->underline_thickness > 0)
3275 ? font->underline_thickness : 1;
3277 /* Determine the offset of underlining from the baseline. */
3278 if (x_underline_at_descent_line)
3279 position = descent - thickness;
3280 else if (x_use_underline_position_properties
3281 && font && font->underline_position >= 0)
3282 position = font->underline_position;
3284 position = lround (font->descent / 2);
3286 position = underline_minimum_offset;
3288 position = max (position, underline_minimum_offset);
3290 /* Ensure underlining is not cropped. */
3291 if (descent <= position)
3293 position = descent - 1;
3296 else if (descent < position + thickness)
3300 s->underline_thickness = thickness;
3301 s->underline_position = position;
3303 r = NSMakeRect (x, s->ybase + position, width, thickness);
3305 if (face->underline_defaulted_p)
3308 [ns_lookup_indexed_color (face->underline_color, s->f) set];
3312 /* Do overline. We follow other terms in using a thickness of 1
3313 and ignoring overline_margin. */
3314 if (face->overline_p)
3317 r = NSMakeRect (x, s->y, width, 1);
3319 if (face->overline_color_defaulted_p)
3322 [ns_lookup_indexed_color (face->overline_color, s->f) set];
3326 /* Do strike-through. We follow other terms for thickness and
3327 vertical position.*/
3328 if (face->strike_through_p)
3331 /* Y-coordinate and height of the glyph string's first glyph.
3332 We cannot use s->y and s->height because those could be
3333 larger if there are taller display elements (e.g., characters
3334 displayed with a larger font) in the same glyph row. */
3335 int glyph_y = s->ybase - s->first_glyph->ascent;
3336 int glyph_height = s->first_glyph->ascent + s->first_glyph->descent;
3337 /* Strike-through width and offset from the glyph string's
3339 unsigned long h = 1;
3342 dy = lrint ((glyph_height - h) / 2);
3343 r = NSMakeRect (x, glyph_y + dy, width, 1);
3345 if (face->strike_through_color_defaulted_p)
3348 [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
3354 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
3355 char left_p, char right_p)
3356 /* --------------------------------------------------------------------------
3357 Draw an unfilled rect inside r, optionally leaving left and/or right open.
3358 Note we can't just use an NSDrawRect command, because of the possibility
3359 of some sides not being drawn, and because the rect will be filled.
3360 -------------------------------------------------------------------------- */
3366 s.size.height = thickness;
3368 s.origin.y += r.size.height - thickness;
3371 s.size.height = r.size.height;
3372 s.origin.y = r.origin.y;
3374 /* left, right (optional) */
3375 s.size.width = thickness;
3380 s.origin.x += r.size.width - thickness;
3387 ns_draw_relief (NSRect r, int thickness, char raised_p,
3388 char top_p, char bottom_p, char left_p, char right_p,
3389 struct glyph_string *s)
3390 /* --------------------------------------------------------------------------
3391 Draw a relief rect inside r, optionally leaving some sides open.
3392 Note we can't just use an NSDrawBezel command, because of the possibility
3393 of some sides not being drawn, and because the rect will be filled.
3394 -------------------------------------------------------------------------- */
3396 static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
3397 NSColor *newBaseCol = nil;
3400 NSTRACE ("ns_draw_relief");
3404 if (s->face->use_box_color_for_shadows_p)
3406 newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
3408 /* else if (s->first_glyph->type == IMAGE_GLYPH
3410 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3412 newBaseCol = IMAGE_BACKGROUND (s->img, s->f, 0);
3416 newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
3419 if (newBaseCol == nil)
3420 newBaseCol = [NSColor grayColor];
3422 if (newBaseCol != baseCol) /* TODO: better check */
3425 baseCol = [newBaseCol retain];
3427 lightCol = [[baseCol highlightWithLevel: 0.2] retain];
3429 darkCol = [[baseCol shadowWithLevel: 0.3] retain];
3432 [(raised_p ? lightCol : darkCol) set];
3434 /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
3437 sr.size.height = thickness;
3438 if (top_p) NSRectFill (sr);
3441 sr.size.height = r.size.height;
3442 sr.size.width = thickness;
3443 if (left_p) NSRectFill (sr);
3445 [(raised_p ? darkCol : lightCol) set];
3448 sr.size.width = r.size.width;
3449 sr.size.height = thickness;
3450 sr.origin.y += r.size.height - thickness;
3451 if (bottom_p) NSRectFill (sr);
3454 sr.size.height = r.size.height;
3455 sr.origin.y = r.origin.y;
3456 sr.size.width = thickness;
3457 sr.origin.x += r.size.width - thickness;
3458 if (right_p) NSRectFill (sr);
3463 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
3464 /* --------------------------------------------------------------------------
3465 Function modeled after x_draw_glyph_string_box ().
3466 Sets up parameters for drawing.
3467 -------------------------------------------------------------------------- */
3469 int right_x, last_x;
3470 char left_p, right_p;
3471 struct glyph *last_glyph;
3476 if (s->hl == DRAW_MOUSE_FACE)
3478 face = FACE_FROM_ID_OR_NULL (s->f,
3479 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3481 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3486 thickness = face->box_line_width;
3488 NSTRACE ("ns_dumpglyphs_box_or_relief");
3490 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
3491 ? WINDOW_RIGHT_EDGE_X (s->w)
3492 : window_box_right (s->w, s->area));
3493 last_glyph = (s->cmp || s->img
3494 ? s->first_glyph : s->first_glyph + s->nchars-1);
3496 right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
3497 ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
3499 left_p = (s->first_glyph->left_box_line_p
3500 || (s->hl == DRAW_MOUSE_FACE
3501 && (s->prev == NULL || s->prev->hl != s->hl)));
3502 right_p = (last_glyph->right_box_line_p
3503 || (s->hl == DRAW_MOUSE_FACE
3504 && (s->next == NULL || s->next->hl != s->hl)));
3506 r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
3508 /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
3509 if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
3511 ns_draw_box (r, abs (thickness),
3512 ns_lookup_indexed_color (face->box_color, s->f),
3517 ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
3518 1, 1, left_p, right_p, s);
3524 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
3525 /* --------------------------------------------------------------------------
3526 Modeled after x_draw_glyph_string_background, which draws BG in
3527 certain cases. Others are left to the text rendering routine.
3528 -------------------------------------------------------------------------- */
3530 NSTRACE ("ns_maybe_dumpglyphs_background");
3532 if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
3534 int box_line_width = max (s->face->box_line_width, 0);
3535 if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
3536 /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font
3537 dimensions, since the actual glyphs might be much
3538 smaller. So in that case we always clear the rectangle
3539 with background color. */
3540 || FONT_TOO_HIGH (s->font)
3541 || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
3544 if (s->hl == DRAW_MOUSE_FACE)
3547 = FACE_FROM_ID_OR_NULL (s->f,
3548 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3550 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3553 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3555 [(NS_FACE_BACKGROUND (face) != 0
3556 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
3557 : FRAME_BACKGROUND_COLOR (s->f)) set];
3560 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
3561 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
3564 if (s->hl != DRAW_CURSOR)
3566 NSRect r = NSMakeRect (s->x, s->y + box_line_width,
3567 s->background_width,
3568 s->height-2*box_line_width);
3572 s->background_filled_p = 1;
3579 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3580 /* --------------------------------------------------------------------------
3581 Renders an image and associated borders.
3582 -------------------------------------------------------------------------- */
3584 EmacsImage *img = s->img->pixmap;
3585 int box_line_vwidth = max (s->face->box_line_width, 0);
3586 int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3587 int bg_x, bg_y, bg_height;
3594 NSTRACE ("ns_dumpglyphs_image");
3596 if (s->face->box != FACE_NO_BOX
3597 && s->first_glyph->left_box_line_p && s->slice.x == 0)
3598 x += abs (s->face->box_line_width);
3601 bg_y = s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
3602 bg_height = s->height;
3603 /* other terms have this, but was causing problems w/tabbar mode */
3604 /* - 2 * box_line_vwidth; */
3606 if (s->slice.x == 0) x += s->img->hmargin;
3607 if (s->slice.y == 0) y += s->img->vmargin;
3609 /* Draw BG: if we need larger area than image itself cleared, do that,
3610 otherwise, since we composite the image under NS (instead of mucking
3611 with its background color), we must clear just the image area. */
3612 if (s->hl == DRAW_MOUSE_FACE)
3614 face = FACE_FROM_ID_OR_NULL (s->f,
3615 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3617 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3620 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3622 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3624 if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3625 || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3627 br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3628 s->background_filled_p = 1;
3632 br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3637 /* Draw the image.. do we need to draw placeholder if img ==nil? */
3640 #ifdef NS_IMPL_COCOA
3641 NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3642 NSRect ir = NSMakeRect (s->slice.x,
3643 s->img->height - s->slice.y - s->slice.height,
3644 s->slice.width, s->slice.height);
3647 operation: NSCompositingOperationSourceOver
3652 [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3653 operation: NSCompositingOperationSourceOver];
3657 if (s->hl == DRAW_CURSOR)
3659 [FRAME_CURSOR_COLOR (s->f) set];
3660 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3661 tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3663 /* Currently on NS img->mask is always 0. Since
3664 get_window_cursor_type specifies a hollow box cursor when on
3665 a non-masked image we never reach this clause. But we put it
3666 in in anticipation of better support for image masks on
3668 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3672 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3675 /* Draw underline, overline, strike-through. */
3676 ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3678 /* Draw relief, if requested */
3679 if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3681 if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3683 th = tool_bar_button_relief >= 0 ?
3684 tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3685 raised_p = (s->hl == DRAW_IMAGE_RAISED);
3689 th = abs (s->img->relief);
3690 raised_p = (s->img->relief > 0);
3693 r.origin.x = x - th;
3694 r.origin.y = y - th;
3695 r.size.width = s->slice.width + 2*th-1;
3696 r.size.height = s->slice.height + 2*th-1;
3697 ns_draw_relief (r, th, raised_p,
3699 s->slice.y + s->slice.height == s->img->height,
3701 s->slice.x + s->slice.width == s->img->width, s);
3704 /* If there is no mask, the background won't be seen,
3705 so draw a rectangle on the image for the cursor.
3706 Do this for all images, getting transparency right is not reliable. */
3707 if (s->hl == DRAW_CURSOR)
3709 int thickness = abs (s->img->relief);
3710 if (thickness == 0) thickness = 1;
3711 ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3717 ns_dumpglyphs_stretch (struct glyph_string *s)
3722 NSColor *fgCol, *bgCol;
3724 if (!s->background_filled_p)
3726 n = ns_get_glyph_string_clip_rect (s, r);
3727 *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3729 ns_focus (s->f, r, n);
3731 if (s->hl == DRAW_MOUSE_FACE)
3733 face = FACE_FROM_ID_OR_NULL (s->f,
3734 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3736 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3739 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3741 bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3742 fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3744 for (i = 0; i < n; ++i)
3746 if (!s->row->full_width_p)
3748 int overrun, leftoverrun;
3750 /* truncate to avoid overwriting fringe and/or scrollbar */
3751 overrun = max (0, (s->x + s->background_width)
3752 - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3753 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3754 r[i].size.width -= overrun;
3756 /* truncate to avoid overwriting to left of the window box */
3757 leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3758 + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3760 if (leftoverrun > 0)
3762 r[i].origin.x += leftoverrun;
3763 r[i].size.width -= leftoverrun;
3766 /* XXX: Try to work between problem where a stretch glyph on
3767 a partially-visible bottom row will clear part of the
3768 modeline, and another where list-buffers headers and similar
3769 rows erroneously have visible_height set to 0. Not sure
3770 where this is coming from as other terms seem not to show. */
3771 r[i].size.height = min (s->height, s->row->visible_height);
3776 /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3777 overwriting cursor (usually when cursor on a tab) */
3778 if (s->hl == DRAW_CURSOR)
3783 width = s->w->phys_cursor_width;
3784 r[i].size.width -= width;
3785 r[i].origin.x += width;
3789 /* Draw overlining, etc. on the cursor. */
3790 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3791 ns_draw_text_decoration (s, face, bgCol, width, x);
3793 ns_draw_text_decoration (s, face, fgCol, width, x);
3800 /* Draw overlining, etc. on the stretch glyph (or the part
3801 of the stretch glyph after the cursor). */
3802 ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3806 s->background_filled_p = 1;
3812 ns_draw_glyph_string_foreground (struct glyph_string *s)
3815 struct font *font = s->font;
3817 /* If first glyph of S has a left box line, start drawing the text
3818 of S to the right of that box line. */
3819 if (s->face && s->face->box != FACE_NO_BOX
3820 && s->first_glyph->left_box_line_p)
3821 x = s->x + eabs (s->face->box_line_width);
3825 flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3826 (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3827 (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3828 NS_DUMPGLYPH_NORMAL));
3831 (s, s->cmp_from, s->nchars, x, s->ybase,
3832 (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3833 || flags == NS_DUMPGLYPH_MOUSEFACE);
3838 ns_draw_composite_glyph_string_foreground (struct glyph_string *s)
3841 struct font *font = s->font;
3843 /* If first glyph of S has a left box line, start drawing the text
3844 of S to the right of that box line. */
3845 if (s->face && s->face->box != FACE_NO_BOX
3846 && s->first_glyph->left_box_line_p)
3847 x = s->x + eabs (s->face->box_line_width);
3851 /* S is a glyph string for a composition. S->cmp_from is the index
3852 of the first character drawn for glyphs of this composition.
3853 S->cmp_from == 0 means we are drawing the very first character of
3854 this composition. */
3856 /* Draw a rectangle for the composition if the font for the very
3857 first character of the composition could not be loaded. */
3858 if (s->font_not_found_p)
3860 if (s->cmp_from == 0)
3862 NSRect r = NSMakeRect (s->x, s->y, s->width-1, s->height -1);
3863 ns_draw_box (r, 1, FRAME_CURSOR_COLOR (s->f), 1, 1);
3866 else if (! s->first_glyph->u.cmp.automatic)
3870 for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
3871 /* TAB in a composition means display glyphs with padding
3872 space on the left or right. */
3873 if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
3875 int xx = x + s->cmp->offsets[j * 2];
3876 int yy = y - s->cmp->offsets[j * 2 + 1];
3878 font->driver->draw (s, j, j + 1, xx, yy, false);
3879 if (s->face->overstrike)
3880 font->driver->draw (s, j, j + 1, xx + 1, yy, false);
3885 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
3890 for (i = j = s->cmp_from; i < s->cmp_to; i++)
3892 glyph = LGSTRING_GLYPH (gstring, i);
3893 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
3894 width += LGLYPH_WIDTH (glyph);
3897 int xoff, yoff, wadjust;
3901 font->driver->draw (s, j, i, x, y, false);
3902 if (s->face->overstrike)
3903 font->driver->draw (s, j, i, x + 1, y, false);
3906 xoff = LGLYPH_XOFF (glyph);
3907 yoff = LGLYPH_YOFF (glyph);
3908 wadjust = LGLYPH_WADJUST (glyph);
3909 font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
3910 if (s->face->overstrike)
3911 font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
3920 font->driver->draw (s, j, i, x, y, false);
3921 if (s->face->overstrike)
3922 font->driver->draw (s, j, i, x + 1, y, false);
3928 ns_draw_glyph_string (struct glyph_string *s)
3929 /* --------------------------------------------------------------------------
3930 External (RIF): Main draw-text call.
3931 -------------------------------------------------------------------------- */
3933 /* TODO (optimize): focus for box and contents draw */
3936 char box_drawn_p = 0;
3937 struct font *font = s->face->font;
3938 if (! font) font = FRAME_FONT (s->f);
3940 NSTRACE_WHEN (NSTRACE_GROUP_GLYPHS, "ns_draw_glyph_string");
3942 if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3945 struct glyph_string *next;
3947 for (width = 0, next = s->next;
3948 next && width < s->right_overhang;
3949 width += next->width, next = next->next)
3950 if (next->first_glyph->type != IMAGE_GLYPH)
3952 if (next->first_glyph->type != STRETCH_GLYPH)
3954 n = ns_get_glyph_string_clip_rect (s->next, r);
3955 ns_focus (s->f, r, n);
3956 ns_maybe_dumpglyphs_background (s->next, 1);
3961 ns_dumpglyphs_stretch (s->next);
3963 next->num_clips = 0;
3967 if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3968 && (s->first_glyph->type == CHAR_GLYPH
3969 || s->first_glyph->type == COMPOSITE_GLYPH))
3971 n = ns_get_glyph_string_clip_rect (s, r);
3972 ns_focus (s->f, r, n);
3973 ns_maybe_dumpglyphs_background (s, 1);
3974 ns_dumpglyphs_box_or_relief (s);
3979 switch (s->first_glyph->type)
3983 n = ns_get_glyph_string_clip_rect (s, r);
3984 ns_focus (s->f, r, n);
3985 ns_dumpglyphs_image (s, r[0]);
3990 ns_dumpglyphs_stretch (s);
3994 case COMPOSITE_GLYPH:
3995 n = ns_get_glyph_string_clip_rect (s, r);
3996 ns_focus (s->f, r, n);
3998 if (s->for_overlaps || (s->cmp_from > 0
3999 && ! s->first_glyph->u.cmp.automatic))
4000 s->background_filled_p = 1;
4002 ns_maybe_dumpglyphs_background
4003 (s, s->first_glyph->type == COMPOSITE_GLYPH);
4005 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
4007 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
4008 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
4009 NS_FACE_FOREGROUND (s->face) = tmp;
4013 BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
4016 ns_draw_composite_glyph_string_foreground (s);
4018 ns_draw_glyph_string_foreground (s);
4022 NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
4023 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
4025 : FRAME_FOREGROUND_COLOR (s->f));
4028 /* Draw underline, overline, strike-through. */
4029 ns_draw_text_decoration (s, s->face, col, s->width, s->x);
4032 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
4034 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
4035 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
4036 NS_FACE_FOREGROUND (s->face) = tmp;
4042 case GLYPHLESS_GLYPH:
4043 n = ns_get_glyph_string_clip_rect (s, r);
4044 ns_focus (s->f, r, n);
4046 if (s->for_overlaps || (s->cmp_from > 0
4047 && ! s->first_glyph->u.cmp.automatic))
4048 s->background_filled_p = 1;
4050 ns_maybe_dumpglyphs_background
4051 (s, s->first_glyph->type == COMPOSITE_GLYPH);
4053 /* Not yet implemented. */
4062 /* Draw box if not done already. */
4063 if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
4065 n = ns_get_glyph_string_clip_rect (s, r);
4066 ns_focus (s->f, r, n);
4067 ns_dumpglyphs_box_or_relief (s);
4076 /* ==========================================================================
4080 ========================================================================== */
4084 ns_send_appdefined (int value)
4085 /* --------------------------------------------------------------------------
4086 Internal: post an appdefined event which EmacsApp-sendEvent will
4087 recognize and take as a command to halt the event loop.
4088 -------------------------------------------------------------------------- */
4090 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_send_appdefined(%d)", value);
4092 // GNUstep needs postEvent to happen on the main thread.
4093 // Cocoa needs nextEventMatchingMask to happen on the main thread too.
4094 if (! [[NSThread currentThread] isMainThread])
4096 EmacsApp *app = (EmacsApp *)NSApp;
4097 app->nextappdefined = value;
4098 [app performSelectorOnMainThread:@selector (sendFromMainThread:)
4104 /* Only post this event if we haven't already posted one. This will end
4105 the [NXApp run] main loop after having processed all events queued at
4108 #ifdef NS_IMPL_COCOA
4109 if (! send_appdefined)
4111 /* OS X 10.10.1 swallows the AppDefined event we are sending ourselves
4112 in certain situations (rapid incoming events).
4113 So check if we have one, if not add one. */
4114 NSEvent *appev = [NSApp nextEventMatchingMask:NSEventMaskApplicationDefined
4115 untilDate:[NSDate distantPast]
4116 inMode:NSDefaultRunLoopMode
4118 if (! appev) send_appdefined = YES;
4122 if (send_appdefined)
4126 /* We only need one NX_APPDEFINED event to stop NXApp from running. */
4127 send_appdefined = NO;
4129 /* Don't need wakeup timer any more */
4132 [timed_entry invalidate];
4133 [timed_entry release];
4137 nxev = [NSEvent otherEventWithType: NSEventTypeApplicationDefined
4138 location: NSMakePoint (0, 0)
4141 windowNumber: [[NSApp mainWindow] windowNumber]
4142 context: [NSApp context]
4147 /* Post an application defined event on the event queue. When this is
4148 received the [NXApp run] will return, thus having processed all
4149 events which are currently queued. */
4150 [NSApp postEvent: nxev atStart: NO];
4154 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
4158 Lisp_Object frame, tail;
4160 if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
4163 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
4165 FOR_EACH_FRAME (tail, frame)
4167 struct frame *f = XFRAME (frame);
4170 EmacsView *view = FRAME_NS_VIEW (f);
4171 [view updateCollectionBehavior];
4177 /* GNUstep does not have cancelTracking. */
4178 #ifdef NS_IMPL_COCOA
4179 /* Check if menu open should be canceled or continued as normal. */
4181 ns_check_menu_open (NSMenu *menu)
4183 /* Click in menu bar? */
4184 NSArray *a = [[NSApp mainMenu] itemArray];
4188 if (menu == nil) // Menu tracking ended.
4190 if (menu_will_open_state == MENU_OPENING)
4191 menu_will_open_state = MENU_NONE;
4195 for (i = 0; ! found && i < [a count]; i++)
4196 found = menu == [[a objectAtIndex:i] submenu];
4199 if (menu_will_open_state == MENU_NONE && emacs_event)
4201 NSEvent *theEvent = [NSApp currentEvent];
4202 struct frame *emacsframe = SELECTED_FRAME ();
4204 [menu cancelTracking];
4205 menu_will_open_state = MENU_PENDING;
4206 emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
4207 EV_TRAILER (theEvent);
4209 CGEventRef ourEvent = CGEventCreate (NULL);
4210 menu_mouse_point = CGEventGetLocation (ourEvent);
4211 CFRelease (ourEvent);
4213 else if (menu_will_open_state == MENU_OPENING)
4215 menu_will_open_state = MENU_NONE;
4220 /* Redo saved menu click if state is MENU_PENDING. */
4222 ns_check_pending_open_menu ()
4224 if (menu_will_open_state == MENU_PENDING)
4226 CGEventSourceRef source
4227 = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
4229 CGEventRef event = CGEventCreateMouseEvent (source,
4230 kCGEventLeftMouseDown,
4232 kCGMouseButtonLeft);
4233 CGEventSetType (event, kCGEventLeftMouseDown);
4234 CGEventPost (kCGHIDEventTap, event);
4238 menu_will_open_state = MENU_OPENING;
4241 #endif /* NS_IMPL_COCOA */
4244 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
4245 /* --------------------------------------------------------------------------
4246 External (hook): Post an event to ourself and keep reading events until
4247 we read it back again. In effect process all events which were waiting.
4248 From 21+ we have to manage the event buffer ourselves.
4249 -------------------------------------------------------------------------- */
4251 struct input_event ev;
4254 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_read_socket");
4256 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
4260 if ([NSApp modalWindow] != nil)
4263 if (hold_event_q.nr > 0)
4266 for (i = 0; i < hold_event_q.nr; ++i)
4267 kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
4268 hold_event_q.nr = 0;
4272 if ([NSThread isMainThread])
4275 n_emacs_events_pending = 0;
4276 ns_init_events (&ev);
4277 q_event_ptr = hold_quit;
4279 /* we manage autorelease pools by allocate/reallocate each time around
4280 the loop; strict nesting is occasionally violated but seems not to
4281 matter.. earlier methods using full nesting caused major memory leaks */
4282 [outerpool release];
4283 outerpool = [[NSAutoreleasePool alloc] init];
4285 /* If have pending open-file requests, attend to the next one of those. */
4286 if (ns_pending_files && [ns_pending_files count] != 0
4287 && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
4289 [ns_pending_files removeObjectAtIndex: 0];
4291 /* Deal with pending service requests. */
4292 else if (ns_pending_service_names && [ns_pending_service_names count] != 0
4294 NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
4295 withArg: [ns_pending_service_args objectAtIndex: 0]])
4297 [ns_pending_service_names removeObjectAtIndex: 0];
4298 [ns_pending_service_args removeObjectAtIndex: 0];
4302 /* Run and wait for events. We must always send one NX_APPDEFINED event
4303 to ourself, otherwise [NXApp run] will never exit. */
4304 send_appdefined = YES;
4305 ns_send_appdefined (-1);
4310 nevents = n_emacs_events_pending;
4311 n_emacs_events_pending = 0;
4312 ns_finish_events ();
4324 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
4325 fd_set *exceptfds, struct timespec *timeout,
4327 /* --------------------------------------------------------------------------
4328 Replacement for select, checking for events
4329 -------------------------------------------------------------------------- */
4333 struct input_event event;
4336 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_select");
4338 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
4342 if (hold_event_q.nr > 0)
4344 /* We already have events pending. */
4350 for (k = 0; k < nfds+1; k++)
4352 if (readfds && FD_ISSET(k, readfds)) ++nr;
4353 if (writefds && FD_ISSET(k, writefds)) ++nr;
4357 || ![NSThread isMainThread]
4358 || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
4359 return thread_select(pselect, nfds, readfds, writefds,
4360 exceptfds, timeout, sigmask);
4363 struct timespec t = {0, 0};
4364 thread_select(pselect, 0, NULL, NULL, NULL, &t, sigmask);
4367 [outerpool release];
4368 outerpool = [[NSAutoreleasePool alloc] init];
4371 send_appdefined = YES;
4374 pthread_mutex_lock (&select_mutex);
4379 select_readfds = *readfds;
4380 select_valid += SELECT_HAVE_READ;
4384 select_writefds = *writefds;
4385 select_valid += SELECT_HAVE_WRITE;
4390 select_timeout = *timeout;
4391 select_valid += SELECT_HAVE_TMO;
4394 pthread_mutex_unlock (&select_mutex);
4396 /* Inform fd_handler that select should be called */
4398 emacs_write_sig (selfds[1], &c, 1);
4400 else if (nr == 0 && timeout)
4402 /* No file descriptor, just a timeout, no need to wake fd_handler */
4403 double time = timespectod (*timeout);
4404 timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
4407 @selector (timeout_handler:)
4412 else /* No timeout and no file descriptors, can this happen? */
4414 /* Send appdefined so we exit from the loop */
4415 ns_send_appdefined (-1);
4419 ns_init_events (&event);
4423 ns_finish_events ();
4424 if (nr > 0 && readfds)
4427 emacs_write_sig (selfds[1], &c, 1);
4431 t = last_appdefined_event_data;
4433 if (t != NO_APPDEFINED_DATA)
4435 last_appdefined_event_data = NO_APPDEFINED_DATA;
4439 /* The NX_APPDEFINED event we received was a timeout. */
4444 /* The NX_APPDEFINED event we received was the result of
4445 at least one real input event arriving. */
4451 /* Received back from select () in fd_handler; copy the results */
4452 pthread_mutex_lock (&select_mutex);
4453 if (readfds) *readfds = select_readfds;
4454 if (writefds) *writefds = select_writefds;
4455 pthread_mutex_unlock (&select_mutex);
4470 ns_run_loop_break ()
4471 /* Break out of the NS run loop in ns_select or ns_read_socket. */
4473 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_run_loop_break");
4475 /* If we don't have a GUI, don't send the event. */
4477 ns_send_appdefined(-1);
4482 /* ==========================================================================
4486 ========================================================================== */
4490 ns_set_vertical_scroll_bar (struct window *window,
4491 int portion, int whole, int position)
4492 /* --------------------------------------------------------------------------
4493 External (hook): Update or add scrollbar
4494 -------------------------------------------------------------------------- */
4498 struct frame *f = XFRAME (WINDOW_FRAME (window));
4499 EmacsView *view = FRAME_NS_VIEW (f);
4501 int window_y, window_height;
4502 int top, left, height, width;
4503 BOOL update_p = YES;
4505 /* optimization; display engine sends WAY too many of these.. */
4506 if (!NILP (window->vertical_scroll_bar))
4508 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4509 if ([bar checkSamePosition: position portion: portion whole: whole])
4511 if (view->scrollbarsNeedingUpdate == 0)
4513 if (!windows_or_buffers_changed)
4517 view->scrollbarsNeedingUpdate--;
4522 NSTRACE ("ns_set_vertical_scroll_bar");
4524 /* Get dimensions. */
4525 window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
4527 height = window_height;
4528 width = NS_SCROLL_BAR_WIDTH (f);
4529 left = WINDOW_SCROLL_BAR_AREA_X (window);
4531 r = NSMakeRect (left, top, width, height);
4532 /* the parent view is flipped, so we need to flip y value */
4534 r.origin.y = (v.size.height - r.size.height - r.origin.y);
4536 XSETWINDOW (win, window);
4539 /* we want at least 5 lines to display a scrollbar */
4540 if (WINDOW_TOTAL_LINES (window) < 5)
4542 if (!NILP (window->vertical_scroll_bar))
4544 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4545 [bar removeFromSuperview];
4546 wset_vertical_scroll_bar (window, Qnil);
4549 ns_clear_frame_area (f, left, top, width, height);
4554 if (NILP (window->vertical_scroll_bar))
4556 if (width > 0 && height > 0)
4557 ns_clear_frame_area (f, left, top, width, height);
4559 bar = [[EmacsScroller alloc] initFrame: r window: win];
4560 wset_vertical_scroll_bar (window, make_save_ptr (bar));
4566 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4567 oldRect = [bar frame];
4568 r.size.width = oldRect.size.width;
4569 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4571 if (oldRect.origin.x != r.origin.x)
4572 ns_clear_frame_area (f, left, top, width, height);
4578 [bar setPosition: position portion: portion whole: whole];
4584 ns_set_horizontal_scroll_bar (struct window *window,
4585 int portion, int whole, int position)
4586 /* --------------------------------------------------------------------------
4587 External (hook): Update or add scrollbar
4588 -------------------------------------------------------------------------- */
4592 struct frame *f = XFRAME (WINDOW_FRAME (window));
4593 EmacsView *view = FRAME_NS_VIEW (f);
4595 int top, height, left, width;
4596 int window_x, window_width;
4597 BOOL update_p = YES;
4599 /* optimization; display engine sends WAY too many of these.. */
4600 if (!NILP (window->horizontal_scroll_bar))
4602 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4603 if ([bar checkSamePosition: position portion: portion whole: whole])
4605 if (view->scrollbarsNeedingUpdate == 0)
4607 if (!windows_or_buffers_changed)
4611 view->scrollbarsNeedingUpdate--;
4616 NSTRACE ("ns_set_horizontal_scroll_bar");
4618 /* Get dimensions. */
4619 window_box (window, ANY_AREA, &window_x, 0, &window_width, 0);
4621 width = window_width;
4622 height = NS_SCROLL_BAR_HEIGHT (f);
4623 top = WINDOW_SCROLL_BAR_AREA_Y (window);
4625 r = NSMakeRect (left, top, width, height);
4626 /* the parent view is flipped, so we need to flip y value */
4628 r.origin.y = (v.size.height - r.size.height - r.origin.y);
4630 XSETWINDOW (win, window);
4633 if (NILP (window->horizontal_scroll_bar))
4635 if (width > 0 && height > 0)
4636 ns_clear_frame_area (f, left, top, width, height);
4638 bar = [[EmacsScroller alloc] initFrame: r window: win];
4639 wset_horizontal_scroll_bar (window, make_save_ptr (bar));
4645 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4646 oldRect = [bar frame];
4647 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4649 if (oldRect.origin.y != r.origin.y)
4650 ns_clear_frame_area (f, left, top, width, height);
4656 /* If there are both horizontal and vertical scroll-bars they leave
4657 a square that belongs to neither. We need to clear it otherwise
4658 it fills with junk. */
4659 if (!NILP (window->vertical_scroll_bar))
4660 ns_clear_frame_area (f, WINDOW_SCROLL_BAR_AREA_X (window), top,
4661 NS_SCROLL_BAR_HEIGHT (f), height);
4664 [bar setPosition: position portion: portion whole: whole];
4670 ns_condemn_scroll_bars (struct frame *f)
4671 /* --------------------------------------------------------------------------
4672 External (hook): arrange for all frame's scrollbars to be removed
4673 at next call to judge_scroll_bars, except for those redeemed.
4674 -------------------------------------------------------------------------- */
4678 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
4680 NSTRACE ("ns_condemn_scroll_bars");
4682 for (i =[subviews count]-1; i >= 0; i--)
4684 view = [subviews objectAtIndex: i];
4685 if ([view isKindOfClass: [EmacsScroller class]])
4692 ns_redeem_scroll_bar (struct window *window)
4693 /* --------------------------------------------------------------------------
4694 External (hook): arrange to spare this window's scrollbar
4695 at next call to judge_scroll_bars.
4696 -------------------------------------------------------------------------- */
4699 NSTRACE ("ns_redeem_scroll_bar");
4700 if (!NILP (window->vertical_scroll_bar)
4701 && WINDOW_HAS_VERTICAL_SCROLL_BAR (window))
4703 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4707 if (!NILP (window->horizontal_scroll_bar)
4708 && WINDOW_HAS_HORIZONTAL_SCROLL_BAR (window))
4710 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4717 ns_judge_scroll_bars (struct frame *f)
4718 /* --------------------------------------------------------------------------
4719 External (hook): destroy all scrollbars on frame that weren't
4720 redeemed after call to condemn_scroll_bars.
4721 -------------------------------------------------------------------------- */
4725 EmacsView *eview = FRAME_NS_VIEW (f);
4726 NSArray *subviews = [[eview superview] subviews];
4729 NSTRACE ("ns_judge_scroll_bars");
4730 for (i = [subviews count]-1; i >= 0; --i)
4732 view = [subviews objectAtIndex: i];
4733 if (![view isKindOfClass: [EmacsScroller class]]) continue;
4739 [eview updateFrameSize: NO];
4742 /* ==========================================================================
4746 ========================================================================== */
4749 x_display_pixel_height (struct ns_display_info *dpyinfo)
4751 NSArray *screens = [NSScreen screens];
4752 NSEnumerator *enumerator = [screens objectEnumerator];
4757 while ((screen = [enumerator nextObject]) != nil)
4758 frame = NSUnionRect (frame, [screen frame]);
4760 return NSHeight (frame);
4764 x_display_pixel_width (struct ns_display_info *dpyinfo)
4766 NSArray *screens = [NSScreen screens];
4767 NSEnumerator *enumerator = [screens objectEnumerator];
4772 while ((screen = [enumerator nextObject]) != nil)
4773 frame = NSUnionRect (frame, [screen frame]);
4775 return NSWidth (frame);
4779 static Lisp_Object ns_string_to_lispmod (const char *s)
4780 /* --------------------------------------------------------------------------
4781 Convert modifier name to lisp symbol
4782 -------------------------------------------------------------------------- */
4784 if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
4786 else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
4788 else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
4790 else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
4792 else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
4794 else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
4802 ns_default (const char *parameter, Lisp_Object *result,
4803 Lisp_Object yesval, Lisp_Object noval,
4804 BOOL is_float, BOOL is_modstring)
4805 /* --------------------------------------------------------------------------
4806 Check a parameter value in user's preferences
4807 -------------------------------------------------------------------------- */
4809 const char *value = ns_get_defaults_value (parameter);
4815 if (c_strcasecmp (value, "YES") == 0)
4817 else if (c_strcasecmp (value, "NO") == 0)
4819 else if (is_float && (f = strtod (value, &pos), pos != value))
4820 *result = make_float (f);
4821 else if (is_modstring && value)
4822 *result = ns_string_to_lispmod (value);
4823 else fprintf (stderr,
4824 "Bad value for default \"%s\": \"%s\"\n", parameter, value);
4830 ns_initialize_display_info (struct ns_display_info *dpyinfo)
4831 /* --------------------------------------------------------------------------
4832 Initialize global info and storage for display.
4833 -------------------------------------------------------------------------- */
4835 NSScreen *screen = [NSScreen mainScreen];
4836 NSWindowDepth depth = [screen depth];
4838 dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
4839 dpyinfo->resy = 72.27;
4840 dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4841 NSColorSpaceFromDepth (depth)]
4842 && ![NSCalibratedWhiteColorSpace isEqualToString:
4843 NSColorSpaceFromDepth (depth)];
4844 dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4845 dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
4846 dpyinfo->color_table->colors = NULL;
4847 dpyinfo->root_window = 42; /* a placeholder.. */
4848 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4849 dpyinfo->n_fonts = 0;
4850 dpyinfo->smallest_font_height = 1;
4851 dpyinfo->smallest_char_width = 1;
4853 reset_mouse_highlight (&dpyinfo->mouse_highlight);
4857 /* This and next define (many of the) public functions in this file. */
4858 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4859 with using despite presence in the "system dependent" redisplay
4860 interface. In addition, many of the ns_ methods have code that is
4861 shared with all terms, indicating need for further refactoring. */
4862 extern frame_parm_handler ns_frame_parm_handlers[];
4863 static struct redisplay_interface ns_redisplay_interface =
4865 ns_frame_parm_handlers,
4869 x_clear_end_of_line,
4871 ns_after_update_window_line,
4872 ns_update_window_begin,
4873 ns_update_window_end,
4874 0, /* flush_display */
4875 x_clear_window_mouse_face,
4876 x_get_glyph_overhangs,
4877 x_fix_overlapping_area,
4878 ns_draw_fringe_bitmap,
4879 0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4880 0, /* destroy_fringe_bitmap */
4881 ns_compute_glyph_string_overhangs,
4882 ns_draw_glyph_string,
4883 ns_define_frame_cursor,
4884 ns_clear_frame_area,
4885 ns_draw_window_cursor,
4886 ns_draw_vertical_window_border,
4887 ns_draw_window_divider,
4888 ns_shift_glyphs_for_insert,
4895 ns_delete_display (struct ns_display_info *dpyinfo)
4901 /* This function is called when the last frame on a display is deleted. */
4903 ns_delete_terminal (struct terminal *terminal)
4905 struct ns_display_info *dpyinfo = terminal->display_info.ns;
4907 NSTRACE ("ns_delete_terminal");
4909 /* Protect against recursive calls. delete_frame in
4910 delete_terminal calls us back when it deletes our last frame. */
4911 if (!terminal->name)
4916 x_destroy_all_bitmaps (dpyinfo);
4917 ns_delete_display (dpyinfo);
4922 static struct terminal *
4923 ns_create_terminal (struct ns_display_info *dpyinfo)
4924 /* --------------------------------------------------------------------------
4925 Set up use of NS before we make the first connection.
4926 -------------------------------------------------------------------------- */
4928 struct terminal *terminal;
4930 NSTRACE ("ns_create_terminal");
4932 terminal = create_terminal (output_ns, &ns_redisplay_interface);
4934 terminal->display_info.ns = dpyinfo;
4935 dpyinfo->terminal = terminal;
4937 terminal->clear_frame_hook = ns_clear_frame;
4938 terminal->ring_bell_hook = ns_ring_bell;
4939 terminal->update_begin_hook = ns_update_begin;
4940 terminal->update_end_hook = ns_update_end;
4941 terminal->read_socket_hook = ns_read_socket;
4942 terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4943 terminal->mouse_position_hook = ns_mouse_position;
4944 terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4945 terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4946 terminal->fullscreen_hook = ns_fullscreen_hook;
4947 terminal->menu_show_hook = ns_menu_show;
4948 terminal->popup_dialog_hook = ns_popup_dialog;
4949 terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4950 terminal->set_horizontal_scroll_bar_hook = ns_set_horizontal_scroll_bar;
4951 terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4952 terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4953 terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4954 terminal->delete_frame_hook = x_destroy_window;
4955 terminal->delete_terminal_hook = ns_delete_terminal;
4956 /* Other hooks are NULL by default. */
4962 struct ns_display_info *
4963 ns_term_init (Lisp_Object display_name)
4964 /* --------------------------------------------------------------------------
4965 Start the Application and get things rolling.
4966 -------------------------------------------------------------------------- */
4968 struct terminal *terminal;
4969 struct ns_display_info *dpyinfo;
4970 static int ns_initialized = 0;
4973 if (ns_initialized) return x_display_list;
4978 NSTRACE ("ns_term_init");
4980 [outerpool release];
4981 outerpool = [[NSAutoreleasePool alloc] init];
4983 /* count object allocs (About, click icon); on macOS use ObjectAlloc tool */
4984 /*GSDebugAllocationActive (YES); */
4988 Fset_input_interrupt_mode (Qnil);
4990 if (selfds[0] == -1)
4992 if (emacs_pipe (selfds) != 0)
4994 fprintf (stderr, "Failed to create pipe: %s\n",
4995 emacs_strerror (errno));
4999 fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
5000 FD_ZERO (&select_readfds);
5001 FD_ZERO (&select_writefds);
5002 pthread_mutex_init (&select_mutex, NULL);
5005 ns_pending_files = [[NSMutableArray alloc] init];
5006 ns_pending_service_names = [[NSMutableArray alloc] init];
5007 ns_pending_service_args = [[NSMutableArray alloc] init];
5009 /* Start app and create the main menu, window, view.
5010 Needs to be here because ns_initialize_display_info () uses AppKit classes.
5011 The view will then ask the NSApp to stop and return to Emacs. */
5012 [EmacsApp sharedApplication];
5015 [NSApp setDelegate: NSApp];
5017 /* Start the select thread. */
5018 [NSThread detachNewThreadSelector:@selector (fd_handler:)
5022 /* debugging: log all notifications */
5023 /* [[NSNotificationCenter defaultCenter] addObserver: NSApp
5024 selector: @selector (logNotification:)
5025 name: nil object: nil]; */
5027 dpyinfo = xzalloc (sizeof *dpyinfo);
5029 ns_initialize_display_info (dpyinfo);
5030 terminal = ns_create_terminal (dpyinfo);
5032 terminal->kboard = allocate_kboard (Qns);
5033 /* Don't let the initial kboard remain current longer than necessary.
5034 That would cause problems if a file loaded on startup tries to
5035 prompt in the mini-buffer. */
5036 if (current_kboard == initial_kboard)
5037 current_kboard = terminal->kboard;
5038 terminal->kboard->reference_count++;
5040 dpyinfo->next = x_display_list;
5041 x_display_list = dpyinfo;
5043 dpyinfo->name_list_element = Fcons (display_name, Qnil);
5045 terminal->name = xlispstrdup (display_name);
5049 if (!inhibit_x_resources)
5051 ns_default ("GSFontAntiAlias", &ns_antialias_text,
5054 /* this is a standard variable */
5055 ns_default ("AppleAntiAliasingThreshold", &tmp,
5056 make_float (10.0), make_float (6.0), YES, NO);
5057 ns_antialias_threshold = NILP (tmp) ? 10.0 : extract_float (tmp);
5060 NSTRACE_MSG ("Colors");
5063 NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
5067 Lisp_Object color_file, color_map, color;
5071 color_file = Fexpand_file_name (build_string ("rgb.txt"),
5072 Fsymbol_value (intern ("data-directory")));
5074 color_map = Fx_load_color_file (color_file);
5075 if (NILP (color_map))
5076 fatal ("Could not read %s.\n", SDATA (color_file));
5078 cl = [[NSColorList alloc] initWithName: @"Emacs"];
5079 for ( ; CONSP (color_map); color_map = XCDR (color_map))
5081 color = XCAR (color_map);
5082 name = SSDATA (XCAR (color));
5083 c = XINT (XCDR (color));
5085 [NSColor colorForEmacsRed: RED_FROM_ULONG (c) / 255.0
5086 green: GREEN_FROM_ULONG (c) / 255.0
5087 blue: BLUE_FROM_ULONG (c) / 255.0
5089 forKey: [NSString stringWithUTF8String: name]];
5091 [cl writeToFile: nil];
5095 NSTRACE_MSG ("Versions");
5098 #ifdef NS_IMPL_GNUSTEP
5099 Vwindow_system_version = build_string (gnustep_base_version);
5101 /*PSnextrelease (128, c); */
5102 char c[DBL_BUFSIZE_BOUND];
5103 int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
5104 Vwindow_system_version = make_unibyte_string (c, len);
5108 delete_keyboard_wait_descriptor (0);
5110 ns_app_name = [[NSProcessInfo processInfo] processName];
5112 /* Set up macOS app menu */
5114 NSTRACE_MSG ("Menu init");
5116 #ifdef NS_IMPL_COCOA
5120 /* set up the application menu */
5121 svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
5122 [svcsMenu setAutoenablesItems: NO];
5123 appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
5124 [appMenu setAutoenablesItems: NO];
5125 mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
5126 dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
5128 [appMenu insertItemWithTitle: @"About Emacs"
5129 action: @selector (orderFrontStandardAboutPanel:)
5132 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
5133 [appMenu insertItemWithTitle: @"Preferences..."
5134 action: @selector (showPreferencesWindow:)
5137 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
5138 item = [appMenu insertItemWithTitle: @"Services"
5139 action: @selector (menuDown:)
5142 [appMenu setSubmenu: svcsMenu forItem: item];
5143 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
5144 [appMenu insertItemWithTitle: @"Hide Emacs"
5145 action: @selector (hide:)
5148 item = [appMenu insertItemWithTitle: @"Hide Others"
5149 action: @selector (hideOtherApplications:)
5152 [item setKeyEquivalentModifierMask: NSEventModifierFlagCommand | NSEventModifierFlagOption];
5153 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
5154 [appMenu insertItemWithTitle: @"Quit Emacs"
5155 action: @selector (terminate:)
5159 item = [mainMenu insertItemWithTitle: ns_app_name
5160 action: @selector (menuDown:)
5163 [mainMenu setSubmenu: appMenu forItem: item];
5164 [dockMenu insertItemWithTitle: @"New Frame"
5165 action: @selector (newFrame:)
5169 [NSApp setMainMenu: mainMenu];
5170 [NSApp setAppleMenu: appMenu];
5171 [NSApp setServicesMenu: svcsMenu];
5172 /* Needed at least on Cocoa, to get dock menu to show windows */
5173 [NSApp setWindowsMenu: [[NSMenu alloc] init]];
5175 [[NSNotificationCenter defaultCenter]
5176 addObserver: mainMenu
5177 selector: @selector (trackingNotification:)
5178 name: NSMenuDidBeginTrackingNotification object: mainMenu];
5179 [[NSNotificationCenter defaultCenter]
5180 addObserver: mainMenu
5181 selector: @selector (trackingNotification:)
5182 name: NSMenuDidEndTrackingNotification object: mainMenu];
5184 #endif /* macOS menu setup */
5186 /* Register our external input/output types, used for determining
5187 applicable services and also drag/drop eligibility. */
5189 NSTRACE_MSG ("Input/output types");
5191 ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
5192 ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
5194 ns_drag_types = [[NSArray arrayWithObjects:
5196 NSTabularTextPboardType,
5197 NSFilenamesPboardType,
5198 NSURLPboardType, nil] retain];
5200 /* If fullscreen is in init/default-frame-alist, focus isn't set
5201 right for fullscreen windows, so set this. */
5202 [NSApp activateIgnoringOtherApps:YES];
5204 NSTRACE_MSG ("Call NSApp run");
5207 ns_do_open_file = YES;
5209 #ifdef NS_IMPL_GNUSTEP
5210 /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
5211 We must re-catch it so subprocess works. */
5212 catch_child_signal ();
5215 NSTRACE_MSG ("ns_term_init done");
5224 ns_term_shutdown (int sig)
5226 [[NSUserDefaults standardUserDefaults] synchronize];
5228 /* code not reached in emacs.c after this is called by shut_down_emacs: */
5229 if (STRINGP (Vauto_save_list_file_name))
5230 unlink (SSDATA (Vauto_save_list_file_name));
5232 if (sig == 0 || sig == SIGTERM)
5234 [NSApp terminate: NSApp];
5236 else // force a stack trace to happen
5243 /* ==========================================================================
5245 EmacsApp implementation
5247 ========================================================================== */
5250 @implementation EmacsApp
5254 NSTRACE ("[EmacsApp init]");
5256 if ((self = [super init]))
5258 #ifdef NS_IMPL_COCOA
5259 self->isFirst = YES;
5261 #ifdef NS_IMPL_GNUSTEP
5262 self->applicationDidFinishLaunchingCalled = NO;
5269 #ifdef NS_IMPL_COCOA
5272 NSTRACE ("[EmacsApp run]");
5274 #ifndef NSAppKitVersionNumber10_9
5275 #define NSAppKitVersionNumber10_9 1265
5278 if ((int)NSAppKitVersionNumber != NSAppKitVersionNumber10_9)
5284 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5286 if (isFirst) [self finishLaunching];
5289 shouldKeepRunning = YES;
5293 pool = [[NSAutoreleasePool alloc] init];
5296 [self nextEventMatchingMask:NSEventMaskAny
5297 untilDate:[NSDate distantFuture]
5298 inMode:NSDefaultRunLoopMode
5301 [self sendEvent:event];
5302 [self updateWindows];
5303 } while (shouldKeepRunning);
5308 - (void)stop: (id)sender
5310 NSTRACE ("[EmacsApp stop:]");
5312 shouldKeepRunning = NO;
5313 // Stop possible dialog also. Noop if no dialog present.
5314 // The file dialog still leaks 7k - 10k on 10.9 though.
5315 [super stop:sender];
5317 #endif /* NS_IMPL_COCOA */
5319 - (void)logNotification: (NSNotification *)notification
5321 NSTRACE ("[EmacsApp logNotification:]");
5323 const char *name = [[notification name] UTF8String];
5324 if (!strstr (name, "Update") && !strstr (name, "NSMenu")
5325 && !strstr (name, "WindowNumber"))
5326 NSLog (@"notification: '%@'", [notification name]);
5330 - (void)sendEvent: (NSEvent *)theEvent
5331 /* --------------------------------------------------------------------------
5332 Called when NSApp is running for each event received. Used to stop
5333 the loop when we choose, since there's no way to just run one iteration.
5334 -------------------------------------------------------------------------- */
5336 int type = [theEvent type];
5337 NSWindow *window = [theEvent window];
5339 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsApp sendEvent:]");
5340 NSTRACE_MSG ("Type: %d", type);
5342 #ifdef NS_IMPL_GNUSTEP
5343 // Keyboard events aren't propagated to file dialogs for some reason.
5344 if ([NSApp modalWindow] != nil &&
5345 (type == NSEventTypeKeyDown || type == NSEventTypeKeyUp || type == NSEventTypeFlagsChanged))
5347 [[NSApp modalWindow] sendEvent: theEvent];
5352 if (represented_filename != nil && represented_frame)
5354 NSString *fstr = represented_filename;
5355 NSView *view = FRAME_NS_VIEW (represented_frame);
5356 #ifdef NS_IMPL_COCOA
5357 /* work around a bug observed on 10.3 and later where
5358 setTitleWithRepresentedFilename does not clear out previous state
5359 if given filename does not exist */
5360 if (! [[NSFileManager defaultManager] fileExistsAtPath: fstr])
5361 [[view window] setRepresentedFilename: @""];
5363 [[view window] setRepresentedFilename: fstr];
5364 [represented_filename release];
5365 represented_filename = nil;
5366 represented_frame = NULL;
5369 if (type == NSEventTypeApplicationDefined)
5371 switch ([theEvent data2])
5373 #ifdef NS_IMPL_COCOA
5374 case NSAPP_DATA2_RUNASSCRIPT:
5379 case NSAPP_DATA2_RUNFILEDIALOG:
5380 ns_run_file_dialog ();
5386 if (type == NSEventTypeCursorUpdate && window == nil)
5388 fprintf (stderr, "Dropping external cursor update event.\n");
5392 if (type == NSEventTypeApplicationDefined)
5394 /* Events posted by ns_send_appdefined interrupt the run loop here.
5395 But, if a modal window is up, an appdefined can still come through,
5396 (e.g., from a makeKeyWindow event) but stopping self also stops the
5397 modal loop. Just defer it until later. */
5398 if ([NSApp modalWindow] == nil)
5400 last_appdefined_event_data = [theEvent data1];
5405 send_appdefined = YES;
5410 #ifdef NS_IMPL_COCOA
5411 /* If no dialog and none of our frames have focus and it is a move, skip it.
5412 It is a mouse move in an auxiliary menu, i.e. on the top right on macOS,
5413 such as Wifi, sound, date or similar.
5414 This prevents "spooky" highlighting in the frame under the menu. */
5415 if (type == NSEventTypeMouseMoved && [NSApp modalWindow] == nil)
5417 struct ns_display_info *di;
5418 BOOL has_focus = NO;
5419 for (di = x_display_list; ! has_focus && di; di = di->next)
5420 has_focus = di->x_focus_frame != 0;
5426 NSTRACE_UNSILENCE();
5428 [super sendEvent: theEvent];
5432 - (void)showPreferencesWindow: (id)sender
5434 struct frame *emacsframe = SELECTED_FRAME ();
5435 NSEvent *theEvent = [NSApp currentEvent];
5439 emacs_event->kind = NS_NONKEY_EVENT;
5440 emacs_event->code = KEY_NS_SHOW_PREFS;
5441 emacs_event->modifiers = 0;
5442 EV_TRAILER (theEvent);
5446 - (void)newFrame: (id)sender
5448 NSTRACE ("[EmacsApp newFrame:]");
5450 struct frame *emacsframe = SELECTED_FRAME ();
5451 NSEvent *theEvent = [NSApp currentEvent];
5455 emacs_event->kind = NS_NONKEY_EVENT;
5456 emacs_event->code = KEY_NS_NEW_FRAME;
5457 emacs_event->modifiers = 0;
5458 EV_TRAILER (theEvent);
5462 /* Open a file (used by below, after going into queue read by ns_read_socket) */
5463 - (BOOL) openFile: (NSString *)fileName
5465 NSTRACE ("[EmacsApp openFile:]");
5467 struct frame *emacsframe = SELECTED_FRAME ();
5468 NSEvent *theEvent = [NSApp currentEvent];
5473 emacs_event->kind = NS_NONKEY_EVENT;
5474 emacs_event->code = KEY_NS_OPEN_FILE_LINE;
5475 ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
5476 ns_input_line = Qnil; /* can be start or cons start,end */
5477 emacs_event->modifiers =0;
5478 EV_TRAILER (theEvent);
5484 /* **************************************************************************
5486 EmacsApp delegate implementation
5488 ************************************************************************** */
5490 - (void)applicationDidFinishLaunching: (NSNotification *)notification
5491 /* --------------------------------------------------------------------------
5492 When application is loaded, terminate event loop in ns_term_init
5493 -------------------------------------------------------------------------- */
5495 NSTRACE ("[EmacsApp applicationDidFinishLaunching:]");
5497 #ifdef NS_IMPL_GNUSTEP
5498 ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
5500 [NSApp setServicesProvider: NSApp];
5502 [self antialiasThresholdDidChange:nil];
5503 #ifdef NS_IMPL_COCOA
5504 [[NSNotificationCenter defaultCenter]
5506 selector:@selector(antialiasThresholdDidChange:)
5507 name:NSAntialiasThresholdChangedNotification
5511 #ifdef NS_IMPL_COCOA
5512 if ([NSApp activationPolicy] == NSApplicationActivationPolicyProhibited) {
5513 /* Set the app's activation policy to regular when we run outside
5514 of a bundle. This is already done for us by Info.plist when we
5515 run inside a bundle. */
5516 [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
5517 [NSApp setApplicationIconImage:
5520 build_string("icons/hicolor/128x128/apps/emacs.png")]];
5524 ns_send_appdefined (-2);
5527 - (void)antialiasThresholdDidChange:(NSNotification *)notification
5529 #ifdef NS_IMPL_COCOA
5530 macfont_update_antialias_threshold ();
5535 /* Termination sequences:
5538 MenuBar | File | Exit:
5539 Select Quit from App menubar:
5541 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5544 Select Quit from Dock menu:
5547 Cancel -> Nothing else
5551 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5556 - (void) terminate: (id)sender
5558 NSTRACE ("[EmacsApp terminate:]");
5560 struct frame *emacsframe = SELECTED_FRAME ();
5565 emacs_event->kind = NS_NONKEY_EVENT;
5566 emacs_event->code = KEY_NS_POWER_OFF;
5567 emacs_event->arg = Qt; /* mark as non-key event */
5568 EV_TRAILER ((id)nil);
5572 runAlertPanel(NSString *title,
5573 NSString *msgFormat,
5574 NSString *defaultButton,
5575 NSString *alternateButton)
5577 #ifdef NS_IMPL_GNUSTEP
5578 return NSRunAlertPanel(title, msgFormat, defaultButton, alternateButton, nil)
5579 == NSAlertDefaultReturn;
5581 NSAlert *alert = [[NSAlert alloc] init];
5582 [alert setAlertStyle: NSAlertStyleCritical];
5583 [alert setMessageText: msgFormat];
5584 [alert addButtonWithTitle: defaultButton];
5585 [alert addButtonWithTitle: alternateButton];
5586 NSInteger ret = [alert runModal];
5588 return ret == NSAlertFirstButtonReturn;
5593 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
5595 NSTRACE ("[EmacsApp applicationShouldTerminate:]");
5599 if (NILP (ns_confirm_quit)) // || ns_shutdown_properly --> TO DO
5600 return NSTerminateNow;
5602 ret = runAlertPanel(ns_app_name,
5603 @"Exit requested. Would you like to Save Buffers and Exit, or Cancel the request?",
5604 @"Save Buffers and Exit", @"Cancel");
5606 return ret ? NSTerminateNow : NSTerminateCancel;
5610 not_in_argv (NSString *arg)
5613 const char *a = [arg UTF8String];
5614 for (k = 1; k < initial_argc; ++k)
5615 if (strcmp (a, initial_argv[k]) == 0) return 0;
5619 /* Notification from the Workspace to open a file */
5620 - (BOOL)application: sender openFile: (NSString *)file
5622 if (ns_do_open_file || not_in_argv (file))
5623 [ns_pending_files addObject: file];
5628 /* Open a file as a temporary file */
5629 - (BOOL)application: sender openTempFile: (NSString *)file
5631 if (ns_do_open_file || not_in_argv (file))
5632 [ns_pending_files addObject: file];
5637 /* Notification from the Workspace to open a file noninteractively (?) */
5638 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
5640 if (ns_do_open_file || not_in_argv (file))
5641 [ns_pending_files addObject: file];
5645 /* Notification from the Workspace to open multiple files */
5646 - (void)application: sender openFiles: (NSArray *)fileList
5648 NSEnumerator *files = [fileList objectEnumerator];
5650 /* Don't open files from the command line unconditionally,
5651 Cocoa parses the command line wrong, --option value tries to open value
5652 if --option is the last option. */
5653 while ((file = [files nextObject]) != nil)
5654 if (ns_do_open_file || not_in_argv (file))
5655 [ns_pending_files addObject: file];
5657 [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
5662 /* Handle dock menu requests. */
5663 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
5669 /* TODO: these may help w/IO switching btwn terminal and NSApp */
5670 - (void)applicationWillBecomeActive: (NSNotification *)notification
5672 NSTRACE ("[EmacsApp applicationWillBecomeActive:]");
5673 //ns_app_active=YES;
5676 - (void)applicationDidBecomeActive: (NSNotification *)notification
5678 NSTRACE ("[EmacsApp applicationDidBecomeActive:]");
5680 #ifdef NS_IMPL_GNUSTEP
5681 if (! applicationDidFinishLaunchingCalled)
5682 [self applicationDidFinishLaunching:notification];
5684 //ns_app_active=YES;
5686 ns_update_auto_hide_menu_bar ();
5687 // No constraining takes place when the application is not active.
5688 ns_constrain_all_frames ();
5690 - (void)applicationDidResignActive: (NSNotification *)notification
5692 NSTRACE ("[EmacsApp applicationDidResignActive:]");
5695 ns_send_appdefined (-1);
5700 /* ==========================================================================
5702 EmacsApp aux handlers for managing event loop
5704 ========================================================================== */
5707 - (void)timeout_handler: (NSTimer *)timedEntry
5708 /* --------------------------------------------------------------------------
5709 The timeout specified to ns_select has passed.
5710 -------------------------------------------------------------------------- */
5712 /*NSTRACE ("timeout_handler"); */
5713 ns_send_appdefined (-2);
5716 - (void)sendFromMainThread:(id)unused
5718 ns_send_appdefined (nextappdefined);
5721 - (void)fd_handler:(id)unused
5722 /* --------------------------------------------------------------------------
5723 Check data waiting on file descriptors and terminate if so
5724 -------------------------------------------------------------------------- */
5727 int waiting = 1, nfds;
5730 fd_set readfds, writefds, *wfds;
5731 struct timespec timeout, *tmo;
5732 NSAutoreleasePool *pool = nil;
5734 /* NSTRACE ("fd_handler"); */
5739 pool = [[NSAutoreleasePool alloc] init];
5745 FD_SET (selfds[0], &fds);
5746 result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
5747 if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
5752 pthread_mutex_lock (&select_mutex);
5755 if (select_valid & SELECT_HAVE_READ)
5756 readfds = select_readfds;
5760 if (select_valid & SELECT_HAVE_WRITE)
5762 writefds = select_writefds;
5767 if (select_valid & SELECT_HAVE_TMO)
5769 timeout = select_timeout;
5775 pthread_mutex_unlock (&select_mutex);
5777 FD_SET (selfds[0], &readfds);
5778 if (selfds[0] >= nfds) nfds = selfds[0]+1;
5780 result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
5783 ns_send_appdefined (-2);
5784 else if (result > 0)
5786 if (FD_ISSET (selfds[0], &readfds))
5788 if (read (selfds[0], &c, 1) == 1 && c == 's')
5793 pthread_mutex_lock (&select_mutex);
5794 if (select_valid & SELECT_HAVE_READ)
5795 select_readfds = readfds;
5796 if (select_valid & SELECT_HAVE_WRITE)
5797 select_writefds = writefds;
5798 if (select_valid & SELECT_HAVE_TMO)
5799 select_timeout = timeout;
5800 pthread_mutex_unlock (&select_mutex);
5802 ns_send_appdefined (result);
5812 /* ==========================================================================
5816 ========================================================================== */
5818 /* called from system: queue for next pass through event loop */
5819 - (void)requestService: (NSPasteboard *)pboard
5820 userData: (NSString *)userData
5821 error: (NSString **)error
5823 [ns_pending_service_names addObject: userData];
5824 [ns_pending_service_args addObject: [NSString stringWithUTF8String:
5825 SSDATA (ns_string_from_pasteboard (pboard))]];
5829 /* called from ns_read_socket to clear queue */
5830 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
5832 struct frame *emacsframe = SELECTED_FRAME ();
5833 NSEvent *theEvent = [NSApp currentEvent];
5835 NSTRACE ("[EmacsApp fulfillService:withArg:]");
5840 emacs_event->kind = NS_NONKEY_EVENT;
5841 emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
5842 ns_input_spi_name = build_string ([name UTF8String]);
5843 ns_input_spi_arg = build_string ([arg UTF8String]);
5844 emacs_event->modifiers = EV_MODIFIERS (theEvent);
5845 EV_TRAILER (theEvent);
5855 /* ==========================================================================
5857 EmacsView implementation
5859 ========================================================================== */
5862 @implementation EmacsView
5864 /* needed to inform when window closed from LISP */
5865 - (void) setWindowClosing: (BOOL)closing
5867 NSTRACE ("[EmacsView setWindowClosing:%d]", closing);
5869 windowClosing = closing;
5875 NSTRACE ("[EmacsView dealloc]");
5877 if (fs_state == FULLSCREEN_BOTH)
5878 [nonfs_window release];
5883 /* called on font panel selection */
5884 - (void)changeFont: (id)sender
5886 NSEvent *e = [[self window] currentEvent];
5887 struct face *face = FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID);
5888 struct font *font = face->font;
5893 NSTRACE ("[EmacsView changeFont:]");
5898 #ifdef NS_IMPL_GNUSTEP
5899 nsfont = ((struct nsfont_info *)font)->nsfont;
5901 #ifdef NS_IMPL_COCOA
5902 nsfont = (NSFont *) macfont_get_nsctfont (font);
5905 if ((newFont = [sender convertFont: nsfont]))
5907 SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
5909 emacs_event->kind = NS_NONKEY_EVENT;
5910 emacs_event->modifiers = 0;
5911 emacs_event->code = KEY_NS_CHANGE_FONT;
5913 size = [newFont pointSize];
5914 ns_input_fontsize = make_number (lrint (size));
5915 ns_input_font = build_string ([[newFont familyName] UTF8String]);
5921 - (BOOL)acceptsFirstResponder
5923 NSTRACE ("[EmacsView acceptsFirstResponder]");
5928 - (void)resetCursorRects
5930 NSRect visible = [self visibleRect];
5931 NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
5932 NSTRACE ("[EmacsView resetCursorRects]");
5934 if (currentCursor == nil)
5935 currentCursor = [NSCursor arrowCursor];
5937 if (!NSIsEmptyRect (visible))
5938 [self addCursorRect: visible cursor: currentCursor];
5939 [currentCursor setOnMouseEntered: YES];
5944 /*****************************************************************************/
5945 /* Keyboard handling. */
5948 - (void)keyDown: (NSEvent *)theEvent
5950 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5952 unsigned fnKeysym = 0;
5953 static NSMutableArray *nsEvArray;
5955 unsigned int flags = [theEvent modifierFlags];
5957 NSTRACE ("[EmacsView keyDown:]");
5959 /* Rhapsody and macOS give up and down events for the arrow keys */
5960 if (ns_fake_keydown == YES)
5961 ns_fake_keydown = NO;
5962 else if ([theEvent type] != NSEventTypeKeyDown)
5968 if (![[self window] isKeyWindow]
5969 && [[theEvent window] isKindOfClass: [EmacsWindow class]]
5970 /* we must avoid an infinite loop here. */
5971 && (EmacsView *)[[theEvent window] delegate] != self)
5973 /* XXX: There is an occasional condition in which, when Emacs display
5974 updates a different frame from the current one, and temporarily
5975 selects it, then processes some interrupt-driven input
5976 (dispnew.c:3878), OS will send the event to the correct NSWindow, but
5977 for some reason that window has its first responder set to the NSView
5978 most recently updated (I guess), which is not the correct one. */
5979 [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
5983 if (nsEvArray == nil)
5984 nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
5986 [NSCursor setHiddenUntilMouseMoves: YES];
5988 if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
5990 clear_mouse_face (hlinfo);
5991 hlinfo->mouse_face_hidden = 1;
5994 if (!processingCompose)
5996 /* When using screen sharing, no left or right information is sent,
5997 so use Left key in those cases. */
5998 int is_left_key, is_right_key;
6000 code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
6001 0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
6003 /* (Carbon way: [theEvent keyCode]) */
6005 /* is it a "function key"? */
6006 /* Note: Sometimes a plain key will have the NSEventModifierFlagNumericPad
6007 flag set (this is probably a bug in the OS).
6009 if (code < 0x00ff && (flags&NSEventModifierFlagNumericPad))
6011 fnKeysym = ns_convert_key ([theEvent keyCode] | NSEventModifierFlagNumericPad);
6015 fnKeysym = ns_convert_key (code);
6020 /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
6021 because Emacs treats Delete and KP-Delete same (in simple.el). */
6022 if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
6023 #ifdef NS_IMPL_GNUSTEP
6024 /* GNUstep uses incompatible keycodes, even for those that are
6025 supposed to be hardware independent. Just check for delete.
6026 Keypad delete does not have keysym 0xFFFF.
6027 See http://savannah.gnu.org/bugs/?25395
6029 || (fnKeysym == 0xFFFF && code == 127)
6032 code = 0xFF08; /* backspace */
6037 /* are there modifiers? */
6038 emacs_event->modifiers = 0;
6040 if (flags & NSEventModifierFlagHelp)
6041 emacs_event->modifiers |= hyper_modifier;
6043 if (flags & NSEventModifierFlagShift)
6044 emacs_event->modifiers |= shift_modifier;
6046 is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
6047 is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
6048 || (! is_right_key && (flags & NSEventModifierFlagCommand) == NSEventModifierFlagCommand);
6051 emacs_event->modifiers |= parse_solitary_modifier
6052 (EQ (ns_right_command_modifier, Qleft)
6053 ? ns_command_modifier
6054 : ns_right_command_modifier);
6058 emacs_event->modifiers |= parse_solitary_modifier
6059 (ns_command_modifier);
6061 /* if super (default), take input manager's word so things like
6062 dvorak / qwerty layout work */
6063 if (EQ (ns_command_modifier, Qsuper)
6065 && [[theEvent characters] length] != 0)
6067 /* XXX: the code we get will be unshifted, so if we have
6068 a shift modifier, must convert ourselves */
6069 if (!(flags & NSEventModifierFlagShift))
6070 code = [[theEvent characters] characterAtIndex: 0];
6072 /* this is ugly and also requires linking w/Carbon framework
6073 (for LMGetKbdType) so for now leave this rare (?) case
6074 undealt with.. in future look into CGEvent methods */
6077 long smv = GetScriptManagerVariable (smKeyScript);
6078 Handle uchrHandle = GetResource
6079 ('uchr', GetScriptVariable (smv, smScriptKeys));
6081 UCKeyTranslate ((UCKeyboardLayout *) *uchrHandle,
6082 [[theEvent characters] characterAtIndex: 0],
6083 kUCKeyActionDisplay,
6084 (flags & ~NSEventModifierFlagCommand) >> 8,
6085 LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
6086 &dummy, 1, &dummy, &code);
6093 is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
6094 is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
6095 || (! is_right_key && (flags & NSEventModifierFlagControl) == NSEventModifierFlagControl);
6098 emacs_event->modifiers |= parse_solitary_modifier
6099 (EQ (ns_right_control_modifier, Qleft)
6100 ? ns_control_modifier
6101 : ns_right_control_modifier);
6104 emacs_event->modifiers |= parse_solitary_modifier
6105 (ns_control_modifier);
6107 if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
6108 emacs_event->modifiers |=
6109 parse_solitary_modifier (ns_function_modifier);
6111 left_is_none = NILP (ns_alternate_modifier)
6112 || EQ (ns_alternate_modifier, Qnone);
6114 is_right_key = (flags & NSRightAlternateKeyMask)
6115 == NSRightAlternateKeyMask;
6116 is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
6118 && (flags & NSEventModifierFlagOption) == NSEventModifierFlagOption);
6122 if ((NILP (ns_right_alternate_modifier)
6123 || EQ (ns_right_alternate_modifier, Qnone)
6124 || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
6126 { /* accept pre-interp alt comb */
6127 if ([[theEvent characters] length] > 0)
6128 code = [[theEvent characters] characterAtIndex: 0];
6129 /*HACK: clear lone shift modifier to stop next if from firing */
6130 if (emacs_event->modifiers == shift_modifier)
6131 emacs_event->modifiers = 0;
6134 emacs_event->modifiers |= parse_solitary_modifier
6135 (EQ (ns_right_alternate_modifier, Qleft)
6136 ? ns_alternate_modifier
6137 : ns_right_alternate_modifier);
6140 if (is_left_key) /* default = meta */
6142 if (left_is_none && !fnKeysym)
6143 { /* accept pre-interp alt comb */
6144 if ([[theEvent characters] length] > 0)
6145 code = [[theEvent characters] characterAtIndex: 0];
6146 /*HACK: clear lone shift modifier to stop next if from firing */
6147 if (emacs_event->modifiers == shift_modifier)
6148 emacs_event->modifiers = 0;
6151 emacs_event->modifiers |=
6152 parse_solitary_modifier (ns_alternate_modifier);
6156 fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
6157 (unsigned) code, fnKeysym, flags, emacs_event->modifiers);
6159 /* if it was a function key or had modifiers, pass it directly to emacs */
6160 if (fnKeysym || (emacs_event->modifiers
6161 && (emacs_event->modifiers != shift_modifier)
6162 && [[theEvent charactersIgnoringModifiers] length] > 0))
6163 /*[[theEvent characters] length] */
6165 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6167 code |= (1<<28)|(3<<16);
6168 else if (code == 0x7f)
6169 code |= (1<<28)|(3<<16);
6171 emacs_event->kind = code > 0xFF
6172 ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6174 emacs_event->code = code;
6175 EV_TRAILER (theEvent);
6176 processingCompose = NO;
6182 if (NS_KEYLOG && !processingCompose)
6183 fprintf (stderr, "keyDown: Begin compose sequence.\n");
6185 processingCompose = YES;
6186 [nsEvArray addObject: theEvent];
6187 [self interpretKeyEvents: nsEvArray];
6188 [nsEvArray removeObject: theEvent];
6192 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
6195 /* <NSTextInput>: called when done composing;
6196 NOTE: also called when we delete over working text, followed immed.
6197 by doCommandBySelector: deleteBackward: */
6198 - (void)insertText: (id)aString
6201 int len = [(NSString *)aString length];
6204 NSTRACE ("[EmacsView insertText:]");
6207 NSLog (@"insertText '%@'\tlen = %d", aString, len);
6208 processingCompose = NO;
6213 /* first, clear any working text */
6214 if (workingText != nil)
6215 [self deleteWorkingText];
6217 /* now insert the string as keystrokes */
6218 for (i =0; i<len; i++)
6220 code = [aString characterAtIndex: i];
6221 /* TODO: still need this? */
6223 code = '~'; /* 0x7E */
6224 if (code != 32) /* Space */
6225 emacs_event->modifiers = 0;
6227 = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6228 emacs_event->code = code;
6229 EV_TRAILER ((id)nil);
6234 /* <NSTextInput>: inserts display of composing characters */
6235 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
6237 NSString *str = [aString respondsToSelector: @selector (string)] ?
6238 [aString string] : aString;
6240 NSTRACE ("[EmacsView setMarkedText:selectedRange:]");
6243 NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
6244 str, (unsigned long)[str length],
6245 (unsigned long)selRange.length,
6246 (unsigned long)selRange.location);
6248 if (workingText != nil)
6249 [self deleteWorkingText];
6250 if ([str length] == 0)
6256 processingCompose = YES;
6257 workingText = [str copy];
6258 ns_working_text = build_string ([workingText UTF8String]);
6260 emacs_event->kind = NS_TEXT_EVENT;
6261 emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
6262 EV_TRAILER ((id)nil);
6266 /* delete display of composing characters [not in <NSTextInput>] */
6267 - (void)deleteWorkingText
6269 NSTRACE ("[EmacsView deleteWorkingText]");
6271 if (workingText == nil)
6274 NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
6275 [workingText release];
6277 processingCompose = NO;
6282 emacs_event->kind = NS_TEXT_EVENT;
6283 emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
6284 EV_TRAILER ((id)nil);
6288 - (BOOL)hasMarkedText
6290 NSTRACE ("[EmacsView hasMarkedText]");
6292 return workingText != nil;
6296 - (NSRange)markedRange
6298 NSTRACE ("[EmacsView markedRange]");
6300 NSRange rng = workingText != nil
6301 ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
6303 NSLog (@"markedRange request");
6310 NSTRACE ("[EmacsView unmarkText]");
6313 NSLog (@"unmark (accept) text");
6314 [self deleteWorkingText];
6315 processingCompose = NO;
6319 /* used to position char selection windows, etc. */
6320 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
6324 struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
6326 NSTRACE ("[EmacsView firstRectForCharacterRange:]");
6329 NSLog (@"firstRectForCharRange request");
6331 rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
6332 rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
6333 pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
6334 pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
6335 +FRAME_LINE_HEIGHT (emacsframe));
6337 pt = [self convertPoint: pt toView: nil];
6339 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
6340 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6341 if ([[self window] respondsToSelector: @selector(convertRectToScreen:)])
6345 rect = [(EmacsWindow *) [self window] convertRectToScreen: rect];
6346 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6350 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
6351 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 \
6352 || defined (NS_IMPL_GNUSTEP)
6354 pt = [[self window] convertBaseToScreen: pt];
6363 - (NSInteger)conversationIdentifier
6365 return (NSInteger)self;
6369 - (void)doCommandBySelector: (SEL)aSelector
6371 NSTRACE ("[EmacsView doCommandBySelector:]");
6374 NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
6376 processingCompose = NO;
6377 if (aSelector == @selector (deleteBackward:))
6379 /* happens when user backspaces over an ongoing composition:
6380 throw a 'delete' into the event queue */
6383 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6384 emacs_event->code = 0xFF08;
6385 EV_TRAILER ((id)nil);
6389 - (NSArray *)validAttributesForMarkedText
6391 static NSArray *arr = nil;
6392 if (arr == nil) arr = [NSArray new];
6393 /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
6397 - (NSRange)selectedRange
6400 NSLog (@"selectedRange request");
6401 return NSMakeRange (NSNotFound, 0);
6404 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
6405 GNUSTEP_GUI_MINOR_VERSION > 22
6406 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
6408 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
6412 NSLog (@"characterIndexForPoint request");
6416 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
6418 static NSAttributedString *str = nil;
6419 if (str == nil) str = [NSAttributedString new];
6421 NSLog (@"attributedSubstringFromRange request");
6425 /* End <NSTextInput> impl. */
6426 /*****************************************************************************/
6429 /* This is what happens when the user presses a mouse button. */
6430 - (void)mouseDown: (NSEvent *)theEvent
6432 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6433 NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
6435 NSTRACE ("[EmacsView mouseDown:]");
6437 [self deleteWorkingText];
6442 dpyinfo->last_mouse_frame = emacsframe;
6443 /* appears to be needed to prevent spurious movement events generated on
6445 emacsframe->mouse_moved = 0;
6447 if ([theEvent type] == NSEventTypeScrollWheel)
6449 CGFloat delta = [theEvent deltaY];
6450 /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
6453 delta = [theEvent deltaX];
6456 NSTRACE_MSG ("deltaIsZero");
6459 emacs_event->kind = HORIZ_WHEEL_EVENT;
6462 emacs_event->kind = WHEEL_EVENT;
6464 emacs_event->code = 0;
6465 emacs_event->modifiers = EV_MODIFIERS (theEvent) |
6466 ((delta > 0) ? up_modifier : down_modifier);
6470 emacs_event->kind = MOUSE_CLICK_EVENT;
6471 emacs_event->code = EV_BUTTON (theEvent);
6472 emacs_event->modifiers = EV_MODIFIERS (theEvent)
6473 | EV_UDMODIFIERS (theEvent);
6475 XSETINT (emacs_event->x, lrint (p.x));
6476 XSETINT (emacs_event->y, lrint (p.y));
6477 EV_TRAILER (theEvent);
6481 - (void)rightMouseDown: (NSEvent *)theEvent
6483 NSTRACE ("[EmacsView rightMouseDown:]");
6484 [self mouseDown: theEvent];
6488 - (void)otherMouseDown: (NSEvent *)theEvent
6490 NSTRACE ("[EmacsView otherMouseDown:]");
6491 [self mouseDown: theEvent];
6495 - (void)mouseUp: (NSEvent *)theEvent
6497 NSTRACE ("[EmacsView mouseUp:]");
6498 [self mouseDown: theEvent];
6502 - (void)rightMouseUp: (NSEvent *)theEvent
6504 NSTRACE ("[EmacsView rightMouseUp:]");
6505 [self mouseDown: theEvent];
6509 - (void)otherMouseUp: (NSEvent *)theEvent
6511 NSTRACE ("[EmacsView otherMouseUp:]");
6512 [self mouseDown: theEvent];
6516 - (void) scrollWheel: (NSEvent *)theEvent
6518 NSTRACE ("[EmacsView scrollWheel:]");
6519 [self mouseDown: theEvent];
6523 /* Tell emacs the mouse has moved. */
6524 - (void)mouseMoved: (NSEvent *)e
6526 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
6527 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6531 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsView mouseMoved:]");
6533 dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
6534 pt = [self convertPoint: [e locationInWindow] fromView: nil];
6535 dpyinfo->last_mouse_motion_x = pt.x;
6536 dpyinfo->last_mouse_motion_y = pt.y;
6538 /* update any mouse face */
6539 if (hlinfo->mouse_face_hidden)
6541 hlinfo->mouse_face_hidden = 0;
6542 clear_mouse_face (hlinfo);
6545 /* tooltip handling */
6546 previous_help_echo_string = help_echo_string;
6547 help_echo_string = Qnil;
6549 if (!NILP (Vmouse_autoselect_window))
6551 NSTRACE_MSG ("mouse_autoselect_window");
6552 static Lisp_Object last_mouse_window;
6554 = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
6556 if (WINDOWP (window)
6557 && !EQ (window, last_mouse_window)
6558 && !EQ (window, selected_window)
6559 && (!NILP (focus_follows_mouse)
6560 || (EQ (XWINDOW (window)->frame,
6561 XWINDOW (selected_window)->frame))))
6563 NSTRACE_MSG ("in_window");
6564 emacs_event->kind = SELECT_WINDOW_EVENT;
6565 emacs_event->frame_or_window = window;
6568 /* Remember the last window where we saw the mouse. */
6569 last_mouse_window = window;
6572 if (!note_mouse_movement (emacsframe, pt.x, pt.y))
6573 help_echo_string = previous_help_echo_string;
6575 XSETFRAME (frame, emacsframe);
6576 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
6578 /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
6579 (note_mouse_highlight), which is called through the
6580 note_mouse_movement () call above */
6581 any_help_event_p = YES;
6582 gen_help_event (help_echo_string, frame, help_echo_window,
6583 help_echo_object, help_echo_pos);
6586 if (emacsframe->mouse_moved && send_appdefined)
6587 ns_send_appdefined (-1);
6591 - (void)mouseDragged: (NSEvent *)e
6593 NSTRACE ("[EmacsView mouseDragged:]");
6594 [self mouseMoved: e];
6598 - (void)rightMouseDragged: (NSEvent *)e
6600 NSTRACE ("[EmacsView rightMouseDragged:]");
6601 [self mouseMoved: e];
6605 - (void)otherMouseDragged: (NSEvent *)e
6607 NSTRACE ("[EmacsView otherMouseDragged:]");
6608 [self mouseMoved: e];
6612 - (BOOL)windowShouldClose: (id)sender
6614 NSEvent *e =[[self window] currentEvent];
6616 NSTRACE ("[EmacsView windowShouldClose:]");
6617 windowClosing = YES;
6620 emacs_event->kind = DELETE_WINDOW_EVENT;
6621 emacs_event->modifiers = 0;
6622 emacs_event->code = 0;
6624 /* Don't close this window, let this be done from lisp code. */
6628 - (void) updateFrameSize: (BOOL) delay
6630 NSWindow *window = [self window];
6631 NSRect wr = [window frame];
6633 int oldc = cols, oldr = rows;
6634 int oldw = FRAME_PIXEL_WIDTH (emacsframe);
6635 int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
6638 NSTRACE ("[EmacsView updateFrameSize:]");
6639 NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
6640 NSTRACE_RECT ("Original frame", wr);
6641 NSTRACE_MSG ("Original columns: %d", cols);
6642 NSTRACE_MSG ("Original rows: %d", rows);
6644 if (! [self isFullscreen])
6646 #ifdef NS_IMPL_GNUSTEP
6647 // GNUstep does not always update the tool bar height. Force it.
6648 if (toolbar && [toolbar isVisible])
6649 update_frame_tool_bar (emacsframe);
6652 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6653 + FRAME_TOOLBAR_HEIGHT (emacsframe);
6656 if (wait_for_tool_bar)
6658 /* The toolbar height is always 0 in fullscreen, so don't wait
6659 for it to become available. */
6660 if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0
6661 && ! [self isFullscreen])
6663 NSTRACE_MSG ("Waiting for toolbar");
6666 wait_for_tool_bar = NO;
6669 neww = (int)wr.size.width - emacsframe->border_width;
6670 newh = (int)wr.size.height - extra;
6672 NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
6673 NSTRACE_MSG ("FRAME_TOOLBAR_HEIGHT: %d", FRAME_TOOLBAR_HEIGHT (emacsframe));
6674 NSTRACE_MSG ("FRAME_NS_TITLEBAR_HEIGHT: %d", FRAME_NS_TITLEBAR_HEIGHT (emacsframe));
6676 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
6677 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
6679 if (cols < MINWIDTH)
6682 if (rows < MINHEIGHT)
6685 NSTRACE_MSG ("New columns: %d", cols);
6686 NSTRACE_MSG ("New rows: %d", rows);
6688 if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
6690 NSView *view = FRAME_NS_VIEW (emacsframe);
6692 change_frame_size (emacsframe,
6693 FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
6694 FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
6696 SET_FRAME_GARBAGED (emacsframe);
6697 cancel_mouse_face (emacsframe);
6699 /* The next two lines appear to be setting the frame to the same
6700 size as it already is. Why are they there? */
6701 // wr = NSMakeRect (0, 0, neww, newh);
6703 // [view setFrame: wr];
6705 // to do: consider using [NSNotificationCenter postNotificationName:].
6706 [self windowDidMove: // Update top/left.
6707 [NSNotification notificationWithName:NSWindowDidMoveNotification
6708 object:[view window]]];
6712 NSTRACE_MSG ("No change");
6716 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
6717 /* normalize frame to gridded text size */
6721 NSTRACE ("[EmacsView windowWillResize:toSize: " NSTRACE_FMT_SIZE "]",
6722 NSTRACE_ARG_SIZE (frameSize));
6723 NSTRACE_RECT ("[sender frame]", [sender frame]);
6724 NSTRACE_FSTYPE ("fs_state", fs_state);
6726 if (fs_state == FULLSCREEN_MAXIMIZED
6727 && (maximized_width != (int)frameSize.width
6728 || maximized_height != (int)frameSize.height))
6729 [self setFSValue: FULLSCREEN_NONE];
6730 else if (fs_state == FULLSCREEN_WIDTH
6731 && maximized_width != (int)frameSize.width)
6732 [self setFSValue: FULLSCREEN_NONE];
6733 else if (fs_state == FULLSCREEN_HEIGHT
6734 && maximized_height != (int)frameSize.height)
6735 [self setFSValue: FULLSCREEN_NONE];
6737 if (fs_state == FULLSCREEN_NONE)
6738 maximized_width = maximized_height = -1;
6740 if (! [self isFullscreen])
6742 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6743 + FRAME_TOOLBAR_HEIGHT (emacsframe);
6746 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
6747 if (cols < MINWIDTH)
6750 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
6751 frameSize.height - extra);
6752 if (rows < MINHEIGHT)
6754 #ifdef NS_IMPL_COCOA
6756 /* this sets window title to have size in it; the wm does this under GS */
6757 NSRect r = [[self window] frame];
6758 if (r.size.height == frameSize.height && r.size.width == frameSize.width)
6766 else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize
6767 && [[self window] title] != NULL)
6770 NSWindow *window = [self window];
6773 char *t = strdup ([[[self window] title] UTF8String]);
6774 char *pos = strstr (t, " — ");
6779 size_title = xmalloc (strlen (old_title) + 40);
6780 esprintf (size_title, "%s — (%d x %d)", old_title, cols, rows);
6781 [window setTitle: [NSString stringWithUTF8String: size_title]];
6786 #endif /* NS_IMPL_COCOA */
6788 NSTRACE_MSG ("cols: %d rows: %d", cols, rows);
6790 /* Restrict the new size to the text gird.
6792 Don't restrict the width if the user only adjusted the height, and
6793 vice versa. (Without this, the frame would shrink, and move
6794 slightly, if the window was resized by dragging one of its
6796 if (!frame_resize_pixelwise)
6798 NSRect r = [[self window] frame];
6800 if (r.size.width != frameSize.width)
6803 FRAME_TEXT_COLS_TO_PIXEL_WIDTH (emacsframe, cols);
6806 if (r.size.height != frameSize.height)
6809 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (emacsframe, rows) + extra;
6813 NSTRACE_RETURN_SIZE (frameSize);
6819 - (void)windowDidResize: (NSNotification *)notification
6821 NSTRACE ("[EmacsView windowDidResize:]");
6822 if (!FRAME_LIVE_P (emacsframe))
6824 NSTRACE_MSG ("Ignored (frame dead)");
6827 if (emacsframe->output_data.ns->in_animation)
6829 NSTRACE_MSG ("Ignored (in animation)");
6833 if (! [self fsIsNative])
6835 NSWindow *theWindow = [notification object];
6836 /* We can get notification on the non-FS window when in
6838 if ([self window] != theWindow) return;
6841 NSTRACE_RECT ("frame", [[notification object] frame]);
6843 #ifdef NS_IMPL_GNUSTEP
6844 NSWindow *theWindow = [notification object];
6846 /* In GNUstep, at least currently, it's possible to get a didResize
6847 without getting a willResize.. therefore we need to act as if we got
6848 the willResize now */
6849 NSSize sz = [theWindow frame].size;
6850 sz = [self windowWillResize: theWindow toSize: sz];
6851 #endif /* NS_IMPL_GNUSTEP */
6853 if (cols > 0 && rows > 0)
6855 [self updateFrameSize: YES];
6858 ns_send_appdefined (-1);
6861 #ifdef NS_IMPL_COCOA
6862 - (void)viewDidEndLiveResize
6864 NSTRACE ("[EmacsView viewDidEndLiveResize]");
6866 [super viewDidEndLiveResize];
6869 [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
6873 maximizing_resize = NO;
6875 #endif /* NS_IMPL_COCOA */
6878 - (void)windowDidBecomeKey: (NSNotification *)notification
6879 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6881 [self windowDidBecomeKey];
6885 - (void)windowDidBecomeKey /* for direct calls */
6887 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6888 struct frame *old_focus = dpyinfo->x_focus_frame;
6890 NSTRACE ("[EmacsView windowDidBecomeKey]");
6892 if (emacsframe != old_focus)
6893 dpyinfo->x_focus_frame = emacsframe;
6895 ns_frame_rehighlight (emacsframe);
6899 emacs_event->kind = FOCUS_IN_EVENT;
6900 EV_TRAILER ((id)nil);
6905 - (void)windowDidResignKey: (NSNotification *)notification
6906 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6908 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6909 BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
6910 NSTRACE ("[EmacsView windowDidResignKey:]");
6913 dpyinfo->x_focus_frame = 0;
6915 emacsframe->mouse_moved = 0;
6916 ns_frame_rehighlight (emacsframe);
6918 /* FIXME: for some reason needed on second and subsequent clicks away
6919 from sole-frame Emacs to get hollow box to show */
6920 if (!windowClosing && [[self window] isVisible] == YES)
6922 x_update_cursor (emacsframe, 1);
6923 x_set_frame_alpha (emacsframe);
6926 if (any_help_event_p)
6929 XSETFRAME (frame, emacsframe);
6930 help_echo_string = Qnil;
6931 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
6934 if (emacs_event && is_focus_frame)
6936 [self deleteWorkingText];
6937 emacs_event->kind = FOCUS_OUT_EVENT;
6938 EV_TRAILER ((id)nil);
6943 - (void)windowWillMiniaturize: sender
6945 NSTRACE ("[EmacsView windowWillMiniaturize:]");
6949 - (void)setFrame:(NSRect)frameRect
6951 NSTRACE ("[EmacsView setFrame:" NSTRACE_FMT_RECT "]",
6952 NSTRACE_ARG_RECT (frameRect));
6954 [super setFrame:(NSRect)frameRect];
6970 - (void)createToolbar: (struct frame *)f
6972 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
6973 NSWindow *window = [view window];
6975 toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
6976 [NSString stringWithFormat: @"Emacs Frame %d",
6978 [toolbar setVisible: NO];
6979 [window setToolbar: toolbar];
6981 /* Don't set frame garbaged until tool bar is up to date?
6982 This avoids an extra clear and redraw (flicker) at frame creation. */
6983 if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
6984 else wait_for_tool_bar = NO;
6987 #ifdef NS_IMPL_COCOA
6989 NSButton *toggleButton;
6990 toggleButton = [window standardWindowButton: NSWindowToolbarButton];
6991 [toggleButton setTarget: self];
6992 [toggleButton setAction: @selector (toggleToolbar: )];
6998 - (instancetype) initFrameFromEmacs: (struct frame *)f
7006 NSTRACE ("[EmacsView initFrameFromEmacs:]");
7007 NSTRACE_MSG ("cols:%d lines:%d", f->text_cols, f->text_lines);
7010 processingCompose = NO;
7011 scrollbarsNeedingUpdate = 0;
7012 fs_state = FULLSCREEN_NONE;
7013 fs_before_fs = next_maximized = -1;
7016 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7017 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7018 if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7020 fs_is_native = ns_use_native_fullscreen;
7023 maximized_width = maximized_height = -1;
7026 ns_userRect = NSMakeRect (0, 0, 0, 0);
7027 r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
7028 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
7029 [self initWithFrame: r];
7030 [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
7032 FRAME_NS_VIEW (f) = self;
7034 #ifdef NS_IMPL_COCOA
7036 maximizing_resize = NO;
7039 win = [[EmacsWindow alloc]
7040 initWithContentRect: r
7041 styleMask: (FRAME_UNDECORATED (f)
7042 ? FRAME_UNDECORATED_FLAGS
7043 : FRAME_DECORATED_FLAGS
7044 #ifdef NS_IMPL_COCOA
7045 | NSWindowStyleMaskResizable
7046 | NSWindowStyleMaskMiniaturizable
7047 | NSWindowStyleMaskClosable
7050 backing: NSBackingStoreBuffered
7053 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7054 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7055 if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7057 [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
7061 bwidth = f->border_width = wr.size.width - r.size.width;
7063 [win setAcceptsMouseMovedEvents: YES];
7064 [win setDelegate: self];
7065 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7066 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7067 if ([win respondsToSelector: @selector(useOptimizedDrawing:)])
7069 [win useOptimizedDrawing: YES];
7072 [[win contentView] addSubview: self];
7075 [self registerForDraggedTypes: ns_drag_types];
7078 name = [NSString stringWithUTF8String:
7079 NILP (tem) ? "Emacs" : SSDATA (tem)];
7080 [win setTitle: name];
7082 /* toolbar support */
7083 if (! FRAME_UNDECORATED (f))
7084 [self createToolbar: f];
7088 [win setMiniwindowTitle:
7089 [NSString stringWithUTF8String: SSDATA (tem)]];
7091 if (FRAME_PARENT_FRAME (f) != NULL)
7093 NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
7094 [parent addChildWindow: win
7095 ordered: NSWindowAbove];
7098 if (FRAME_Z_GROUP (f) != z_group_none)
7099 win.level = NSNormalWindowLevel
7100 + (FRAME_Z_GROUP_BELOW (f) ? -1 : 1);
7103 NSScreen *screen = [win screen];
7107 NSPoint pt = NSMakePoint
7108 (IN_BOUND (-SCREENMAX, f->left_pos
7109 + NS_PARENT_WINDOW_LEFT_POS (f), SCREENMAX),
7110 IN_BOUND (-SCREENMAX,
7111 NS_PARENT_WINDOW_TOP_POS (f) - f->top_pos,
7114 [win setFrameTopLeftPoint: pt];
7116 NSTRACE_RECT ("new frame", [win frame]);
7120 [win makeFirstResponder: self];
7122 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7123 (FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID)),
7125 [win setBackgroundColor: col];
7126 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7127 [win setOpaque: NO];
7129 #if !defined (NS_IMPL_COCOA) \
7130 || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7131 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7132 if ([self respondsToSelector: @selector(allocateGState)])
7134 [self allocateGState];
7136 [NSApp registerServicesMenuSendTypes: ns_send_types
7137 returnTypes: [NSArray array]];
7139 /* macOS Sierra automatically enables tabbed windows. We can't
7140 allow this to be enabled until it's available on a Free system.
7141 Currently it only happens by accident and is buggy anyway. */
7142 #if defined (NS_IMPL_COCOA) \
7143 && MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
7144 #if MAC_OS_X_VERSION_MIN_REQUIRED < 101200
7145 if ([win respondsToSelector: @selector(setTabbingMode:)])
7147 [win setTabbingMode: NSWindowTabbingModeDisallowed];
7155 - (void)windowDidMove: sender
7157 NSWindow *win = [self window];
7158 NSRect r = [win frame];
7159 NSArray *screens = [NSScreen screens];
7160 NSScreen *screen = [screens objectAtIndex: 0];
7162 NSTRACE ("[EmacsView windowDidMove:]");
7164 if (!emacsframe->output_data.ns)
7168 emacsframe->left_pos = r.origin.x - NS_PARENT_WINDOW_LEFT_POS (emacsframe);
7169 emacsframe->top_pos =
7170 NS_PARENT_WINDOW_TOP_POS (emacsframe) - (r.origin.y + r.size.height);
7174 emacs_event->kind = MOVE_FRAME_EVENT;
7175 EV_TRAILER ((id)nil);
7181 /* Called AFTER method below, but before our windowWillResize call there leads
7182 to windowDidResize -> x_set_window_size. Update emacs' notion of frame
7183 location so set_window_size moves the frame. */
7184 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
7186 NSTRACE (("[EmacsView windowShouldZoom:toFrame:" NSTRACE_FMT_RECT "]"
7187 NSTRACE_FMT_RETURN "YES"),
7188 NSTRACE_ARG_RECT (newFrame));
7190 emacsframe->output_data.ns->zooming = 1;
7195 /* Override to do something slightly nonstandard, but nice. First click on
7196 zoom button will zoom vertically. Second will zoom completely. Third
7197 returns to original. */
7198 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
7199 defaultFrame:(NSRect)defaultFrame
7201 // TODO: Rename to "currentFrame" and assign "result" properly in
7203 NSRect result = [sender frame];
7205 NSTRACE (("[EmacsView windowWillUseStandardFrame:defaultFrame:"
7206 NSTRACE_FMT_RECT "]"),
7207 NSTRACE_ARG_RECT (defaultFrame));
7208 NSTRACE_FSTYPE ("fs_state", fs_state);
7209 NSTRACE_FSTYPE ("fs_before_fs", fs_before_fs);
7210 NSTRACE_FSTYPE ("next_maximized", next_maximized);
7211 NSTRACE_RECT ("ns_userRect", ns_userRect);
7212 NSTRACE_RECT ("[sender frame]", [sender frame]);
7214 if (fs_before_fs != -1) /* Entering fullscreen */
7216 NSTRACE_MSG ("Entering fullscreen");
7217 result = defaultFrame;
7221 // Save the window size and position (frame) before the resize.
7222 if (fs_state != FULLSCREEN_MAXIMIZED
7223 && fs_state != FULLSCREEN_WIDTH)
7225 ns_userRect.size.width = result.size.width;
7226 ns_userRect.origin.x = result.origin.x;
7229 if (fs_state != FULLSCREEN_MAXIMIZED
7230 && fs_state != FULLSCREEN_HEIGHT)
7232 ns_userRect.size.height = result.size.height;
7233 ns_userRect.origin.y = result.origin.y;
7236 NSTRACE_RECT ("ns_userRect (2)", ns_userRect);
7238 if (next_maximized == FULLSCREEN_HEIGHT
7239 || (next_maximized == -1
7240 && abs ((int)(defaultFrame.size.height - result.size.height))
7241 > FRAME_LINE_HEIGHT (emacsframe)))
7244 NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7245 maximized_height = result.size.height = defaultFrame.size.height;
7246 maximized_width = -1;
7247 result.origin.y = defaultFrame.origin.y;
7248 if (ns_userRect.size.height != 0)
7250 result.origin.x = ns_userRect.origin.x;
7251 result.size.width = ns_userRect.size.width;
7253 [self setFSValue: FULLSCREEN_HEIGHT];
7254 #ifdef NS_IMPL_COCOA
7255 maximizing_resize = YES;
7258 else if (next_maximized == FULLSCREEN_WIDTH)
7260 NSTRACE_MSG ("FULLSCREEN_WIDTH");
7261 maximized_width = result.size.width = defaultFrame.size.width;
7262 maximized_height = -1;
7263 result.origin.x = defaultFrame.origin.x;
7264 if (ns_userRect.size.width != 0)
7266 result.origin.y = ns_userRect.origin.y;
7267 result.size.height = ns_userRect.size.height;
7269 [self setFSValue: FULLSCREEN_WIDTH];
7271 else if (next_maximized == FULLSCREEN_MAXIMIZED
7272 || (next_maximized == -1
7273 && abs ((int)(defaultFrame.size.width - result.size.width))
7274 > FRAME_COLUMN_WIDTH (emacsframe)))
7276 NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7278 result = defaultFrame; /* second click */
7279 maximized_width = result.size.width;
7280 maximized_height = result.size.height;
7281 [self setFSValue: FULLSCREEN_MAXIMIZED];
7282 #ifdef NS_IMPL_COCOA
7283 maximizing_resize = YES;
7289 NSTRACE_MSG ("Restore");
7290 result = ns_userRect.size.height ? ns_userRect : result;
7291 NSTRACE_RECT ("restore (2)", result);
7292 ns_userRect = NSMakeRect (0, 0, 0, 0);
7293 #ifdef NS_IMPL_COCOA
7294 maximizing_resize = fs_state != FULLSCREEN_NONE;
7296 [self setFSValue: FULLSCREEN_NONE];
7297 maximized_width = maximized_height = -1;
7301 if (fs_before_fs == -1) next_maximized = -1;
7303 NSTRACE_RECT ("Final ns_userRect", ns_userRect);
7304 NSTRACE_MSG ("Final maximized_width: %d", maximized_width);
7305 NSTRACE_MSG ("Final maximized_height: %d", maximized_height);
7306 NSTRACE_FSTYPE ("Final next_maximized", next_maximized);
7308 [self windowWillResize: sender toSize: result.size];
7310 NSTRACE_RETURN_RECT (result);
7316 - (void)windowDidDeminiaturize: sender
7318 NSTRACE ("[EmacsView windowDidDeminiaturize:]");
7319 if (!emacsframe->output_data.ns)
7322 SET_FRAME_ICONIFIED (emacsframe, 0);
7323 SET_FRAME_VISIBLE (emacsframe, 1);
7324 windows_or_buffers_changed = 63;
7328 emacs_event->kind = DEICONIFY_EVENT;
7329 EV_TRAILER ((id)nil);
7334 - (void)windowDidExpose: sender
7336 NSTRACE ("[EmacsView windowDidExpose:]");
7337 if (!emacsframe->output_data.ns)
7340 SET_FRAME_VISIBLE (emacsframe, 1);
7341 SET_FRAME_GARBAGED (emacsframe);
7343 if (send_appdefined)
7344 ns_send_appdefined (-1);
7348 - (void)windowDidMiniaturize: sender
7350 NSTRACE ("[EmacsView windowDidMiniaturize:]");
7351 if (!emacsframe->output_data.ns)
7354 SET_FRAME_ICONIFIED (emacsframe, 1);
7355 SET_FRAME_VISIBLE (emacsframe, 0);
7359 emacs_event->kind = ICONIFY_EVENT;
7360 EV_TRAILER ((id)nil);
7364 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7365 - (NSApplicationPresentationOptions)window:(NSWindow *)window
7366 willUseFullScreenPresentationOptions:
7367 (NSApplicationPresentationOptions)proposedOptions
7369 return proposedOptions|NSApplicationPresentationAutoHideToolbar;
7373 - (void)windowWillEnterFullScreen:(NSNotification *)notification
7375 NSTRACE ("[EmacsView windowWillEnterFullScreen:]");
7376 [self windowWillEnterFullScreen];
7378 - (void)windowWillEnterFullScreen /* provided for direct calls */
7380 NSTRACE ("[EmacsView windowWillEnterFullScreen]");
7381 fs_before_fs = fs_state;
7384 - (void)windowDidEnterFullScreen:(NSNotification *)notification
7386 NSTRACE ("[EmacsView windowDidEnterFullScreen:]");
7387 [self windowDidEnterFullScreen];
7390 - (void)windowDidEnterFullScreen /* provided for direct calls */
7392 NSTRACE ("[EmacsView windowDidEnterFullScreen]");
7393 [self setFSValue: FULLSCREEN_BOTH];
7394 if (! [self fsIsNative])
7396 [self windowDidBecomeKey];
7397 [nonfs_window orderOut:self];
7401 BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
7402 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 \
7403 && MAC_OS_X_VERSION_MIN_REQUIRED <= 1070
7404 unsigned val = (unsigned)[NSApp presentationOptions];
7406 // Mac OS X 10.7 bug fix, the menu won't appear without this.
7407 // val is non-zero on other macOS versions.
7410 NSApplicationPresentationOptions options
7411 = NSApplicationPresentationAutoHideDock
7412 | NSApplicationPresentationAutoHideMenuBar
7413 | NSApplicationPresentationFullScreen
7414 | NSApplicationPresentationAutoHideToolbar;
7416 [NSApp setPresentationOptions: options];
7419 [toolbar setVisible:tbar_visible];
7423 - (void)windowWillExitFullScreen:(NSNotification *)notification
7425 NSTRACE ("[EmacsView windowWillExitFullScreen:]");
7426 [self windowWillExitFullScreen];
7429 - (void)windowWillExitFullScreen /* provided for direct calls */
7431 NSTRACE ("[EmacsView windowWillExitFullScreen]");
7432 if (!FRAME_LIVE_P (emacsframe))
7434 NSTRACE_MSG ("Ignored (frame dead)");
7437 if (next_maximized != -1)
7438 fs_before_fs = next_maximized;
7441 - (void)windowDidExitFullScreen:(NSNotification *)notification
7443 NSTRACE ("[EmacsView windowDidExitFullScreen:]");
7444 [self windowDidExitFullScreen];
7447 - (void)windowDidExitFullScreen /* provided for direct calls */
7449 NSTRACE ("[EmacsView windowDidExitFullScreen]");
7450 if (!FRAME_LIVE_P (emacsframe))
7452 NSTRACE_MSG ("Ignored (frame dead)");
7455 [self setFSValue: fs_before_fs];
7457 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7458 [self updateCollectionBehavior];
7460 if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
7462 [toolbar setVisible:YES];
7463 update_frame_tool_bar (emacsframe);
7464 [self updateFrameSize:YES];
7465 [[self window] display];
7468 [toolbar setVisible:NO];
7470 if (next_maximized != -1)
7471 [[self window] performZoom:self];
7476 return fs_is_native;
7479 - (BOOL)isFullscreen
7485 res = (nonfs_window != nil);
7489 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7490 res = (([[self window] styleMask] & NSWindowStyleMaskFullScreen) != 0);
7496 NSTRACE ("[EmacsView isFullscreen] " NSTRACE_FMT_RETURN " %d",
7502 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7503 - (void)updateCollectionBehavior
7505 NSTRACE ("[EmacsView updateCollectionBehavior]");
7507 if (! [self isFullscreen])
7509 NSWindow *win = [self window];
7510 NSWindowCollectionBehavior b = [win collectionBehavior];
7511 if (ns_use_native_fullscreen)
7512 b |= NSWindowCollectionBehaviorFullScreenPrimary;
7514 b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
7516 [win setCollectionBehavior: b];
7517 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7518 if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7520 fs_is_native = ns_use_native_fullscreen;
7525 - (void)toggleFullScreen: (id)sender
7533 NSTRACE ("[EmacsView toggleFullScreen:]");
7537 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7538 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7539 if ([[self window] respondsToSelector: @selector(toggleFullScreen:)])
7541 [[self window] toggleFullScreen:sender];
7547 onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
7550 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7551 (FACE_FROM_ID (f, DEFAULT_FACE_ID)),
7554 if (fs_state != FULLSCREEN_BOTH)
7556 NSScreen *screen = [w screen];
7558 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
7559 /* Hide ghost menu bar on secondary monitor? */
7561 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
7562 && [NSScreen respondsToSelector: @selector(screensHaveSeparateSpaces)]
7565 onFirstScreen = [NSScreen screensHaveSeparateSpaces];
7567 /* Hide dock and menubar if we are on the primary screen. */
7570 #ifdef NS_IMPL_COCOA
7571 NSApplicationPresentationOptions options
7572 = NSApplicationPresentationAutoHideDock
7573 | NSApplicationPresentationAutoHideMenuBar;
7575 [NSApp setPresentationOptions: options];
7577 [NSMenu setMenuBarVisible:NO];
7581 fw = [[EmacsFSWindow alloc]
7582 initWithContentRect:[w contentRectForFrameRect:wr]
7583 styleMask:NSWindowStyleMaskBorderless
7584 backing:NSBackingStoreBuffered
7588 [fw setContentView:[w contentView]];
7589 [fw setTitle:[w title]];
7590 [fw setDelegate:self];
7591 [fw setAcceptsMouseMovedEvents: YES];
7592 #if !defined (NS_IMPL_COCOA) \
7593 || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7594 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7595 if ([fw respondsToSelector: @selector(useOptimizedDrawing:)])
7597 [fw useOptimizedDrawing: YES];
7599 [fw setBackgroundColor: col];
7600 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7603 f->border_width = 0;
7607 [self windowWillEnterFullScreen];
7608 [fw makeKeyAndOrderFront:NSApp];
7609 [fw makeFirstResponder:self];
7611 r = [fw frameRectForContentRect:[screen frame]];
7612 [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
7613 [self windowDidEnterFullScreen];
7624 #ifdef NS_IMPL_COCOA
7625 [NSApp setPresentationOptions: NSApplicationPresentationDefault];
7627 [NSMenu setMenuBarVisible:YES];
7631 [w setContentView:[fw contentView]];
7632 [w setBackgroundColor: col];
7633 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7636 f->border_width = bwidth;
7638 // to do: consider using [NSNotificationCenter postNotificationName:] to send notifications.
7640 [self windowWillExitFullScreen];
7641 [fw setFrame: [w frame] display:YES animate:ns_use_fullscreen_animation];
7643 [w makeKeyAndOrderFront:NSApp];
7644 [self windowDidExitFullScreen];
7645 [self updateFrameSize:YES];
7651 NSTRACE ("[EmacsView handleFS]");
7653 if (fs_state != emacsframe->want_fullscreen)
7655 if (fs_state == FULLSCREEN_BOTH)
7657 NSTRACE_MSG ("fs_state == FULLSCREEN_BOTH");
7658 [self toggleFullScreen:self];
7661 switch (emacsframe->want_fullscreen)
7663 case FULLSCREEN_BOTH:
7664 NSTRACE_MSG ("FULLSCREEN_BOTH");
7665 [self toggleFullScreen:self];
7667 case FULLSCREEN_WIDTH:
7668 NSTRACE_MSG ("FULLSCREEN_WIDTH");
7669 next_maximized = FULLSCREEN_WIDTH;
7670 if (fs_state != FULLSCREEN_BOTH)
7671 [[self window] performZoom:self];
7673 case FULLSCREEN_HEIGHT:
7674 NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7675 next_maximized = FULLSCREEN_HEIGHT;
7676 if (fs_state != FULLSCREEN_BOTH)
7677 [[self window] performZoom:self];
7679 case FULLSCREEN_MAXIMIZED:
7680 NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7681 next_maximized = FULLSCREEN_MAXIMIZED;
7682 if (fs_state != FULLSCREEN_BOTH)
7683 [[self window] performZoom:self];
7685 case FULLSCREEN_NONE:
7686 NSTRACE_MSG ("FULLSCREEN_NONE");
7687 if (fs_state != FULLSCREEN_BOTH)
7689 next_maximized = FULLSCREEN_NONE;
7690 [[self window] performZoom:self];
7695 emacsframe->want_fullscreen = FULLSCREEN_NONE;
7700 - (void) setFSValue: (int)value
7702 NSTRACE ("[EmacsView setFSValue:" NSTRACE_FMT_FSTYPE "]",
7703 NSTRACE_ARG_FSTYPE(value));
7705 Lisp_Object lval = Qnil;
7708 case FULLSCREEN_BOTH:
7711 case FULLSCREEN_WIDTH:
7714 case FULLSCREEN_HEIGHT:
7717 case FULLSCREEN_MAXIMIZED:
7721 store_frame_param (emacsframe, Qfullscreen, lval);
7725 - (void)mouseEntered: (NSEvent *)theEvent
7727 NSTRACE ("[EmacsView mouseEntered:]");
7729 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7730 = EV_TIMESTAMP (theEvent);
7734 - (void)mouseExited: (NSEvent *)theEvent
7736 Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
7738 NSTRACE ("[EmacsView mouseExited:]");
7743 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7744 = EV_TIMESTAMP (theEvent);
7746 if (emacsframe == hlinfo->mouse_face_mouse_frame)
7748 clear_mouse_face (hlinfo);
7749 hlinfo->mouse_face_mouse_frame = 0;
7754 - (instancetype)menuDown: sender
7756 NSTRACE ("[EmacsView menuDown:]");
7757 if (context_menu_value == -1)
7758 context_menu_value = [sender tag];
7761 NSInteger tag = [sender tag];
7762 find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
7763 emacsframe->menu_bar_vector,
7767 ns_send_appdefined (-1);
7772 - (EmacsToolbar *)toolbar
7778 /* this gets called on toolbar button click */
7779 - (instancetype)toolbarClicked: (id)item
7782 int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
7784 NSTRACE ("[EmacsView toolbarClicked:]");
7789 /* send first event (for some reason two needed) */
7790 theEvent = [[self window] currentEvent];
7791 emacs_event->kind = TOOL_BAR_EVENT;
7792 XSETFRAME (emacs_event->arg, emacsframe);
7793 EV_TRAILER (theEvent);
7795 emacs_event->kind = TOOL_BAR_EVENT;
7796 /* XSETINT (emacs_event->code, 0); */
7797 emacs_event->arg = AREF (emacsframe->tool_bar_items,
7798 idx + TOOL_BAR_ITEM_KEY);
7799 emacs_event->modifiers = EV_MODIFIERS (theEvent);
7800 EV_TRAILER (theEvent);
7805 - (instancetype)toggleToolbar: (id)sender
7807 NSTRACE ("[EmacsView toggleToolbar:]");
7812 emacs_event->kind = NS_NONKEY_EVENT;
7813 emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
7814 EV_TRAILER ((id)nil);
7819 - (void)drawRect: (NSRect)rect
7821 int x = NSMinX (rect), y = NSMinY (rect);
7822 int width = NSWidth (rect), height = NSHeight (rect);
7824 NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
7825 NSTRACE_ARG_RECT(rect));
7827 if (!emacsframe || !emacsframe->output_data.ns)
7830 ns_clear_frame_area (emacsframe, x, y, width, height);
7832 expose_frame (emacsframe, x, y, width, height);
7836 drawRect: may be called (at least in Mac OS X 10.5) for invisible
7837 views as well for some reason. Thus, do not infer visibility
7840 emacsframe->async_visible = 1;
7841 emacsframe->async_iconified = 0;
7846 /* NSDraggingDestination protocol methods. Actually this is not really a
7847 protocol, but a category of Object. O well... */
7849 -(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
7851 NSTRACE ("[EmacsView draggingEntered:]");
7852 return NSDragOperationGeneric;
7856 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
7862 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
7867 NSEvent *theEvent = [[self window] currentEvent];
7869 NSDragOperation op = [sender draggingSourceOperationMask];
7872 NSTRACE ("[EmacsView performDragOperation:]");
7877 position = [self convertPoint: [sender draggingLocation] fromView: nil];
7878 x = lrint (position.x); y = lrint (position.y);
7880 pb = [sender draggingPasteboard];
7881 type = [pb availableTypeFromArray: ns_drag_types];
7883 if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
7884 // URL drags contain all operations (0xf), don't allow all to be set.
7887 if (op & NSDragOperationLink)
7888 modifiers |= NSEventModifierFlagControl;
7889 if (op & NSDragOperationCopy)
7890 modifiers |= NSEventModifierFlagOption;
7891 if (op & NSDragOperationGeneric)
7892 modifiers |= NSEventModifierFlagCommand;
7895 modifiers = EV_MODIFIERS2 (modifiers);
7900 else if ([type isEqualToString: NSFilenamesPboardType])
7903 NSEnumerator *fenum;
7906 if (!(files = [pb propertyListForType: type]))
7909 fenum = [files objectEnumerator];
7910 while ( (file = [fenum nextObject]) )
7912 emacs_event->kind = DRAG_N_DROP_EVENT;
7913 XSETINT (emacs_event->x, x);
7914 XSETINT (emacs_event->y, y);
7915 ns_input_file = append2 (ns_input_file,
7916 build_string ([file UTF8String]));
7917 emacs_event->modifiers = modifiers;
7918 emacs_event->arg = list2 (Qfile, build_string ([file UTF8String]));
7919 EV_TRAILER (theEvent);
7923 else if ([type isEqualToString: NSURLPboardType])
7925 NSURL *url = [NSURL URLFromPasteboard: pb];
7926 if (url == nil) return NO;
7928 emacs_event->kind = DRAG_N_DROP_EVENT;
7929 XSETINT (emacs_event->x, x);
7930 XSETINT (emacs_event->y, y);
7931 emacs_event->modifiers = modifiers;
7932 emacs_event->arg = list2 (Qurl,
7933 build_string ([[url absoluteString]
7935 EV_TRAILER (theEvent);
7937 if ([url isFileURL] != NO)
7939 NSString *file = [url path];
7940 ns_input_file = append2 (ns_input_file,
7941 build_string ([file UTF8String]));
7945 else if ([type isEqualToString: NSStringPboardType]
7946 || [type isEqualToString: NSTabularTextPboardType])
7950 if (! (data = [pb stringForType: type]))
7953 emacs_event->kind = DRAG_N_DROP_EVENT;
7954 XSETINT (emacs_event->x, x);
7955 XSETINT (emacs_event->y, y);
7956 emacs_event->modifiers = modifiers;
7957 emacs_event->arg = list2 (Qnil, build_string ([data UTF8String]));
7958 EV_TRAILER (theEvent);
7963 fprintf (stderr, "Invalid data type in dragging pasteboard");
7969 - (id) validRequestorForSendType: (NSString *)typeSent
7970 returnType: (NSString *)typeReturned
7972 NSTRACE ("[EmacsView validRequestorForSendType:returnType:]");
7973 if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
7974 && typeReturned == nil)
7976 if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
7980 return [super validRequestorForSendType: typeSent
7981 returnType: typeReturned];
7985 /* The next two methods are part of NSServicesRequests informal protocol,
7986 supposedly called when a services menu item is chosen from this app.
7987 But this should not happen because we override the services menu with our
7988 own entries which call ns-perform-service.
7989 Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
7990 So let's at least stub them out until further investigation can be done. */
7992 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
7994 /* we could call ns_string_from_pasteboard(pboard) here but then it should
7995 be written into the buffer in place of the existing selection..
7996 ordinary service calls go through functions defined in ns-win.el */
8000 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
8002 NSArray *typesDeclared;
8005 NSTRACE ("[EmacsView writeSelectionToPasteboard:types:]");
8007 /* We only support NSStringPboardType */
8008 if ([types containsObject:NSStringPboardType] == NO) {
8012 val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8013 if (CONSP (val) && SYMBOLP (XCAR (val)))
8016 if (CONSP (val) && NILP (XCDR (val)))
8019 if (! STRINGP (val))
8022 typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
8023 [pb declareTypes:typesDeclared owner:nil];
8024 ns_string_to_pasteboard (pb, val);
8029 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
8030 (gives a miniaturized version of the window); currently we use the latter for
8031 frames whose active buffer doesn't correspond to any file
8032 (e.g., '*scratch*') */
8033 - (instancetype)setMiniwindowImage: (BOOL) setMini
8035 id image = [[self window] miniwindowImage];
8036 NSTRACE ("[EmacsView setMiniwindowImage:%d]", setMini);
8038 /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
8039 about "AppleDockIconEnabled" notwithstanding, however the set message
8040 below has its effect nonetheless. */
8041 if (image != emacsframe->output_data.ns->miniimage)
8043 if (image && [image isKindOfClass: [EmacsImage class]])
8045 [[self window] setMiniwindowImage:
8046 setMini ? emacsframe->output_data.ns->miniimage : nil];
8053 - (void) setRows: (int) r andColumns: (int) c
8055 NSTRACE ("[EmacsView setRows:%d andColumns:%d]", r, c);
8060 - (int) fullscreenState
8065 @end /* EmacsView */
8069 /* ==========================================================================
8071 EmacsWindow implementation
8073 ========================================================================== */
8075 @implementation EmacsWindow
8077 #ifdef NS_IMPL_COCOA
8078 - (id)accessibilityAttributeValue:(NSString *)attribute
8080 Lisp_Object str = Qnil;
8081 struct frame *f = SELECTED_FRAME ();
8082 struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
8084 NSTRACE ("[EmacsWindow accessibilityAttributeValue:]");
8086 if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
8087 return NSAccessibilityTextFieldRole;
8089 if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
8090 && curbuf && ! NILP (BVAR (curbuf, mark_active)))
8092 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8094 else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
8096 if (! NILP (BVAR (curbuf, mark_active)))
8097 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8101 ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
8102 ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
8103 ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
8105 if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
8106 str = make_uninit_multibyte_string (range, byte_range);
8108 str = make_uninit_string (range);
8109 /* To check: This returns emacs-utf-8, which is a superset of utf-8.
8110 Is this a problem? */
8111 memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
8118 if (CONSP (str) && SYMBOLP (XCAR (str)))
8121 if (CONSP (str) && NILP (XCDR (str)))
8126 const char *utfStr = SSDATA (str);
8127 NSString *nsStr = [NSString stringWithUTF8String: utfStr];
8132 return [super accessibilityAttributeValue:attribute];
8134 #endif /* NS_IMPL_COCOA */
8136 /* Constrain size and placement of a frame.
8138 By returning the original "frameRect", the frame is not
8139 constrained. This can lead to unwanted situations where, for
8140 example, the menu bar covers the frame.
8142 The default implementation (accessed using "super") constrains the
8143 frame to the visible area of SCREEN, minus the menu bar (if
8144 present) and the Dock. Note that default implementation also calls
8145 windowWillResize, with the frame it thinks should have. (This can
8146 make the frame exit maximized mode.)
8148 Note that this should work in situations where multiple monitors
8149 are present. Common configurations are side-by-side monitors and a
8150 monitor on top of another (e.g. when a laptop is placed under a
8152 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
8154 NSTRACE ("[EmacsWindow constrainFrameRect:" NSTRACE_FMT_RECT " toScreen:]",
8155 NSTRACE_ARG_RECT (frameRect));
8157 #ifdef NS_IMPL_COCOA
8158 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
8159 // If separate spaces is on, it is like each screen is independent. There is
8160 // no spanning of frames across screens.
8162 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
8163 [NSScreen respondsToSelector: @selector(screensHaveSeparateSpaces)] &&
8165 [NSScreen screensHaveSeparateSpaces])
8167 NSTRACE_MSG ("Screens have separate spaces");
8168 frameRect = [super constrainFrameRect:frameRect toScreen:screen];
8169 NSTRACE_RETURN_RECT (frameRect);
8173 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 */
8175 // Check that the proposed frameRect is visible in at least one
8176 // screen. If it is not, ask the system to reposition it (only
8177 // for non-child windows).
8179 if (!FRAME_PARENT_FRAME (((EmacsView *)[self delegate])->emacsframe))
8181 NSArray *screens = [NSScreen screens];
8182 NSUInteger nr_screens = [screens count];
8185 BOOL frame_on_screen = NO;
8187 for (i = 0; i < nr_screens; ++i)
8189 NSScreen *s = [screens objectAtIndex: i];
8190 NSRect scrRect = [s frame];
8192 if (NSIntersectsRect(frameRect, scrRect))
8194 frame_on_screen = YES;
8199 if (!frame_on_screen)
8201 NSTRACE_MSG ("Frame outside screens; constraining");
8202 frameRect = [super constrainFrameRect:frameRect toScreen:screen];
8203 NSTRACE_RETURN_RECT (frameRect);
8209 return constrain_frame_rect(frameRect,
8210 [(EmacsView *)[self delegate] isFullscreen]);
8214 - (void)performZoom:(id)sender
8216 NSTRACE ("[EmacsWindow performZoom:]");
8218 return [super performZoom:sender];
8221 - (void)zoom:(id)sender
8223 NSTRACE ("[EmacsWindow zoom:]");
8225 ns_update_auto_hide_menu_bar();
8227 // Below are three zoom implementations. In the final commit, the
8228 // idea is that the last should be included.
8231 // Native zoom done using the standard zoom animation. Size of the
8232 // resulting frame reduced to accommodate the Dock and, if present,
8234 [super zoom:sender];
8237 // Native zoom done using the standard zoom animation, plus an
8238 // explicit resize to cover the full screen, except the menu-bar and
8239 // dock, if present.
8240 [super zoom:sender];
8242 // After the native zoom, resize the resulting frame to fill the
8243 // entire screen, except the menu-bar.
8245 // This works for all practical purposes. (The only minor oddity is
8246 // when transiting from full-height frame to a maximized, the
8247 // animation reduces the height of the frame slightly (to the 4
8248 // pixels needed to accommodate the Doc) before it snaps back into
8249 // full height. The user would need a very trained eye to spot
8251 NSScreen * screen = [self screen];
8254 int fs_state = [(EmacsView *)[self delegate] fullscreenState];
8256 NSTRACE_FSTYPE ("fullscreenState", fs_state);
8258 NSRect sr = [screen frame];
8259 struct EmacsMargins margins
8260 = ns_screen_margins_ignoring_hidden_dock(screen);
8262 NSRect wr = [self frame];
8263 NSTRACE_RECT ("Rect after zoom", wr);
8267 if (fs_state == FULLSCREEN_MAXIMIZED
8268 || fs_state == FULLSCREEN_HEIGHT)
8270 newWr.origin.y = sr.origin.y + margins.bottom;
8271 newWr.size.height = sr.size.height - margins.top - margins.bottom;
8274 if (fs_state == FULLSCREEN_MAXIMIZED
8275 || fs_state == FULLSCREEN_WIDTH)
8277 newWr.origin.x = sr.origin.x + margins.left;
8278 newWr.size.width = sr.size.width - margins.right - margins.left;
8281 if (newWr.size.width != wr.size.width
8282 || newWr.size.height != wr.size.height
8283 || newWr.origin.x != wr.origin.x
8284 || newWr.origin.y != wr.origin.y)
8286 NSTRACE_MSG ("New frame different");
8287 [self setFrame: newWr display: NO];
8291 // Non-native zoom which is done instantaneously. The resulting
8292 // frame covers the entire screen, except the menu-bar and dock, if
8294 NSScreen * screen = [self screen];
8297 NSRect sr = [screen frame];
8298 struct EmacsMargins margins
8299 = ns_screen_margins_ignoring_hidden_dock(screen);
8301 sr.size.height -= (margins.top + margins.bottom);
8302 sr.size.width -= (margins.left + margins.right);
8303 sr.origin.x += margins.left;
8304 sr.origin.y += margins.bottom;
8306 sr = [[self delegate] windowWillUseStandardFrame:self
8308 [self setFrame: sr display: NO];
8313 - (void)setFrame:(NSRect)windowFrame
8314 display:(BOOL)displayViews
8316 NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT " display:%d]",
8317 NSTRACE_ARG_RECT (windowFrame), displayViews);
8319 [super setFrame:windowFrame display:displayViews];
8322 - (void)setFrame:(NSRect)windowFrame
8323 display:(BOOL)displayViews
8324 animate:(BOOL)performAnimation
8326 NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT
8327 " display:%d performAnimation:%d]",
8328 NSTRACE_ARG_RECT (windowFrame), displayViews, performAnimation);
8330 [super setFrame:windowFrame display:displayViews animate:performAnimation];
8333 - (void)setFrameTopLeftPoint:(NSPoint)point
8335 NSTRACE ("[EmacsWindow setFrameTopLeftPoint:" NSTRACE_FMT_POINT "]",
8336 NSTRACE_ARG_POINT (point));
8338 [super setFrameTopLeftPoint:point];
8341 - (BOOL)canBecomeKeyWindow
8343 return !FRAME_NO_ACCEPT_FOCUS (((EmacsView *)[self delegate])->emacsframe);
8345 @end /* EmacsWindow */
8348 @implementation EmacsFSWindow
8350 - (BOOL)canBecomeKeyWindow
8355 - (BOOL)canBecomeMainWindow
8362 /* ==========================================================================
8364 EmacsScroller implementation
8366 ========================================================================== */
8369 @implementation EmacsScroller
8371 /* for repeat button push */
8372 #define SCROLL_BAR_FIRST_DELAY 0.5
8373 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
8375 + (CGFloat) scrollerWidth
8377 /* TODO: if we want to allow variable widths, this is the place to do it,
8378 however neither GNUstep nor Cocoa support it very well */
8380 #if defined (NS_IMPL_COCOA) \
8381 && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
8382 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
8383 if ([NSScroller respondsToSelector:
8384 @selector(scrollerWidthForControlSize:scrollerStyle:)])
8386 r = [NSScroller scrollerWidthForControlSize: NSControlSizeRegular
8387 scrollerStyle: NSScrollerStyleLegacy];
8388 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
8391 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
8392 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 \
8393 || defined (NS_IMPL_GNUSTEP)
8394 r = [NSScroller scrollerWidth];
8399 - (instancetype)initFrame: (NSRect )r window: (Lisp_Object)nwin
8401 NSTRACE ("[EmacsScroller initFrame: window:]");
8403 if (r.size.width > r.size.height)
8408 [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
8409 [self setContinuous: YES];
8410 [self setEnabled: YES];
8412 /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
8413 locked against the top and bottom edges, and right edge on macOS, where
8414 scrollers are on right. */
8415 #ifdef NS_IMPL_GNUSTEP
8416 [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
8418 [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
8421 window = XWINDOW (nwin);
8424 pixel_length = NSWidth (r);
8426 pixel_length = NSHeight (r);
8427 if (pixel_length == 0) pixel_length = 1;
8428 min_portion = 20 / pixel_length;
8430 frame = XFRAME (window->frame);
8431 if (FRAME_LIVE_P (frame))
8434 EmacsView *view = FRAME_NS_VIEW (frame);
8435 NSView *sview = [[view window] contentView];
8436 NSArray *subs = [sview subviews];
8438 /* disable optimization stopping redraw of other scrollbars */
8439 view->scrollbarsNeedingUpdate = 0;
8440 for (i =[subs count]-1; i >= 0; i--)
8441 if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
8442 view->scrollbarsNeedingUpdate++;
8443 [sview addSubview: self];
8446 /* [self setFrame: r]; */
8452 - (void)setFrame: (NSRect)newRect
8454 NSTRACE ("[EmacsScroller setFrame:]");
8456 /* block_input (); */
8458 pixel_length = NSWidth (newRect);
8460 pixel_length = NSHeight (newRect);
8461 if (pixel_length == 0) pixel_length = 1;
8462 min_portion = 20 / pixel_length;
8463 [super setFrame: newRect];
8464 /* unblock_input (); */
8470 NSTRACE ("[EmacsScroller dealloc]");
8474 wset_horizontal_scroll_bar (window, Qnil);
8476 wset_vertical_scroll_bar (window, Qnil);
8483 - (instancetype)condemn
8485 NSTRACE ("[EmacsScroller condemn]");
8491 - (instancetype)reprieve
8493 NSTRACE ("[EmacsScroller reprieve]");
8501 NSTRACE ("[EmacsScroller judge]");
8502 bool ret = condemned;
8507 /* ensure other scrollbar updates after deletion */
8508 view = (EmacsView *)FRAME_NS_VIEW (frame);
8510 view->scrollbarsNeedingUpdate++;
8514 wset_horizontal_scroll_bar (window, Qnil);
8516 wset_vertical_scroll_bar (window, Qnil);
8519 [self removeFromSuperview];
8527 - (void)resetCursorRects
8529 NSRect visible = [self visibleRect];
8530 NSTRACE ("[EmacsScroller resetCursorRects]");
8532 if (!NSIsEmptyRect (visible))
8533 [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
8534 [[NSCursor arrowCursor] setOnMouseEntered: YES];
8538 - (int) checkSamePosition: (int) position portion: (int) portion
8541 return em_position ==position && em_portion ==portion && em_whole ==whole
8542 && portion != whole; /* needed for resize empty buf */
8546 - (instancetype)setPosition: (int)position portion: (int)portion whole: (int)whole
8548 NSTRACE ("[EmacsScroller setPosition:portion:whole:]");
8550 em_position = position;
8551 em_portion = portion;
8554 if (portion >= whole)
8556 #ifdef NS_IMPL_COCOA
8557 [self setKnobProportion: 1.0];
8558 [self setDoubleValue: 1.0];
8560 [self setFloatValue: 0.0 knobProportion: 1.0];
8567 portion = max ((float)whole*min_portion/pixel_length, portion);
8568 pos = (float)position / (whole - portion);
8569 por = (CGFloat)portion/whole;
8570 #ifdef NS_IMPL_COCOA
8571 [self setKnobProportion: por];
8572 [self setDoubleValue: pos];
8574 [self setFloatValue: pos knobProportion: por];
8581 /* set up emacs_event */
8582 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
8586 NSTRACE ("[EmacsScroller sendScrollEventAtLoc:fromEvent:]");
8591 emacs_event->part = last_hit_part;
8592 emacs_event->code = 0;
8593 emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
8594 XSETWINDOW (win, window);
8595 emacs_event->frame_or_window = win;
8596 emacs_event->timestamp = EV_TIMESTAMP (e);
8597 emacs_event->arg = Qnil;
8601 emacs_event->kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT;
8602 XSETINT (emacs_event->x, em_whole * loc / pixel_length);
8603 XSETINT (emacs_event->y, em_whole);
8607 emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
8608 XSETINT (emacs_event->x, loc);
8609 XSETINT (emacs_event->y, pixel_length-20);
8614 n_emacs_events_pending++;
8615 kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
8618 hold_event (emacs_event);
8619 EVENT_INIT (*emacs_event);
8620 ns_send_appdefined (-1);
8624 /* called manually thru timer to implement repeated button action w/hold-down */
8625 - (instancetype)repeatScroll: (NSTimer *)scrollEntry
8627 NSEvent *e = [[self window] currentEvent];
8628 NSPoint p = [[self window] mouseLocationOutsideOfEventStream];
8629 BOOL inKnob = [self testPart: p] == NSScrollerKnob;
8631 NSTRACE ("[EmacsScroller repeatScroll:]");
8633 /* clear timer if need be */
8634 if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
8636 [scroll_repeat_entry invalidate];
8637 [scroll_repeat_entry release];
8638 scroll_repeat_entry = nil;
8644 = [[NSTimer scheduledTimerWithTimeInterval:
8645 SCROLL_BAR_CONTINUOUS_DELAY
8647 selector: @selector (repeatScroll:)
8653 [self sendScrollEventAtLoc: 0 fromEvent: e];
8658 /* Asynchronous mouse tracking for scroller. This allows us to dispatch
8659 mouseDragged events without going into a modal loop. */
8660 - (void)mouseDown: (NSEvent *)e
8663 /* hitPart is only updated AFTER event is passed on */
8664 NSScrollerPart part = [self testPart: [e locationInWindow]];
8665 CGFloat loc, kloc, pos UNINIT;
8668 NSTRACE ("[EmacsScroller mouseDown:]");
8672 case NSScrollerDecrementPage:
8673 last_hit_part = horizontal ? scroll_bar_before_handle : scroll_bar_above_handle; break;
8674 case NSScrollerIncrementPage:
8675 last_hit_part = horizontal ? scroll_bar_after_handle : scroll_bar_below_handle; break;
8676 case NSScrollerDecrementLine:
8677 last_hit_part = horizontal ? scroll_bar_left_arrow : scroll_bar_up_arrow; break;
8678 case NSScrollerIncrementLine:
8679 last_hit_part = horizontal ? scroll_bar_right_arrow : scroll_bar_down_arrow; break;
8680 case NSScrollerKnob:
8681 last_hit_part = horizontal ? scroll_bar_horizontal_handle : scroll_bar_handle; break;
8682 case NSScrollerKnobSlot: /* GNUstep-only */
8683 last_hit_part = scroll_bar_move_ratio; break;
8684 default: /* NSScrollerNoPart? */
8685 fprintf (stderr, "EmacsScroller-mouseDown: unexpected part %ld\n",
8690 if (part == NSScrollerKnob || part == NSScrollerKnobSlot)
8692 /* handle, or on GNUstep possibly slot */
8693 NSEvent *fake_event;
8696 /* compute float loc in slot and mouse offset on knob */
8697 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8701 length = NSWidth (sr);
8702 loc = ([e locationInWindow].x - NSMinX (sr));
8706 length = NSHeight (sr);
8707 loc = length - ([e locationInWindow].y - NSMinY (sr));
8715 else if (loc >= length)
8725 kr = [self convertRect: [self rectForPart: NSScrollerKnob]
8728 kloc = ([e locationInWindow].x - NSMinX (kr));
8730 kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
8732 last_mouse_offset = kloc;
8734 if (part != NSScrollerKnob)
8735 /* this is a slot click on GNUstep: go straight there */
8738 /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
8739 fake_event = [NSEvent mouseEventWithType: NSEventTypeLeftMouseUp
8740 location: [e locationInWindow]
8741 modifierFlags: [e modifierFlags]
8742 timestamp: [e timestamp]
8743 windowNumber: [e windowNumber]
8745 eventNumber: [e eventNumber]
8746 clickCount: [e clickCount]
8747 pressure: [e pressure]];
8748 [super mouseUp: fake_event];
8752 pos = 0; /* ignored */
8754 /* set a timer to repeat, as we can't let superclass do this modally */
8756 = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
8758 selector: @selector (repeatScroll:)
8764 if (part != NSScrollerKnob)
8765 [self sendScrollEventAtLoc: pos fromEvent: e];
8769 /* Called as we manually track scroller drags, rather than superclass. */
8770 - (void)mouseDragged: (NSEvent *)e
8776 NSTRACE ("[EmacsScroller mouseDragged:]");
8778 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8783 length = NSWidth (sr);
8784 loc = ([e locationInWindow].x - NSMinX (sr));
8788 length = NSHeight (sr);
8789 loc = length - ([e locationInWindow].y - NSMinY (sr));
8796 else if (loc >= length + last_mouse_offset)
8798 loc = length + last_mouse_offset;
8801 pos = (loc - last_mouse_offset);
8802 [self sendScrollEventAtLoc: pos fromEvent: e];
8806 - (void)mouseUp: (NSEvent *)e
8808 NSTRACE ("[EmacsScroller mouseUp:]");
8810 if (scroll_repeat_entry)
8812 [scroll_repeat_entry invalidate];
8813 [scroll_repeat_entry release];
8814 scroll_repeat_entry = nil;
8816 last_hit_part = scroll_bar_above_handle;
8820 /* treat scrollwheel events in the bar as though they were in the main window */
8821 - (void) scrollWheel: (NSEvent *)theEvent
8823 NSTRACE ("[EmacsScroller scrollWheel:]");
8825 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
8826 [view mouseDown: theEvent];
8829 @end /* EmacsScroller */
8832 #ifdef NS_IMPL_GNUSTEP
8833 /* Dummy class to get rid of startup warnings. */
8834 @implementation EmacsDocument
8840 /* ==========================================================================
8842 Font-related functions; these used to be in nsfaces.m
8844 ========================================================================== */
8848 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
8850 struct font *font = XFONT_OBJECT (font_object);
8851 EmacsView *view = FRAME_NS_VIEW (f);
8852 int font_ascent, font_descent;
8855 fontset = fontset_from_font (font_object);
8856 FRAME_FONTSET (f) = fontset;
8858 if (FRAME_FONT (f) == font)
8859 /* This font is already set in frame F. There's nothing more to
8863 FRAME_FONT (f) = font;
8865 FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
8866 FRAME_COLUMN_WIDTH (f) = font->average_width;
8867 get_font_ascent_descent (font, &font_ascent, &font_descent);
8868 FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
8870 /* Compute the scroll bar width in character columns. */
8871 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
8873 int wid = FRAME_COLUMN_WIDTH (f);
8874 FRAME_CONFIG_SCROLL_BAR_COLS (f)
8875 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
8879 int wid = FRAME_COLUMN_WIDTH (f);
8880 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
8883 /* Compute the scroll bar height in character lines. */
8884 if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0)
8886 int height = FRAME_LINE_HEIGHT (f);
8887 FRAME_CONFIG_SCROLL_BAR_LINES (f)
8888 = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
8892 int height = FRAME_LINE_HEIGHT (f);
8893 FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
8896 /* Now make the frame display the given font. */
8897 if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
8898 adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
8899 FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
8906 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
8907 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
8911 ns_xlfd_to_fontname (const char *xlfd)
8912 /* --------------------------------------------------------------------------
8913 Convert an X font name (XLFD) to an NS font name.
8914 Only family is used.
8915 The string returned is temporarily allocated.
8916 -------------------------------------------------------------------------- */
8918 char *name = xmalloc (180);
8922 if (!strncmp (xlfd, "--", 2))
8923 sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
8925 sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
8927 /* stopgap for malformed XLFD input */
8928 if (strlen (name) == 0)
8929 strcpy (name, "Monaco");
8931 /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
8932 also uppercase after '-' or ' ' */
8933 name[0] = c_toupper (name[0]);
8934 for (len =strlen (name), i =0; i<len; i++)
8940 name[i+1] = c_toupper (name[i+1]);
8942 else if (name[i] == '_')
8946 name[i+1] = c_toupper (name[i+1]);
8949 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name); */
8950 ret = [[NSString stringWithUTF8String: name] UTF8String];
8957 syms_of_nsterm (void)
8959 NSTRACE ("syms_of_nsterm");
8961 ns_antialias_threshold = 10.0;
8963 /* from 23+ we need to tell emacs what modifiers there are.. */
8964 DEFSYM (Qmodifier_value, "modifier-value");
8965 DEFSYM (Qalt, "alt");
8966 DEFSYM (Qhyper, "hyper");
8967 DEFSYM (Qmeta, "meta");
8968 DEFSYM (Qsuper, "super");
8969 DEFSYM (Qcontrol, "control");
8970 DEFSYM (QUTF8_STRING, "UTF8_STRING");
8972 DEFSYM (Qfile, "file");
8973 DEFSYM (Qurl, "url");
8975 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
8976 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
8977 Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
8978 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
8979 Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
8981 DEFVAR_LISP ("ns-input-file", ns_input_file,
8982 "The file specified in the last NS event.");
8983 ns_input_file =Qnil;
8985 DEFVAR_LISP ("ns-working-text", ns_working_text,
8986 "String for visualizing working composition sequence.");
8987 ns_working_text =Qnil;
8989 DEFVAR_LISP ("ns-input-font", ns_input_font,
8990 "The font specified in the last NS event.");
8991 ns_input_font =Qnil;
8993 DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
8994 "The fontsize specified in the last NS event.");
8995 ns_input_fontsize =Qnil;
8997 DEFVAR_LISP ("ns-input-line", ns_input_line,
8998 "The line specified in the last NS event.");
8999 ns_input_line =Qnil;
9001 DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
9002 "The service name specified in the last NS event.");
9003 ns_input_spi_name =Qnil;
9005 DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
9006 "The service argument specified in the last NS event.");
9007 ns_input_spi_arg =Qnil;
9009 DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
9010 "This variable describes the behavior of the alternate or option key.\n\
9011 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9013 Set to none means that the alternate / option key is not interpreted by Emacs\n\
9014 at all, allowing it to be used at a lower level for accented character entry.");
9015 ns_alternate_modifier = Qmeta;
9017 DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
9018 "This variable describes the behavior of the right alternate or option key.\n\
9019 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9021 Set to left means be the same key as `ns-alternate-modifier'.\n\
9022 Set to none means that the alternate / option key is not interpreted by Emacs\n\
9023 at all, allowing it to be used at a lower level for accented character entry.");
9024 ns_right_alternate_modifier = Qleft;
9026 DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
9027 "This variable describes the behavior of the command key.\n\
9028 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9030 ns_command_modifier = Qsuper;
9032 DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
9033 "This variable describes the behavior of the right command key.\n\
9034 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9036 Set to left means be the same key as `ns-command-modifier'.\n\
9037 Set to none means that the command / option key is not interpreted by Emacs\n\
9038 at all, allowing it to be used at a lower level for accented character entry.");
9039 ns_right_command_modifier = Qleft;
9041 DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
9042 "This variable describes the behavior of the control key.\n\
9043 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9045 ns_control_modifier = Qcontrol;
9047 DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
9048 "This variable describes the behavior of the right control key.\n\
9049 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9051 Set to left means be the same key as `ns-control-modifier'.\n\
9052 Set to none means that the control / option key is not interpreted by Emacs\n\
9053 at all, allowing it to be used at a lower level for accented character entry.");
9054 ns_right_control_modifier = Qleft;
9056 DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
9057 "This variable describes the behavior of the function key (on laptops).\n\
9058 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9060 Set to none means that the function key is not interpreted by Emacs at all,\n\
9061 allowing it to be used at a lower level for accented character entry.");
9062 ns_function_modifier = Qnone;
9064 DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
9065 "Non-nil (the default) means to render text antialiased.");
9066 ns_antialias_text = Qt;
9068 DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
9069 "Whether to confirm application quit using dialog.");
9070 ns_confirm_quit = Qnil;
9072 DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
9073 doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
9074 Only works on Mac OS X 10.6 or later. */);
9075 ns_auto_hide_menu_bar = Qnil;
9077 DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
9078 doc: /*Non-nil means to use native fullscreen on Mac OS X 10.7 and later.
9079 Nil means use fullscreen the old (< 10.7) way. The old way works better with
9080 multiple monitors, but lacks tool bar. This variable is ignored on
9081 Mac OS X < 10.7. Default is t. */);
9082 ns_use_native_fullscreen = YES;
9083 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
9085 DEFVAR_BOOL ("ns-use-fullscreen-animation", ns_use_fullscreen_animation,
9086 doc: /*Non-nil means use animation on non-native fullscreen.
9087 For native fullscreen, this does nothing.
9088 Default is nil. */);
9089 ns_use_fullscreen_animation = NO;
9091 DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
9092 doc: /*Non-nil means to use sRGB colorspace on Mac OS X 10.7 and later.
9093 Note that this does not apply to images.
9094 This variable is ignored on Mac OS X < 10.7 and GNUstep. */);
9095 ns_use_srgb_colorspace = YES;
9097 /* TODO: move to common code */
9098 DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
9099 doc: /* Which toolkit scroll bars Emacs uses, if any.
9100 A value of nil means Emacs doesn't use toolkit scroll bars.
9101 With the X Window system, the value is a symbol describing the
9102 X toolkit. Possible values are: gtk, motif, xaw, or xaw3d.
9103 With MS Windows or Nextstep, the value is t. */);
9104 Vx_toolkit_scroll_bars = Qt;
9106 DEFVAR_BOOL ("x-use-underline-position-properties",
9107 x_use_underline_position_properties,
9108 doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
9109 A value of nil means ignore them. If you encounter fonts with bogus
9110 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
9111 to 4.1, set this to nil. */);
9112 x_use_underline_position_properties = 0;
9114 DEFVAR_BOOL ("x-underline-at-descent-line",
9115 x_underline_at_descent_line,
9116 doc: /* Non-nil means to draw the underline at the same place as the descent line.
9117 A value of nil means to draw the underline according to the value of the
9118 variable `x-use-underline-position-properties', which is usually at the
9119 baseline level. The default value is nil. */);
9120 x_underline_at_descent_line = 0;
9122 /* Tell Emacs about this window system. */
9123 Fprovide (Qns, Qnil);
9125 DEFSYM (Qcocoa, "cocoa");
9126 DEFSYM (Qgnustep, "gnustep");
9128 #ifdef NS_IMPL_COCOA
9129 Fprovide (Qcocoa, Qnil);
9132 Fprovide (Qgnustep, Qnil);