1 /* NeXT/Open/GNUstep / macOS communication module. -*- coding: utf-8 -*-
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2018 Free Software
6 This file is part of GNU Emacs.
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or (at
11 your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
22 Originally by Carl Edman
23 Updated by Christian Limpach (chris@nice.ch)
24 OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
25 macOS/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
26 GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
29 /* This should be the first include, as it may set up #defines affecting
30 interpretation of even the system includes. */
36 #include <sys/types.h>
43 #include <c-strcase.h>
47 #include "blockinput.h"
48 #include "sysselect.h"
51 #include "character.h"
53 #include "composite.h"
56 #include "termhooks.h"
64 #ifdef NS_IMPL_GNUSTEP
70 #include <Carbon/Carbon.h>
73 static EmacsMenu *dockMenu;
75 static EmacsMenu *mainMenu;
78 /* ==========================================================================
80 NSTRACE, Trace support.
82 ========================================================================== */
86 /* The following use "volatile" since they can be accessed from
88 volatile int nstrace_num = 0;
89 volatile int nstrace_depth = 0;
91 /* When 0, no trace is emitted. This is used by NSTRACE_WHEN and
92 NSTRACE_UNLESS to silence functions called.
94 TODO: This should really be a thread-local variable, to avoid that
95 a function with disabled trace thread silence trace output in
96 another. However, in practice this seldom is a problem. */
97 volatile int nstrace_enabled_global = 1;
99 /* Called when nstrace_enabled goes out of scope. */
100 void nstrace_leave(int * pointer_to_nstrace_enabled)
102 if (*pointer_to_nstrace_enabled)
109 /* Called when nstrace_saved_enabled_global goes out of scope. */
110 void nstrace_restore_global_trace_state(int * pointer_to_saved_enabled_global)
112 nstrace_enabled_global = *pointer_to_saved_enabled_global;
116 char const * nstrace_fullscreen_type_name (int fs_type)
120 case -1: return "-1";
121 case FULLSCREEN_NONE: return "FULLSCREEN_NONE";
122 case FULLSCREEN_WIDTH: return "FULLSCREEN_WIDTH";
123 case FULLSCREEN_HEIGHT: return "FULLSCREEN_HEIGHT";
124 case FULLSCREEN_BOTH: return "FULLSCREEN_BOTH";
125 case FULLSCREEN_MAXIMIZED: return "FULLSCREEN_MAXIMIZED";
126 default: return "FULLSCREEN_?????";
132 /* ==========================================================================
134 NSColor, EmacsColor category.
136 ========================================================================== */
137 @implementation NSColor (EmacsColor)
138 + (NSColor *)colorForEmacsRed:(CGFloat)red green:(CGFloat)green
139 blue:(CGFloat)blue alpha:(CGFloat)alpha
141 #if defined (NS_IMPL_COCOA) \
142 && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
143 if (ns_use_srgb_colorspace
144 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
145 && [NSColor respondsToSelector:
146 @selector(colorWithSRGBRed:green:blue:alpha:)]
149 return [NSColor colorWithSRGBRed: red
154 return [NSColor colorWithCalibratedRed: red
160 - (NSColor *)colorUsingDefaultColorSpace
162 /* FIXMES: We're checking for colorWithSRGBRed here so this will
163 only work in the same place as in the method above. It should
164 really be a check whether we're on macOS 10.7 or above. */
165 #if defined (NS_IMPL_COCOA) \
166 && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
167 if (ns_use_srgb_colorspace
168 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
169 && [NSColor respondsToSelector:
170 @selector(colorWithSRGBRed:green:blue:alpha:)]
173 return [self colorUsingColorSpace: [NSColorSpace sRGBColorSpace]];
175 return [self colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
180 /* ==========================================================================
184 ========================================================================== */
186 /* Convert a symbol indexed with an NSxxx value to a value as defined
187 in keyboard.c (lispy_function_key). I hope this is a correct way
188 of doing things... */
189 static unsigned convert_ns_to_X_keysym[] =
191 NSHomeFunctionKey, 0x50,
192 NSLeftArrowFunctionKey, 0x51,
193 NSUpArrowFunctionKey, 0x52,
194 NSRightArrowFunctionKey, 0x53,
195 NSDownArrowFunctionKey, 0x54,
196 NSPageUpFunctionKey, 0x55,
197 NSPageDownFunctionKey, 0x56,
198 NSEndFunctionKey, 0x57,
199 NSBeginFunctionKey, 0x58,
200 NSSelectFunctionKey, 0x60,
201 NSPrintFunctionKey, 0x61,
202 NSClearLineFunctionKey, 0x0B,
203 NSExecuteFunctionKey, 0x62,
204 NSInsertFunctionKey, 0x63,
205 NSUndoFunctionKey, 0x65,
206 NSRedoFunctionKey, 0x66,
207 NSMenuFunctionKey, 0x67,
208 NSFindFunctionKey, 0x68,
209 NSHelpFunctionKey, 0x6A,
210 NSBreakFunctionKey, 0x6B,
212 NSF1FunctionKey, 0xBE,
213 NSF2FunctionKey, 0xBF,
214 NSF3FunctionKey, 0xC0,
215 NSF4FunctionKey, 0xC1,
216 NSF5FunctionKey, 0xC2,
217 NSF6FunctionKey, 0xC3,
218 NSF7FunctionKey, 0xC4,
219 NSF8FunctionKey, 0xC5,
220 NSF9FunctionKey, 0xC6,
221 NSF10FunctionKey, 0xC7,
222 NSF11FunctionKey, 0xC8,
223 NSF12FunctionKey, 0xC9,
224 NSF13FunctionKey, 0xCA,
225 NSF14FunctionKey, 0xCB,
226 NSF15FunctionKey, 0xCC,
227 NSF16FunctionKey, 0xCD,
228 NSF17FunctionKey, 0xCE,
229 NSF18FunctionKey, 0xCF,
230 NSF19FunctionKey, 0xD0,
231 NSF20FunctionKey, 0xD1,
232 NSF21FunctionKey, 0xD2,
233 NSF22FunctionKey, 0xD3,
234 NSF23FunctionKey, 0xD4,
235 NSF24FunctionKey, 0xD5,
237 NSBackspaceCharacter, 0x08, /* 8: Not on some KBs. */
238 NSDeleteCharacter, 0xFF, /* 127: Big 'delete' key upper right. */
239 NSDeleteFunctionKey, 0x9F, /* 63272: Del forw key off main array. */
241 NSTabCharacter, 0x09,
242 0x19, 0x09, /* left tab->regular since pass shift */
243 NSCarriageReturnCharacter, 0x0D,
244 NSNewlineCharacter, 0x0D,
245 NSEnterCharacter, 0x8D,
247 0x41|NSEventModifierFlagNumericPad, 0xAE, /* KP_Decimal */
248 0x43|NSEventModifierFlagNumericPad, 0xAA, /* KP_Multiply */
249 0x45|NSEventModifierFlagNumericPad, 0xAB, /* KP_Add */
250 0x4B|NSEventModifierFlagNumericPad, 0xAF, /* KP_Divide */
251 0x4E|NSEventModifierFlagNumericPad, 0xAD, /* KP_Subtract */
252 0x51|NSEventModifierFlagNumericPad, 0xBD, /* KP_Equal */
253 0x52|NSEventModifierFlagNumericPad, 0xB0, /* KP_0 */
254 0x53|NSEventModifierFlagNumericPad, 0xB1, /* KP_1 */
255 0x54|NSEventModifierFlagNumericPad, 0xB2, /* KP_2 */
256 0x55|NSEventModifierFlagNumericPad, 0xB3, /* KP_3 */
257 0x56|NSEventModifierFlagNumericPad, 0xB4, /* KP_4 */
258 0x57|NSEventModifierFlagNumericPad, 0xB5, /* KP_5 */
259 0x58|NSEventModifierFlagNumericPad, 0xB6, /* KP_6 */
260 0x59|NSEventModifierFlagNumericPad, 0xB7, /* KP_7 */
261 0x5B|NSEventModifierFlagNumericPad, 0xB8, /* KP_8 */
262 0x5C|NSEventModifierFlagNumericPad, 0xB9, /* KP_9 */
264 0x1B, 0x1B /* escape */
267 /* On macOS picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
268 the maximum font size to NOT antialias. On GNUstep there is currently
269 no way to control this behavior. */
270 float ns_antialias_threshold;
272 NSArray *ns_send_types = 0, *ns_return_types = 0;
273 static NSArray *ns_drag_types = 0;
274 NSString *ns_app_name = @"Emacs"; /* default changed later */
276 /* Display variables */
277 struct ns_display_info *x_display_list; /* Chain of existing displays */
278 long context_menu_value = 0;
281 static struct frame *ns_updating_frame;
282 static NSView *focus_view = NULL;
283 static int ns_window_num = 0;
284 #ifdef NS_IMPL_GNUSTEP
285 static NSRect uRect; // TODO: This is dead, remove it?
287 static BOOL gsaved = NO;
288 static BOOL ns_fake_keydown = NO;
290 static BOOL ns_menu_bar_is_hidden = NO;
292 /* The number of times NSDisableScreenUpdates has been called. */
293 static int disable_screen_updates_count = 0;
295 /* static int debug_lock = 0; */
298 static BOOL send_appdefined = YES;
299 #define NO_APPDEFINED_DATA (-8)
300 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
301 static NSTimer *timed_entry = 0;
302 static NSTimer *scroll_repeat_entry = nil;
303 static fd_set select_readfds, select_writefds;
304 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
305 static int select_nfds = 0, select_valid = 0;
306 static struct timespec select_timeout = { 0, 0 };
307 static int selfds[2] = { -1, -1 };
308 static pthread_mutex_t select_mutex;
309 static NSAutoreleasePool *outerpool;
310 static struct input_event *emacs_event = NULL;
311 static struct input_event *q_event_ptr = NULL;
312 static int n_emacs_events_pending = 0;
313 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
314 *ns_pending_service_args;
315 static BOOL ns_do_open_file = NO;
316 static BOOL ns_last_use_native_fullscreen;
318 /* Non-zero means that a HELP_EVENT has been generated since Emacs
321 static BOOL any_help_event_p = NO;
324 struct input_event *q;
330 static NSString *represented_filename = nil;
331 static struct frame *represented_frame = 0;
335 * State for pending menu activation:
336 * MENU_NONE Normal state
337 * MENU_PENDING A menu has been clicked on, but has been canceled so we can
338 * run lisp to update the menu.
339 * MENU_OPENING Menu is up to date, and the click event is redone so the menu
343 #define MENU_PENDING 1
344 #define MENU_OPENING 2
345 static int menu_will_open_state = MENU_NONE;
347 /* Saved position for menu click. */
348 static CGPoint menu_mouse_point;
351 /* Convert modifiers in a NeXTstep event to emacs style modifiers. */
352 #define NS_FUNCTION_KEY_MASK 0x800000
353 #define NSLeftControlKeyMask (0x000001 | NSEventModifierFlagControl)
354 #define NSRightControlKeyMask (0x002000 | NSEventModifierFlagControl)
355 #define NSLeftCommandKeyMask (0x000008 | NSEventModifierFlagCommand)
356 #define NSRightCommandKeyMask (0x000010 | NSEventModifierFlagCommand)
357 #define NSLeftAlternateKeyMask (0x000020 | NSEventModifierFlagOption)
358 #define NSRightAlternateKeyMask (0x000040 | NSEventModifierFlagOption)
361 ev_modifiers_helper (unsigned int flags, unsigned int left_mask,
362 unsigned int right_mask, unsigned int either_mask,
363 Lisp_Object left_modifier, Lisp_Object right_modifier)
365 unsigned int modifiers = 0;
367 if (flags & either_mask)
369 BOOL left_key = (flags & left_mask) == left_mask;
370 BOOL right_key = (flags & right_mask) == right_mask
371 && ! EQ (right_modifier, Qleft);
374 modifiers |= parse_solitary_modifier (right_modifier);
376 /* GNUstep (and possibly macOS in certain circumstances) doesn't
377 differentiate between the left and right keys, so if we can't
378 identify which key it is, we use the left key setting. */
379 if (left_key || ! right_key)
380 modifiers |= parse_solitary_modifier (left_modifier);
386 #define EV_MODIFIERS2(flags) \
387 (((flags & NSEventModifierFlagHelp) ? \
388 hyper_modifier : 0) \
389 | ((flags & NSEventModifierFlagShift) ? \
390 shift_modifier : 0) \
391 | ((flags & NS_FUNCTION_KEY_MASK) ? \
392 parse_solitary_modifier (ns_function_modifier) : 0) \
393 | ev_modifiers_helper (flags, NSLeftControlKeyMask, \
394 NSRightControlKeyMask, \
395 NSEventModifierFlagControl, \
396 ns_control_modifier, \
397 ns_right_control_modifier) \
398 | ev_modifiers_helper (flags, NSLeftCommandKeyMask, \
399 NSRightCommandKeyMask, \
400 NSEventModifierFlagCommand, \
401 ns_command_modifier, \
402 ns_right_command_modifier) \
403 | ev_modifiers_helper (flags, NSLeftAlternateKeyMask, \
404 NSRightAlternateKeyMask, \
405 NSEventModifierFlagOption, \
406 ns_alternate_modifier, \
407 ns_right_alternate_modifier))
409 #define EV_MODIFIERS(e) EV_MODIFIERS2 ([e modifierFlags])
411 #define EV_UDMODIFIERS(e) \
412 ((([e type] == NSEventTypeLeftMouseDown) ? down_modifier : 0) \
413 | (([e type] == NSEventTypeRightMouseDown) ? down_modifier : 0) \
414 | (([e type] == NSEventTypeOtherMouseDown) ? down_modifier : 0) \
415 | (([e type] == NSEventTypeLeftMouseDragged) ? down_modifier : 0) \
416 | (([e type] == NSEventTypeRightMouseDragged) ? down_modifier : 0) \
417 | (([e type] == NSEventTypeOtherMouseDragged) ? down_modifier : 0) \
418 | (([e type] == NSEventTypeLeftMouseUp) ? up_modifier : 0) \
419 | (([e type] == NSEventTypeRightMouseUp) ? up_modifier : 0) \
420 | (([e type] == NSEventTypeOtherMouseUp) ? up_modifier : 0))
422 #define EV_BUTTON(e) \
423 ((([e type] == NSEventTypeLeftMouseDown) || ([e type] == NSEventTypeLeftMouseUp)) ? 0 : \
424 (([e type] == NSEventTypeRightMouseDown) || ([e type] == NSEventTypeRightMouseUp)) ? 2 : \
425 [e buttonNumber] - 1)
427 /* Convert the time field to a timestamp in milliseconds. */
428 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
430 /* This is a piece of code which is common to all the event handling
431 methods. Maybe it should even be a function. */
432 #define EV_TRAILER(e) \
434 XSETFRAME (emacs_event->frame_or_window, emacsframe); \
438 #define EV_TRAILER2(e) \
440 if (e) emacs_event->timestamp = EV_TIMESTAMP (e); \
443 Lisp_Object tem = Vinhibit_quit; \
444 Vinhibit_quit = Qt; \
445 n_emacs_events_pending++; \
446 kbd_buffer_store_event_hold (emacs_event, q_event_ptr); \
447 Vinhibit_quit = tem; \
450 hold_event (emacs_event); \
451 EVENT_INIT (*emacs_event); \
452 ns_send_appdefined (-1); \
456 /* These flags will be OR'd or XOR'd with the NSWindow's styleMask
457 property depending on what we're doing. */
458 #define FRAME_DECORATED_FLAGS (NSWindowStyleMaskTitled \
459 | NSWindowStyleMaskResizable \
460 | NSWindowStyleMaskMiniaturizable \
461 | NSWindowStyleMaskClosable)
462 #define FRAME_UNDECORATED_FLAGS NSWindowStyleMaskBorderless
464 /* TODO: Get rid of need for these forward declarations. */
465 static void ns_condemn_scroll_bars (struct frame *f);
466 static void ns_judge_scroll_bars (struct frame *f);
469 /* ==========================================================================
473 ========================================================================== */
476 ns_set_represented_filename (struct frame *f)
478 Lisp_Object filename, encoded_filename;
479 Lisp_Object buf = XWINDOW (f->selected_window)->contents;
480 NSAutoreleasePool *pool;
483 NSTRACE ("ns_set_represented_filename");
485 if (f->explicit_name || ! NILP (f->title))
489 pool = [[NSAutoreleasePool alloc] init];
490 filename = BVAR (XBUFFER (buf), filename);
492 if (! NILP (filename))
494 encoded_filename = ENCODE_UTF_8 (filename);
496 fstr = [NSString stringWithUTF8String: SSDATA (encoded_filename)];
497 if (fstr == nil) fstr = @"";
502 represented_filename = [fstr retain];
503 represented_frame = f;
510 ns_init_events (struct input_event *ev)
517 ns_finish_events (void)
523 hold_event (struct input_event *event)
525 if (hold_event_q.nr == hold_event_q.cap)
527 if (hold_event_q.cap == 0) hold_event_q.cap = 10;
528 else hold_event_q.cap *= 2;
530 xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
533 hold_event_q.q[hold_event_q.nr++] = *event;
534 /* Make sure ns_read_socket is called, i.e. we have input. */
536 send_appdefined = YES;
540 append2 (Lisp_Object list, Lisp_Object item)
541 /* --------------------------------------------------------------------------
542 Utility to append to a list
543 -------------------------------------------------------------------------- */
545 return CALLN (Fnconc, list, list1 (item));
550 ns_etc_directory (void)
551 /* If running as a self-contained app bundle, return as a string the
552 filename of the etc directory, if present; else nil. */
554 NSBundle *bundle = [NSBundle mainBundle];
555 NSString *resourceDir = [bundle resourcePath];
556 NSString *resourcePath;
557 NSFileManager *fileManager = [NSFileManager defaultManager];
560 resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
561 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
563 if (isDir) return [resourcePath UTF8String];
571 /* If running as a self-contained app bundle, return as a path string
572 the filenames of the libexec and bin directories, ie libexec:bin.
573 Otherwise, return nil.
574 Normally, Emacs does not add its own bin/ directory to the PATH.
575 However, a self-contained NS build has a different layout, with
576 bin/ and libexec/ subdirectories in the directory that contains
578 We put libexec first, because init_callproc_1 uses the first
579 element to initialize exec-directory. An alternative would be
580 for init_callproc to check for invocation-directory/libexec.
583 NSBundle *bundle = [NSBundle mainBundle];
584 NSString *resourceDir = [bundle resourcePath];
585 NSString *binDir = [bundle bundlePath];
586 NSString *resourcePath, *resourcePaths;
588 NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
589 NSFileManager *fileManager = [NSFileManager defaultManager];
591 NSEnumerator *pathEnum;
594 range = [resourceDir rangeOfString: @"Contents"];
595 if (range.location != NSNotFound)
597 binDir = [binDir stringByAppendingPathComponent: @"Contents"];
599 binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
603 paths = [binDir stringsByAppendingPaths:
604 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
605 pathEnum = [paths objectEnumerator];
608 while ((resourcePath = [pathEnum nextObject]))
610 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
613 if ([resourcePaths length] > 0)
615 = [resourcePaths stringByAppendingString: pathSeparator];
617 = [resourcePaths stringByAppendingString: resourcePath];
620 if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
628 /* If running as a self-contained app bundle, return as a path string
629 the filenames of the site-lisp and lisp directories.
630 Ie, site-lisp:lisp. Otherwise, return nil. */
632 NSBundle *bundle = [NSBundle mainBundle];
633 NSString *resourceDir = [bundle resourcePath];
634 NSString *resourcePath, *resourcePaths;
635 NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
636 NSFileManager *fileManager = [NSFileManager defaultManager];
638 NSArray *paths = [resourceDir stringsByAppendingPaths:
639 [NSArray arrayWithObjects:
640 @"site-lisp", @"lisp", nil]];
641 NSEnumerator *pathEnum = [paths objectEnumerator];
644 /* Hack to skip site-lisp. */
645 if (no_site_lisp) resourcePath = [pathEnum nextObject];
647 while ((resourcePath = [pathEnum nextObject]))
649 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
652 if ([resourcePaths length] > 0)
654 = [resourcePaths stringByAppendingString: pathSeparator];
656 = [resourcePaths stringByAppendingString: resourcePath];
659 if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
666 ns_init_locale (void)
667 /* macOS doesn't set any environment variables for the locale when run
668 from the GUI. Get the locale from the OS and set LANG. */
670 NSLocale *locale = [NSLocale currentLocale];
672 NSTRACE ("ns_init_locale");
676 /* It seems macOS should probably use UTF-8 everywhere.
677 'localeIdentifier' does not specify the encoding, and I can't
678 find any way to get the OS to tell us which encoding to use,
679 so hard-code '.UTF-8'. */
680 NSString *localeID = [NSString stringWithFormat:@"%@.UTF-8",
681 [locale localeIdentifier]];
683 /* Set LANG to locale, but not if LANG is already set. */
684 setenv("LANG", [localeID UTF8String], 0);
686 @catch (NSException *e)
688 NSLog (@"Locale detection failed: %@: %@", [e name], [e reason]);
694 ns_release_object (void *obj)
695 /* --------------------------------------------------------------------------
696 Release an object (callable from C)
697 -------------------------------------------------------------------------- */
704 ns_retain_object (void *obj)
705 /* --------------------------------------------------------------------------
706 Retain an object (callable from C)
707 -------------------------------------------------------------------------- */
714 ns_alloc_autorelease_pool (void)
715 /* --------------------------------------------------------------------------
716 Allocate a pool for temporary objects (callable from C)
717 -------------------------------------------------------------------------- */
719 return [[NSAutoreleasePool alloc] init];
724 ns_release_autorelease_pool (void *pool)
725 /* --------------------------------------------------------------------------
726 Free a pool and temporary objects it refers to (callable from C)
727 -------------------------------------------------------------------------- */
729 ns_release_object (pool);
734 /* Disabling screen updates can be used to make several actions appear
735 "atomic" to the end user. It seems some actions can still update
738 When we re-enable screen updates the number of calls to
739 NSEnableScreenUpdates should match the number to
740 NSDisableScreenUpdates.
742 We use these functions to prevent the user seeing a blank frame
743 after it has been resized. x_set_window_size disables updates and
744 when redisplay completes unwind_redisplay enables them again
748 ns_disable_screen_updates (void)
750 NSDisableScreenUpdates ();
751 disable_screen_updates_count++;
755 ns_enable_screen_updates (void)
756 /* Re-enable screen updates. Called from unwind_redisplay. */
758 while (disable_screen_updates_count > 0)
760 NSEnableScreenUpdates ();
761 disable_screen_updates_count--;
768 ns_menu_bar_should_be_hidden (void)
769 /* True, if the menu bar should be hidden. */
771 return !NILP (ns_auto_hide_menu_bar)
772 && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
785 static struct EmacsMargins
786 ns_screen_margins (NSScreen *screen)
787 /* The parts of SCREEN used by the operating system. */
789 NSTRACE ("ns_screen_margins");
791 struct EmacsMargins margins;
793 NSRect screenFrame = [screen frame];
794 NSRect screenVisibleFrame = [screen visibleFrame];
796 /* Sometimes, visibleFrame isn't up-to-date with respect to a hidden
797 menu bar, check this explicitly. */
798 if (ns_menu_bar_should_be_hidden())
804 CGFloat frameTop = screenFrame.origin.y + screenFrame.size.height;
805 CGFloat visibleFrameTop = (screenVisibleFrame.origin.y
806 + screenVisibleFrame.size.height);
808 margins.top = frameTop - visibleFrameTop;
812 CGFloat frameRight = screenFrame.origin.x + screenFrame.size.width;
813 CGFloat visibleFrameRight = (screenVisibleFrame.origin.x
814 + screenVisibleFrame.size.width);
815 margins.right = frameRight - visibleFrameRight;
818 margins.bottom = screenVisibleFrame.origin.y - screenFrame.origin.y;
819 margins.left = screenVisibleFrame.origin.x - screenFrame.origin.x;
821 NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
831 /* A screen margin between 1 and DOCK_IGNORE_LIMIT (inclusive) is
832 assumed to contain a hidden dock. macOS currently use 4 pixels for
833 this, however, to be future compatible, a larger value is used. */
834 #define DOCK_IGNORE_LIMIT 6
836 static struct EmacsMargins
837 ns_screen_margins_ignoring_hidden_dock (NSScreen *screen)
838 /* The parts of SCREEN used by the operating system, excluding the parts
839 reserved for a hidden dock. */
841 NSTRACE ("ns_screen_margins_ignoring_hidden_dock");
843 struct EmacsMargins margins = ns_screen_margins(screen);
845 /* macOS (currently) reserved 4 pixels along the edge where a hidden
846 dock is located. Unfortunately, it's not possible to find the
847 location and information about if the dock is hidden. Instead,
848 it is assumed that if the margin of an edge is less than
849 DOCK_IGNORE_LIMIT, it contains a hidden dock. */
850 if (margins.left <= DOCK_IGNORE_LIMIT)
854 if (margins.right <= DOCK_IGNORE_LIMIT)
858 if (margins.top <= DOCK_IGNORE_LIMIT)
862 /* Note: This doesn't occur in current versions of macOS, but
863 included for completeness and future compatibility. */
864 if (margins.bottom <= DOCK_IGNORE_LIMIT)
869 NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
880 ns_menu_bar_height (NSScreen *screen)
881 /* The height of the menu bar, if visible.
883 Note: Don't use this when fullscreen is enabled -- the screen
884 sometimes includes, sometimes excludes the menu bar area. */
886 struct EmacsMargins margins = ns_screen_margins(screen);
888 CGFloat res = margins.top;
890 NSTRACE ("ns_menu_bar_height " NSTRACE_FMT_RETURN " %.0f", res);
896 /* ==========================================================================
898 Focus (clipping) and screen update
900 ========================================================================== */
903 // Window constraining
904 // -------------------
906 // To ensure that the windows are not placed under the menu bar, they
907 // are typically moved by the call-back constrainFrameRect. However,
908 // by overriding it, it's possible to inhibit this, leaving the window
909 // in it's original position.
911 // It's possible to hide the menu bar. However, technically, it's only
912 // possible to hide it when the application is active. To ensure that
913 // this work properly, the menu bar and window constraining are
914 // deferred until the application becomes active.
916 // Even though it's not possible to manually move a window above the
917 // top of the screen, it is allowed if it's done programmatically,
918 // when the menu is hidden. This allows the editable area to cover the
919 // full screen height.
924 // Use the following extra files:
927 // ;; Hide menu and place frame slightly above the top of the screen.
928 // (setq ns-auto-hide-menu-bar t)
929 // (set-frame-position (selected-frame) 0 -20)
933 // emacs -Q -l init.el
935 // Result: No menu bar, and the title bar should be above the screen.
941 // Result: Menu bar visible, frame placed immediately below the menu.
944 static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
946 NSTRACE ("constrain_frame_rect(" NSTRACE_FMT_RECT ")",
947 NSTRACE_ARG_RECT (frameRect));
949 // --------------------
950 // Collect information about the screen the frame is covering.
953 NSArray *screens = [NSScreen screens];
954 NSUInteger nr_screens = [screens count];
958 // The height of the menu bar, if present in any screen the frame is
960 int menu_bar_height = 0;
962 // A rectangle covering all the screen the frame is displayed in.
963 NSRect multiscreenRect = NSMakeRect(0, 0, 0, 0);
964 for (i = 0; i < nr_screens; ++i )
966 NSScreen *s = [screens objectAtIndex: i];
967 NSRect scrRect = [s frame];
969 NSTRACE_MSG ("Screen %d: " NSTRACE_FMT_RECT,
970 i, NSTRACE_ARG_RECT (scrRect));
972 if (NSIntersectionRect (frameRect, scrRect).size.height != 0)
974 multiscreenRect = NSUnionRect (multiscreenRect, scrRect);
978 CGFloat screen_menu_bar_height = ns_menu_bar_height (s);
979 menu_bar_height = max(menu_bar_height, screen_menu_bar_height);
984 NSTRACE_RECT ("multiscreenRect", multiscreenRect);
986 NSTRACE_MSG ("menu_bar_height: %d", menu_bar_height);
988 if (multiscreenRect.size.width == 0
989 || multiscreenRect.size.height == 0)
991 // Failed to find any monitor, give up.
992 NSTRACE_MSG ("multiscreenRect empty");
993 NSTRACE_RETURN_RECT (frameRect);
998 // --------------------
999 // Find a suitable placement.
1002 if (ns_menu_bar_should_be_hidden())
1004 // When the menu bar is hidden, the user may place part of the
1005 // frame above the top of the screen, for example to hide the
1008 // Hence, keep the original position.
1012 // Ensure that the frame is below the menu bar, or below the top
1015 // This assume that the menu bar is placed at the top in the
1016 // rectangle that covers the monitors. (It doesn't have to be,
1017 // but if it's not it's hard to do anything useful.)
1018 CGFloat topOfWorkArea = (multiscreenRect.origin.y
1019 + multiscreenRect.size.height
1022 CGFloat topOfFrame = frameRect.origin.y + frameRect.size.height;
1023 if (topOfFrame > topOfWorkArea)
1025 frameRect.origin.y -= topOfFrame - topOfWorkArea;
1026 NSTRACE_RECT ("After placement adjust", frameRect);
1030 // Include the following section to restrict frame to the screens.
1031 // (If so, update it to allow the frame to stretch down below the
1034 // --------------------
1035 // Ensure frame doesn't stretch below the screens.
1038 CGFloat diff = multiscreenRect.origin.y - frameRect.origin.y;
1042 frameRect.origin.y = multiscreenRect.origin.y;
1043 frameRect.size.height -= diff;
1047 NSTRACE_RETURN_RECT (frameRect);
1053 ns_constrain_all_frames (void)
1054 /* --------------------------------------------------------------------------
1055 Ensure that the menu bar doesn't cover any frames.
1056 -------------------------------------------------------------------------- */
1058 Lisp_Object tail, frame;
1060 NSTRACE ("ns_constrain_all_frames");
1064 FOR_EACH_FRAME (tail, frame)
1066 struct frame *f = XFRAME (frame);
1069 EmacsView *view = FRAME_NS_VIEW (f);
1071 if (![view isFullscreen])
1074 setFrame:constrain_frame_rect([[view window] frame], false)
1085 ns_update_auto_hide_menu_bar (void)
1086 /* --------------------------------------------------------------------------
1087 Show or hide the menu bar, based on user setting.
1088 -------------------------------------------------------------------------- */
1090 #ifdef NS_IMPL_COCOA
1091 NSTRACE ("ns_update_auto_hide_menu_bar");
1095 if (NSApp != nil && [NSApp isActive])
1097 // Note, "setPresentationOptions" triggers an error unless the
1098 // application is active.
1099 BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
1101 if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
1103 NSApplicationPresentationOptions options
1104 = NSApplicationPresentationDefault;
1106 if (menu_bar_should_be_hidden)
1107 options |= NSApplicationPresentationAutoHideMenuBar
1108 | NSApplicationPresentationAutoHideDock;
1110 [NSApp setPresentationOptions: options];
1112 ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
1114 if (!ns_menu_bar_is_hidden)
1116 ns_constrain_all_frames ();
1127 ns_update_begin (struct frame *f)
1128 /* --------------------------------------------------------------------------
1129 Prepare for a grouped sequence of drawing calls
1130 external (RIF) call; whole frame, called before update_window_begin
1131 -------------------------------------------------------------------------- */
1133 EmacsView *view = FRAME_NS_VIEW (f);
1134 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_begin");
1136 ns_update_auto_hide_menu_bar ();
1138 #ifdef NS_IMPL_COCOA
1139 if ([view isFullscreen] && [view fsIsNative])
1141 // Fix reappearing tool bar in fullscreen for Mac OS X 10.7
1142 BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
1143 NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
1144 if (! tbar_visible != ! [toolbar isVisible])
1145 [toolbar setVisible: tbar_visible];
1149 ns_updating_frame = f;
1152 /* drawRect may have been called for say the minibuffer, and then clip path
1153 is for the minibuffer. But the display engine may draw more because
1154 we have set the frame as garbaged. So reset clip path to the whole
1156 #ifdef NS_IMPL_COCOA
1159 NSRect r = [view frame];
1160 NSRect cr = [[view window] frame];
1161 /* If a large frame size is set, r may be larger than the window frame
1162 before constrained. In that case don't change the clip path, as we
1163 will clear in to the tool bar and title bar. */
1165 + FRAME_NS_TITLEBAR_HEIGHT (f)
1166 + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
1168 bp = [[NSBezierPath bezierPathWithRect: r] retain];
1175 #ifdef NS_IMPL_GNUSTEP
1176 uRect = NSMakeRect (0, 0, 0, 0);
1182 ns_update_window_begin (struct window *w)
1183 /* --------------------------------------------------------------------------
1184 Prepare for a grouped sequence of drawing calls
1185 external (RIF) call; for one window, called after update_begin
1186 -------------------------------------------------------------------------- */
1188 struct frame *f = XFRAME (WINDOW_FRAME (w));
1189 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1191 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_begin");
1192 w->output_cursor = w->cursor;
1196 if (f == hlinfo->mouse_face_mouse_frame)
1198 /* Don't do highlighting for mouse motion during the update. */
1199 hlinfo->mouse_face_defer = 1;
1201 /* If the frame needs to be redrawn,
1202 simply forget about any prior mouse highlighting. */
1203 if (FRAME_GARBAGED_P (f))
1204 hlinfo->mouse_face_window = Qnil;
1206 /* (further code for mouse faces ifdef'd out in other terms elided) */
1214 ns_update_window_end (struct window *w, bool cursor_on_p,
1215 bool mouse_face_overwritten_p)
1216 /* --------------------------------------------------------------------------
1217 Finished a grouped sequence of drawing calls
1218 external (RIF) call; for one window called before update_end
1219 -------------------------------------------------------------------------- */
1221 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_end");
1223 /* note: this fn is nearly identical in all terms */
1224 if (!w->pseudo_window_p)
1229 display_and_set_cursor (w, 1,
1230 w->output_cursor.hpos, w->output_cursor.vpos,
1231 w->output_cursor.x, w->output_cursor.y);
1233 if (draw_window_fringes (w, 1))
1235 if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
1236 x_draw_right_divider (w);
1238 x_draw_vertical_border (w);
1244 /* If a row with mouse-face was overwritten, arrange for
1245 frame_up_to_date to redisplay the mouse highlight. */
1246 if (mouse_face_overwritten_p)
1247 reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
1252 ns_update_end (struct frame *f)
1253 /* --------------------------------------------------------------------------
1254 Finished a grouped sequence of drawing calls
1255 external (RIF) call; for whole frame, called after update_window_end
1256 -------------------------------------------------------------------------- */
1258 EmacsView *view = FRAME_NS_VIEW (f);
1260 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_end");
1262 /* if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
1263 MOUSE_HL_INFO (f)->mouse_face_defer = 0;
1268 [[view window] flushWindow];
1271 ns_updating_frame = NULL;
1275 ns_focus (struct frame *f, NSRect *r, int n)
1276 /* --------------------------------------------------------------------------
1277 Internal: Focus on given frame. During small local updates this is used to
1278 draw, however during large updates, ns_update_begin and ns_update_end are
1279 called to wrap the whole thing, in which case these calls are stubbed out.
1280 Except, on GNUstep, we accumulate the rectangle being drawn into, because
1281 the back end won't do this automatically, and will just end up flushing
1283 -------------------------------------------------------------------------- */
1285 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_focus");
1288 NSTRACE_RECT ("r", *r);
1291 if (f != ns_updating_frame)
1293 NSView *view = FRAME_NS_VIEW (f);
1294 if (view != focus_view)
1296 if (focus_view != NULL)
1298 [focus_view unlockFocus];
1299 [[focus_view window] flushWindow];
1306 /* if (view) debug_lock++; */
1313 [[NSGraphicsContext currentContext] saveGraphicsState];
1315 NSRectClipList (r, 2);
1324 ns_unfocus (struct frame *f)
1325 /* --------------------------------------------------------------------------
1326 Internal: Remove focus on given frame
1327 -------------------------------------------------------------------------- */
1329 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_unfocus");
1333 [[NSGraphicsContext currentContext] restoreGraphicsState];
1337 if (f != ns_updating_frame)
1339 if (focus_view != NULL)
1341 [focus_view unlockFocus];
1342 [[focus_view window] flushWindow];
1351 ns_clip_to_row (struct window *w, struct glyph_row *row,
1352 enum glyph_row_area area, BOOL gc)
1353 /* --------------------------------------------------------------------------
1354 Internal (but parallels other terms): Focus drawing on given row
1355 -------------------------------------------------------------------------- */
1357 struct frame *f = XFRAME (WINDOW_FRAME (w));
1359 int window_x, window_y, window_width;
1361 window_box (w, area, &window_x, &window_y, &window_width, 0);
1363 clip_rect.origin.x = window_x;
1364 clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
1365 clip_rect.origin.y = max (clip_rect.origin.y, window_y);
1366 clip_rect.size.width = window_width;
1367 clip_rect.size.height = row->visible_height;
1369 ns_focus (f, &clip_rect, 1);
1373 /* ==========================================================================
1375 Visible bell and beep.
1377 ========================================================================== */
1380 // This bell implementation shows the visual bell image asynchronously
1381 // from the rest of Emacs. This is done by adding a NSView to the
1382 // superview of the Emacs window and removing it using a timer.
1384 // Unfortunately, some Emacs operations, like scrolling, is done using
1385 // low-level primitives that copy the content of the window, including
1386 // the bell image. To some extent, this is handled by removing the
1387 // image prior to scrolling and marking that the window is in need for
1390 // To test this code, make sure that there is no artifacts of the bell
1391 // image in the following situations. Use a non-empty buffer (like the
1392 // tutorial) to ensure that a scroll is performed:
1394 // * Single-window: C-g C-v
1396 // * Side-by-windows: C-x 3 C-g C-v
1398 // * Windows above each other: C-x 2 C-g C-v
1400 @interface EmacsBell : NSImageView
1402 // Number of currently active bells.
1403 unsigned int nestCount;
1407 - (void)show:(NSView *)view;
1412 @implementation EmacsBell
1416 NSTRACE ("[EmacsBell init]");
1417 if ((self = [super init]))
1421 #ifdef NS_IMPL_GNUSTEP
1422 // GNUstep doesn't provide named images. This was reported in
1423 // 2011, see https://savannah.gnu.org/bugs/?33396
1425 // As a drop in replacement, a semitransparent gray square is used.
1426 self.image = [[NSImage alloc] initWithSize:NSMakeSize(32 * 5, 32 * 5)];
1427 [self.image lockFocus];
1428 [[NSColor colorForEmacsRed:0.5 green:0.5 blue:0.5 alpha:0.5] set];
1429 NSRectFill(NSMakeRect(0, 0, 32, 32));
1430 [self.image unlockFocus];
1432 self.image = [NSImage imageNamed:NSImageNameCaution];
1433 [self.image setSize:NSMakeSize(self.image.size.width * 5,
1434 self.image.size.height * 5)];
1440 - (void)show:(NSView *)view
1442 NSTRACE ("[EmacsBell show:]");
1443 NSTRACE_MSG ("nestCount: %u", nestCount);
1445 // Show the image, unless it's already shown.
1448 NSRect rect = [view bounds];
1450 pos.x = rect.origin.x + (rect.size.width - self.image.size.width )/2;
1451 pos.y = rect.origin.y + (rect.size.height - self.image.size.height)/2;
1453 [self setFrameOrigin:pos];
1454 [self setFrameSize:self.image.size];
1458 [[[view window] contentView] addSubview:self
1459 positioned:NSWindowAbove
1465 [self performSelector:@selector(hide) withObject:self afterDelay:0.5];
1471 // Note: Trace output from this method isn't shown, reason unknown.
1472 // NSTRACE ("[EmacsBell hide]");
1477 // Remove the image once the last bell became inactive.
1487 NSTRACE ("[EmacsBell remove]");
1490 NSTRACE_MSG ("removeFromSuperview");
1491 [self removeFromSuperview];
1492 mView.needsDisplay = YES;
1500 static EmacsBell * bell_view = nil;
1503 ns_ring_bell (struct frame *f)
1504 /* --------------------------------------------------------------------------
1506 -------------------------------------------------------------------------- */
1508 NSTRACE ("ns_ring_bell");
1511 struct frame *frame = SELECTED_FRAME ();
1514 if (bell_view == nil)
1516 bell_view = [[EmacsBell alloc] init];
1522 view = FRAME_NS_VIEW (frame);
1525 [bell_view show:view];
1539 /* --------------------------------------------------------------------------
1540 Ensure the bell is hidden.
1541 -------------------------------------------------------------------------- */
1543 NSTRACE ("hide_bell");
1545 if (bell_view != nil)
1552 /* ==========================================================================
1554 Frame / window manager related functions
1556 ========================================================================== */
1560 ns_raise_frame (struct frame *f, BOOL make_key)
1561 /* --------------------------------------------------------------------------
1562 Bring window to foreground and if make_key is YES, give it focus.
1563 -------------------------------------------------------------------------- */
1567 check_window_system (f);
1568 view = FRAME_NS_VIEW (f);
1570 if (FRAME_VISIBLE_P (f))
1573 [[view window] makeKeyAndOrderFront: NSApp];
1575 [[view window] orderFront: NSApp];
1582 ns_lower_frame (struct frame *f)
1583 /* --------------------------------------------------------------------------
1585 -------------------------------------------------------------------------- */
1589 check_window_system (f);
1590 view = FRAME_NS_VIEW (f);
1592 [[view window] orderBack: NSApp];
1598 ns_frame_raise_lower (struct frame *f, bool raise)
1599 /* --------------------------------------------------------------------------
1601 -------------------------------------------------------------------------- */
1603 NSTRACE ("ns_frame_raise_lower");
1606 ns_raise_frame (f, YES);
1613 ns_frame_rehighlight (struct frame *frame)
1614 /* --------------------------------------------------------------------------
1615 External (hook): called on things like window switching within frame
1616 -------------------------------------------------------------------------- */
1618 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1619 struct frame *old_highlight = dpyinfo->x_highlight_frame;
1621 NSTRACE ("ns_frame_rehighlight");
1622 if (dpyinfo->x_focus_frame)
1624 dpyinfo->x_highlight_frame
1625 = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1626 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1627 : dpyinfo->x_focus_frame);
1628 if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1630 fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1631 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1635 dpyinfo->x_highlight_frame = 0;
1637 if (dpyinfo->x_highlight_frame &&
1638 dpyinfo->x_highlight_frame != old_highlight)
1642 x_update_cursor (old_highlight, 1);
1643 x_set_frame_alpha (old_highlight);
1645 if (dpyinfo->x_highlight_frame)
1647 x_update_cursor (dpyinfo->x_highlight_frame, 1);
1648 x_set_frame_alpha (dpyinfo->x_highlight_frame);
1655 x_make_frame_visible (struct frame *f)
1656 /* --------------------------------------------------------------------------
1657 External: Show the window (X11 semantics)
1658 -------------------------------------------------------------------------- */
1660 NSTRACE ("x_make_frame_visible");
1661 /* XXX: at some points in past this was not needed, as the only place that
1662 called this (frame.c:Fraise_frame ()) also called raise_lower;
1663 if this ends up the case again, comment this out again. */
1664 if (!FRAME_VISIBLE_P (f))
1666 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1667 NSWindow *window = [view window];
1669 SET_FRAME_VISIBLE (f, 1);
1670 ns_raise_frame (f, ! FRAME_NO_FOCUS_ON_MAP (f));
1672 /* Making a new frame from a fullscreen frame will make the new frame
1673 fullscreen also. So skip handleFS as this will print an error. */
1674 if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1675 && [view isFullscreen])
1678 if (f->want_fullscreen != FULLSCREEN_NONE)
1685 /* Making a frame invisible seems to break the parent->child
1686 relationship, so reinstate it. */
1687 if ([window parentWindow] == nil && FRAME_PARENT_FRAME (f) != NULL)
1689 NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
1692 [parent addChildWindow: window
1693 ordered: NSWindowAbove];
1696 /* If the parent frame moved while the child frame was
1697 invisible, the child frame's position won't have been
1698 updated. Make sure it's in the right place now. */
1699 x_set_offset(f, f->left_pos, f->top_pos, 0);
1706 x_make_frame_invisible (struct frame *f)
1707 /* --------------------------------------------------------------------------
1708 External: Hide the window (X11 semantics)
1709 -------------------------------------------------------------------------- */
1712 NSTRACE ("x_make_frame_invisible");
1713 check_window_system (f);
1714 view = FRAME_NS_VIEW (f);
1715 [[view window] orderOut: NSApp];
1716 SET_FRAME_VISIBLE (f, 0);
1717 SET_FRAME_ICONIFIED (f, 0);
1722 x_iconify_frame (struct frame *f)
1723 /* --------------------------------------------------------------------------
1724 External: Iconify window
1725 -------------------------------------------------------------------------- */
1728 struct ns_display_info *dpyinfo;
1730 NSTRACE ("x_iconify_frame");
1731 check_window_system (f);
1732 view = FRAME_NS_VIEW (f);
1733 dpyinfo = FRAME_DISPLAY_INFO (f);
1735 if (dpyinfo->x_highlight_frame == f)
1736 dpyinfo->x_highlight_frame = 0;
1738 if ([[view window] windowNumber] <= 0)
1740 /* The window is still deferred. Make it very small, bring it
1741 on screen and order it out. */
1742 NSRect s = { { 100, 100}, {0, 0} };
1744 t = [[view window] frame];
1745 [[view window] setFrame: s display: NO];
1746 [[view window] orderBack: NSApp];
1747 [[view window] orderOut: NSApp];
1748 [[view window] setFrame: t display: NO];
1751 /* Processing input while Emacs is being minimized can cause a
1752 crash, so block it for the duration. */
1754 [[view window] miniaturize: NSApp];
1758 /* Free X resources of frame F. */
1761 x_free_frame_resources (struct frame *f)
1764 struct ns_display_info *dpyinfo;
1765 Mouse_HLInfo *hlinfo;
1767 NSTRACE ("x_free_frame_resources");
1768 check_window_system (f);
1769 view = FRAME_NS_VIEW (f);
1770 dpyinfo = FRAME_DISPLAY_INFO (f);
1771 hlinfo = MOUSE_HL_INFO (f);
1773 [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1777 free_frame_menubar (f);
1778 free_frame_faces (f);
1780 if (f == dpyinfo->x_focus_frame)
1781 dpyinfo->x_focus_frame = 0;
1782 if (f == dpyinfo->x_highlight_frame)
1783 dpyinfo->x_highlight_frame = 0;
1784 if (f == hlinfo->mouse_face_mouse_frame)
1785 reset_mouse_highlight (hlinfo);
1787 if (f->output_data.ns->miniimage != nil)
1788 [f->output_data.ns->miniimage release];
1790 [[view window] close];
1793 xfree (f->output_data.ns);
1799 x_destroy_window (struct frame *f)
1800 /* --------------------------------------------------------------------------
1801 External: Delete the window
1802 -------------------------------------------------------------------------- */
1804 NSTRACE ("x_destroy_window");
1806 /* If this frame has a parent window, detach it as not doing so can
1807 cause a crash in GNUStep. */
1808 if (FRAME_PARENT_FRAME (f) != NULL)
1810 NSWindow *child = [FRAME_NS_VIEW (f) window];
1811 NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
1813 [parent removeChildWindow: child];
1816 check_window_system (f);
1817 x_free_frame_resources (f);
1823 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1824 /* --------------------------------------------------------------------------
1825 External: Position the window
1826 -------------------------------------------------------------------------- */
1828 NSView *view = FRAME_NS_VIEW (f);
1829 NSScreen *screen = [[view window] screen];
1831 NSTRACE ("x_set_offset");
1840 if (FRAME_PARENT_FRAME (f) == NULL && screen)
1842 f->left_pos = f->size_hint_flags & XNegative
1843 ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1845 /* We use visibleFrame here to take menu bar into account.
1846 Ideally we should also adjust left/top with visibleFrame.origin. */
1848 f->top_pos = f->size_hint_flags & YNegative
1849 ? ([screen visibleFrame].size.height + f->top_pos
1850 - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1851 - FRAME_TOOLBAR_HEIGHT (f))
1853 #ifdef NS_IMPL_GNUSTEP
1854 if (f->left_pos < 100)
1855 f->left_pos = 100; /* don't overlap menu */
1858 else if (FRAME_PARENT_FRAME (f) != NULL)
1860 struct frame *parent = FRAME_PARENT_FRAME (f);
1862 /* On X negative values for child frames always result in
1863 positioning relative to the bottom right corner of the
1865 if (f->left_pos < 0)
1866 f->left_pos = FRAME_PIXEL_WIDTH (parent) - FRAME_PIXEL_WIDTH (f) + f->left_pos;
1869 f->top_pos = FRAME_PIXEL_HEIGHT (parent) + FRAME_TOOLBAR_HEIGHT (parent)
1870 - FRAME_PIXEL_HEIGHT (f) + f->top_pos;
1873 /* Constrain the setFrameTopLeftPoint so we don't move behind the
1875 NSPoint pt = NSMakePoint (SCREENMAXBOUND (f->left_pos
1876 + NS_PARENT_WINDOW_LEFT_POS (f)),
1877 SCREENMAXBOUND (NS_PARENT_WINDOW_TOP_POS (f)
1879 NSTRACE_POINT ("setFrameTopLeftPoint", pt);
1880 [[view window] setFrameTopLeftPoint: pt];
1881 f->size_hint_flags &= ~(XNegative|YNegative);
1889 x_set_window_size (struct frame *f,
1890 bool change_gravity,
1894 /* --------------------------------------------------------------------------
1895 Adjust window pixel size based on given character grid size
1896 Impl is a bit more complex than other terms, need to do some
1898 -------------------------------------------------------------------------- */
1900 EmacsView *view = FRAME_NS_VIEW (f);
1901 NSWindow *window = [view window];
1902 NSRect wr = [window frame];
1903 int pixelwidth, pixelheight;
1904 int orig_height = wr.size.height;
1906 NSTRACE ("x_set_window_size");
1911 NSTRACE_RECT ("current", wr);
1912 NSTRACE_MSG ("Width:%d Height:%d Pixelwise:%d", width, height, pixelwise);
1913 NSTRACE_MSG ("Font %d x %d", FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f));
1917 #ifdef NS_IMPL_COCOA
1918 /* To prevent showing the user a blank frame, stop updates being
1919 flushed to the screen until after redisplay has completed. This
1920 breaks live resize (resizing with a mouse), so don't do it if
1921 we're in a live resize loop. */
1922 if (![view inLiveResize])
1923 ns_disable_screen_updates ();
1928 pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1929 pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1933 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, width);
1934 pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1937 wr.size.width = pixelwidth + f->border_width;
1938 wr.size.height = pixelheight;
1939 if (! [view isFullscreen])
1940 wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1941 + FRAME_TOOLBAR_HEIGHT (f);
1943 /* Do not try to constrain to this screen. We may have multiple
1944 screens, and want Emacs to span those. Constraining to screen
1945 prevents that, and that is not nice to the user. */
1946 if (f->output_data.ns->zooming)
1947 f->output_data.ns->zooming = 0;
1949 wr.origin.y += orig_height - wr.size.height;
1951 frame_size_history_add
1952 (f, Qx_set_window_size_1, width, height,
1953 list5 (Fcons (make_number (pixelwidth), make_number (pixelheight)),
1954 Fcons (make_number (wr.size.width), make_number (wr.size.height)),
1955 make_number (f->border_width),
1956 make_number (FRAME_NS_TITLEBAR_HEIGHT (f)),
1957 make_number (FRAME_TOOLBAR_HEIGHT (f))));
1959 [window setFrame: wr display: YES];
1961 [view updateFrameSize: NO];
1965 #ifdef NS_IMPL_COCOA
1967 x_set_undecorated (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1968 /* --------------------------------------------------------------------------
1969 Set frame F's `undecorated' parameter. If non-nil, F's window-system
1970 window is drawn without decorations, title, minimize/maximize boxes
1971 and external borders. This usually means that the window cannot be
1972 dragged, resized, iconified, maximized or deleted with the mouse. If
1973 nil, draw the frame with all the elements listed above unless these
1974 have been suspended via window manager settings.
1976 GNUStep cannot change an existing window's style.
1977 -------------------------------------------------------------------------- */
1979 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1980 NSWindow *window = [view window];
1982 NSTRACE ("x_set_undecorated");
1984 if (!EQ (new_value, old_value))
1988 if (NILP (new_value))
1990 FRAME_UNDECORATED (f) = false;
1991 [window setStyleMask: ((window.styleMask | FRAME_DECORATED_FLAGS)
1992 ^ FRAME_UNDECORATED_FLAGS)];
1994 [view createToolbar: f];
1998 [window setToolbar: nil];
1999 /* Do I need to release the toolbar here? */
2001 FRAME_UNDECORATED (f) = true;
2002 [window setStyleMask: ((window.styleMask | FRAME_UNDECORATED_FLAGS)
2003 ^ FRAME_DECORATED_FLAGS)];
2006 /* At this point it seems we don't have an active NSResponder,
2007 so some key presses (TAB) are swallowed by the system. */
2008 [window makeFirstResponder: view];
2010 [view updateFrameSize: NO];
2014 #endif /* NS_IMPL_COCOA */
2017 x_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
2018 /* --------------------------------------------------------------------------
2019 Set frame F's `parent-frame' parameter. If non-nil, make F a child
2020 frame of the frame specified by that parameter. Technically, this
2021 makes F's window-system window a child window of the parent frame's
2022 window-system window. If nil, make F's window-system window a
2023 top-level window--a child of its display's root window.
2025 A child frame's `left' and `top' parameters specify positions
2026 relative to the top-left corner of its parent frame's native
2027 rectangle. On macOS moving a parent frame moves all its child
2028 frames too, keeping their position relative to the parent
2029 unaltered. When a parent frame is iconified or made invisible, its
2030 child frames are made invisible. When a parent frame is deleted,
2031 its child frames are deleted too.
2033 Whether a child frame has a tool bar may be window-system or window
2034 manager dependent. It's advisable to disable it via the frame
2037 Some window managers may not honor this parameter.
2038 -------------------------------------------------------------------------- */
2040 struct frame *p = NULL;
2041 NSWindow *parent, *child;
2043 NSTRACE ("x_set_parent_frame");
2045 if (!NILP (new_value)
2046 && (!FRAMEP (new_value)
2047 || !FRAME_LIVE_P (p = XFRAME (new_value))
2048 || !FRAME_NS_P (p)))
2050 store_frame_param (f, Qparent_frame, old_value);
2051 error ("Invalid specification of `parent-frame'");
2054 if (p != FRAME_PARENT_FRAME (f))
2056 parent = [FRAME_NS_VIEW (p) window];
2057 child = [FRAME_NS_VIEW (f) window];
2060 [parent addChildWindow: child
2061 ordered: NSWindowAbove];
2064 fset_parent_frame (f, new_value);
2069 x_set_no_focus_on_map (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
2070 /* Set frame F's `no-focus-on-map' parameter which, if non-nil, means
2071 * that F's window-system window does not want to receive input focus
2072 * when it is mapped. (A frame's window is mapped when the frame is
2073 * displayed for the first time and when the frame changes its state
2074 * from `iconified' or `invisible' to `visible'.)
2076 * Some window managers may not honor this parameter. */
2078 NSTRACE ("x_set_no_focus_on_map");
2080 if (!EQ (new_value, old_value))
2082 FRAME_NO_FOCUS_ON_MAP (f) = !NILP (new_value);
2087 x_set_no_accept_focus (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
2088 /* Set frame F's `no-accept-focus' parameter which, if non-nil, hints
2089 * that F's window-system window does not want to receive input focus
2090 * via mouse clicks or by moving the mouse into it.
2092 * If non-nil, this may have the unwanted side-effect that a user cannot
2093 * scroll a non-selected frame with the mouse.
2095 * Some window managers may not honor this parameter. */
2097 NSTRACE ("x_set_no_accept_focus");
2099 if (!EQ (new_value, old_value))
2100 FRAME_NO_ACCEPT_FOCUS (f) = !NILP (new_value);
2104 x_set_z_group (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
2105 /* Set frame F's `z-group' parameter. If `above', F's window-system
2106 window is displayed above all windows that do not have the `above'
2107 property set. If nil, F's window is shown below all windows that
2108 have the `above' property set and above all windows that have the
2109 `below' property set. If `below', F's window is displayed below
2110 all windows that do.
2112 Some window managers may not honor this parameter. */
2114 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2115 NSWindow *window = [view window];
2117 NSTRACE ("x_set_z_group");
2119 if (NILP (new_value))
2121 window.level = NSNormalWindowLevel;
2122 FRAME_Z_GROUP (f) = z_group_none;
2124 else if (EQ (new_value, Qabove))
2126 window.level = NSNormalWindowLevel + 1;
2127 FRAME_Z_GROUP (f) = z_group_above;
2129 else if (EQ (new_value, Qabove_suspended))
2131 /* Not sure what level this should be. */
2132 window.level = NSNormalWindowLevel + 1;
2133 FRAME_Z_GROUP (f) = z_group_above_suspended;
2135 else if (EQ (new_value, Qbelow))
2137 window.level = NSNormalWindowLevel - 1;
2138 FRAME_Z_GROUP (f) = z_group_below;
2141 error ("Invalid z-group specification");
2144 #ifdef NS_IMPL_COCOA
2146 ns_set_appearance (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
2148 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
2149 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2150 NSWindow *window = [view window];
2152 NSTRACE ("ns_set_appearance");
2154 #ifndef NSAppKitVersionNumber10_10
2155 #define NSAppKitVersionNumber10_10 1343
2158 if (NSAppKitVersionNumber < NSAppKitVersionNumber10_10)
2161 if (EQ (new_value, Qdark))
2163 window.appearance = [NSAppearance
2164 appearanceNamed: NSAppearanceNameVibrantDark];
2165 FRAME_NS_APPEARANCE (f) = ns_appearance_vibrant_dark;
2169 window.appearance = [NSAppearance
2170 appearanceNamed: NSAppearanceNameAqua];
2171 FRAME_NS_APPEARANCE (f) = ns_appearance_aqua;
2173 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 */
2177 ns_set_transparent_titlebar (struct frame *f, Lisp_Object new_value,
2178 Lisp_Object old_value)
2180 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
2181 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2182 NSWindow *window = [view window];
2184 NSTRACE ("ns_set_transparent_titlebar");
2186 if ([window respondsToSelector: @selector(titlebarAppearsTransparent)]
2187 && !EQ (new_value, old_value))
2189 window.titlebarAppearsTransparent = !NILP (new_value);
2190 FRAME_NS_TRANSPARENT_TITLEBAR (f) = !NILP (new_value);
2192 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 */
2194 #endif /* NS_IMPL_COCOA */
2197 ns_fullscreen_hook (struct frame *f)
2199 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2201 NSTRACE ("ns_fullscreen_hook");
2203 if (!FRAME_VISIBLE_P (f))
2206 if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
2208 /* Old style fs don't initiate correctly if created from
2209 init/default-frame alist, so use a timer (not nice...). */
2210 [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
2211 selector: @selector (handleFS)
2212 userInfo: nil repeats: NO];
2221 /* ==========================================================================
2225 ========================================================================== */
2229 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
2231 struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
2232 if (idx < 1 || idx >= color_table->avail)
2234 return color_table->colors[idx];
2239 ns_index_color (NSColor *color, struct frame *f)
2241 struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
2245 if (!color_table->colors)
2247 color_table->size = NS_COLOR_CAPACITY;
2248 color_table->avail = 1; /* skip idx=0 as marker */
2249 color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
2250 color_table->colors[0] = nil;
2251 color_table->empty_indices = [[NSMutableSet alloc] init];
2254 /* Do we already have this color? */
2255 for (i = 1; i < color_table->avail; i++)
2256 if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
2259 if ([color_table->empty_indices count] > 0)
2261 NSNumber *index = [color_table->empty_indices anyObject];
2262 [color_table->empty_indices removeObject: index];
2263 idx = [index unsignedLongValue];
2267 if (color_table->avail == color_table->size)
2268 color_table->colors =
2269 xpalloc (color_table->colors, &color_table->size, 1,
2270 min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
2271 idx = color_table->avail++;
2274 color_table->colors[idx] = color;
2276 /* fprintf(stderr, "color_table: allocated %d\n",idx); */
2282 ns_get_color (const char *name, NSColor **col)
2283 /* --------------------------------------------------------------------------
2285 -------------------------------------------------------------------------- */
2286 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
2287 X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
2288 See https://lists.gnu.org/r/emacs-devel/2009-07/msg01203.html. */
2291 static char hex[20];
2293 float r = -1.0, g, b;
2294 NSString *nsname = [NSString stringWithUTF8String: name];
2296 NSTRACE ("ns_get_color(%s, **)", name);
2300 if ([nsname isEqualToString: @"ns_selection_bg_color"])
2302 #ifdef NS_IMPL_COCOA
2303 NSString *defname = [[NSUserDefaults standardUserDefaults]
2304 stringForKey: @"AppleHighlightColor"];
2309 if ((new = [NSColor selectedTextBackgroundColor]) != nil)
2311 *col = [new colorUsingDefaultColorSpace];
2316 nsname = NS_SELECTION_BG_COLOR_DEFAULT;
2318 name = [nsname UTF8String];
2320 else if ([nsname isEqualToString: @"ns_selection_fg_color"])
2322 /* NOTE: macOS applications normally don't set foreground
2323 selection, but text may be unreadable if we don't. */
2324 if ((new = [NSColor selectedTextColor]) != nil)
2326 *col = [new colorUsingDefaultColorSpace];
2331 nsname = NS_SELECTION_FG_COLOR_DEFAULT;
2332 name = [nsname UTF8String];
2335 /* First, check for some sort of numeric specification. */
2338 if (name[0] == '0' || name[0] == '1' || name[0] == '.') /* RGB decimal */
2340 NSScanner *scanner = [NSScanner scannerWithString: nsname];
2341 [scanner scanFloat: &r];
2342 [scanner scanFloat: &g];
2343 [scanner scanFloat: &b];
2345 else if (!strncmp(name, "rgb:", 4)) /* A newer X11 format -- rgb:r/g/b */
2346 scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
2347 else if (name[0] == '#') /* An old X11 format; convert to newer */
2349 int len = (strlen(name) - 1);
2350 int start = (len % 3 == 0) ? 1 : len / 4 + 1;
2352 scaling = strlen(name+start) / 3;
2353 for (i = 0; i < 3; i++)
2354 sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
2355 name + start + i * scaling);
2356 hex[3 * (scaling + 1) - 1] = '\0';
2361 unsigned int rr, gg, bb;
2362 float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
2363 if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
2373 *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
2378 /* Otherwise, color is expected to be from a list */
2380 NSEnumerator *lenum, *cenum;
2384 #ifdef NS_IMPL_GNUSTEP
2385 /* XXX: who is wrong, the requestor or the implementation? */
2386 if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
2388 nsname = @"highlightColor";
2391 lenum = [[NSColorList availableColorLists] objectEnumerator];
2392 while ( (clist = [lenum nextObject]) && new == nil)
2394 cenum = [[clist allKeys] objectEnumerator];
2395 while ( (name = [cenum nextObject]) && new == nil )
2397 if ([name compare: nsname
2398 options: NSCaseInsensitiveSearch] == NSOrderedSame )
2399 new = [clist colorWithKey: name];
2405 *col = [new colorUsingDefaultColorSpace];
2412 ns_lisp_to_color (Lisp_Object color, NSColor **col)
2413 /* --------------------------------------------------------------------------
2414 Convert a Lisp string object to a NS color.
2415 -------------------------------------------------------------------------- */
2417 NSTRACE ("ns_lisp_to_color");
2418 if (STRINGP (color))
2419 return ns_get_color (SSDATA (color), col);
2420 else if (SYMBOLP (color))
2421 return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
2427 ns_query_color(void *col, XColor *color_def, int setPixel)
2428 /* --------------------------------------------------------------------------
2429 Get ARGB values out of NSColor col and put them into color_def.
2430 If setPixel, set the pixel to a concatenated version.
2431 and set color_def pixel to the resulting index.
2432 -------------------------------------------------------------------------- */
2434 EmacsCGFloat r, g, b, a;
2436 [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
2437 color_def->red = r * 65535;
2438 color_def->green = g * 65535;
2439 color_def->blue = b * 65535;
2441 if (setPixel == YES)
2443 = ARGB_TO_ULONG((int)(a*255),
2444 (int)(r*255), (int)(g*255), (int)(b*255));
2449 ns_defined_color (struct frame *f,
2454 /* --------------------------------------------------------------------------
2455 Return true if named color found, and set color_def rgb accordingly.
2456 If makeIndex and alloc are nonzero put the color in the color_table,
2457 and set color_def pixel to the resulting index.
2458 If makeIndex is zero, set color_def pixel to ARGB.
2459 Return false if not found.
2460 -------------------------------------------------------------------------- */
2463 NSTRACE_WHEN (NSTRACE_GROUP_COLOR, "ns_defined_color");
2466 if (ns_get_color (name, &col) != 0) /* Color not found */
2471 if (makeIndex && alloc)
2472 color_def->pixel = ns_index_color (col, f);
2473 ns_query_color (col, color_def, !makeIndex);
2480 x_set_frame_alpha (struct frame *f)
2481 /* --------------------------------------------------------------------------
2482 change the entire-frame transparency
2483 -------------------------------------------------------------------------- */
2485 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2487 double alpha_min = 1.0;
2489 NSTRACE ("x_set_frame_alpha");
2491 if (dpyinfo->x_highlight_frame == f)
2492 alpha = f->alpha[0];
2494 alpha = f->alpha[1];
2496 if (FLOATP (Vframe_alpha_lower_limit))
2497 alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
2498 else if (INTEGERP (Vframe_alpha_lower_limit))
2499 alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
2503 else if (1.0 < alpha)
2505 else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
2508 #ifdef NS_IMPL_COCOA
2510 EmacsView *view = FRAME_NS_VIEW (f);
2511 [[view window] setAlphaValue: alpha];
2517 /* ==========================================================================
2521 ========================================================================== */
2525 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
2526 /* --------------------------------------------------------------------------
2527 Programmatically reposition mouse pointer in pixel coordinates
2528 -------------------------------------------------------------------------- */
2530 NSTRACE ("frame_set_mouse_pixel_position");
2532 /* FIXME: what about GNUstep? */
2533 #ifdef NS_IMPL_COCOA
2535 CGPointMake(f->left_pos + pix_x,
2536 f->top_pos + pix_y +
2537 FRAME_NS_TITLEBAR_HEIGHT(f) + FRAME_TOOLBAR_HEIGHT(f));
2538 CGWarpMouseCursorPosition (mouse_pos);
2543 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
2544 /* ------------------------------------------------------------------------
2545 Called by EmacsView on mouseMovement events. Passes on
2546 to emacs mainstream code if we moved off of a rect of interest
2547 known as last_mouse_glyph.
2548 ------------------------------------------------------------------------ */
2550 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
2553 // NSTRACE ("note_mouse_movement");
2555 dpyinfo->last_mouse_motion_frame = frame;
2556 r = &dpyinfo->last_mouse_glyph;
2558 /* Note, this doesn't get called for enter/leave, since we don't have a
2559 position. Those are taken care of in the corresponding NSView methods. */
2561 /* Has movement gone beyond last rect we were tracking? */
2562 if (x < r->origin.x || x >= r->origin.x + r->size.width
2563 || y < r->origin.y || y >= r->origin.y + r->size.height)
2565 ns_update_begin (frame);
2566 frame->mouse_moved = 1;
2567 note_mouse_highlight (frame, x, y);
2568 remember_mouse_glyph (frame, x, y, r);
2569 ns_update_end (frame);
2578 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
2579 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
2581 /* --------------------------------------------------------------------------
2582 External (hook): inform emacs about mouse position and hit parts.
2583 If a scrollbar is being dragged, set bar_window, part, x, y, time.
2584 x & y should be position in the scrollbar (the whole bar, not the handle)
2585 and length of scrollbar respectively.
2586 -------------------------------------------------------------------------- */
2590 Lisp_Object frame, tail;
2592 struct ns_display_info *dpyinfo;
2594 NSTRACE ("ns_mouse_position");
2598 fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
2602 dpyinfo = FRAME_DISPLAY_INFO (*fp);
2606 /* Clear the mouse-moved flag for every frame on this display. */
2607 FOR_EACH_FRAME (tail, frame)
2608 if (FRAME_NS_P (XFRAME (frame))
2609 && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
2610 XFRAME (frame)->mouse_moved = 0;
2612 dpyinfo->last_mouse_scroll_bar = nil;
2613 if (dpyinfo->last_mouse_frame
2614 && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
2615 f = dpyinfo->last_mouse_frame;
2617 f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame : SELECTED_FRAME ();
2619 if (f && FRAME_NS_P (f))
2621 view = FRAME_NS_VIEW (*fp);
2623 position = [[view window] mouseLocationOutsideOfEventStream];
2624 position = [view convertPoint: position fromView: nil];
2625 remember_mouse_glyph (f, position.x, position.y,
2626 &dpyinfo->last_mouse_glyph);
2627 NSTRACE_POINT ("position", position);
2629 if (bar_window) *bar_window = Qnil;
2630 if (part) *part = scroll_bar_above_handle;
2632 if (x) XSETINT (*x, lrint (position.x));
2633 if (y) XSETINT (*y, lrint (position.y));
2635 *time = dpyinfo->last_mouse_movement_time;
2644 ns_frame_up_to_date (struct frame *f)
2645 /* --------------------------------------------------------------------------
2646 External (hook): Fix up mouse highlighting right after a full update.
2647 Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
2648 -------------------------------------------------------------------------- */
2650 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_frame_up_to_date");
2654 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
2655 if (f == hlinfo->mouse_face_mouse_frame)
2659 note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
2660 hlinfo->mouse_face_mouse_x,
2661 hlinfo->mouse_face_mouse_y);
2670 ns_define_frame_cursor (struct frame *f, Cursor cursor)
2671 /* --------------------------------------------------------------------------
2672 External (RIF): set frame mouse pointer type.
2673 -------------------------------------------------------------------------- */
2675 NSTRACE ("ns_define_frame_cursor");
2676 if (FRAME_POINTER_TYPE (f) != cursor)
2678 EmacsView *view = FRAME_NS_VIEW (f);
2679 FRAME_POINTER_TYPE (f) = cursor;
2680 [[view window] invalidateCursorRectsForView: view];
2681 /* Redisplay assumes this function also draws the changed frame
2682 cursor, but this function doesn't, so do it explicitly. */
2683 x_update_cursor (f, 1);
2689 /* ==========================================================================
2693 ========================================================================== */
2697 ns_convert_key (unsigned code)
2698 /* --------------------------------------------------------------------------
2699 Internal call used by NSView-keyDown.
2700 -------------------------------------------------------------------------- */
2702 const unsigned last_keysym = ARRAYELTS (convert_ns_to_X_keysym);
2704 /* An array would be faster, but less easy to read. */
2705 for (keysym = 0; keysym < last_keysym; keysym += 2)
2706 if (code == convert_ns_to_X_keysym[keysym])
2707 return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
2709 /* if decide to use keyCode and Carbon table, use this line:
2710 return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
2715 x_get_keysym_name (int keysym)
2716 /* --------------------------------------------------------------------------
2717 Called by keyboard.c. Not sure if the return val is important, except
2719 -------------------------------------------------------------------------- */
2721 static char value[16];
2722 NSTRACE ("x_get_keysym_name");
2723 sprintf (value, "%d", keysym);
2727 #ifdef NS_IMPL_COCOA
2729 ns_get_shifted_character (NSEvent *event)
2730 /* Look up the character corresponding to the key pressed on the
2731 current keyboard layout and the currently configured shift-like
2732 modifiers. This ignores the control-like modifiers that cause
2733 [event characters] to give us the wrong result.
2735 Although UCKeyTranslate doesn't require the Carbon framework, some
2736 of the surrounding paraphernalia does, so this function makes
2737 Carbon a requirement. */
2739 static UInt32 dead_key_state;
2741 /* UCKeyTranslate may return up to 255 characters. If the buffer
2742 isn't large enough then it produces an error. What kind of
2743 keyboard inputs 255 characters in a single keypress? */
2745 UniCharCount max_string_length = 255;
2746 UniCharCount actual_string_length = 0;
2749 CFDataRef layout_ref = (CFDataRef) TISGetInputSourceProperty
2750 (TISCopyCurrentKeyboardLayoutInputSource (), kTISPropertyUnicodeKeyLayoutData);
2751 UCKeyboardLayout* layout = (UCKeyboardLayout*) CFDataGetBytePtr (layout_ref);
2753 UInt32 flags = [event modifierFlags];
2754 UInt32 modifiers = (flags & NSEventModifierFlagShift) ? shiftKey : 0;
2756 NSTRACE ("ns_get_shifted_character");
2758 if ((flags & NSRightAlternateKeyMask) == NSRightAlternateKeyMask
2759 && (EQ (ns_right_alternate_modifier, Qnone)
2760 || (EQ (ns_right_alternate_modifier, Qleft)
2761 && EQ (ns_alternate_modifier, Qnone))))
2762 modifiers |= rightOptionKey;
2764 if ((flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
2765 && EQ (ns_alternate_modifier, Qnone))
2766 modifiers |= optionKey;
2768 if ((flags & NSRightCommandKeyMask) == NSRightCommandKeyMask
2769 && (EQ (ns_right_command_modifier, Qnone)
2770 || (EQ (ns_right_command_modifier, Qleft)
2771 && EQ (ns_command_modifier, Qnone))))
2772 /* Carbon doesn't differentiate between left and right command
2774 modifiers |= cmdKey;
2776 if ((flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
2777 && EQ (ns_command_modifier, Qnone))
2778 modifiers |= cmdKey;
2780 result = UCKeyTranslate (layout, [event keyCode], kUCKeyActionDown,
2781 (modifiers >> 8) & 0xFF, LMGetKbdType (),
2782 kUCKeyTranslateNoDeadKeysBit, &dead_key_state,
2783 max_string_length, &actual_string_length, buf);
2787 NSLog(@"Failed to translate character '%@' with modifiers %x",
2788 [event characters], modifiers);
2792 /* FIXME: What do we do if more than one code unit is returned? */
2793 if (actual_string_length > 0)
2798 #endif /* NS_IMPL_COCOA */
2800 /* ==========================================================================
2802 Block drawing operations
2804 ========================================================================== */
2808 ns_redraw_scroll_bars (struct frame *f)
2812 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2813 NSTRACE ("ns_redraw_scroll_bars");
2814 for (i =[subviews count]-1; i >= 0; i--)
2816 view = [subviews objectAtIndex: i];
2817 if (![view isKindOfClass: [EmacsScroller class]]) continue;
2824 ns_clear_frame (struct frame *f)
2825 /* --------------------------------------------------------------------------
2826 External (hook): Erase the entire frame
2827 -------------------------------------------------------------------------- */
2829 NSView *view = FRAME_NS_VIEW (f);
2832 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame");
2834 /* comes on initial frame because we have
2835 after-make-frame-functions = select-frame */
2836 if (!FRAME_DEFAULT_FACE (f))
2839 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2844 ns_focus (f, &r, 1);
2845 [ns_lookup_indexed_color (NS_FACE_BACKGROUND
2846 (FACE_FROM_ID (f, DEFAULT_FACE_ID)), f) set];
2850 /* as of 2006/11 or so this is now needed */
2851 ns_redraw_scroll_bars (f);
2857 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2858 /* --------------------------------------------------------------------------
2859 External (RIF): Clear section of frame
2860 -------------------------------------------------------------------------- */
2862 NSRect r = NSMakeRect (x, y, width, height);
2863 NSView *view = FRAME_NS_VIEW (f);
2864 struct face *face = FRAME_DEFAULT_FACE (f);
2869 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame_area");
2871 r = NSIntersectionRect (r, [view frame]);
2872 ns_focus (f, &r, 1);
2873 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2882 ns_copy_bits (struct frame *f, NSRect src, NSRect dest)
2884 NSTRACE ("ns_copy_bits");
2886 if (FRAME_NS_VIEW (f))
2888 hide_bell(); // Ensure the bell image isn't scrolled.
2890 ns_focus (f, &dest, 1);
2891 [FRAME_NS_VIEW (f) scrollRect: src
2892 by: NSMakeSize (dest.origin.x - src.origin.x,
2893 dest.origin.y - src.origin.y)];
2899 ns_scroll_run (struct window *w, struct run *run)
2900 /* --------------------------------------------------------------------------
2901 External (RIF): Insert or delete n lines at line vpos.
2902 -------------------------------------------------------------------------- */
2904 struct frame *f = XFRAME (w->frame);
2905 int x, y, width, height, from_y, to_y, bottom_y;
2907 NSTRACE ("ns_scroll_run");
2909 /* begin copy from other terms */
2910 /* Get frame-relative bounding box of the text display area of W,
2911 without mode lines. Include in this box the left and right
2913 window_box (w, ANY_AREA, &x, &y, &width, &height);
2915 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2916 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2917 bottom_y = y + height;
2921 /* Scrolling up. Make sure we don't copy part of the mode
2922 line at the bottom. */
2923 if (from_y + run->height > bottom_y)
2924 height = bottom_y - from_y;
2926 height = run->height;
2930 /* Scrolling down. Make sure we don't copy over the mode line.
2932 if (to_y + run->height > bottom_y)
2933 height = bottom_y - to_y;
2935 height = run->height;
2937 /* end copy from other terms */
2947 NSRect srcRect = NSMakeRect (x, from_y, width, height);
2948 NSRect dstRect = NSMakeRect (x, to_y, width, height);
2950 ns_copy_bits (f, srcRect , dstRect);
2958 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2959 /* --------------------------------------------------------------------------
2960 External (RIF): preparatory to fringe update after text was updated
2961 -------------------------------------------------------------------------- */
2966 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_after_update_window_line");
2968 /* begin copy from other terms */
2971 if (!desired_row->mode_line_p && !w->pseudo_window_p)
2972 desired_row->redraw_fringe_bitmaps_p = 1;
2974 /* When a window has disappeared, make sure that no rest of
2975 full-width rows stays visible in the internal border. */
2976 if (windows_or_buffers_changed
2977 && desired_row->full_width_p
2978 && (f = XFRAME (w->frame),
2979 width = FRAME_INTERNAL_BORDER_WIDTH (f),
2981 && (height = desired_row->visible_height,
2984 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2987 ns_clear_frame_area (f, 0, y, width, height);
2988 ns_clear_frame_area (f,
2989 FRAME_PIXEL_WIDTH (f) - width,
2997 ns_shift_glyphs_for_insert (struct frame *f,
2998 int x, int y, int width, int height,
3000 /* --------------------------------------------------------------------------
3001 External (RIF): copy an area horizontally, don't worry about clearing src
3002 -------------------------------------------------------------------------- */
3004 NSRect srcRect = NSMakeRect (x, y, width, height);
3005 NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
3007 NSTRACE ("ns_shift_glyphs_for_insert");
3009 ns_copy_bits (f, srcRect, dstRect);
3014 /* ==========================================================================
3016 Character encoding and metrics
3018 ========================================================================== */
3022 ns_compute_glyph_string_overhangs (struct glyph_string *s)
3023 /* --------------------------------------------------------------------------
3024 External (RIF); compute left/right overhang of whole string and set in s
3025 -------------------------------------------------------------------------- */
3027 struct font *font = s->font;
3031 struct font_metrics metrics;
3032 unsigned int codes[2];
3033 codes[0] = *(s->char2b);
3034 codes[1] = *(s->char2b + s->nchars - 1);
3036 font->driver->text_extents (font, codes, 2, &metrics);
3037 s->left_overhang = -metrics.lbearing;
3039 = metrics.rbearing > metrics.width
3040 ? metrics.rbearing - metrics.width : 0;
3044 s->left_overhang = 0;
3045 if (EQ (font->driver->type, Qns))
3046 s->right_overhang = ((struct nsfont_info *)font)->ital ?
3047 FONT_HEIGHT (font) * 0.2 : 0;
3049 s->right_overhang = 0;
3055 /* ==========================================================================
3057 Fringe and cursor drawing
3059 ========================================================================== */
3062 extern int max_used_fringe_bitmap;
3064 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
3065 struct draw_fringe_bitmap_params *p)
3066 /* --------------------------------------------------------------------------
3067 External (RIF); fringe-related
3068 -------------------------------------------------------------------------- */
3070 /* Fringe bitmaps comes in two variants, normal and periodic. A
3071 periodic bitmap is used to create a continuous pattern. Since a
3072 bitmap is rendered one text line at a time, the start offset (dh)
3073 of the bitmap varies. Concretely, this is used for the empty
3076 For a bitmap, "h + dh" is the full height and is always
3077 invariant. For a normal bitmap "dh" is zero.
3079 For example, when the period is three and the full height is 72
3080 the following combinations exists:
3086 struct frame *f = XFRAME (WINDOW_FRAME (w));
3087 struct face *face = p->face;
3088 static EmacsImage **bimgs = NULL;
3089 static int nBimgs = 0;
3091 NSTRACE_WHEN (NSTRACE_GROUP_FRINGE, "ns_draw_fringe_bitmap");
3092 NSTRACE_MSG ("which:%d cursor:%d overlay:%d width:%d height:%d period:%d",
3093 p->which, p->cursor_p, p->overlay_p, p->wd, p->h, p->dh);
3095 /* grow bimgs if needed */
3096 if (nBimgs < max_used_fringe_bitmap)
3098 bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
3099 memset (bimgs + nBimgs, 0,
3100 (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
3101 nBimgs = max_used_fringe_bitmap;
3104 /* Must clip because of partially visible lines. */
3105 ns_clip_to_row (w, row, ANY_AREA, YES);
3109 int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
3111 if (bx >= 0 && nx > 0)
3113 NSRect r = NSMakeRect (bx, by, nx, ny);
3115 [ns_lookup_indexed_color (face->background, f) set];
3122 NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
3123 EmacsImage *img = bimgs[p->which - 1];
3127 // Note: For "periodic" images, allocate one EmacsImage for
3128 // the base image, and use it for all dh:s.
3129 unsigned short *bits = p->bits;
3130 int full_height = p->h + p->dh;
3132 unsigned char *cbits = xmalloc (full_height);
3134 for (i = 0; i < full_height; i++)
3136 img = [[EmacsImage alloc] initFromXBM: cbits width: 8
3139 bimgs[p->which - 1] = img;
3143 NSTRACE_RECT ("r", r);
3146 /* Since we composite the bitmap instead of just blitting it, we need
3147 to erase the whole background. */
3148 [ns_lookup_indexed_color(face->background, f) set];
3154 bm_color = ns_lookup_indexed_color(face->foreground, f);
3155 else if (p->overlay_p)
3156 bm_color = ns_lookup_indexed_color(face->background, f);
3158 bm_color = f->output_data.ns->cursor_color;
3159 [img setXBMColor: bm_color];
3162 #ifdef NS_IMPL_COCOA
3163 // Note: For periodic images, the full image height is "h + hd".
3164 // By using the height h, a suitable part of the image is used.
3165 NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h);
3167 NSTRACE_RECT ("fromRect", fromRect);
3171 operation: NSCompositingOperationSourceOver
3177 NSPoint pt = r.origin;
3179 [img compositeToPoint: pt operation: NSCompositingOperationSourceOver];
3188 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
3189 int x, int y, enum text_cursor_kinds cursor_type,
3190 int cursor_width, bool on_p, bool active_p)
3191 /* --------------------------------------------------------------------------
3192 External call (RIF): draw cursor.
3193 Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
3194 -------------------------------------------------------------------------- */
3197 int fx, fy, h, cursor_height;
3198 struct frame *f = WINDOW_XFRAME (w);
3199 struct glyph *phys_cursor_glyph;
3200 struct glyph *cursor_glyph;
3202 NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
3204 /* If cursor is out of bounds, don't draw garbage. This can happen
3205 in mini-buffer windows when switching between echo area glyphs
3208 NSTRACE ("ns_draw_window_cursor");
3213 w->phys_cursor_type = cursor_type;
3214 w->phys_cursor_on_p = on_p;
3216 if (cursor_type == NO_CURSOR)
3218 w->phys_cursor_width = 0;
3222 if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
3224 if (glyph_row->exact_window_width_line_p
3225 && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
3227 glyph_row->cursor_in_fringe_p = 1;
3228 draw_fringe_bitmap (w, glyph_row, 0);
3233 /* We draw the cursor (with NSRectFill), then draw the glyph on top
3234 (other terminals do it the other way round). We must set
3235 w->phys_cursor_width to the cursor width. For bar cursors, that
3236 is CURSOR_WIDTH; for box cursors, it is the glyph width. */
3237 get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
3239 /* The above get_phys_cursor_geometry call set w->phys_cursor_width
3240 to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
3241 if (cursor_type == BAR_CURSOR)
3243 if (cursor_width < 1)
3244 cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
3246 /* The bar cursor should never be wider than the glyph. */
3247 if (cursor_width < w->phys_cursor_width)
3248 w->phys_cursor_width = cursor_width;
3250 /* If we have an HBAR, "cursor_width" MAY specify height. */
3251 else if (cursor_type == HBAR_CURSOR)
3253 cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
3254 if (cursor_height > glyph_row->height)
3255 cursor_height = glyph_row->height;
3256 if (h > cursor_height) // Cursor smaller than line height, move down
3257 fy += h - cursor_height;
3261 r.origin.x = fx, r.origin.y = fy;
3263 r.size.width = w->phys_cursor_width;
3265 /* Prevent the cursor from being drawn outside the text area. */
3266 ns_clip_to_row (w, glyph_row, TEXT_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
3269 face = FACE_FROM_ID_OR_NULL (f, phys_cursor_glyph->face_id);
3270 if (face && NS_FACE_BACKGROUND (face)
3271 == ns_index_color (FRAME_CURSOR_COLOR (f), f))
3273 [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
3274 hollow_color = FRAME_CURSOR_COLOR (f);
3277 [FRAME_CURSOR_COLOR (f) set];
3279 #ifdef NS_IMPL_COCOA
3280 /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
3281 atomic. Cleaner ways of doing this should be investigated.
3282 One way would be to set a global variable DRAWING_CURSOR
3283 when making the call to draw_phys..(), don't focus in that
3284 case, then move the ns_unfocus() here after that call. */
3285 NSDisableScreenUpdates ();
3288 switch (cursor_type)
3290 case DEFAULT_CURSOR:
3293 case FILLED_BOX_CURSOR:
3296 case HOLLOW_BOX_CURSOR:
3299 NSRectFill (NSInsetRect (r, 1, 1));
3300 [FRAME_CURSOR_COLOR (f) set];
3307 /* If the character under cursor is R2L, draw the bar cursor
3308 on the right of its glyph, rather than on the left. */
3309 cursor_glyph = get_phys_cursor_glyph (w);
3310 if ((cursor_glyph->resolved_level & 1) != 0)
3311 s.origin.x += cursor_glyph->pixel_width - s.size.width;
3318 /* draw the character under the cursor */
3319 if (cursor_type != NO_CURSOR)
3320 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
3322 #ifdef NS_IMPL_COCOA
3323 NSEnableScreenUpdates ();
3330 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
3331 /* --------------------------------------------------------------------------
3332 External (RIF): Draw a vertical line.
3333 -------------------------------------------------------------------------- */
3335 struct frame *f = XFRAME (WINDOW_FRAME (w));
3337 NSRect r = NSMakeRect (x, y0, 1, y1-y0);
3339 NSTRACE ("ns_draw_vertical_window_border");
3341 face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID);
3343 ns_focus (f, &r, 1);
3345 [ns_lookup_indexed_color(face->foreground, f) set];
3353 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
3354 /* --------------------------------------------------------------------------
3355 External (RIF): Draw a window divider.
3356 -------------------------------------------------------------------------- */
3358 struct frame *f = XFRAME (WINDOW_FRAME (w));
3359 struct face *face = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FACE_ID);
3360 struct face *face_first
3361 = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID);
3362 struct face *face_last
3363 = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_LAST_PIXEL_FACE_ID);
3364 unsigned long color = face ? face->foreground : FRAME_FOREGROUND_PIXEL (f);
3365 unsigned long color_first = (face_first
3366 ? face_first->foreground
3367 : FRAME_FOREGROUND_PIXEL (f));
3368 unsigned long color_last = (face_last
3369 ? face_last->foreground
3370 : FRAME_FOREGROUND_PIXEL (f));
3371 NSRect divider = NSMakeRect (x0, y0, x1-x0, y1-y0);
3373 NSTRACE ("ns_draw_window_divider");
3375 ns_focus (f, ÷r, 1);
3377 if ((y1 - y0 > x1 - x0) && (x1 - x0 >= 3))
3378 /* A vertical divider, at least three pixels wide: Draw first and
3379 last pixels differently. */
3381 [ns_lookup_indexed_color(color_first, f) set];
3382 NSRectFill(NSMakeRect (x0, y0, 1, y1 - y0));
3383 [ns_lookup_indexed_color(color, f) set];
3384 NSRectFill(NSMakeRect (x0 + 1, y0, x1 - x0 - 2, y1 - y0));
3385 [ns_lookup_indexed_color(color_last, f) set];
3386 NSRectFill(NSMakeRect (x1 - 1, y0, 1, y1 - y0));
3388 else if ((x1 - x0 > y1 - y0) && (y1 - y0 >= 3))
3389 /* A horizontal divider, at least three pixels high: Draw first and
3390 last pixels differently. */
3392 [ns_lookup_indexed_color(color_first, f) set];
3393 NSRectFill(NSMakeRect (x0, y0, x1 - x0, 1));
3394 [ns_lookup_indexed_color(color, f) set];
3395 NSRectFill(NSMakeRect (x0, y0 + 1, x1 - x0, y1 - y0 - 2));
3396 [ns_lookup_indexed_color(color_last, f) set];
3397 NSRectFill(NSMakeRect (x0, y1 - 1, x1 - x0, 1));
3401 /* In any other case do not draw the first and last pixels
3403 [ns_lookup_indexed_color(color, f) set];
3404 NSRectFill(divider);
3411 ns_show_hourglass (struct frame *f)
3413 /* TODO: add NSProgressIndicator to all frames. */
3417 ns_hide_hourglass (struct frame *f)
3419 /* TODO: remove NSProgressIndicator from all frames. */
3422 /* ==========================================================================
3424 Glyph drawing operations
3426 ========================================================================== */
3429 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
3430 /* --------------------------------------------------------------------------
3431 Wrapper utility to account for internal border width on full-width lines,
3432 and allow top full-width rows to hit the frame top. nr should be pointer
3433 to two successive NSRects. Number of rects actually used is returned.
3434 -------------------------------------------------------------------------- */
3436 int n = get_glyph_string_clip_rects (s, nr, 2);
3440 /* --------------------------------------------------------------------
3441 Draw a wavy line under glyph string s. The wave fills wave_height
3448 wave_height = 3 | * * * *
3449 --------------------------------------------------------------------- */
3452 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
3454 int wave_height = 3, wave_length = 2;
3455 int y, dx, dy, odd, xmax;
3460 dy = wave_height - 1;
3461 y = s->ybase - wave_height + 3;
3464 /* Find and set clipping rectangle */
3465 waveClip = NSMakeRect (x, y, width, wave_height);
3466 [[NSGraphicsContext currentContext] saveGraphicsState];
3467 NSRectClip (waveClip);
3469 /* Draw the waves */
3470 a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
3472 odd = (int)(a.x/dx) % 2;
3473 a.y = b.y = y + 0.5;
3482 [NSBezierPath strokeLineFromPoint:a toPoint:b];
3483 a.x = b.x, a.y = b.y;
3484 b.x += dx, b.y = y + 0.5 + odd*dy;
3488 /* Restore previous clipping rectangle(s) */
3489 [[NSGraphicsContext currentContext] restoreGraphicsState];
3495 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
3496 NSColor *defaultCol, CGFloat width, CGFloat x)
3497 /* --------------------------------------------------------------------------
3498 Draw underline, overline, and strike-through on glyph string s.
3499 -------------------------------------------------------------------------- */
3501 if (s->for_overlaps)
3505 if (face->underline_p)
3507 if (s->face->underline_type == FACE_UNDER_WAVE)
3509 if (face->underline_defaulted_p)
3512 [ns_lookup_indexed_color (face->underline_color, s->f) set];
3514 ns_draw_underwave (s, width, x);
3516 else if (s->face->underline_type == FACE_UNDER_LINE)
3520 unsigned long thickness, position;
3522 /* If the prev was underlined, match its appearance. */
3523 if (s->prev && s->prev->face->underline_p
3524 && s->prev->face->underline_type == FACE_UNDER_LINE
3525 && s->prev->underline_thickness > 0)
3527 thickness = s->prev->underline_thickness;
3528 position = s->prev->underline_position;
3532 struct font *font = font_for_underline_metrics (s);
3533 unsigned long descent = s->y + s->height - s->ybase;
3534 unsigned long minimum_offset;
3535 BOOL underline_at_descent_line, use_underline_position_properties;
3536 Lisp_Object val = buffer_local_value (Qunderline_minimum_offset,
3539 minimum_offset = XFASTINT (val);
3542 val = buffer_local_value (Qx_underline_at_descent_line,
3544 underline_at_descent_line = !(NILP (val) || EQ (val, Qunbound));
3545 val = buffer_local_value (Qx_use_underline_position_properties,
3547 use_underline_position_properties =
3548 !(NILP (val) || EQ (val, Qunbound));
3550 /* Use underline thickness of font, defaulting to 1. */
3551 thickness = (font && font->underline_thickness > 0)
3552 ? font->underline_thickness : 1;
3554 /* Determine the offset of underlining from the baseline. */
3555 if (underline_at_descent_line)
3556 position = descent - thickness;
3557 else if (use_underline_position_properties
3558 && font && font->underline_position >= 0)
3559 position = font->underline_position;
3561 position = lround (font->descent / 2);
3563 position = minimum_offset;
3565 position = max (position, minimum_offset);
3567 /* Ensure underlining is not cropped. */
3568 if (descent <= position)
3570 position = descent - 1;
3573 else if (descent < position + thickness)
3577 s->underline_thickness = thickness;
3578 s->underline_position = position;
3580 r = NSMakeRect (x, s->ybase + position, width, thickness);
3582 if (face->underline_defaulted_p)
3585 [ns_lookup_indexed_color (face->underline_color, s->f) set];
3589 /* Do overline. We follow other terms in using a thickness of 1
3590 and ignoring overline_margin. */
3591 if (face->overline_p)
3594 r = NSMakeRect (x, s->y, width, 1);
3596 if (face->overline_color_defaulted_p)
3599 [ns_lookup_indexed_color (face->overline_color, s->f) set];
3603 /* Do strike-through. We follow other terms for thickness and
3604 vertical position. */
3605 if (face->strike_through_p)
3608 /* Y-coordinate and height of the glyph string's first glyph.
3609 We cannot use s->y and s->height because those could be
3610 larger if there are taller display elements (e.g., characters
3611 displayed with a larger font) in the same glyph row. */
3612 int glyph_y = s->ybase - s->first_glyph->ascent;
3613 int glyph_height = s->first_glyph->ascent + s->first_glyph->descent;
3614 /* Strike-through width and offset from the glyph string's
3616 unsigned long h = 1;
3619 dy = lrint ((glyph_height - h) / 2);
3620 r = NSMakeRect (x, glyph_y + dy, width, 1);
3622 if (face->strike_through_color_defaulted_p)
3625 [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
3631 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
3632 char left_p, char right_p)
3633 /* --------------------------------------------------------------------------
3634 Draw an unfilled rect inside r, optionally leaving left and/or right open.
3635 Note we can't just use an NSDrawRect command, because of the possibility
3636 of some sides not being drawn, and because the rect will be filled.
3637 -------------------------------------------------------------------------- */
3643 s.size.height = thickness;
3645 s.origin.y += r.size.height - thickness;
3648 s.size.height = r.size.height;
3649 s.origin.y = r.origin.y;
3651 /* left, right (optional) */
3652 s.size.width = thickness;
3657 s.origin.x += r.size.width - thickness;
3664 ns_draw_relief (NSRect r, int thickness, char raised_p,
3665 char top_p, char bottom_p, char left_p, char right_p,
3666 struct glyph_string *s)
3667 /* --------------------------------------------------------------------------
3668 Draw a relief rect inside r, optionally leaving some sides open.
3669 Note we can't just use an NSDrawBezel command, because of the possibility
3670 of some sides not being drawn, and because the rect will be filled.
3671 -------------------------------------------------------------------------- */
3673 static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
3674 NSColor *newBaseCol = nil;
3677 NSTRACE ("ns_draw_relief");
3681 if (s->face->use_box_color_for_shadows_p)
3683 newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
3685 /* else if (s->first_glyph->type == IMAGE_GLYPH
3687 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3689 newBaseCol = IMAGE_BACKGROUND (s->img, s->f, 0);
3693 newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
3696 if (newBaseCol == nil)
3697 newBaseCol = [NSColor grayColor];
3699 if (newBaseCol != baseCol) /* TODO: better check */
3702 baseCol = [newBaseCol retain];
3704 lightCol = [[baseCol highlightWithLevel: 0.2] retain];
3706 darkCol = [[baseCol shadowWithLevel: 0.3] retain];
3709 [(raised_p ? lightCol : darkCol) set];
3711 /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
3714 sr.size.height = thickness;
3715 if (top_p) NSRectFill (sr);
3718 sr.size.height = r.size.height;
3719 sr.size.width = thickness;
3720 if (left_p) NSRectFill (sr);
3722 [(raised_p ? darkCol : lightCol) set];
3725 sr.size.width = r.size.width;
3726 sr.size.height = thickness;
3727 sr.origin.y += r.size.height - thickness;
3728 if (bottom_p) NSRectFill (sr);
3731 sr.size.height = r.size.height;
3732 sr.origin.y = r.origin.y;
3733 sr.size.width = thickness;
3734 sr.origin.x += r.size.width - thickness;
3735 if (right_p) NSRectFill (sr);
3740 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
3741 /* --------------------------------------------------------------------------
3742 Function modeled after x_draw_glyph_string_box ().
3743 Sets up parameters for drawing.
3744 -------------------------------------------------------------------------- */
3746 int right_x, last_x;
3747 char left_p, right_p;
3748 struct glyph *last_glyph;
3753 if (s->hl == DRAW_MOUSE_FACE)
3755 face = FACE_FROM_ID_OR_NULL (s->f,
3756 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3758 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3763 thickness = face->box_line_width;
3765 NSTRACE ("ns_dumpglyphs_box_or_relief");
3767 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
3768 ? WINDOW_RIGHT_EDGE_X (s->w)
3769 : window_box_right (s->w, s->area));
3770 last_glyph = (s->cmp || s->img
3771 ? s->first_glyph : s->first_glyph + s->nchars-1);
3773 right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
3774 ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
3776 left_p = (s->first_glyph->left_box_line_p
3777 || (s->hl == DRAW_MOUSE_FACE
3778 && (s->prev == NULL || s->prev->hl != s->hl)));
3779 right_p = (last_glyph->right_box_line_p
3780 || (s->hl == DRAW_MOUSE_FACE
3781 && (s->next == NULL || s->next->hl != s->hl)));
3783 r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
3785 /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
3786 if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
3788 ns_draw_box (r, abs (thickness),
3789 ns_lookup_indexed_color (face->box_color, s->f),
3794 ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
3795 1, 1, left_p, right_p, s);
3801 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
3802 /* --------------------------------------------------------------------------
3803 Modeled after x_draw_glyph_string_background, which draws BG in
3804 certain cases. Others are left to the text rendering routine.
3805 -------------------------------------------------------------------------- */
3807 NSTRACE ("ns_maybe_dumpglyphs_background");
3809 if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
3811 int box_line_width = max (s->face->box_line_width, 0);
3812 if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
3813 /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font
3814 dimensions, since the actual glyphs might be much
3815 smaller. So in that case we always clear the rectangle
3816 with background color. */
3817 || FONT_TOO_HIGH (s->font)
3818 || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
3821 if (s->hl == DRAW_MOUSE_FACE)
3824 = FACE_FROM_ID_OR_NULL (s->f,
3825 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3827 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3830 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3832 [(NS_FACE_BACKGROUND (face) != 0
3833 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
3834 : FRAME_BACKGROUND_COLOR (s->f)) set];
3837 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
3838 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
3841 if (s->hl != DRAW_CURSOR)
3843 NSRect r = NSMakeRect (s->x, s->y + box_line_width,
3844 s->background_width,
3845 s->height-2*box_line_width);
3849 s->background_filled_p = 1;
3856 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3857 /* --------------------------------------------------------------------------
3858 Renders an image and associated borders.
3859 -------------------------------------------------------------------------- */
3861 EmacsImage *img = s->img->pixmap;
3862 int box_line_vwidth = max (s->face->box_line_width, 0);
3863 int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3864 int bg_x, bg_y, bg_height;
3871 NSTRACE ("ns_dumpglyphs_image");
3873 if (s->face->box != FACE_NO_BOX
3874 && s->first_glyph->left_box_line_p && s->slice.x == 0)
3875 x += abs (s->face->box_line_width);
3878 bg_y = s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
3879 bg_height = s->height;
3880 /* other terms have this, but was causing problems w/tabbar mode */
3881 /* - 2 * box_line_vwidth; */
3883 if (s->slice.x == 0) x += s->img->hmargin;
3884 if (s->slice.y == 0) y += s->img->vmargin;
3886 /* Draw BG: if we need larger area than image itself cleared, do that,
3887 otherwise, since we composite the image under NS (instead of mucking
3888 with its background color), we must clear just the image area. */
3889 if (s->hl == DRAW_MOUSE_FACE)
3891 face = FACE_FROM_ID_OR_NULL (s->f,
3892 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3894 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3897 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3899 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3901 if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3902 || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3904 br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3905 s->background_filled_p = 1;
3909 br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3914 /* Draw the image... do we need to draw placeholder if img == nil? */
3917 #ifdef NS_IMPL_COCOA
3918 NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3919 NSRect ir = NSMakeRect (s->slice.x,
3920 s->img->height - s->slice.y - s->slice.height,
3921 s->slice.width, s->slice.height);
3924 operation: NSCompositingOperationSourceOver
3929 [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3930 operation: NSCompositingOperationSourceOver];
3934 if (s->hl == DRAW_CURSOR)
3936 [FRAME_CURSOR_COLOR (s->f) set];
3937 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3938 tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3940 /* Currently on NS img->mask is always 0. Since
3941 get_window_cursor_type specifies a hollow box cursor when on
3942 a non-masked image we never reach this clause. But we put it
3943 in, in anticipation of better support for image masks on
3945 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3949 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3952 /* Draw underline, overline, strike-through. */
3953 ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3955 /* Draw relief, if requested */
3956 if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3958 if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3960 th = tool_bar_button_relief >= 0 ?
3961 tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3962 raised_p = (s->hl == DRAW_IMAGE_RAISED);
3966 th = abs (s->img->relief);
3967 raised_p = (s->img->relief > 0);
3970 r.origin.x = x - th;
3971 r.origin.y = y - th;
3972 r.size.width = s->slice.width + 2*th-1;
3973 r.size.height = s->slice.height + 2*th-1;
3974 ns_draw_relief (r, th, raised_p,
3976 s->slice.y + s->slice.height == s->img->height,
3978 s->slice.x + s->slice.width == s->img->width, s);
3981 /* If there is no mask, the background won't be seen,
3982 so draw a rectangle on the image for the cursor.
3983 Do this for all images, getting transparency right is not reliable. */
3984 if (s->hl == DRAW_CURSOR)
3986 int thickness = abs (s->img->relief);
3987 if (thickness == 0) thickness = 1;
3988 ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3994 ns_dumpglyphs_stretch (struct glyph_string *s)
3999 NSColor *fgCol, *bgCol;
4001 if (!s->background_filled_p)
4003 n = ns_get_glyph_string_clip_rect (s, r);
4004 *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
4006 ns_focus (s->f, r, n);
4008 if (s->hl == DRAW_MOUSE_FACE)
4010 face = FACE_FROM_ID_OR_NULL (s->f,
4011 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
4013 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
4016 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
4018 bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
4019 fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
4021 for (i = 0; i < n; ++i)
4023 if (!s->row->full_width_p)
4025 int overrun, leftoverrun;
4027 /* truncate to avoid overwriting fringe and/or scrollbar */
4028 overrun = max (0, (s->x + s->background_width)
4029 - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
4030 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
4031 r[i].size.width -= overrun;
4033 /* truncate to avoid overwriting to left of the window box */
4034 leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
4035 + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
4037 if (leftoverrun > 0)
4039 r[i].origin.x += leftoverrun;
4040 r[i].size.width -= leftoverrun;
4043 /* XXX: Try to work between problem where a stretch glyph on
4044 a partially-visible bottom row will clear part of the
4045 modeline, and another where list-buffers headers and similar
4046 rows erroneously have visible_height set to 0. Not sure
4047 where this is coming from as other terms seem not to show. */
4048 r[i].size.height = min (s->height, s->row->visible_height);
4053 /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
4054 overwriting cursor (usually when cursor on a tab). */
4055 if (s->hl == DRAW_CURSOR)
4060 width = s->w->phys_cursor_width;
4061 r[i].size.width -= width;
4062 r[i].origin.x += width;
4066 /* Draw overlining, etc. on the cursor. */
4067 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
4068 ns_draw_text_decoration (s, face, bgCol, width, x);
4070 ns_draw_text_decoration (s, face, fgCol, width, x);
4077 /* Draw overlining, etc. on the stretch glyph (or the part
4078 of the stretch glyph after the cursor). */
4079 ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
4083 s->background_filled_p = 1;
4089 ns_draw_glyph_string_foreground (struct glyph_string *s)
4092 struct font *font = s->font;
4094 /* If first glyph of S has a left box line, start drawing the text
4095 of S to the right of that box line. */
4096 if (s->face && s->face->box != FACE_NO_BOX
4097 && s->first_glyph->left_box_line_p)
4098 x = s->x + eabs (s->face->box_line_width);
4102 flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
4103 (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
4104 (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
4105 NS_DUMPGLYPH_NORMAL));
4108 (s, s->cmp_from, s->nchars, x, s->ybase,
4109 (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
4110 || flags == NS_DUMPGLYPH_MOUSEFACE);
4115 ns_draw_composite_glyph_string_foreground (struct glyph_string *s)
4118 struct font *font = s->font;
4120 /* If first glyph of S has a left box line, start drawing the text
4121 of S to the right of that box line. */
4122 if (s->face && s->face->box != FACE_NO_BOX
4123 && s->first_glyph->left_box_line_p)
4124 x = s->x + eabs (s->face->box_line_width);
4128 /* S is a glyph string for a composition. S->cmp_from is the index
4129 of the first character drawn for glyphs of this composition.
4130 S->cmp_from == 0 means we are drawing the very first character of
4131 this composition. */
4133 /* Draw a rectangle for the composition if the font for the very
4134 first character of the composition could not be loaded. */
4135 if (s->font_not_found_p)
4137 if (s->cmp_from == 0)
4139 NSRect r = NSMakeRect (s->x, s->y, s->width-1, s->height -1);
4140 ns_draw_box (r, 1, FRAME_CURSOR_COLOR (s->f), 1, 1);
4143 else if (! s->first_glyph->u.cmp.automatic)
4147 for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
4148 /* TAB in a composition means display glyphs with padding
4149 space on the left or right. */
4150 if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
4152 int xx = x + s->cmp->offsets[j * 2];
4153 int yy = y - s->cmp->offsets[j * 2 + 1];
4155 font->driver->draw (s, j, j + 1, xx, yy, false);
4156 if (s->face->overstrike)
4157 font->driver->draw (s, j, j + 1, xx + 1, yy, false);
4162 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
4167 for (i = j = s->cmp_from; i < s->cmp_to; i++)
4169 glyph = LGSTRING_GLYPH (gstring, i);
4170 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
4171 width += LGLYPH_WIDTH (glyph);
4174 int xoff, yoff, wadjust;
4178 font->driver->draw (s, j, i, x, y, false);
4179 if (s->face->overstrike)
4180 font->driver->draw (s, j, i, x + 1, y, false);
4183 xoff = LGLYPH_XOFF (glyph);
4184 yoff = LGLYPH_YOFF (glyph);
4185 wadjust = LGLYPH_WADJUST (glyph);
4186 font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
4187 if (s->face->overstrike)
4188 font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
4197 font->driver->draw (s, j, i, x, y, false);
4198 if (s->face->overstrike)
4199 font->driver->draw (s, j, i, x + 1, y, false);
4205 ns_draw_glyph_string (struct glyph_string *s)
4206 /* --------------------------------------------------------------------------
4207 External (RIF): Main draw-text call.
4208 -------------------------------------------------------------------------- */
4210 /* TODO (optimize): focus for box and contents draw */
4213 char box_drawn_p = 0;
4214 struct font *font = s->face->font;
4215 if (! font) font = FRAME_FONT (s->f);
4217 NSTRACE_WHEN (NSTRACE_GROUP_GLYPHS, "ns_draw_glyph_string");
4219 if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
4222 struct glyph_string *next;
4224 for (width = 0, next = s->next;
4225 next && width < s->right_overhang;
4226 width += next->width, next = next->next)
4227 if (next->first_glyph->type != IMAGE_GLYPH)
4229 if (next->first_glyph->type != STRETCH_GLYPH)
4231 n = ns_get_glyph_string_clip_rect (s->next, r);
4232 ns_focus (s->f, r, n);
4233 ns_maybe_dumpglyphs_background (s->next, 1);
4238 ns_dumpglyphs_stretch (s->next);
4240 next->num_clips = 0;
4244 if (!s->for_overlaps && s->face->box != FACE_NO_BOX
4245 && (s->first_glyph->type == CHAR_GLYPH
4246 || s->first_glyph->type == COMPOSITE_GLYPH))
4248 n = ns_get_glyph_string_clip_rect (s, r);
4249 ns_focus (s->f, r, n);
4250 ns_maybe_dumpglyphs_background (s, 1);
4251 ns_dumpglyphs_box_or_relief (s);
4256 switch (s->first_glyph->type)
4260 n = ns_get_glyph_string_clip_rect (s, r);
4261 ns_focus (s->f, r, n);
4262 ns_dumpglyphs_image (s, r[0]);
4267 ns_dumpglyphs_stretch (s);
4271 case COMPOSITE_GLYPH:
4272 n = ns_get_glyph_string_clip_rect (s, r);
4273 ns_focus (s->f, r, n);
4275 if (s->for_overlaps || (s->cmp_from > 0
4276 && ! s->first_glyph->u.cmp.automatic))
4277 s->background_filled_p = 1;
4279 ns_maybe_dumpglyphs_background
4280 (s, s->first_glyph->type == COMPOSITE_GLYPH);
4282 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
4284 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
4285 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
4286 NS_FACE_FOREGROUND (s->face) = tmp;
4290 BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
4293 ns_draw_composite_glyph_string_foreground (s);
4295 ns_draw_glyph_string_foreground (s);
4299 NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
4300 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
4302 : FRAME_FOREGROUND_COLOR (s->f));
4305 /* Draw underline, overline, strike-through. */
4306 ns_draw_text_decoration (s, s->face, col, s->width, s->x);
4309 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
4311 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
4312 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
4313 NS_FACE_FOREGROUND (s->face) = tmp;
4319 case GLYPHLESS_GLYPH:
4320 n = ns_get_glyph_string_clip_rect (s, r);
4321 ns_focus (s->f, r, n);
4323 if (s->for_overlaps || (s->cmp_from > 0
4324 && ! s->first_glyph->u.cmp.automatic))
4325 s->background_filled_p = 1;
4327 ns_maybe_dumpglyphs_background
4328 (s, s->first_glyph->type == COMPOSITE_GLYPH);
4330 /* Not yet implemented. */
4339 /* Draw box if not done already. */
4340 if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
4342 n = ns_get_glyph_string_clip_rect (s, r);
4343 ns_focus (s->f, r, n);
4344 ns_dumpglyphs_box_or_relief (s);
4353 /* ==========================================================================
4357 ========================================================================== */
4361 ns_send_appdefined (int value)
4362 /* --------------------------------------------------------------------------
4363 Internal: post an appdefined event which EmacsApp-sendEvent will
4364 recognize and take as a command to halt the event loop.
4365 -------------------------------------------------------------------------- */
4367 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_send_appdefined(%d)", value);
4369 // GNUstep needs postEvent to happen on the main thread.
4370 // Cocoa needs nextEventMatchingMask to happen on the main thread too.
4371 if (! [[NSThread currentThread] isMainThread])
4373 EmacsApp *app = (EmacsApp *)NSApp;
4374 app->nextappdefined = value;
4375 [app performSelectorOnMainThread:@selector (sendFromMainThread:)
4381 /* Only post this event if we haven't already posted one. This will end
4382 the [NXApp run] main loop after having processed all events queued at
4385 #ifdef NS_IMPL_COCOA
4386 if (! send_appdefined)
4388 /* OS X 10.10.1 swallows the AppDefined event we are sending ourselves
4389 in certain situations (rapid incoming events).
4390 So check if we have one, if not add one. */
4391 NSEvent *appev = [NSApp nextEventMatchingMask:NSEventMaskApplicationDefined
4392 untilDate:[NSDate distantPast]
4393 inMode:NSDefaultRunLoopMode
4395 if (! appev) send_appdefined = YES;
4399 if (send_appdefined)
4403 /* We only need one NX_APPDEFINED event to stop NXApp from running. */
4404 send_appdefined = NO;
4406 /* Don't need wakeup timer any more. */
4409 [timed_entry invalidate];
4410 [timed_entry release];
4414 nxev = [NSEvent otherEventWithType: NSEventTypeApplicationDefined
4415 location: NSMakePoint (0, 0)
4418 windowNumber: [[NSApp mainWindow] windowNumber]
4419 context: [NSApp context]
4424 /* Post an application defined event on the event queue. When this is
4425 received the [NXApp run] will return, thus having processed all
4426 events which are currently queued. */
4427 [NSApp postEvent: nxev atStart: NO];
4431 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
4435 Lisp_Object frame, tail;
4437 if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
4440 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
4442 FOR_EACH_FRAME (tail, frame)
4444 struct frame *f = XFRAME (frame);
4447 EmacsView *view = FRAME_NS_VIEW (f);
4448 [view updateCollectionBehavior];
4454 /* GNUstep does not have cancelTracking. */
4455 #ifdef NS_IMPL_COCOA
4456 /* Check if menu open should be canceled or continued as normal. */
4458 ns_check_menu_open (NSMenu *menu)
4460 /* Click in menu bar? */
4461 NSArray *a = [[NSApp mainMenu] itemArray];
4465 if (menu == nil) // Menu tracking ended.
4467 if (menu_will_open_state == MENU_OPENING)
4468 menu_will_open_state = MENU_NONE;
4472 for (i = 0; ! found && i < [a count]; i++)
4473 found = menu == [[a objectAtIndex:i] submenu];
4476 if (menu_will_open_state == MENU_NONE && emacs_event)
4478 NSEvent *theEvent = [NSApp currentEvent];
4479 struct frame *emacsframe = SELECTED_FRAME ();
4481 [menu cancelTracking];
4482 menu_will_open_state = MENU_PENDING;
4483 emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
4484 EV_TRAILER (theEvent);
4486 CGEventRef ourEvent = CGEventCreate (NULL);
4487 menu_mouse_point = CGEventGetLocation (ourEvent);
4488 CFRelease (ourEvent);
4490 else if (menu_will_open_state == MENU_OPENING)
4492 menu_will_open_state = MENU_NONE;
4497 /* Redo saved menu click if state is MENU_PENDING. */
4499 ns_check_pending_open_menu ()
4501 if (menu_will_open_state == MENU_PENDING)
4503 CGEventSourceRef source
4504 = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
4506 CGEventRef event = CGEventCreateMouseEvent (source,
4507 kCGEventLeftMouseDown,
4509 kCGMouseButtonLeft);
4510 CGEventSetType (event, kCGEventLeftMouseDown);
4511 CGEventPost (kCGHIDEventTap, event);
4515 menu_will_open_state = MENU_OPENING;
4518 #endif /* NS_IMPL_COCOA */
4521 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
4522 /* --------------------------------------------------------------------------
4523 External (hook): Post an event to ourself and keep reading events until
4524 we read it back again. In effect process all events which were waiting.
4525 From 21+ we have to manage the event buffer ourselves.
4526 -------------------------------------------------------------------------- */
4528 struct input_event ev;
4531 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_read_socket");
4533 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
4537 if ([NSApp modalWindow] != nil)
4540 if (hold_event_q.nr > 0)
4543 for (i = 0; i < hold_event_q.nr; ++i)
4544 kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
4545 hold_event_q.nr = 0;
4549 if ([NSThread isMainThread])
4552 n_emacs_events_pending = 0;
4553 ns_init_events (&ev);
4554 q_event_ptr = hold_quit;
4556 /* We manage autorelease pools by allocate/reallocate each time around
4557 the loop; strict nesting is occasionally violated but seems not to
4558 matter... earlier methods using full nesting caused major memory leaks. */
4559 [outerpool release];
4560 outerpool = [[NSAutoreleasePool alloc] init];
4562 /* If have pending open-file requests, attend to the next one of those. */
4563 if (ns_pending_files && [ns_pending_files count] != 0
4564 && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
4566 [ns_pending_files removeObjectAtIndex: 0];
4568 /* Deal with pending service requests. */
4569 else if (ns_pending_service_names && [ns_pending_service_names count] != 0
4571 NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
4572 withArg: [ns_pending_service_args objectAtIndex: 0]])
4574 [ns_pending_service_names removeObjectAtIndex: 0];
4575 [ns_pending_service_args removeObjectAtIndex: 0];
4579 /* Run and wait for events. We must always send one NX_APPDEFINED event
4580 to ourself, otherwise [NXApp run] will never exit. */
4581 send_appdefined = YES;
4582 ns_send_appdefined (-1);
4587 nevents = n_emacs_events_pending;
4588 n_emacs_events_pending = 0;
4589 ns_finish_events ();
4601 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
4602 fd_set *exceptfds, struct timespec *timeout,
4604 /* --------------------------------------------------------------------------
4605 Replacement for select, checking for events
4606 -------------------------------------------------------------------------- */
4610 struct input_event event;
4613 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_select");
4615 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
4619 if (hold_event_q.nr > 0)
4621 /* We already have events pending. */
4627 for (k = 0; k < nfds+1; k++)
4629 if (readfds && FD_ISSET(k, readfds)) ++nr;
4630 if (writefds && FD_ISSET(k, writefds)) ++nr;
4634 || ![NSThread isMainThread]
4635 || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
4636 return thread_select(pselect, nfds, readfds, writefds,
4637 exceptfds, timeout, sigmask);
4640 struct timespec t = {0, 0};
4641 thread_select(pselect, 0, NULL, NULL, NULL, &t, sigmask);
4644 [outerpool release];
4645 outerpool = [[NSAutoreleasePool alloc] init];
4648 send_appdefined = YES;
4651 pthread_mutex_lock (&select_mutex);
4656 select_readfds = *readfds;
4657 select_valid += SELECT_HAVE_READ;
4661 select_writefds = *writefds;
4662 select_valid += SELECT_HAVE_WRITE;
4667 select_timeout = *timeout;
4668 select_valid += SELECT_HAVE_TMO;
4671 pthread_mutex_unlock (&select_mutex);
4673 /* Inform fd_handler that select should be called. */
4675 emacs_write_sig (selfds[1], &c, 1);
4677 else if (nr == 0 && timeout)
4679 /* No file descriptor, just a timeout, no need to wake fd_handler. */
4680 double time = timespectod (*timeout);
4681 timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
4684 @selector (timeout_handler:)
4689 else /* No timeout and no file descriptors, can this happen? */
4691 /* Send appdefined so we exit from the loop. */
4692 ns_send_appdefined (-1);
4696 ns_init_events (&event);
4700 ns_finish_events ();
4701 if (nr > 0 && readfds)
4704 emacs_write_sig (selfds[1], &c, 1);
4708 t = last_appdefined_event_data;
4710 if (t != NO_APPDEFINED_DATA)
4712 last_appdefined_event_data = NO_APPDEFINED_DATA;
4716 /* The NX_APPDEFINED event we received was a timeout. */
4721 /* The NX_APPDEFINED event we received was the result of
4722 at least one real input event arriving. */
4728 /* Received back from select () in fd_handler; copy the results. */
4729 pthread_mutex_lock (&select_mutex);
4730 if (readfds) *readfds = select_readfds;
4731 if (writefds) *writefds = select_writefds;
4732 pthread_mutex_unlock (&select_mutex);
4747 ns_run_loop_break ()
4748 /* Break out of the NS run loop in ns_select or ns_read_socket. */
4750 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_run_loop_break");
4752 /* If we don't have a GUI, don't send the event. */
4754 ns_send_appdefined(-1);
4759 /* ==========================================================================
4763 ========================================================================== */
4767 ns_set_vertical_scroll_bar (struct window *window,
4768 int portion, int whole, int position)
4769 /* --------------------------------------------------------------------------
4770 External (hook): Update or add scrollbar
4771 -------------------------------------------------------------------------- */
4775 struct frame *f = XFRAME (WINDOW_FRAME (window));
4776 EmacsView *view = FRAME_NS_VIEW (f);
4778 int window_y, window_height;
4779 int top, left, height, width;
4780 BOOL update_p = YES;
4782 /* Optimization; display engine sends WAY too many of these. */
4783 if (!NILP (window->vertical_scroll_bar))
4785 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4786 if ([bar checkSamePosition: position portion: portion whole: whole])
4788 if (view->scrollbarsNeedingUpdate == 0)
4790 if (!windows_or_buffers_changed)
4794 view->scrollbarsNeedingUpdate--;
4799 NSTRACE ("ns_set_vertical_scroll_bar");
4801 /* Get dimensions. */
4802 window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
4804 height = window_height;
4805 width = NS_SCROLL_BAR_WIDTH (f);
4806 left = WINDOW_SCROLL_BAR_AREA_X (window);
4808 r = NSMakeRect (left, top, width, height);
4809 /* The parent view is flipped, so we need to flip y value. */
4811 r.origin.y = (v.size.height - r.size.height - r.origin.y);
4813 XSETWINDOW (win, window);
4816 /* We want at least 5 lines to display a scrollbar. */
4817 if (WINDOW_TOTAL_LINES (window) < 5)
4819 if (!NILP (window->vertical_scroll_bar))
4821 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4822 [bar removeFromSuperview];
4823 wset_vertical_scroll_bar (window, Qnil);
4826 ns_clear_frame_area (f, left, top, width, height);
4831 if (NILP (window->vertical_scroll_bar))
4833 if (width > 0 && height > 0)
4834 ns_clear_frame_area (f, left, top, width, height);
4836 bar = [[EmacsScroller alloc] initFrame: r window: win];
4837 wset_vertical_scroll_bar (window, make_save_ptr (bar));
4843 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4844 oldRect = [bar frame];
4845 r.size.width = oldRect.size.width;
4846 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4848 if (oldRect.origin.x != r.origin.x)
4849 ns_clear_frame_area (f, left, top, width, height);
4855 [bar setPosition: position portion: portion whole: whole];
4861 ns_set_horizontal_scroll_bar (struct window *window,
4862 int portion, int whole, int position)
4863 /* --------------------------------------------------------------------------
4864 External (hook): Update or add scrollbar.
4865 -------------------------------------------------------------------------- */
4869 struct frame *f = XFRAME (WINDOW_FRAME (window));
4870 EmacsView *view = FRAME_NS_VIEW (f);
4872 int top, height, left, width;
4873 int window_x, window_width;
4874 BOOL update_p = YES;
4876 /* Optimization; display engine sends WAY too many of these. */
4877 if (!NILP (window->horizontal_scroll_bar))
4879 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4880 if ([bar checkSamePosition: position portion: portion whole: whole])
4882 if (view->scrollbarsNeedingUpdate == 0)
4884 if (!windows_or_buffers_changed)
4888 view->scrollbarsNeedingUpdate--;
4893 NSTRACE ("ns_set_horizontal_scroll_bar");
4895 /* Get dimensions. */
4896 window_box (window, ANY_AREA, &window_x, 0, &window_width, 0);
4898 width = window_width;
4899 height = NS_SCROLL_BAR_HEIGHT (f);
4900 top = WINDOW_SCROLL_BAR_AREA_Y (window);
4902 r = NSMakeRect (left, top, width, height);
4903 /* The parent view is flipped, so we need to flip y value. */
4905 r.origin.y = (v.size.height - r.size.height - r.origin.y);
4907 XSETWINDOW (win, window);
4910 if (NILP (window->horizontal_scroll_bar))
4912 if (width > 0 && height > 0)
4913 ns_clear_frame_area (f, left, top, width, height);
4915 bar = [[EmacsScroller alloc] initFrame: r window: win];
4916 wset_horizontal_scroll_bar (window, make_save_ptr (bar));
4922 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4923 oldRect = [bar frame];
4924 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4926 if (oldRect.origin.y != r.origin.y)
4927 ns_clear_frame_area (f, left, top, width, height);
4933 /* If there are both horizontal and vertical scroll-bars they leave
4934 a square that belongs to neither. We need to clear it otherwise
4935 it fills with junk. */
4936 if (!NILP (window->vertical_scroll_bar))
4937 ns_clear_frame_area (f, WINDOW_SCROLL_BAR_AREA_X (window), top,
4938 NS_SCROLL_BAR_HEIGHT (f), height);
4941 [bar setPosition: position portion: portion whole: whole];
4947 ns_condemn_scroll_bars (struct frame *f)
4948 /* --------------------------------------------------------------------------
4949 External (hook): arrange for all frame's scrollbars to be removed
4950 at next call to judge_scroll_bars, except for those redeemed.
4951 -------------------------------------------------------------------------- */
4955 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
4957 NSTRACE ("ns_condemn_scroll_bars");
4959 for (i =[subviews count]-1; i >= 0; i--)
4961 view = [subviews objectAtIndex: i];
4962 if ([view isKindOfClass: [EmacsScroller class]])
4969 ns_redeem_scroll_bar (struct window *window)
4970 /* --------------------------------------------------------------------------
4971 External (hook): arrange to spare this window's scrollbar
4972 at next call to judge_scroll_bars.
4973 -------------------------------------------------------------------------- */
4976 NSTRACE ("ns_redeem_scroll_bar");
4977 if (!NILP (window->vertical_scroll_bar)
4978 && WINDOW_HAS_VERTICAL_SCROLL_BAR (window))
4980 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4984 if (!NILP (window->horizontal_scroll_bar)
4985 && WINDOW_HAS_HORIZONTAL_SCROLL_BAR (window))
4987 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4994 ns_judge_scroll_bars (struct frame *f)
4995 /* --------------------------------------------------------------------------
4996 External (hook): destroy all scrollbars on frame that weren't
4997 redeemed after call to condemn_scroll_bars.
4998 -------------------------------------------------------------------------- */
5002 EmacsView *eview = FRAME_NS_VIEW (f);
5003 NSArray *subviews = [[eview superview] subviews];
5006 NSTRACE ("ns_judge_scroll_bars");
5007 for (i = [subviews count]-1; i >= 0; --i)
5009 view = [subviews objectAtIndex: i];
5010 if (![view isKindOfClass: [EmacsScroller class]]) continue;
5016 [eview updateFrameSize: NO];
5019 /* ==========================================================================
5023 ========================================================================== */
5026 x_display_pixel_height (struct ns_display_info *dpyinfo)
5028 NSArray *screens = [NSScreen screens];
5029 NSEnumerator *enumerator = [screens objectEnumerator];
5034 while ((screen = [enumerator nextObject]) != nil)
5035 frame = NSUnionRect (frame, [screen frame]);
5037 return NSHeight (frame);
5041 x_display_pixel_width (struct ns_display_info *dpyinfo)
5043 NSArray *screens = [NSScreen screens];
5044 NSEnumerator *enumerator = [screens objectEnumerator];
5049 while ((screen = [enumerator nextObject]) != nil)
5050 frame = NSUnionRect (frame, [screen frame]);
5052 return NSWidth (frame);
5056 static Lisp_Object ns_string_to_lispmod (const char *s)
5057 /* --------------------------------------------------------------------------
5058 Convert modifier name to lisp symbol.
5059 -------------------------------------------------------------------------- */
5061 if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
5063 else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
5065 else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
5067 else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
5069 else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
5071 else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
5079 ns_default (const char *parameter, Lisp_Object *result,
5080 Lisp_Object yesval, Lisp_Object noval,
5081 BOOL is_float, BOOL is_modstring)
5082 /* --------------------------------------------------------------------------
5083 Check a parameter value in user's preferences.
5084 -------------------------------------------------------------------------- */
5086 const char *value = ns_get_defaults_value (parameter);
5092 if (c_strcasecmp (value, "YES") == 0)
5094 else if (c_strcasecmp (value, "NO") == 0)
5096 else if (is_float && (f = strtod (value, &pos), pos != value))
5097 *result = make_float (f);
5098 else if (is_modstring && value)
5099 *result = ns_string_to_lispmod (value);
5100 else fprintf (stderr,
5101 "Bad value for default \"%s\": \"%s\"\n", parameter, value);
5107 ns_initialize_display_info (struct ns_display_info *dpyinfo)
5108 /* --------------------------------------------------------------------------
5109 Initialize global info and storage for display.
5110 -------------------------------------------------------------------------- */
5112 NSScreen *screen = [NSScreen mainScreen];
5113 NSWindowDepth depth = [screen depth];
5115 dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
5116 dpyinfo->resy = 72.27;
5117 dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
5118 NSColorSpaceFromDepth (depth)]
5119 && ![NSCalibratedWhiteColorSpace isEqualToString:
5120 NSColorSpaceFromDepth (depth)];
5121 dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
5122 dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
5123 dpyinfo->color_table->colors = NULL;
5124 dpyinfo->root_window = 42; /* A placeholder. */
5125 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
5126 dpyinfo->n_fonts = 0;
5127 dpyinfo->smallest_font_height = 1;
5128 dpyinfo->smallest_char_width = 1;
5130 reset_mouse_highlight (&dpyinfo->mouse_highlight);
5134 /* This and next define (many of the) public functions in this file. */
5135 /* x_... are generic versions in xdisp.c that we, and other terms, get away
5136 with using despite presence in the "system dependent" redisplay
5137 interface. In addition, many of the ns_ methods have code that is
5138 shared with all terms, indicating need for further refactoring. */
5139 extern frame_parm_handler ns_frame_parm_handlers[];
5140 static struct redisplay_interface ns_redisplay_interface =
5142 ns_frame_parm_handlers,
5146 x_clear_end_of_line,
5148 ns_after_update_window_line,
5149 ns_update_window_begin,
5150 ns_update_window_end,
5151 0, /* flush_display */
5152 x_clear_window_mouse_face,
5153 x_get_glyph_overhangs,
5154 x_fix_overlapping_area,
5155 ns_draw_fringe_bitmap,
5156 0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
5157 0, /* destroy_fringe_bitmap */
5158 ns_compute_glyph_string_overhangs,
5159 ns_draw_glyph_string,
5160 ns_define_frame_cursor,
5161 ns_clear_frame_area,
5162 ns_draw_window_cursor,
5163 ns_draw_vertical_window_border,
5164 ns_draw_window_divider,
5165 ns_shift_glyphs_for_insert,
5172 ns_delete_display (struct ns_display_info *dpyinfo)
5178 /* This function is called when the last frame on a display is deleted. */
5180 ns_delete_terminal (struct terminal *terminal)
5182 struct ns_display_info *dpyinfo = terminal->display_info.ns;
5184 NSTRACE ("ns_delete_terminal");
5186 /* Protect against recursive calls. delete_frame in
5187 delete_terminal calls us back when it deletes our last frame. */
5188 if (!terminal->name)
5193 x_destroy_all_bitmaps (dpyinfo);
5194 ns_delete_display (dpyinfo);
5199 static struct terminal *
5200 ns_create_terminal (struct ns_display_info *dpyinfo)
5201 /* --------------------------------------------------------------------------
5202 Set up use of NS before we make the first connection.
5203 -------------------------------------------------------------------------- */
5205 struct terminal *terminal;
5207 NSTRACE ("ns_create_terminal");
5209 terminal = create_terminal (output_ns, &ns_redisplay_interface);
5211 terminal->display_info.ns = dpyinfo;
5212 dpyinfo->terminal = terminal;
5214 terminal->clear_frame_hook = ns_clear_frame;
5215 terminal->ring_bell_hook = ns_ring_bell;
5216 terminal->update_begin_hook = ns_update_begin;
5217 terminal->update_end_hook = ns_update_end;
5218 terminal->read_socket_hook = ns_read_socket;
5219 terminal->frame_up_to_date_hook = ns_frame_up_to_date;
5220 terminal->mouse_position_hook = ns_mouse_position;
5221 terminal->frame_rehighlight_hook = ns_frame_rehighlight;
5222 terminal->frame_raise_lower_hook = ns_frame_raise_lower;
5223 terminal->fullscreen_hook = ns_fullscreen_hook;
5224 terminal->menu_show_hook = ns_menu_show;
5225 terminal->popup_dialog_hook = ns_popup_dialog;
5226 terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
5227 terminal->set_horizontal_scroll_bar_hook = ns_set_horizontal_scroll_bar;
5228 terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
5229 terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
5230 terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
5231 terminal->delete_frame_hook = x_destroy_window;
5232 terminal->delete_terminal_hook = ns_delete_terminal;
5233 /* Other hooks are NULL by default. */
5239 struct ns_display_info *
5240 ns_term_init (Lisp_Object display_name)
5241 /* --------------------------------------------------------------------------
5242 Start the Application and get things rolling.
5243 -------------------------------------------------------------------------- */
5245 struct terminal *terminal;
5246 struct ns_display_info *dpyinfo;
5247 static int ns_initialized = 0;
5250 if (ns_initialized) return x_display_list;
5255 NSTRACE ("ns_term_init");
5257 [outerpool release];
5258 outerpool = [[NSAutoreleasePool alloc] init];
5260 /* count object allocs (About, click icon); on macOS use ObjectAlloc tool */
5261 /*GSDebugAllocationActive (YES); */
5265 Fset_input_interrupt_mode (Qnil);
5267 if (selfds[0] == -1)
5269 if (emacs_pipe (selfds) != 0)
5271 fprintf (stderr, "Failed to create pipe: %s\n",
5272 emacs_strerror (errno));
5276 fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
5277 FD_ZERO (&select_readfds);
5278 FD_ZERO (&select_writefds);
5279 pthread_mutex_init (&select_mutex, NULL);
5282 ns_pending_files = [[NSMutableArray alloc] init];
5283 ns_pending_service_names = [[NSMutableArray alloc] init];
5284 ns_pending_service_args = [[NSMutableArray alloc] init];
5286 /* Start app and create the main menu, window, view.
5287 Needs to be here because ns_initialize_display_info () uses AppKit classes.
5288 The view will then ask the NSApp to stop and return to Emacs. */
5289 [EmacsApp sharedApplication];
5292 [NSApp setDelegate: NSApp];
5294 /* Start the select thread. */
5295 [NSThread detachNewThreadSelector:@selector (fd_handler:)
5299 /* debugging: log all notifications */
5300 /* [[NSNotificationCenter defaultCenter] addObserver: NSApp
5301 selector: @selector (logNotification:)
5302 name: nil object: nil]; */
5304 dpyinfo = xzalloc (sizeof *dpyinfo);
5306 ns_initialize_display_info (dpyinfo);
5307 terminal = ns_create_terminal (dpyinfo);
5309 terminal->kboard = allocate_kboard (Qns);
5310 /* Don't let the initial kboard remain current longer than necessary.
5311 That would cause problems if a file loaded on startup tries to
5312 prompt in the mini-buffer. */
5313 if (current_kboard == initial_kboard)
5314 current_kboard = terminal->kboard;
5315 terminal->kboard->reference_count++;
5317 dpyinfo->next = x_display_list;
5318 x_display_list = dpyinfo;
5320 dpyinfo->name_list_element = Fcons (display_name, Qnil);
5322 terminal->name = xlispstrdup (display_name);
5326 if (!inhibit_x_resources)
5328 ns_default ("GSFontAntiAlias", &ns_antialias_text,
5331 /* this is a standard variable */
5332 ns_default ("AppleAntiAliasingThreshold", &tmp,
5333 make_float (10.0), make_float (6.0), YES, NO);
5334 ns_antialias_threshold = NILP (tmp) ? 10.0 : extract_float (tmp);
5337 NSTRACE_MSG ("Colors");
5340 NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
5344 Lisp_Object color_file, color_map, color;
5348 color_file = Fexpand_file_name (build_string ("rgb.txt"),
5349 Fsymbol_value (intern ("data-directory")));
5351 color_map = Fx_load_color_file (color_file);
5352 if (NILP (color_map))
5353 fatal ("Could not read %s.\n", SDATA (color_file));
5355 cl = [[NSColorList alloc] initWithName: @"Emacs"];
5356 for ( ; CONSP (color_map); color_map = XCDR (color_map))
5358 color = XCAR (color_map);
5359 name = SSDATA (XCAR (color));
5360 c = XINT (XCDR (color));
5362 [NSColor colorForEmacsRed: RED_FROM_ULONG (c) / 255.0
5363 green: GREEN_FROM_ULONG (c) / 255.0
5364 blue: BLUE_FROM_ULONG (c) / 255.0
5366 forKey: [NSString stringWithUTF8String: name]];
5368 [cl writeToFile: nil];
5372 NSTRACE_MSG ("Versions");
5375 #ifdef NS_IMPL_GNUSTEP
5376 Vwindow_system_version = build_string (gnustep_base_version);
5378 /* PSnextrelease (128, c); */
5379 char c[DBL_BUFSIZE_BOUND];
5380 int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
5381 Vwindow_system_version = make_unibyte_string (c, len);
5385 delete_keyboard_wait_descriptor (0);
5387 ns_app_name = [[NSProcessInfo processInfo] processName];
5389 /* Set up macOS app menu */
5391 NSTRACE_MSG ("Menu init");
5393 #ifdef NS_IMPL_COCOA
5397 /* set up the application menu */
5398 svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
5399 [svcsMenu setAutoenablesItems: NO];
5400 appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
5401 [appMenu setAutoenablesItems: NO];
5402 mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
5403 dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
5405 [appMenu insertItemWithTitle: @"About Emacs"
5406 action: @selector (orderFrontStandardAboutPanel:)
5409 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
5410 [appMenu insertItemWithTitle: @"Preferences..."
5411 action: @selector (showPreferencesWindow:)
5414 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
5415 item = [appMenu insertItemWithTitle: @"Services"
5416 action: @selector (menuDown:)
5419 [appMenu setSubmenu: svcsMenu forItem: item];
5420 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
5421 [appMenu insertItemWithTitle: @"Hide Emacs"
5422 action: @selector (hide:)
5425 item = [appMenu insertItemWithTitle: @"Hide Others"
5426 action: @selector (hideOtherApplications:)
5429 [item setKeyEquivalentModifierMask: NSEventModifierFlagCommand | NSEventModifierFlagOption];
5430 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
5431 [appMenu insertItemWithTitle: @"Quit Emacs"
5432 action: @selector (terminate:)
5436 item = [mainMenu insertItemWithTitle: ns_app_name
5437 action: @selector (menuDown:)
5440 [mainMenu setSubmenu: appMenu forItem: item];
5441 [dockMenu insertItemWithTitle: @"New Frame"
5442 action: @selector (newFrame:)
5446 [NSApp setMainMenu: mainMenu];
5447 [NSApp setAppleMenu: appMenu];
5448 [NSApp setServicesMenu: svcsMenu];
5449 /* Needed at least on Cocoa, to get dock menu to show windows */
5450 [NSApp setWindowsMenu: [[NSMenu alloc] init]];
5452 [[NSNotificationCenter defaultCenter]
5453 addObserver: mainMenu
5454 selector: @selector (trackingNotification:)
5455 name: NSMenuDidBeginTrackingNotification object: mainMenu];
5456 [[NSNotificationCenter defaultCenter]
5457 addObserver: mainMenu
5458 selector: @selector (trackingNotification:)
5459 name: NSMenuDidEndTrackingNotification object: mainMenu];
5461 #endif /* macOS menu setup */
5463 /* Register our external input/output types, used for determining
5464 applicable services and also drag/drop eligibility. */
5466 NSTRACE_MSG ("Input/output types");
5468 ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
5469 ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
5471 ns_drag_types = [[NSArray arrayWithObjects:
5473 NSTabularTextPboardType,
5474 NSFilenamesPboardType,
5475 NSURLPboardType, nil] retain];
5477 /* If fullscreen is in init/default-frame-alist, focus isn't set
5478 right for fullscreen windows, so set this. */
5479 [NSApp activateIgnoringOtherApps:YES];
5481 NSTRACE_MSG ("Call NSApp run");
5484 ns_do_open_file = YES;
5486 #ifdef NS_IMPL_GNUSTEP
5487 /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
5488 We must re-catch it so subprocess works. */
5489 catch_child_signal ();
5492 NSTRACE_MSG ("ns_term_init done");
5501 ns_term_shutdown (int sig)
5503 [[NSUserDefaults standardUserDefaults] synchronize];
5505 /* code not reached in emacs.c after this is called by shut_down_emacs: */
5506 if (STRINGP (Vauto_save_list_file_name))
5507 unlink (SSDATA (Vauto_save_list_file_name));
5509 if (sig == 0 || sig == SIGTERM)
5511 [NSApp terminate: NSApp];
5513 else // force a stack trace to happen
5520 /* ==========================================================================
5522 EmacsApp implementation
5524 ========================================================================== */
5527 @implementation EmacsApp
5531 NSTRACE ("[EmacsApp init]");
5533 if ((self = [super init]))
5535 #ifdef NS_IMPL_COCOA
5536 self->isFirst = YES;
5538 #ifdef NS_IMPL_GNUSTEP
5539 self->applicationDidFinishLaunchingCalled = NO;
5546 #ifdef NS_IMPL_COCOA
5549 NSTRACE ("[EmacsApp run]");
5551 #ifndef NSAppKitVersionNumber10_9
5552 #define NSAppKitVersionNumber10_9 1265
5555 if ((int)NSAppKitVersionNumber != NSAppKitVersionNumber10_9)
5561 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5563 if (isFirst) [self finishLaunching];
5566 shouldKeepRunning = YES;
5570 pool = [[NSAutoreleasePool alloc] init];
5573 [self nextEventMatchingMask:NSEventMaskAny
5574 untilDate:[NSDate distantFuture]
5575 inMode:NSDefaultRunLoopMode
5578 [self sendEvent:event];
5579 [self updateWindows];
5580 } while (shouldKeepRunning);
5585 - (void)stop: (id)sender
5587 NSTRACE ("[EmacsApp stop:]");
5589 shouldKeepRunning = NO;
5590 // Stop possible dialog also. Noop if no dialog present.
5591 // The file dialog still leaks 7k - 10k on 10.9 though.
5592 [super stop:sender];
5594 #endif /* NS_IMPL_COCOA */
5596 - (void)logNotification: (NSNotification *)notification
5598 NSTRACE ("[EmacsApp logNotification:]");
5600 const char *name = [[notification name] UTF8String];
5601 if (!strstr (name, "Update") && !strstr (name, "NSMenu")
5602 && !strstr (name, "WindowNumber"))
5603 NSLog (@"notification: '%@'", [notification name]);
5607 - (void)sendEvent: (NSEvent *)theEvent
5608 /* --------------------------------------------------------------------------
5609 Called when NSApp is running for each event received. Used to stop
5610 the loop when we choose, since there's no way to just run one iteration.
5611 -------------------------------------------------------------------------- */
5613 int type = [theEvent type];
5614 NSWindow *window = [theEvent window];
5616 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsApp sendEvent:]");
5617 NSTRACE_MSG ("Type: %d", type);
5619 #ifdef NS_IMPL_GNUSTEP
5620 // Keyboard events aren't propagated to file dialogs for some reason.
5621 if ([NSApp modalWindow] != nil &&
5622 (type == NSEventTypeKeyDown || type == NSEventTypeKeyUp || type == NSEventTypeFlagsChanged))
5624 [[NSApp modalWindow] sendEvent: theEvent];
5629 if (represented_filename != nil && represented_frame)
5631 NSString *fstr = represented_filename;
5632 NSView *view = FRAME_NS_VIEW (represented_frame);
5633 #ifdef NS_IMPL_COCOA
5634 /* Work around a bug observed on 10.3 and later where
5635 setTitleWithRepresentedFilename does not clear out previous state
5636 if given filename does not exist. */
5637 if (! [[NSFileManager defaultManager] fileExistsAtPath: fstr])
5638 [[view window] setRepresentedFilename: @""];
5640 [[view window] setRepresentedFilename: fstr];
5641 [represented_filename release];
5642 represented_filename = nil;
5643 represented_frame = NULL;
5646 if (type == NSEventTypeApplicationDefined)
5648 switch ([theEvent data2])
5650 #ifdef NS_IMPL_COCOA
5651 case NSAPP_DATA2_RUNASSCRIPT:
5656 case NSAPP_DATA2_RUNFILEDIALOG:
5657 ns_run_file_dialog ();
5663 if (type == NSEventTypeCursorUpdate && window == nil)
5665 fprintf (stderr, "Dropping external cursor update event.\n");
5669 if (type == NSEventTypeApplicationDefined)
5671 /* Events posted by ns_send_appdefined interrupt the run loop here.
5672 But, if a modal window is up, an appdefined can still come through,
5673 (e.g., from a makeKeyWindow event) but stopping self also stops the
5674 modal loop. Just defer it until later. */
5675 if ([NSApp modalWindow] == nil)
5677 last_appdefined_event_data = [theEvent data1];
5682 send_appdefined = YES;
5687 #ifdef NS_IMPL_COCOA
5688 /* If no dialog and none of our frames have focus and it is a move, skip it.
5689 It is a mouse move in an auxiliary menu, i.e. on the top right on macOS,
5690 such as Wifi, sound, date or similar.
5691 This prevents "spooky" highlighting in the frame under the menu. */
5692 if (type == NSEventTypeMouseMoved && [NSApp modalWindow] == nil)
5694 struct ns_display_info *di;
5695 BOOL has_focus = NO;
5696 for (di = x_display_list; ! has_focus && di; di = di->next)
5697 has_focus = di->x_focus_frame != 0;
5703 NSTRACE_UNSILENCE();
5705 [super sendEvent: theEvent];
5709 - (void)showPreferencesWindow: (id)sender
5711 struct frame *emacsframe = SELECTED_FRAME ();
5712 NSEvent *theEvent = [NSApp currentEvent];
5716 emacs_event->kind = NS_NONKEY_EVENT;
5717 emacs_event->code = KEY_NS_SHOW_PREFS;
5718 emacs_event->modifiers = 0;
5719 EV_TRAILER (theEvent);
5723 - (void)newFrame: (id)sender
5725 NSTRACE ("[EmacsApp newFrame:]");
5727 struct frame *emacsframe = SELECTED_FRAME ();
5728 NSEvent *theEvent = [NSApp currentEvent];
5732 emacs_event->kind = NS_NONKEY_EVENT;
5733 emacs_event->code = KEY_NS_NEW_FRAME;
5734 emacs_event->modifiers = 0;
5735 EV_TRAILER (theEvent);
5739 /* Open a file (used by below, after going into queue read by ns_read_socket). */
5740 - (BOOL) openFile: (NSString *)fileName
5742 NSTRACE ("[EmacsApp openFile:]");
5744 struct frame *emacsframe = SELECTED_FRAME ();
5745 NSEvent *theEvent = [NSApp currentEvent];
5750 emacs_event->kind = NS_NONKEY_EVENT;
5751 emacs_event->code = KEY_NS_OPEN_FILE_LINE;
5752 ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
5753 ns_input_line = Qnil; /* can be start or cons start,end */
5754 emacs_event->modifiers =0;
5755 EV_TRAILER (theEvent);
5761 /* **************************************************************************
5763 EmacsApp delegate implementation
5765 ************************************************************************** */
5767 - (void)applicationDidFinishLaunching: (NSNotification *)notification
5768 /* --------------------------------------------------------------------------
5769 When application is loaded, terminate event loop in ns_term_init.
5770 -------------------------------------------------------------------------- */
5772 NSTRACE ("[EmacsApp applicationDidFinishLaunching:]");
5774 #ifdef NS_IMPL_GNUSTEP
5775 ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
5777 [NSApp setServicesProvider: NSApp];
5779 [self antialiasThresholdDidChange:nil];
5780 #ifdef NS_IMPL_COCOA
5781 [[NSNotificationCenter defaultCenter]
5783 selector:@selector(antialiasThresholdDidChange:)
5784 name:NSAntialiasThresholdChangedNotification
5788 #ifdef NS_IMPL_COCOA
5789 if ([NSApp activationPolicy] == NSApplicationActivationPolicyProhibited) {
5790 /* Set the app's activation policy to regular when we run outside
5791 of a bundle. This is already done for us by Info.plist when we
5792 run inside a bundle. */
5793 [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
5794 [NSApp setApplicationIconImage:
5797 build_string("icons/hicolor/128x128/apps/emacs.png")]];
5801 ns_send_appdefined (-2);
5804 - (void)antialiasThresholdDidChange:(NSNotification *)notification
5806 #ifdef NS_IMPL_COCOA
5807 macfont_update_antialias_threshold ();
5812 /* Termination sequences:
5815 MenuBar | File | Exit:
5816 Select Quit from App menubar:
5818 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5821 Select Quit from Dock menu:
5824 Cancel -> Nothing else
5828 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5833 - (void) terminate: (id)sender
5835 NSTRACE ("[EmacsApp terminate:]");
5837 struct frame *emacsframe = SELECTED_FRAME ();
5842 emacs_event->kind = NS_NONKEY_EVENT;
5843 emacs_event->code = KEY_NS_POWER_OFF;
5844 emacs_event->arg = Qt; /* mark as non-key event */
5845 EV_TRAILER ((id)nil);
5849 runAlertPanel(NSString *title,
5850 NSString *msgFormat,
5851 NSString *defaultButton,
5852 NSString *alternateButton)
5854 #ifdef NS_IMPL_GNUSTEP
5855 return NSRunAlertPanel(title, msgFormat, defaultButton, alternateButton, nil)
5856 == NSAlertDefaultReturn;
5858 NSAlert *alert = [[NSAlert alloc] init];
5859 [alert setAlertStyle: NSAlertStyleCritical];
5860 [alert setMessageText: msgFormat];
5861 [alert addButtonWithTitle: defaultButton];
5862 [alert addButtonWithTitle: alternateButton];
5863 NSInteger ret = [alert runModal];
5865 return ret == NSAlertFirstButtonReturn;
5870 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
5872 NSTRACE ("[EmacsApp applicationShouldTerminate:]");
5876 if (NILP (ns_confirm_quit)) // || ns_shutdown_properly --> TO DO
5877 return NSTerminateNow;
5879 ret = runAlertPanel(ns_app_name,
5880 @"Exit requested. Would you like to Save Buffers and Exit, or Cancel the request?",
5881 @"Save Buffers and Exit", @"Cancel");
5883 return ret ? NSTerminateNow : NSTerminateCancel;
5887 not_in_argv (NSString *arg)
5890 const char *a = [arg UTF8String];
5891 for (k = 1; k < initial_argc; ++k)
5892 if (strcmp (a, initial_argv[k]) == 0) return 0;
5896 /* Notification from the Workspace to open a file. */
5897 - (BOOL)application: sender openFile: (NSString *)file
5899 if (ns_do_open_file || not_in_argv (file))
5900 [ns_pending_files addObject: file];
5905 /* Open a file as a temporary file. */
5906 - (BOOL)application: sender openTempFile: (NSString *)file
5908 if (ns_do_open_file || not_in_argv (file))
5909 [ns_pending_files addObject: file];
5914 /* Notification from the Workspace to open a file noninteractively (?). */
5915 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
5917 if (ns_do_open_file || not_in_argv (file))
5918 [ns_pending_files addObject: file];
5922 /* Notification from the Workspace to open multiple files. */
5923 - (void)application: sender openFiles: (NSArray *)fileList
5925 NSEnumerator *files = [fileList objectEnumerator];
5927 /* Don't open files from the command line unconditionally,
5928 Cocoa parses the command line wrong, --option value tries to open value
5929 if --option is the last option. */
5930 while ((file = [files nextObject]) != nil)
5931 if (ns_do_open_file || not_in_argv (file))
5932 [ns_pending_files addObject: file];
5934 [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
5939 /* Handle dock menu requests. */
5940 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
5946 /* TODO: these may help w/IO switching between terminal and NSApp. */
5947 - (void)applicationWillBecomeActive: (NSNotification *)notification
5949 NSTRACE ("[EmacsApp applicationWillBecomeActive:]");
5950 // ns_app_active=YES;
5953 - (void)applicationDidBecomeActive: (NSNotification *)notification
5955 NSTRACE ("[EmacsApp applicationDidBecomeActive:]");
5957 #ifdef NS_IMPL_GNUSTEP
5958 if (! applicationDidFinishLaunchingCalled)
5959 [self applicationDidFinishLaunching:notification];
5961 // ns_app_active=YES;
5963 ns_update_auto_hide_menu_bar ();
5964 // No constraining takes place when the application is not active.
5965 ns_constrain_all_frames ();
5967 - (void)applicationDidResignActive: (NSNotification *)notification
5969 NSTRACE ("[EmacsApp applicationDidResignActive:]");
5971 // ns_app_active=NO;
5972 ns_send_appdefined (-1);
5977 /* ==========================================================================
5979 EmacsApp aux handlers for managing event loop
5981 ========================================================================== */
5984 - (void)timeout_handler: (NSTimer *)timedEntry
5985 /* --------------------------------------------------------------------------
5986 The timeout specified to ns_select has passed.
5987 -------------------------------------------------------------------------- */
5989 /* NSTRACE ("timeout_handler"); */
5990 ns_send_appdefined (-2);
5993 - (void)sendFromMainThread:(id)unused
5995 ns_send_appdefined (nextappdefined);
5998 - (void)fd_handler:(id)unused
5999 /* --------------------------------------------------------------------------
6000 Check data waiting on file descriptors and terminate if so.
6001 -------------------------------------------------------------------------- */
6004 int waiting = 1, nfds;
6007 fd_set readfds, writefds, *wfds;
6008 struct timespec timeout, *tmo;
6009 NSAutoreleasePool *pool = nil;
6011 /* NSTRACE ("fd_handler"); */
6016 pool = [[NSAutoreleasePool alloc] init];
6022 FD_SET (selfds[0], &fds);
6023 result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
6024 if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
6029 pthread_mutex_lock (&select_mutex);
6032 if (select_valid & SELECT_HAVE_READ)
6033 readfds = select_readfds;
6037 if (select_valid & SELECT_HAVE_WRITE)
6039 writefds = select_writefds;
6044 if (select_valid & SELECT_HAVE_TMO)
6046 timeout = select_timeout;
6052 pthread_mutex_unlock (&select_mutex);
6054 FD_SET (selfds[0], &readfds);
6055 if (selfds[0] >= nfds) nfds = selfds[0]+1;
6057 result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
6060 ns_send_appdefined (-2);
6061 else if (result > 0)
6063 if (FD_ISSET (selfds[0], &readfds))
6065 if (read (selfds[0], &c, 1) == 1 && c == 's')
6070 pthread_mutex_lock (&select_mutex);
6071 if (select_valid & SELECT_HAVE_READ)
6072 select_readfds = readfds;
6073 if (select_valid & SELECT_HAVE_WRITE)
6074 select_writefds = writefds;
6075 if (select_valid & SELECT_HAVE_TMO)
6076 select_timeout = timeout;
6077 pthread_mutex_unlock (&select_mutex);
6079 ns_send_appdefined (result);
6089 /* ==========================================================================
6093 ========================================================================== */
6095 /* Called from system: queue for next pass through event loop. */
6096 - (void)requestService: (NSPasteboard *)pboard
6097 userData: (NSString *)userData
6098 error: (NSString **)error
6100 [ns_pending_service_names addObject: userData];
6101 [ns_pending_service_args addObject: [NSString stringWithUTF8String:
6102 SSDATA (ns_string_from_pasteboard (pboard))]];
6106 /* Called from ns_read_socket to clear queue. */
6107 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
6109 struct frame *emacsframe = SELECTED_FRAME ();
6110 NSEvent *theEvent = [NSApp currentEvent];
6112 NSTRACE ("[EmacsApp fulfillService:withArg:]");
6117 emacs_event->kind = NS_NONKEY_EVENT;
6118 emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
6119 ns_input_spi_name = build_string ([name UTF8String]);
6120 ns_input_spi_arg = build_string ([arg UTF8String]);
6121 emacs_event->modifiers = EV_MODIFIERS (theEvent);
6122 EV_TRAILER (theEvent);
6131 /* ==========================================================================
6133 EmacsView implementation
6135 ========================================================================== */
6138 @implementation EmacsView
6140 /* Needed to inform when window closed from lisp. */
6141 - (void) setWindowClosing: (BOOL)closing
6143 NSTRACE ("[EmacsView setWindowClosing:%d]", closing);
6145 windowClosing = closing;
6151 NSTRACE ("[EmacsView dealloc]");
6153 if (fs_state == FULLSCREEN_BOTH)
6154 [nonfs_window release];
6159 /* Called on font panel selection. */
6160 - (void)changeFont: (id)sender
6162 NSEvent *e = [[self window] currentEvent];
6163 struct face *face = FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID);
6164 struct font *font = face->font;
6169 NSTRACE ("[EmacsView changeFont:]");
6174 #ifdef NS_IMPL_GNUSTEP
6175 nsfont = ((struct nsfont_info *)font)->nsfont;
6177 #ifdef NS_IMPL_COCOA
6178 nsfont = (NSFont *) macfont_get_nsctfont (font);
6181 if ((newFont = [sender convertFont: nsfont]))
6183 SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
6185 emacs_event->kind = NS_NONKEY_EVENT;
6186 emacs_event->modifiers = 0;
6187 emacs_event->code = KEY_NS_CHANGE_FONT;
6189 size = [newFont pointSize];
6190 ns_input_fontsize = make_number (lrint (size));
6191 ns_input_font = build_string ([[newFont familyName] UTF8String]);
6197 - (BOOL)acceptsFirstResponder
6199 NSTRACE ("[EmacsView acceptsFirstResponder]");
6204 - (void)resetCursorRects
6206 NSRect visible = [self visibleRect];
6207 NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
6208 NSTRACE ("[EmacsView resetCursorRects]");
6210 if (currentCursor == nil)
6211 currentCursor = [NSCursor arrowCursor];
6213 if (!NSIsEmptyRect (visible))
6214 [self addCursorRect: visible cursor: currentCursor];
6216 #if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 101300
6217 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101300
6218 if ([currentCursor respondsToSelector: @selector(setOnMouseEntered)])
6220 [currentCursor setOnMouseEntered: YES];
6226 /*****************************************************************************/
6227 /* Keyboard handling. */
6230 - (void)keyDown: (NSEvent *)theEvent
6232 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
6234 unsigned fnKeysym = 0;
6235 static NSMutableArray *nsEvArray;
6236 unsigned int flags = [theEvent modifierFlags];
6238 NSTRACE ("[EmacsView keyDown:]");
6240 /* Rhapsody and macOS give up and down events for the arrow keys. */
6241 if (ns_fake_keydown == YES)
6242 ns_fake_keydown = NO;
6243 else if ([theEvent type] != NSEventTypeKeyDown)
6249 if (![[self window] isKeyWindow]
6250 && [[theEvent window] isKindOfClass: [EmacsWindow class]]
6251 /* We must avoid an infinite loop here. */
6252 && (EmacsView *)[[theEvent window] delegate] != self)
6254 /* XXX: There is an occasional condition in which, when Emacs display
6255 updates a different frame from the current one, and temporarily
6256 selects it, then processes some interrupt-driven input
6257 (dispnew.c:3878), OS will send the event to the correct NSWindow, but
6258 for some reason that window has its first responder set to the NSView
6259 most recently updated (I guess), which is not the correct one. */
6260 [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
6264 if (nsEvArray == nil)
6265 nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
6267 [NSCursor setHiddenUntilMouseMoves: YES];
6269 if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
6271 clear_mouse_face (hlinfo);
6272 hlinfo->mouse_face_hidden = 1;
6275 if (!processingCompose)
6277 /* FIXME: What should happen for key sequences with more than
6279 code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
6280 0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
6282 /* Is it a "function key"? */
6283 /* Note: Sometimes a plain key will have the NSEventModifierFlagNumericPad
6284 flag set (this is probably a bug in the OS). */
6285 if (code < 0x00ff && (flags&NSEventModifierFlagNumericPad))
6287 fnKeysym = ns_convert_key ([theEvent keyCode] | NSEventModifierFlagNumericPad);
6291 fnKeysym = ns_convert_key (code);
6296 /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
6297 because Emacs treats Delete and KP-Delete same (in simple.el). */
6298 if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
6299 #ifdef NS_IMPL_GNUSTEP
6300 /* GNUstep uses incompatible keycodes, even for those that are
6301 supposed to be hardware independent. Just check for delete.
6302 Keypad delete does not have keysym 0xFFFF.
6303 See https://savannah.gnu.org/bugs/?25395 */
6304 || (fnKeysym == 0xFFFF && code == 127)
6307 code = 0xFF08; /* backspace */
6312 /* The ⌘ and ⌥ modifiers can be either shift-like (for alternate
6313 character input) or control-like (as command prefix). If we
6314 have only shift-like modifiers, then we should use the
6315 translated characters (returned by the characters method); if
6316 we have only control-like modifiers, then we should use the
6317 untranslated characters (returned by the
6318 charactersIgnoringModifiers method). An annoyance happens if
6319 we have both shift-like and control-like modifiers because
6320 the NSEvent API doesn’t let us ignore only some modifiers.
6321 In that case we use UCKeyTranslate (ns_get_shifted_character)
6322 to look up the correct character. */
6324 /* EV_MODIFIERS2 uses parse_solitary_modifier on all known
6325 modifier keys, which returns 0 for shift-like modifiers.
6326 Therefore its return value is the set of control-like
6328 emacs_event->modifiers = EV_MODIFIERS2 (flags);
6330 /* Function keys (such as the F-keys, arrow keys, etc.) set
6331 modifiers as though the fn key has been pressed when it
6332 hasn't. Also some combinations of fn and a function key
6333 return a different key than was pressed (e.g. fn-<left> gives
6334 <home>). We need to unset the fn modifier in these cases.
6335 FIXME: Can we avoid setting it in the first place? */
6336 if (fnKeysym && (flags & NS_FUNCTION_KEY_MASK))
6337 emacs_event->modifiers ^= parse_solitary_modifier (ns_function_modifier);
6340 fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
6341 code, fnKeysym, flags, emacs_event->modifiers);
6343 /* If it was a function key or had control-like modifiers, pass
6344 it directly to Emacs. */
6345 if (fnKeysym || (emacs_event->modifiers
6346 && (emacs_event->modifiers != shift_modifier)
6347 && [[theEvent charactersIgnoringModifiers] length] > 0))
6349 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6350 /* FIXME: What are the next four lines supposed to do? */
6352 code |= (1<<28)|(3<<16);
6353 else if (code == 0x7f)
6354 code |= (1<<28)|(3<<16);
6357 #ifdef NS_IMPL_COCOA
6358 /* We potentially have both shift- and control-like
6359 modifiers in use, so find the correct character
6360 ignoring any control-like ones. */
6361 code = ns_get_shifted_character (theEvent);
6364 /* FIXME: This seems wrong, characters in the range
6365 [0x80, 0xFF] are not ASCII characters. Can’t we just
6366 use MULTIBYTE_CHAR_KEYSTROKE_EVENT here for all kinds
6368 emacs_event->kind = code > 0xFF
6369 ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6372 emacs_event->code = code;
6373 EV_TRAILER (theEvent);
6374 processingCompose = NO;
6379 /* If we get here, a non-function key without control-like modifiers
6380 was hit. Use interpretKeyEvents, which in turn will call
6382 https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/EventOverview/HandlingKeyEvents/HandlingKeyEvents.html. */
6384 if (NS_KEYLOG && !processingCompose)
6385 fprintf (stderr, "keyDown: Begin compose sequence.\n");
6387 /* FIXME: interpretKeyEvents doesn’t seem to send insertText if ⌘ is
6388 used as shift-like modifier, at least on El Capitan. Mask it
6389 out. This shouldn’t be needed though; we should figure out what
6390 the correct way of handling ⌘ is. */
6391 if ([theEvent modifierFlags] & NSEventModifierFlagCommand)
6392 theEvent = [NSEvent keyEventWithType:[theEvent type]
6393 location:[theEvent locationInWindow]
6394 modifierFlags:[theEvent modifierFlags] & ~NSEventModifierFlagCommand
6395 timestamp:[theEvent timestamp]
6396 windowNumber:[theEvent windowNumber]
6398 characters:[theEvent characters]
6399 charactersIgnoringModifiers:[theEvent charactersIgnoringModifiers]
6400 isARepeat:[theEvent isARepeat]
6401 keyCode:[theEvent keyCode]];
6403 processingCompose = YES;
6404 /* FIXME: Use [NSArray arrayWithObject:theEvent]? */
6405 [nsEvArray addObject: theEvent];
6406 [self interpretKeyEvents: nsEvArray];
6407 [nsEvArray removeObject: theEvent];
6411 /* <NSTextInput> implementation (called through [super interpretKeyEvents:]). */
6414 /* <NSTextInput>: called when done composing;
6415 NOTE: also called when we delete over working text, followed
6416 immediately by doCommandBySelector: deleteBackward: */
6417 - (void)insertText: (id)aString
6422 NSTRACE ("[EmacsView insertText:]");
6424 if ([aString isKindOfClass:[NSAttributedString class]])
6425 s = [aString string];
6432 NSLog (@"insertText '%@'\tlen = %lu", aString, (unsigned long) len);
6433 processingCompose = NO;
6438 /* First, clear any working text. */
6439 if (workingText != nil)
6440 [self deleteWorkingText];
6442 /* It might be preferable to use getCharacters:range: below,
6443 cf. https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CocoaPerformance/Articles/StringDrawing.html#//apple_ref/doc/uid/TP40001445-112378.
6444 However, we probably can't use SAFE_NALLOCA here because it might
6447 /* Now insert the string as keystrokes. */
6448 for (NSUInteger i = 0; i < len; i++)
6450 NSUInteger code = [s characterAtIndex:i];
6451 if (UTF_16_HIGH_SURROGATE_P (code) && i < len - 1)
6453 unichar low = [s characterAtIndex:i + 1];
6454 if (UTF_16_LOW_SURROGATE_P (low))
6456 code = surrogates_to_codepoint (low, code);
6460 /* TODO: still need this? */
6462 code = '~'; /* 0x7E */
6463 if (code != 32) /* Space */
6464 emacs_event->modifiers = 0;
6466 = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6467 emacs_event->code = code;
6468 EV_TRAILER ((id)nil);
6473 /* <NSTextInput>: inserts display of composing characters. */
6474 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
6476 NSString *str = [aString respondsToSelector: @selector (string)] ?
6477 [aString string] : aString;
6479 NSTRACE ("[EmacsView setMarkedText:selectedRange:]");
6482 NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
6483 str, (unsigned long)[str length],
6484 (unsigned long)selRange.length,
6485 (unsigned long)selRange.location);
6487 if (workingText != nil)
6488 [self deleteWorkingText];
6489 if ([str length] == 0)
6495 processingCompose = YES;
6496 workingText = [str copy];
6497 ns_working_text = build_string ([workingText UTF8String]);
6499 emacs_event->kind = NS_TEXT_EVENT;
6500 emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
6501 EV_TRAILER ((id)nil);
6505 /* Delete display of composing characters [not in <NSTextInput>]. */
6506 - (void)deleteWorkingText
6508 NSTRACE ("[EmacsView deleteWorkingText]");
6510 if (workingText == nil)
6513 NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
6514 [workingText release];
6516 processingCompose = NO;
6521 emacs_event->kind = NS_TEXT_EVENT;
6522 emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
6523 EV_TRAILER ((id)nil);
6527 - (BOOL)hasMarkedText
6529 NSTRACE ("[EmacsView hasMarkedText]");
6531 return workingText != nil;
6535 - (NSRange)markedRange
6537 NSTRACE ("[EmacsView markedRange]");
6539 NSRange rng = workingText != nil
6540 ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
6542 NSLog (@"markedRange request");
6549 NSTRACE ("[EmacsView unmarkText]");
6552 NSLog (@"unmark (accept) text");
6553 [self deleteWorkingText];
6554 processingCompose = NO;
6558 /* Used to position char selection windows, etc. */
6559 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
6563 struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
6565 NSTRACE ("[EmacsView firstRectForCharacterRange:]");
6568 NSLog (@"firstRectForCharRange request");
6570 rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
6571 rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
6572 pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
6573 pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
6574 +FRAME_LINE_HEIGHT (emacsframe));
6576 pt = [self convertPoint: pt toView: nil];
6578 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
6579 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6580 if ([[self window] respondsToSelector: @selector(convertRectToScreen:)])
6584 rect = [(EmacsWindow *) [self window] convertRectToScreen: rect];
6585 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6589 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
6590 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 \
6591 || defined (NS_IMPL_GNUSTEP)
6593 pt = [[self window] convertBaseToScreen: pt];
6602 - (NSInteger)conversationIdentifier
6604 return (NSInteger)self;
6608 - (void)doCommandBySelector: (SEL)aSelector
6610 NSTRACE ("[EmacsView doCommandBySelector:]");
6613 NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
6615 processingCompose = NO;
6616 if (aSelector == @selector (deleteBackward:))
6618 /* Happens when user backspaces over an ongoing composition:
6619 throw a 'delete' into the event queue. */
6622 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6623 emacs_event->code = 0xFF08;
6624 EV_TRAILER ((id)nil);
6628 - (NSArray *)validAttributesForMarkedText
6630 static NSArray *arr = nil;
6631 if (arr == nil) arr = [NSArray new];
6632 /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
6636 - (NSRange)selectedRange
6639 NSLog (@"selectedRange request");
6640 return NSMakeRange (NSNotFound, 0);
6643 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
6644 GNUSTEP_GUI_MINOR_VERSION > 22
6645 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
6647 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
6651 NSLog (@"characterIndexForPoint request");
6655 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
6657 static NSAttributedString *str = nil;
6658 if (str == nil) str = [NSAttributedString new];
6660 NSLog (@"attributedSubstringFromRange request");
6664 /* End <NSTextInput> implementation. */
6665 /*****************************************************************************/
6668 /* This is what happens when the user presses a mouse button. */
6669 - (void)mouseDown: (NSEvent *)theEvent
6671 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6672 NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
6674 NSTRACE ("[EmacsView mouseDown:]");
6676 [self deleteWorkingText];
6681 dpyinfo->last_mouse_frame = emacsframe;
6682 /* Appears to be needed to prevent spurious movement events generated on
6684 emacsframe->mouse_moved = 0;
6686 if ([theEvent type] == NSEventTypeScrollWheel)
6688 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
6689 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6690 if ([theEvent respondsToSelector:@selector(hasPreciseScrollingDeltas)])
6693 /* If the input device is a touchpad or similar, use precise
6694 * scrolling deltas. These are measured in pixels, so we
6695 * have to add them up until they exceed one line height,
6696 * then we can send a scroll wheel event.
6698 * If the device only has coarse scrolling deltas, like a
6699 * real mousewheel, the deltas represent a ratio of whole
6700 * lines, so round up the number of lines. This means we
6701 * always send one scroll event per click, but can still
6702 * scroll more than one line if the OS tells us to.
6708 /* FIXME: At the top or bottom of the buffer we should
6709 * ignore momentum-phase events. */
6710 if (! ns_use_mwheel_momentum
6711 && [theEvent momentumPhase] != NSEventPhaseNone)
6714 if ([theEvent hasPreciseScrollingDeltas])
6716 static int totalDeltaX, totalDeltaY;
6719 if (NUMBERP (ns_mwheel_line_height))
6720 lineHeight = XINT (ns_mwheel_line_height);
6723 /* FIXME: Use actual line height instead of the default. */
6724 lineHeight = default_line_pixel_height
6725 (XWINDOW (FRAME_SELECTED_WINDOW (emacsframe)));
6728 if ([theEvent phase] == NSEventPhaseBegan)
6734 totalDeltaX += [theEvent scrollingDeltaX];
6735 totalDeltaY += [theEvent scrollingDeltaY];
6737 /* Calculate the number of lines, if any, to scroll, and
6738 * reset the total delta for the direction we're NOT
6739 * scrolling so that small movements don't add up. */
6740 if (abs (totalDeltaX) > abs (totalDeltaY)
6741 && abs (totalDeltaX) > lineHeight)
6744 scrollUp = totalDeltaX > 0;
6746 lines = abs (totalDeltaX / lineHeight);
6747 totalDeltaX = totalDeltaX % lineHeight;
6750 else if (abs (totalDeltaY) >= abs (totalDeltaX)
6751 && abs (totalDeltaY) > lineHeight)
6754 scrollUp = totalDeltaY > 0;
6756 lines = abs (totalDeltaY / lineHeight);
6757 totalDeltaY = totalDeltaY % lineHeight;
6761 if (lines > 1 && ! ns_use_mwheel_acceleration)
6768 if ([theEvent scrollingDeltaY] == 0)
6771 delta = [theEvent scrollingDeltaX];
6776 delta = [theEvent scrollingDeltaY];
6779 lines = (ns_use_mwheel_acceleration)
6780 ? ceil (fabs (delta)) : 1;
6782 scrollUp = delta > 0;
6788 emacs_event->kind = horizontal ? HORIZ_WHEEL_EVENT : WHEEL_EVENT;
6789 emacs_event->arg = (make_number (lines));
6791 emacs_event->code = 0;
6792 emacs_event->modifiers = EV_MODIFIERS (theEvent) |
6793 (scrollUp ? up_modifier : down_modifier);
6794 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6798 #endif /* defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
6799 #if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6801 CGFloat delta = [theEvent deltaY];
6802 /* Mac notebooks send wheel events with delta equal to 0
6803 when trackpad scrolling. */
6806 delta = [theEvent deltaX];
6809 NSTRACE_MSG ("deltaIsZero");
6812 emacs_event->kind = HORIZ_WHEEL_EVENT;
6815 emacs_event->kind = WHEEL_EVENT;
6817 emacs_event->code = 0;
6818 emacs_event->modifiers = EV_MODIFIERS (theEvent) |
6819 ((delta > 0) ? up_modifier : down_modifier);
6825 emacs_event->kind = MOUSE_CLICK_EVENT;
6826 emacs_event->code = EV_BUTTON (theEvent);
6827 emacs_event->modifiers = EV_MODIFIERS (theEvent)
6828 | EV_UDMODIFIERS (theEvent);
6831 XSETINT (emacs_event->x, lrint (p.x));
6832 XSETINT (emacs_event->y, lrint (p.y));
6833 EV_TRAILER (theEvent);
6838 - (void)rightMouseDown: (NSEvent *)theEvent
6840 NSTRACE ("[EmacsView rightMouseDown:]");
6841 [self mouseDown: theEvent];
6845 - (void)otherMouseDown: (NSEvent *)theEvent
6847 NSTRACE ("[EmacsView otherMouseDown:]");
6848 [self mouseDown: theEvent];
6852 - (void)mouseUp: (NSEvent *)theEvent
6854 NSTRACE ("[EmacsView mouseUp:]");
6855 [self mouseDown: theEvent];
6859 - (void)rightMouseUp: (NSEvent *)theEvent
6861 NSTRACE ("[EmacsView rightMouseUp:]");
6862 [self mouseDown: theEvent];
6866 - (void)otherMouseUp: (NSEvent *)theEvent
6868 NSTRACE ("[EmacsView otherMouseUp:]");
6869 [self mouseDown: theEvent];
6873 - (void) scrollWheel: (NSEvent *)theEvent
6875 NSTRACE ("[EmacsView scrollWheel:]");
6876 [self mouseDown: theEvent];
6880 /* Tell emacs the mouse has moved. */
6881 - (void)mouseMoved: (NSEvent *)e
6883 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
6884 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6888 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsView mouseMoved:]");
6890 dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
6891 pt = [self convertPoint: [e locationInWindow] fromView: nil];
6892 dpyinfo->last_mouse_motion_x = pt.x;
6893 dpyinfo->last_mouse_motion_y = pt.y;
6895 /* Update any mouse face. */
6896 if (hlinfo->mouse_face_hidden)
6898 hlinfo->mouse_face_hidden = 0;
6899 clear_mouse_face (hlinfo);
6902 /* Tooltip handling. */
6903 previous_help_echo_string = help_echo_string;
6904 help_echo_string = Qnil;
6906 if (!NILP (Vmouse_autoselect_window))
6908 NSTRACE_MSG ("mouse_autoselect_window");
6909 static Lisp_Object last_mouse_window;
6911 = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
6913 if (WINDOWP (window)
6914 && !EQ (window, last_mouse_window)
6915 && !EQ (window, selected_window)
6916 && (!NILP (focus_follows_mouse)
6917 || (EQ (XWINDOW (window)->frame,
6918 XWINDOW (selected_window)->frame))))
6920 NSTRACE_MSG ("in_window");
6921 emacs_event->kind = SELECT_WINDOW_EVENT;
6922 emacs_event->frame_or_window = window;
6925 /* Remember the last window where we saw the mouse. */
6926 last_mouse_window = window;
6929 if (!note_mouse_movement (emacsframe, pt.x, pt.y))
6930 help_echo_string = previous_help_echo_string;
6932 XSETFRAME (frame, emacsframe);
6933 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
6935 /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
6936 (note_mouse_highlight), which is called through the
6937 note_mouse_movement () call above. */
6938 any_help_event_p = YES;
6939 gen_help_event (help_echo_string, frame, help_echo_window,
6940 help_echo_object, help_echo_pos);
6943 if (emacsframe->mouse_moved && send_appdefined)
6944 ns_send_appdefined (-1);
6948 - (void)mouseDragged: (NSEvent *)e
6950 NSTRACE ("[EmacsView mouseDragged:]");
6951 [self mouseMoved: e];
6955 - (void)rightMouseDragged: (NSEvent *)e
6957 NSTRACE ("[EmacsView rightMouseDragged:]");
6958 [self mouseMoved: e];
6962 - (void)otherMouseDragged: (NSEvent *)e
6964 NSTRACE ("[EmacsView otherMouseDragged:]");
6965 [self mouseMoved: e];
6969 - (BOOL)windowShouldClose: (id)sender
6971 NSEvent *e =[[self window] currentEvent];
6973 NSTRACE ("[EmacsView windowShouldClose:]");
6974 windowClosing = YES;
6977 emacs_event->kind = DELETE_WINDOW_EVENT;
6978 emacs_event->modifiers = 0;
6979 emacs_event->code = 0;
6981 /* Don't close this window, let this be done from lisp code. */
6985 - (void) updateFrameSize: (BOOL) delay
6987 NSWindow *window = [self window];
6988 NSRect wr = [window frame];
6990 int oldc = cols, oldr = rows;
6991 int oldw = FRAME_PIXEL_WIDTH (emacsframe);
6992 int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
6995 NSTRACE ("[EmacsView updateFrameSize:]");
6996 NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
6997 NSTRACE_RECT ("Original frame", wr);
6998 NSTRACE_MSG ("Original columns: %d", cols);
6999 NSTRACE_MSG ("Original rows: %d", rows);
7001 if (! [self isFullscreen])
7004 #ifdef NS_IMPL_GNUSTEP
7005 // GNUstep does not always update the tool bar height. Force it.
7006 if (toolbar && [toolbar isVisible])
7007 update_frame_tool_bar (emacsframe);
7010 toolbar_height = FRAME_TOOLBAR_HEIGHT (emacsframe);
7011 if (toolbar_height < 0)
7012 toolbar_height = 35;
7014 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
7018 if (wait_for_tool_bar)
7020 /* The toolbar height is always 0 in fullscreen and undecorated
7021 frames, so don't wait for it to become available. */
7022 if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0
7023 && FRAME_UNDECORATED (emacsframe) == false
7024 && ! [self isFullscreen])
7026 NSTRACE_MSG ("Waiting for toolbar");
7029 wait_for_tool_bar = NO;
7032 neww = (int)wr.size.width - emacsframe->border_width;
7033 newh = (int)wr.size.height - extra;
7035 NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
7036 NSTRACE_MSG ("FRAME_TOOLBAR_HEIGHT: %d", FRAME_TOOLBAR_HEIGHT (emacsframe));
7037 NSTRACE_MSG ("FRAME_NS_TITLEBAR_HEIGHT: %d", FRAME_NS_TITLEBAR_HEIGHT (emacsframe));
7039 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
7040 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
7042 if (cols < MINWIDTH)
7045 if (rows < MINHEIGHT)
7048 NSTRACE_MSG ("New columns: %d", cols);
7049 NSTRACE_MSG ("New rows: %d", rows);
7051 if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
7053 NSView *view = FRAME_NS_VIEW (emacsframe);
7055 change_frame_size (emacsframe,
7056 FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
7057 FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
7059 SET_FRAME_GARBAGED (emacsframe);
7060 cancel_mouse_face (emacsframe);
7062 /* The next two lines set the frame to the same size as we've
7063 already set above. We need to do this when we switch back
7064 from non-native fullscreen, in other circumstances it appears
7065 to be a noop. (bug#28872) */
7066 wr = NSMakeRect (0, 0, neww, newh);
7067 [view setFrame: wr];
7069 // To do: consider using [NSNotificationCenter postNotificationName:].
7070 [self windowDidMove: // Update top/left.
7071 [NSNotification notificationWithName:NSWindowDidMoveNotification
7072 object:[view window]]];
7076 NSTRACE_MSG ("No change");
7080 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
7081 /* Normalize frame to gridded text size. */
7085 NSTRACE ("[EmacsView windowWillResize:toSize: " NSTRACE_FMT_SIZE "]",
7086 NSTRACE_ARG_SIZE (frameSize));
7087 NSTRACE_RECT ("[sender frame]", [sender frame]);
7088 NSTRACE_FSTYPE ("fs_state", fs_state);
7090 if (!FRAME_LIVE_P (emacsframe))
7093 if (fs_state == FULLSCREEN_MAXIMIZED
7094 && (maximized_width != (int)frameSize.width
7095 || maximized_height != (int)frameSize.height))
7096 [self setFSValue: FULLSCREEN_NONE];
7097 else if (fs_state == FULLSCREEN_WIDTH
7098 && maximized_width != (int)frameSize.width)
7099 [self setFSValue: FULLSCREEN_NONE];
7100 else if (fs_state == FULLSCREEN_HEIGHT
7101 && maximized_height != (int)frameSize.height)
7102 [self setFSValue: FULLSCREEN_NONE];
7104 if (fs_state == FULLSCREEN_NONE)
7105 maximized_width = maximized_height = -1;
7107 if (! [self isFullscreen])
7109 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
7110 + FRAME_TOOLBAR_HEIGHT (emacsframe);
7113 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
7114 if (cols < MINWIDTH)
7117 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
7118 frameSize.height - extra);
7119 if (rows < MINHEIGHT)
7121 #ifdef NS_IMPL_COCOA
7123 /* This sets window title to have size in it; the wm does this under GS. */
7124 NSRect r = [[self window] frame];
7125 if (r.size.height == frameSize.height && r.size.width == frameSize.width)
7133 else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize
7134 && [[self window] title] != NULL)
7137 NSWindow *window = [self window];
7140 char *t = strdup ([[[self window] title] UTF8String]);
7141 char *pos = strstr (t, " — ");
7146 size_title = xmalloc (strlen (old_title) + 40);
7147 esprintf (size_title, "%s — (%d x %d)", old_title, cols, rows);
7148 [window setTitle: [NSString stringWithUTF8String: size_title]];
7153 #endif /* NS_IMPL_COCOA */
7155 NSTRACE_MSG ("cols: %d rows: %d", cols, rows);
7157 /* Restrict the new size to the text grid.
7159 Don't restrict the width if the user only adjusted the height, and
7160 vice versa. (Without this, the frame would shrink, and move
7161 slightly, if the window was resized by dragging one of its
7163 if (!frame_resize_pixelwise)
7165 NSRect r = [[self window] frame];
7167 if (r.size.width != frameSize.width)
7170 FRAME_TEXT_COLS_TO_PIXEL_WIDTH (emacsframe, cols);
7173 if (r.size.height != frameSize.height)
7176 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (emacsframe, rows) + extra;
7180 NSTRACE_RETURN_SIZE (frameSize);
7186 - (void)windowDidResize: (NSNotification *)notification
7188 NSTRACE ("[EmacsView windowDidResize:]");
7189 if (!FRAME_LIVE_P (emacsframe))
7191 NSTRACE_MSG ("Ignored (frame dead)");
7194 if (emacsframe->output_data.ns->in_animation)
7196 NSTRACE_MSG ("Ignored (in animation)");
7200 if (! [self fsIsNative])
7202 NSWindow *theWindow = [notification object];
7203 /* We can get notification on the non-FS window when in
7205 if ([self window] != theWindow) return;
7208 NSTRACE_RECT ("frame", [[notification object] frame]);
7210 #ifdef NS_IMPL_GNUSTEP
7211 NSWindow *theWindow = [notification object];
7213 /* In GNUstep, at least currently, it's possible to get a didResize
7214 without getting a willResize, therefore we need to act as if we got
7215 the willResize now. */
7216 NSSize sz = [theWindow frame].size;
7217 sz = [self windowWillResize: theWindow toSize: sz];
7218 #endif /* NS_IMPL_GNUSTEP */
7220 if (cols > 0 && rows > 0)
7222 [self updateFrameSize: YES];
7225 ns_send_appdefined (-1);
7228 #ifdef NS_IMPL_COCOA
7229 - (void)viewDidEndLiveResize
7231 NSTRACE ("[EmacsView viewDidEndLiveResize]");
7233 [super viewDidEndLiveResize];
7236 [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
7240 maximizing_resize = NO;
7242 #endif /* NS_IMPL_COCOA */
7245 - (void)windowDidBecomeKey: (NSNotification *)notification
7246 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
7248 [self windowDidBecomeKey];
7252 - (void)windowDidBecomeKey /* for direct calls */
7254 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
7255 struct frame *old_focus = dpyinfo->x_focus_frame;
7257 NSTRACE ("[EmacsView windowDidBecomeKey]");
7259 if (emacsframe != old_focus)
7260 dpyinfo->x_focus_frame = emacsframe;
7262 ns_frame_rehighlight (emacsframe);
7266 emacs_event->kind = FOCUS_IN_EVENT;
7267 EV_TRAILER ((id)nil);
7272 - (void)windowDidResignKey: (NSNotification *)notification
7273 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
7275 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
7276 BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
7277 NSTRACE ("[EmacsView windowDidResignKey:]");
7280 dpyinfo->x_focus_frame = 0;
7282 emacsframe->mouse_moved = 0;
7283 ns_frame_rehighlight (emacsframe);
7285 /* FIXME: for some reason needed on second and subsequent clicks away
7286 from sole-frame Emacs to get hollow box to show. */
7287 if (!windowClosing && [[self window] isVisible] == YES)
7289 x_update_cursor (emacsframe, 1);
7290 x_set_frame_alpha (emacsframe);
7293 if (any_help_event_p)
7296 XSETFRAME (frame, emacsframe);
7297 help_echo_string = Qnil;
7298 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
7301 if (emacs_event && is_focus_frame)
7303 [self deleteWorkingText];
7304 emacs_event->kind = FOCUS_OUT_EVENT;
7305 EV_TRAILER ((id)nil);
7310 - (void)windowWillMiniaturize: sender
7312 NSTRACE ("[EmacsView windowWillMiniaturize:]");
7316 - (void)setFrame:(NSRect)frameRect
7318 NSTRACE ("[EmacsView setFrame:" NSTRACE_FMT_RECT "]",
7319 NSTRACE_ARG_RECT (frameRect));
7321 [super setFrame:(NSRect)frameRect];
7337 - (void)createToolbar: (struct frame *)f
7339 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
7340 NSWindow *window = [view window];
7342 toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
7343 [NSString stringWithFormat: @"Emacs Frame %d",
7345 [toolbar setVisible: NO];
7346 [window setToolbar: toolbar];
7348 /* Don't set frame garbaged until tool bar is up to date?
7349 This avoids an extra clear and redraw (flicker) at frame creation. */
7350 if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
7351 else wait_for_tool_bar = NO;
7354 #ifdef NS_IMPL_COCOA
7356 NSButton *toggleButton;
7357 toggleButton = [window standardWindowButton: NSWindowToolbarButton];
7358 [toggleButton setTarget: self];
7359 [toggleButton setAction: @selector (toggleToolbar: )];
7365 - (instancetype) initFrameFromEmacs: (struct frame *)f
7373 NSTRACE ("[EmacsView initFrameFromEmacs:]");
7374 NSTRACE_MSG ("cols:%d lines:%d", f->text_cols, f->text_lines);
7377 processingCompose = NO;
7378 scrollbarsNeedingUpdate = 0;
7379 fs_state = FULLSCREEN_NONE;
7380 fs_before_fs = next_maximized = -1;
7383 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7384 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7385 if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7387 fs_is_native = ns_use_native_fullscreen;
7390 maximized_width = maximized_height = -1;
7393 ns_userRect = NSMakeRect (0, 0, 0, 0);
7394 r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
7395 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
7396 [self initWithFrame: r];
7397 [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
7399 FRAME_NS_VIEW (f) = self;
7401 #ifdef NS_IMPL_COCOA
7403 maximizing_resize = NO;
7406 win = [[EmacsWindow alloc]
7407 initWithContentRect: r
7408 styleMask: (FRAME_UNDECORATED (f)
7409 ? FRAME_UNDECORATED_FLAGS
7410 : FRAME_DECORATED_FLAGS)
7411 backing: NSBackingStoreBuffered
7414 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7415 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7416 if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7418 [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
7422 bwidth = f->border_width = wr.size.width - r.size.width;
7424 [win setAcceptsMouseMovedEvents: YES];
7425 [win setDelegate: self];
7426 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7427 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7428 if ([win respondsToSelector: @selector(useOptimizedDrawing:)])
7430 [win useOptimizedDrawing: YES];
7433 [[win contentView] addSubview: self];
7436 [self registerForDraggedTypes: ns_drag_types];
7439 name = [NSString stringWithUTF8String:
7440 NILP (tem) ? "Emacs" : SSDATA (tem)];
7441 [win setTitle: name];
7443 /* toolbar support */
7444 if (! FRAME_UNDECORATED (f))
7445 [self createToolbar: f];
7447 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
7448 #ifndef NSAppKitVersionNumber10_10
7449 #define NSAppKitVersionNumber10_10 1343
7452 if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_10
7453 && FRAME_NS_APPEARANCE (f) != ns_appearance_aqua)
7454 win.appearance = [NSAppearance
7455 appearanceNamed: NSAppearanceNameVibrantDark];
7458 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
7459 if ([win respondsToSelector: @selector(titlebarAppearsTransparent)])
7460 win.titlebarAppearsTransparent = FRAME_NS_TRANSPARENT_TITLEBAR (f);
7465 [win setMiniwindowTitle:
7466 [NSString stringWithUTF8String: SSDATA (tem)]];
7468 if (FRAME_PARENT_FRAME (f) != NULL)
7470 NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
7471 [parent addChildWindow: win
7472 ordered: NSWindowAbove];
7475 if (FRAME_Z_GROUP (f) != z_group_none)
7476 win.level = NSNormalWindowLevel
7477 + (FRAME_Z_GROUP_BELOW (f) ? -1 : 1);
7480 NSScreen *screen = [win screen];
7484 NSPoint pt = NSMakePoint
7485 (IN_BOUND (-SCREENMAX, f->left_pos
7486 + NS_PARENT_WINDOW_LEFT_POS (f), SCREENMAX),
7487 IN_BOUND (-SCREENMAX,
7488 NS_PARENT_WINDOW_TOP_POS (f) - f->top_pos,
7491 [win setFrameTopLeftPoint: pt];
7493 NSTRACE_RECT ("new frame", [win frame]);
7497 [win makeFirstResponder: self];
7499 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7500 (FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID)),
7502 [win setBackgroundColor: col];
7503 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7504 [win setOpaque: NO];
7506 #if !defined (NS_IMPL_COCOA) \
7507 || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7508 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7509 if ([self respondsToSelector: @selector(allocateGState)])
7511 [self allocateGState];
7513 [NSApp registerServicesMenuSendTypes: ns_send_types
7514 returnTypes: [NSArray array]];
7516 /* macOS Sierra automatically enables tabbed windows. We can't
7517 allow this to be enabled until it's available on a Free system.
7518 Currently it only happens by accident and is buggy anyway. */
7519 #if defined (NS_IMPL_COCOA) \
7520 && MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
7521 #if MAC_OS_X_VERSION_MIN_REQUIRED < 101200
7522 if ([win respondsToSelector: @selector(setTabbingMode:)])
7524 [win setTabbingMode: NSWindowTabbingModeDisallowed];
7532 - (void)windowDidMove: sender
7534 NSWindow *win = [self window];
7535 NSRect r = [win frame];
7536 NSArray *screens = [NSScreen screens];
7537 NSScreen *screen = [screens objectAtIndex: 0];
7539 NSTRACE ("[EmacsView windowDidMove:]");
7541 if (!emacsframe->output_data.ns)
7545 emacsframe->left_pos = r.origin.x - NS_PARENT_WINDOW_LEFT_POS (emacsframe);
7546 emacsframe->top_pos =
7547 NS_PARENT_WINDOW_TOP_POS (emacsframe) - (r.origin.y + r.size.height);
7551 emacs_event->kind = MOVE_FRAME_EVENT;
7552 EV_TRAILER ((id)nil);
7558 /* Called AFTER method below, but before our windowWillResize call there leads
7559 to windowDidResize -> x_set_window_size. Update emacs' notion of frame
7560 location so set_window_size moves the frame. */
7561 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
7563 NSTRACE (("[EmacsView windowShouldZoom:toFrame:" NSTRACE_FMT_RECT "]"
7564 NSTRACE_FMT_RETURN "YES"),
7565 NSTRACE_ARG_RECT (newFrame));
7567 emacsframe->output_data.ns->zooming = 1;
7572 /* Override to do something slightly nonstandard, but nice. First click on
7573 zoom button will zoom vertically. Second will zoom completely. Third
7574 returns to original. */
7575 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
7576 defaultFrame:(NSRect)defaultFrame
7578 // TODO: Rename to "currentFrame" and assign "result" properly in
7580 NSRect result = [sender frame];
7582 NSTRACE (("[EmacsView windowWillUseStandardFrame:defaultFrame:"
7583 NSTRACE_FMT_RECT "]"),
7584 NSTRACE_ARG_RECT (defaultFrame));
7585 NSTRACE_FSTYPE ("fs_state", fs_state);
7586 NSTRACE_FSTYPE ("fs_before_fs", fs_before_fs);
7587 NSTRACE_FSTYPE ("next_maximized", next_maximized);
7588 NSTRACE_RECT ("ns_userRect", ns_userRect);
7589 NSTRACE_RECT ("[sender frame]", [sender frame]);
7591 if (fs_before_fs != -1) /* Entering fullscreen */
7593 NSTRACE_MSG ("Entering fullscreen");
7594 result = defaultFrame;
7598 // Save the window size and position (frame) before the resize.
7599 if (fs_state != FULLSCREEN_MAXIMIZED
7600 && fs_state != FULLSCREEN_WIDTH)
7602 ns_userRect.size.width = result.size.width;
7603 ns_userRect.origin.x = result.origin.x;
7606 if (fs_state != FULLSCREEN_MAXIMIZED
7607 && fs_state != FULLSCREEN_HEIGHT)
7609 ns_userRect.size.height = result.size.height;
7610 ns_userRect.origin.y = result.origin.y;
7613 NSTRACE_RECT ("ns_userRect (2)", ns_userRect);
7615 if (next_maximized == FULLSCREEN_HEIGHT
7616 || (next_maximized == -1
7617 && abs ((int)(defaultFrame.size.height - result.size.height))
7618 > FRAME_LINE_HEIGHT (emacsframe)))
7621 NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7622 maximized_height = result.size.height = defaultFrame.size.height;
7623 maximized_width = -1;
7624 result.origin.y = defaultFrame.origin.y;
7625 if (ns_userRect.size.height != 0)
7627 result.origin.x = ns_userRect.origin.x;
7628 result.size.width = ns_userRect.size.width;
7630 [self setFSValue: FULLSCREEN_HEIGHT];
7631 #ifdef NS_IMPL_COCOA
7632 maximizing_resize = YES;
7635 else if (next_maximized == FULLSCREEN_WIDTH)
7637 NSTRACE_MSG ("FULLSCREEN_WIDTH");
7638 maximized_width = result.size.width = defaultFrame.size.width;
7639 maximized_height = -1;
7640 result.origin.x = defaultFrame.origin.x;
7641 if (ns_userRect.size.width != 0)
7643 result.origin.y = ns_userRect.origin.y;
7644 result.size.height = ns_userRect.size.height;
7646 [self setFSValue: FULLSCREEN_WIDTH];
7648 else if (next_maximized == FULLSCREEN_MAXIMIZED
7649 || (next_maximized == -1
7650 && abs ((int)(defaultFrame.size.width - result.size.width))
7651 > FRAME_COLUMN_WIDTH (emacsframe)))
7653 NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7655 result = defaultFrame; /* second click */
7656 maximized_width = result.size.width;
7657 maximized_height = result.size.height;
7658 [self setFSValue: FULLSCREEN_MAXIMIZED];
7659 #ifdef NS_IMPL_COCOA
7660 maximizing_resize = YES;
7666 NSTRACE_MSG ("Restore");
7667 result = ns_userRect.size.height ? ns_userRect : result;
7668 NSTRACE_RECT ("restore (2)", result);
7669 ns_userRect = NSMakeRect (0, 0, 0, 0);
7670 #ifdef NS_IMPL_COCOA
7671 maximizing_resize = fs_state != FULLSCREEN_NONE;
7673 [self setFSValue: FULLSCREEN_NONE];
7674 maximized_width = maximized_height = -1;
7678 if (fs_before_fs == -1) next_maximized = -1;
7680 NSTRACE_RECT ("Final ns_userRect", ns_userRect);
7681 NSTRACE_MSG ("Final maximized_width: %d", maximized_width);
7682 NSTRACE_MSG ("Final maximized_height: %d", maximized_height);
7683 NSTRACE_FSTYPE ("Final next_maximized", next_maximized);
7685 [self windowWillResize: sender toSize: result.size];
7687 NSTRACE_RETURN_RECT (result);
7693 - (void)windowDidDeminiaturize: sender
7695 NSTRACE ("[EmacsView windowDidDeminiaturize:]");
7696 if (!emacsframe->output_data.ns)
7699 SET_FRAME_ICONIFIED (emacsframe, 0);
7700 SET_FRAME_VISIBLE (emacsframe, 1);
7701 windows_or_buffers_changed = 63;
7705 emacs_event->kind = DEICONIFY_EVENT;
7706 EV_TRAILER ((id)nil);
7711 - (void)windowDidExpose: sender
7713 NSTRACE ("[EmacsView windowDidExpose:]");
7714 if (!emacsframe->output_data.ns)
7717 SET_FRAME_VISIBLE (emacsframe, 1);
7718 SET_FRAME_GARBAGED (emacsframe);
7720 if (send_appdefined)
7721 ns_send_appdefined (-1);
7725 - (void)windowDidMiniaturize: sender
7727 NSTRACE ("[EmacsView windowDidMiniaturize:]");
7728 if (!emacsframe->output_data.ns)
7731 SET_FRAME_ICONIFIED (emacsframe, 1);
7732 SET_FRAME_VISIBLE (emacsframe, 0);
7736 emacs_event->kind = ICONIFY_EVENT;
7737 EV_TRAILER ((id)nil);
7741 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7742 - (NSApplicationPresentationOptions)window:(NSWindow *)window
7743 willUseFullScreenPresentationOptions:
7744 (NSApplicationPresentationOptions)proposedOptions
7746 return proposedOptions|NSApplicationPresentationAutoHideToolbar;
7750 - (void)windowWillEnterFullScreen:(NSNotification *)notification
7752 NSTRACE ("[EmacsView windowWillEnterFullScreen:]");
7753 [self windowWillEnterFullScreen];
7755 - (void)windowWillEnterFullScreen /* provided for direct calls */
7757 NSTRACE ("[EmacsView windowWillEnterFullScreen]");
7758 fs_before_fs = fs_state;
7761 - (void)windowDidEnterFullScreen:(NSNotification *)notification
7763 NSTRACE ("[EmacsView windowDidEnterFullScreen:]");
7764 [self windowDidEnterFullScreen];
7767 - (void)windowDidEnterFullScreen /* provided for direct calls */
7769 NSTRACE ("[EmacsView windowDidEnterFullScreen]");
7770 [self setFSValue: FULLSCREEN_BOTH];
7771 if (! [self fsIsNative])
7773 [self windowDidBecomeKey];
7774 [nonfs_window orderOut:self];
7778 BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
7779 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 \
7780 && MAC_OS_X_VERSION_MIN_REQUIRED <= 1070
7781 unsigned val = (unsigned)[NSApp presentationOptions];
7783 // Mac OS X 10.7 bug fix, the menu won't appear without this.
7784 // val is non-zero on other macOS versions.
7787 NSApplicationPresentationOptions options
7788 = NSApplicationPresentationAutoHideDock
7789 | NSApplicationPresentationAutoHideMenuBar
7790 | NSApplicationPresentationFullScreen
7791 | NSApplicationPresentationAutoHideToolbar;
7793 [NSApp setPresentationOptions: options];
7796 [toolbar setVisible:tbar_visible];
7800 - (void)windowWillExitFullScreen:(NSNotification *)notification
7802 NSTRACE ("[EmacsView windowWillExitFullScreen:]");
7803 [self windowWillExitFullScreen];
7806 - (void)windowWillExitFullScreen /* provided for direct calls */
7808 NSTRACE ("[EmacsView windowWillExitFullScreen]");
7809 if (!FRAME_LIVE_P (emacsframe))
7811 NSTRACE_MSG ("Ignored (frame dead)");
7814 if (next_maximized != -1)
7815 fs_before_fs = next_maximized;
7818 - (void)windowDidExitFullScreen:(NSNotification *)notification
7820 NSTRACE ("[EmacsView windowDidExitFullScreen:]");
7821 [self windowDidExitFullScreen];
7824 - (void)windowDidExitFullScreen /* provided for direct calls */
7826 NSTRACE ("[EmacsView windowDidExitFullScreen]");
7827 if (!FRAME_LIVE_P (emacsframe))
7829 NSTRACE_MSG ("Ignored (frame dead)");
7832 [self setFSValue: fs_before_fs];
7834 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7835 [self updateCollectionBehavior];
7837 if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
7839 [toolbar setVisible:YES];
7840 update_frame_tool_bar (emacsframe);
7841 [self updateFrameSize:YES];
7842 [[self window] display];
7845 [toolbar setVisible:NO];
7847 if (next_maximized != -1)
7848 [[self window] performZoom:self];
7853 return fs_is_native;
7856 - (BOOL)isFullscreen
7862 res = (nonfs_window != nil);
7866 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7867 res = (([[self window] styleMask] & NSWindowStyleMaskFullScreen) != 0);
7873 NSTRACE ("[EmacsView isFullscreen] " NSTRACE_FMT_RETURN " %d",
7879 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7880 - (void)updateCollectionBehavior
7882 NSTRACE ("[EmacsView updateCollectionBehavior]");
7884 if (! [self isFullscreen])
7886 NSWindow *win = [self window];
7887 NSWindowCollectionBehavior b = [win collectionBehavior];
7888 if (ns_use_native_fullscreen)
7889 b |= NSWindowCollectionBehaviorFullScreenPrimary;
7891 b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
7893 [win setCollectionBehavior: b];
7894 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7895 if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7897 fs_is_native = ns_use_native_fullscreen;
7902 - (void)toggleFullScreen: (id)sender
7910 NSTRACE ("[EmacsView toggleFullScreen:]");
7914 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7915 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7916 if ([[self window] respondsToSelector: @selector(toggleFullScreen:)])
7918 [[self window] toggleFullScreen:sender];
7924 onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
7927 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7928 (FACE_FROM_ID (f, DEFAULT_FACE_ID)),
7931 if (fs_state != FULLSCREEN_BOTH)
7933 NSScreen *screen = [w screen];
7935 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
7936 /* Hide ghost menu bar on secondary monitor? */
7938 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
7939 && [NSScreen respondsToSelector: @selector(screensHaveSeparateSpaces)]
7942 onFirstScreen = [NSScreen screensHaveSeparateSpaces];
7944 /* Hide dock and menubar if we are on the primary screen. */
7947 #ifdef NS_IMPL_COCOA
7948 NSApplicationPresentationOptions options
7949 = NSApplicationPresentationAutoHideDock
7950 | NSApplicationPresentationAutoHideMenuBar;
7952 [NSApp setPresentationOptions: options];
7954 [NSMenu setMenuBarVisible:NO];
7958 fw = [[EmacsFSWindow alloc]
7959 initWithContentRect:[w contentRectForFrameRect:wr]
7960 styleMask:NSWindowStyleMaskBorderless
7961 backing:NSBackingStoreBuffered
7965 [fw setContentView:[w contentView]];
7966 [fw setTitle:[w title]];
7967 [fw setDelegate:self];
7968 [fw setAcceptsMouseMovedEvents: YES];
7969 #if !defined (NS_IMPL_COCOA) \
7970 || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7971 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7972 if ([fw respondsToSelector: @selector(useOptimizedDrawing:)])
7974 [fw useOptimizedDrawing: YES];
7976 [fw setBackgroundColor: col];
7977 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7980 f->border_width = 0;
7984 [self windowWillEnterFullScreen];
7985 [fw makeKeyAndOrderFront:NSApp];
7986 [fw makeFirstResponder:self];
7988 r = [fw frameRectForContentRect:[screen frame]];
7989 [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
7990 [self windowDidEnterFullScreen];
8001 #ifdef NS_IMPL_COCOA
8002 [NSApp setPresentationOptions: NSApplicationPresentationDefault];
8004 [NSMenu setMenuBarVisible:YES];
8008 [w setContentView:[fw contentView]];
8009 [w setBackgroundColor: col];
8010 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
8013 f->border_width = bwidth;
8015 // To do: consider using [NSNotificationCenter postNotificationName:] to
8016 // send notifications.
8018 [self windowWillExitFullScreen];
8019 [fw setFrame: [w frame] display:YES animate:ns_use_fullscreen_animation];
8021 [w makeKeyAndOrderFront:NSApp];
8022 [self windowDidExitFullScreen];
8023 [self updateFrameSize:YES];
8029 NSTRACE ("[EmacsView handleFS]");
8031 if (fs_state != emacsframe->want_fullscreen)
8033 if (fs_state == FULLSCREEN_BOTH)
8035 NSTRACE_MSG ("fs_state == FULLSCREEN_BOTH");
8036 [self toggleFullScreen:self];
8039 switch (emacsframe->want_fullscreen)
8041 case FULLSCREEN_BOTH:
8042 NSTRACE_MSG ("FULLSCREEN_BOTH");
8043 [self toggleFullScreen:self];
8045 case FULLSCREEN_WIDTH:
8046 NSTRACE_MSG ("FULLSCREEN_WIDTH");
8047 next_maximized = FULLSCREEN_WIDTH;
8048 if (fs_state != FULLSCREEN_BOTH)
8049 [[self window] performZoom:self];
8051 case FULLSCREEN_HEIGHT:
8052 NSTRACE_MSG ("FULLSCREEN_HEIGHT");
8053 next_maximized = FULLSCREEN_HEIGHT;
8054 if (fs_state != FULLSCREEN_BOTH)
8055 [[self window] performZoom:self];
8057 case FULLSCREEN_MAXIMIZED:
8058 NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
8059 next_maximized = FULLSCREEN_MAXIMIZED;
8060 if (fs_state != FULLSCREEN_BOTH)
8061 [[self window] performZoom:self];
8063 case FULLSCREEN_NONE:
8064 NSTRACE_MSG ("FULLSCREEN_NONE");
8065 if (fs_state != FULLSCREEN_BOTH)
8067 next_maximized = FULLSCREEN_NONE;
8068 [[self window] performZoom:self];
8073 emacsframe->want_fullscreen = FULLSCREEN_NONE;
8078 - (void) setFSValue: (int)value
8080 NSTRACE ("[EmacsView setFSValue:" NSTRACE_FMT_FSTYPE "]",
8081 NSTRACE_ARG_FSTYPE(value));
8083 Lisp_Object lval = Qnil;
8086 case FULLSCREEN_BOTH:
8089 case FULLSCREEN_WIDTH:
8092 case FULLSCREEN_HEIGHT:
8095 case FULLSCREEN_MAXIMIZED:
8099 store_frame_param (emacsframe, Qfullscreen, lval);
8103 - (void)mouseEntered: (NSEvent *)theEvent
8105 NSTRACE ("[EmacsView mouseEntered:]");
8107 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
8108 = EV_TIMESTAMP (theEvent);
8112 - (void)mouseExited: (NSEvent *)theEvent
8114 Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
8116 NSTRACE ("[EmacsView mouseExited:]");
8121 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
8122 = EV_TIMESTAMP (theEvent);
8124 if (emacsframe == hlinfo->mouse_face_mouse_frame)
8126 clear_mouse_face (hlinfo);
8127 hlinfo->mouse_face_mouse_frame = 0;
8132 - (instancetype)menuDown: sender
8134 NSTRACE ("[EmacsView menuDown:]");
8135 if (context_menu_value == -1)
8136 context_menu_value = [sender tag];
8139 NSInteger tag = [sender tag];
8140 find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
8141 emacsframe->menu_bar_vector,
8145 ns_send_appdefined (-1);
8150 - (EmacsToolbar *)toolbar
8156 /* This gets called on toolbar button click. */
8157 - (instancetype)toolbarClicked: (id)item
8160 int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
8162 NSTRACE ("[EmacsView toolbarClicked:]");
8167 /* Send first event (for some reason two needed). */
8168 theEvent = [[self window] currentEvent];
8169 emacs_event->kind = TOOL_BAR_EVENT;
8170 XSETFRAME (emacs_event->arg, emacsframe);
8171 EV_TRAILER (theEvent);
8173 emacs_event->kind = TOOL_BAR_EVENT;
8174 /* XSETINT (emacs_event->code, 0); */
8175 emacs_event->arg = AREF (emacsframe->tool_bar_items,
8176 idx + TOOL_BAR_ITEM_KEY);
8177 emacs_event->modifiers = EV_MODIFIERS (theEvent);
8178 EV_TRAILER (theEvent);
8183 - (instancetype)toggleToolbar: (id)sender
8185 NSTRACE ("[EmacsView toggleToolbar:]");
8190 emacs_event->kind = NS_NONKEY_EVENT;
8191 emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
8192 EV_TRAILER ((id)nil);
8197 - (void)drawRect: (NSRect)rect
8199 int x = NSMinX (rect), y = NSMinY (rect);
8200 int width = NSWidth (rect), height = NSHeight (rect);
8202 NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
8203 NSTRACE_ARG_RECT(rect));
8205 if (!emacsframe || !emacsframe->output_data.ns)
8208 ns_clear_frame_area (emacsframe, x, y, width, height);
8210 expose_frame (emacsframe, x, y, width, height);
8214 drawRect: may be called (at least in Mac OS X 10.5) for invisible
8215 views as well for some reason. Thus, do not infer visibility
8218 emacsframe->async_visible = 1;
8219 emacsframe->async_iconified = 0;
8224 /* NSDraggingDestination protocol methods. Actually this is not really a
8225 protocol, but a category of Object. O well... */
8227 -(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
8229 NSTRACE ("[EmacsView draggingEntered:]");
8230 return NSDragOperationGeneric;
8234 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
8240 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
8245 NSEvent *theEvent = [[self window] currentEvent];
8247 NSDragOperation op = [sender draggingSourceOperationMask];
8250 NSTRACE ("[EmacsView performDragOperation:]");
8255 position = [self convertPoint: [sender draggingLocation] fromView: nil];
8256 x = lrint (position.x); y = lrint (position.y);
8258 pb = [sender draggingPasteboard];
8259 type = [pb availableTypeFromArray: ns_drag_types];
8261 if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
8262 // URL drags contain all operations (0xf), don't allow all to be set.
8265 if (op & NSDragOperationLink)
8266 modifiers |= NSEventModifierFlagControl;
8267 if (op & NSDragOperationCopy)
8268 modifiers |= NSEventModifierFlagOption;
8269 if (op & NSDragOperationGeneric)
8270 modifiers |= NSEventModifierFlagCommand;
8273 modifiers = EV_MODIFIERS2 (modifiers);
8278 else if ([type isEqualToString: NSFilenamesPboardType])
8281 NSEnumerator *fenum;
8284 if (!(files = [pb propertyListForType: type]))
8287 fenum = [files objectEnumerator];
8288 while ( (file = [fenum nextObject]) )
8290 emacs_event->kind = DRAG_N_DROP_EVENT;
8291 XSETINT (emacs_event->x, x);
8292 XSETINT (emacs_event->y, y);
8293 emacs_event->modifiers = modifiers;
8294 emacs_event->arg = list2 (Qfile, build_string ([file UTF8String]));
8295 EV_TRAILER (theEvent);
8299 else if ([type isEqualToString: NSURLPboardType])
8301 NSURL *url = [NSURL URLFromPasteboard: pb];
8302 if (url == nil) return NO;
8304 emacs_event->kind = DRAG_N_DROP_EVENT;
8305 XSETINT (emacs_event->x, x);
8306 XSETINT (emacs_event->y, y);
8307 emacs_event->modifiers = modifiers;
8308 emacs_event->arg = list2 (Qurl,
8309 build_string ([[url absoluteString]
8311 EV_TRAILER (theEvent);
8313 if ([url isFileURL] != NO)
8315 NSString *file = [url path];
8316 ns_input_file = append2 (ns_input_file,
8317 build_string ([file UTF8String]));
8321 else if ([type isEqualToString: NSStringPboardType]
8322 || [type isEqualToString: NSTabularTextPboardType])
8326 if (! (data = [pb stringForType: type]))
8329 emacs_event->kind = DRAG_N_DROP_EVENT;
8330 XSETINT (emacs_event->x, x);
8331 XSETINT (emacs_event->y, y);
8332 emacs_event->modifiers = modifiers;
8333 emacs_event->arg = list2 (Qnil, build_string ([data UTF8String]));
8334 EV_TRAILER (theEvent);
8339 fprintf (stderr, "Invalid data type in dragging pasteboard");
8345 - (id) validRequestorForSendType: (NSString *)typeSent
8346 returnType: (NSString *)typeReturned
8348 NSTRACE ("[EmacsView validRequestorForSendType:returnType:]");
8349 if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
8350 && typeReturned == nil)
8352 if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
8356 return [super validRequestorForSendType: typeSent
8357 returnType: typeReturned];
8361 /* The next two methods are part of NSServicesRequests informal protocol,
8362 supposedly called when a services menu item is chosen from this app.
8363 But this should not happen because we override the services menu with our
8364 own entries which call ns-perform-service.
8365 Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
8366 So let's at least stub them out until further investigation can be done. */
8368 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
8370 /* We could call ns_string_from_pasteboard(pboard) here but then it should
8371 be written into the buffer in place of the existing selection.
8372 Ordinary service calls go through functions defined in ns-win.el. */
8376 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
8378 NSArray *typesDeclared;
8381 NSTRACE ("[EmacsView writeSelectionToPasteboard:types:]");
8383 /* We only support NSStringPboardType. */
8384 if ([types containsObject:NSStringPboardType] == NO) {
8388 val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8389 if (CONSP (val) && SYMBOLP (XCAR (val)))
8392 if (CONSP (val) && NILP (XCDR (val)))
8395 if (! STRINGP (val))
8398 typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
8399 [pb declareTypes:typesDeclared owner:nil];
8400 ns_string_to_pasteboard (pb, val);
8405 /* setMini = YES means set from internal (gives a finder icon), NO means set nil
8406 (gives a miniaturized version of the window); currently we use the latter for
8407 frames whose active buffer doesn't correspond to any file
8408 (e.g., '*scratch*'). */
8409 - (instancetype)setMiniwindowImage: (BOOL) setMini
8411 id image = [[self window] miniwindowImage];
8412 NSTRACE ("[EmacsView setMiniwindowImage:%d]", setMini);
8414 /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
8415 about "AppleDockIconEnabled" notwithstanding, however the set message
8416 below has its effect nonetheless. */
8417 if (image != emacsframe->output_data.ns->miniimage)
8419 if (image && [image isKindOfClass: [EmacsImage class]])
8421 [[self window] setMiniwindowImage:
8422 setMini ? emacsframe->output_data.ns->miniimage : nil];
8429 - (void) setRows: (int) r andColumns: (int) c
8431 NSTRACE ("[EmacsView setRows:%d andColumns:%d]", r, c);
8436 - (int) fullscreenState
8441 @end /* EmacsView */
8445 /* ==========================================================================
8447 EmacsWindow implementation
8449 ========================================================================== */
8451 @implementation EmacsWindow
8453 #ifdef NS_IMPL_COCOA
8454 - (id)accessibilityAttributeValue:(NSString *)attribute
8456 Lisp_Object str = Qnil;
8457 struct frame *f = SELECTED_FRAME ();
8458 struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
8460 NSTRACE ("[EmacsWindow accessibilityAttributeValue:]");
8462 if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
8463 return NSAccessibilityTextFieldRole;
8465 if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
8466 && curbuf && ! NILP (BVAR (curbuf, mark_active)))
8468 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8470 else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
8472 if (! NILP (BVAR (curbuf, mark_active)))
8473 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8477 ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
8478 ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
8479 ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
8481 if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
8482 str = make_uninit_multibyte_string (range, byte_range);
8484 str = make_uninit_string (range);
8485 /* To check: This returns emacs-utf-8, which is a superset of utf-8.
8486 Is this a problem? */
8487 memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
8494 if (CONSP (str) && SYMBOLP (XCAR (str)))
8497 if (CONSP (str) && NILP (XCDR (str)))
8502 const char *utfStr = SSDATA (str);
8503 NSString *nsStr = [NSString stringWithUTF8String: utfStr];
8508 return [super accessibilityAttributeValue:attribute];
8510 #endif /* NS_IMPL_COCOA */
8512 /* Constrain size and placement of a frame.
8514 By returning the original "frameRect", the frame is not
8515 constrained. This can lead to unwanted situations where, for
8516 example, the menu bar covers the frame.
8518 The default implementation (accessed using "super") constrains the
8519 frame to the visible area of SCREEN, minus the menu bar (if
8520 present) and the Dock. Note that default implementation also calls
8521 windowWillResize, with the frame it thinks should have. (This can
8522 make the frame exit maximized mode.)
8524 Note that this should work in situations where multiple monitors
8525 are present. Common configurations are side-by-side monitors and a
8526 monitor on top of another (e.g. when a laptop is placed under a
8528 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
8530 NSTRACE ("[EmacsWindow constrainFrameRect:" NSTRACE_FMT_RECT " toScreen:]",
8531 NSTRACE_ARG_RECT (frameRect));
8533 #ifdef NS_IMPL_COCOA
8534 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
8535 // If separate spaces is on, it is like each screen is independent. There is
8536 // no spanning of frames across screens.
8538 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
8539 [NSScreen respondsToSelector: @selector(screensHaveSeparateSpaces)] &&
8541 [NSScreen screensHaveSeparateSpaces])
8543 NSTRACE_MSG ("Screens have separate spaces");
8544 frameRect = [super constrainFrameRect:frameRect toScreen:screen];
8545 NSTRACE_RETURN_RECT (frameRect);
8549 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 */
8551 // Check that the proposed frameRect is visible in at least one
8552 // screen. If it is not, ask the system to reposition it (only
8553 // for non-child windows).
8555 if (!FRAME_PARENT_FRAME (((EmacsView *)[self delegate])->emacsframe))
8557 NSArray *screens = [NSScreen screens];
8558 NSUInteger nr_screens = [screens count];
8561 BOOL frame_on_screen = NO;
8563 for (i = 0; i < nr_screens; ++i)
8565 NSScreen *s = [screens objectAtIndex: i];
8566 NSRect scrRect = [s frame];
8568 if (NSIntersectsRect(frameRect, scrRect))
8570 frame_on_screen = YES;
8575 if (!frame_on_screen)
8577 NSTRACE_MSG ("Frame outside screens; constraining");
8578 frameRect = [super constrainFrameRect:frameRect toScreen:screen];
8579 NSTRACE_RETURN_RECT (frameRect);
8585 return constrain_frame_rect(frameRect,
8586 [(EmacsView *)[self delegate] isFullscreen]);
8590 - (void)performZoom:(id)sender
8592 NSTRACE ("[EmacsWindow performZoom:]");
8594 return [super performZoom:sender];
8597 - (void)zoom:(id)sender
8599 NSTRACE ("[EmacsWindow zoom:]");
8601 ns_update_auto_hide_menu_bar();
8603 // Below are three zoom implementations. In the final commit, the
8604 // idea is that the last should be included.
8607 // Native zoom done using the standard zoom animation. Size of the
8608 // resulting frame reduced to accommodate the Dock and, if present,
8610 [super zoom:sender];
8613 // Native zoom done using the standard zoom animation, plus an
8614 // explicit resize to cover the full screen, except the menu-bar and
8615 // dock, if present.
8616 [super zoom:sender];
8618 // After the native zoom, resize the resulting frame to fill the
8619 // entire screen, except the menu-bar.
8621 // This works for all practical purposes. (The only minor oddity is
8622 // when transiting from full-height frame to a maximized, the
8623 // animation reduces the height of the frame slightly (to the 4
8624 // pixels needed to accommodate the Doc) before it snaps back into
8625 // full height. The user would need a very trained eye to spot
8627 NSScreen * screen = [self screen];
8630 int fs_state = [(EmacsView *)[self delegate] fullscreenState];
8632 NSTRACE_FSTYPE ("fullscreenState", fs_state);
8634 NSRect sr = [screen frame];
8635 struct EmacsMargins margins
8636 = ns_screen_margins_ignoring_hidden_dock(screen);
8638 NSRect wr = [self frame];
8639 NSTRACE_RECT ("Rect after zoom", wr);
8643 if (fs_state == FULLSCREEN_MAXIMIZED
8644 || fs_state == FULLSCREEN_HEIGHT)
8646 newWr.origin.y = sr.origin.y + margins.bottom;
8647 newWr.size.height = sr.size.height - margins.top - margins.bottom;
8650 if (fs_state == FULLSCREEN_MAXIMIZED
8651 || fs_state == FULLSCREEN_WIDTH)
8653 newWr.origin.x = sr.origin.x + margins.left;
8654 newWr.size.width = sr.size.width - margins.right - margins.left;
8657 if (newWr.size.width != wr.size.width
8658 || newWr.size.height != wr.size.height
8659 || newWr.origin.x != wr.origin.x
8660 || newWr.origin.y != wr.origin.y)
8662 NSTRACE_MSG ("New frame different");
8663 [self setFrame: newWr display: NO];
8667 // Non-native zoom which is done instantaneously. The resulting
8668 // frame covers the entire screen, except the menu-bar and dock, if
8670 NSScreen * screen = [self screen];
8673 NSRect sr = [screen frame];
8674 struct EmacsMargins margins
8675 = ns_screen_margins_ignoring_hidden_dock(screen);
8677 sr.size.height -= (margins.top + margins.bottom);
8678 sr.size.width -= (margins.left + margins.right);
8679 sr.origin.x += margins.left;
8680 sr.origin.y += margins.bottom;
8682 sr = [[self delegate] windowWillUseStandardFrame:self
8684 [self setFrame: sr display: NO];
8689 - (void)setFrame:(NSRect)windowFrame
8690 display:(BOOL)displayViews
8692 NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT " display:%d]",
8693 NSTRACE_ARG_RECT (windowFrame), displayViews);
8695 [super setFrame:windowFrame display:displayViews];
8698 - (void)setFrame:(NSRect)windowFrame
8699 display:(BOOL)displayViews
8700 animate:(BOOL)performAnimation
8702 NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT
8703 " display:%d performAnimation:%d]",
8704 NSTRACE_ARG_RECT (windowFrame), displayViews, performAnimation);
8706 [super setFrame:windowFrame display:displayViews animate:performAnimation];
8709 - (void)setFrameTopLeftPoint:(NSPoint)point
8711 NSTRACE ("[EmacsWindow setFrameTopLeftPoint:" NSTRACE_FMT_POINT "]",
8712 NSTRACE_ARG_POINT (point));
8714 [super setFrameTopLeftPoint:point];
8717 - (BOOL)canBecomeKeyWindow
8719 return !FRAME_NO_ACCEPT_FOCUS (((EmacsView *)[self delegate])->emacsframe);
8721 @end /* EmacsWindow */
8724 @implementation EmacsFSWindow
8726 - (BOOL)canBecomeKeyWindow
8731 - (BOOL)canBecomeMainWindow
8738 /* ==========================================================================
8740 EmacsScroller implementation
8742 ========================================================================== */
8745 @implementation EmacsScroller
8747 /* for repeat button push */
8748 #define SCROLL_BAR_FIRST_DELAY 0.5
8749 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
8751 + (CGFloat) scrollerWidth
8753 /* TODO: if we want to allow variable widths, this is the place to do it,
8754 however neither GNUstep nor Cocoa support it very well. */
8756 #if defined (NS_IMPL_COCOA) \
8757 && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
8758 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
8759 if ([NSScroller respondsToSelector:
8760 @selector(scrollerWidthForControlSize:scrollerStyle:)])
8762 r = [NSScroller scrollerWidthForControlSize: NSControlSizeRegular
8763 scrollerStyle: NSScrollerStyleLegacy];
8764 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
8767 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
8768 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 \
8769 || defined (NS_IMPL_GNUSTEP)
8770 r = [NSScroller scrollerWidth];
8775 - (instancetype)initFrame: (NSRect )r window: (Lisp_Object)nwin
8777 NSTRACE ("[EmacsScroller initFrame: window:]");
8779 if (r.size.width > r.size.height)
8784 [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
8785 [self setContinuous: YES];
8786 [self setEnabled: YES];
8788 /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
8789 locked against the top and bottom edges, and right edge on macOS, where
8790 scrollers are on right. */
8791 #ifdef NS_IMPL_GNUSTEP
8792 [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
8794 [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
8797 window = XWINDOW (nwin);
8800 pixel_length = NSWidth (r);
8802 pixel_length = NSHeight (r);
8803 if (pixel_length == 0) pixel_length = 1;
8804 min_portion = 20 / pixel_length;
8806 frame = XFRAME (window->frame);
8807 if (FRAME_LIVE_P (frame))
8810 EmacsView *view = FRAME_NS_VIEW (frame);
8811 NSView *sview = [[view window] contentView];
8812 NSArray *subs = [sview subviews];
8814 /* Disable optimization stopping redraw of other scrollbars. */
8815 view->scrollbarsNeedingUpdate = 0;
8816 for (i =[subs count]-1; i >= 0; i--)
8817 if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
8818 view->scrollbarsNeedingUpdate++;
8819 [sview addSubview: self];
8822 /* [self setFrame: r]; */
8828 - (void)setFrame: (NSRect)newRect
8830 NSTRACE ("[EmacsScroller setFrame:]");
8832 /* block_input (); */
8834 pixel_length = NSWidth (newRect);
8836 pixel_length = NSHeight (newRect);
8837 if (pixel_length == 0) pixel_length = 1;
8838 min_portion = 20 / pixel_length;
8839 [super setFrame: newRect];
8840 /* unblock_input (); */
8846 NSTRACE ("[EmacsScroller dealloc]");
8850 wset_horizontal_scroll_bar (window, Qnil);
8852 wset_vertical_scroll_bar (window, Qnil);
8859 - (instancetype)condemn
8861 NSTRACE ("[EmacsScroller condemn]");
8867 - (instancetype)reprieve
8869 NSTRACE ("[EmacsScroller reprieve]");
8877 NSTRACE ("[EmacsScroller judge]");
8878 bool ret = condemned;
8883 /* Ensure other scrollbar updates after deletion. */
8884 view = (EmacsView *)FRAME_NS_VIEW (frame);
8886 view->scrollbarsNeedingUpdate++;
8890 wset_horizontal_scroll_bar (window, Qnil);
8892 wset_vertical_scroll_bar (window, Qnil);
8895 [self removeFromSuperview];
8903 - (void)resetCursorRects
8905 NSRect visible = [self visibleRect];
8906 NSTRACE ("[EmacsScroller resetCursorRects]");
8908 if (!NSIsEmptyRect (visible))
8909 [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
8911 #if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 101300
8912 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101300
8913 if ([[NSCursor arrowCursor] respondsToSelector:
8914 @selector(setOnMouseEntered)])
8916 [[NSCursor arrowCursor] setOnMouseEntered: YES];
8921 - (int) checkSamePosition: (int) position portion: (int) portion
8924 return em_position ==position && em_portion ==portion && em_whole ==whole
8925 && portion != whole; /* Needed for resizing empty buffer. */
8929 - (instancetype)setPosition: (int)position portion: (int)portion whole: (int)whole
8931 NSTRACE ("[EmacsScroller setPosition:portion:whole:]");
8933 em_position = position;
8934 em_portion = portion;
8937 if (portion >= whole)
8939 #ifdef NS_IMPL_COCOA
8940 [self setKnobProportion: 1.0];
8941 [self setDoubleValue: 1.0];
8943 [self setFloatValue: 0.0 knobProportion: 1.0];
8950 portion = max ((float)whole*min_portion/pixel_length, portion);
8951 pos = (float)position / (whole - portion);
8952 por = (CGFloat)portion/whole;
8953 #ifdef NS_IMPL_COCOA
8954 [self setKnobProportion: por];
8955 [self setDoubleValue: pos];
8957 [self setFloatValue: pos knobProportion: por];
8964 /* Set up emacs_event. */
8965 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
8969 NSTRACE ("[EmacsScroller sendScrollEventAtLoc:fromEvent:]");
8974 emacs_event->part = last_hit_part;
8975 emacs_event->code = 0;
8976 emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
8977 XSETWINDOW (win, window);
8978 emacs_event->frame_or_window = win;
8979 emacs_event->timestamp = EV_TIMESTAMP (e);
8980 emacs_event->arg = Qnil;
8984 emacs_event->kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT;
8985 XSETINT (emacs_event->x, em_whole * loc / pixel_length);
8986 XSETINT (emacs_event->y, em_whole);
8990 emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
8991 XSETINT (emacs_event->x, loc);
8992 XSETINT (emacs_event->y, pixel_length-20);
8997 n_emacs_events_pending++;
8998 kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
9001 hold_event (emacs_event);
9002 EVENT_INIT (*emacs_event);
9003 ns_send_appdefined (-1);
9007 /* Called manually through timer to implement repeated button action
9009 - (instancetype)repeatScroll: (NSTimer *)scrollEntry
9011 NSEvent *e = [[self window] currentEvent];
9012 NSPoint p = [[self window] mouseLocationOutsideOfEventStream];
9013 BOOL inKnob = [self testPart: p] == NSScrollerKnob;
9015 NSTRACE ("[EmacsScroller repeatScroll:]");
9017 /* Clear timer if need be. */
9018 if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
9020 [scroll_repeat_entry invalidate];
9021 [scroll_repeat_entry release];
9022 scroll_repeat_entry = nil;
9028 = [[NSTimer scheduledTimerWithTimeInterval:
9029 SCROLL_BAR_CONTINUOUS_DELAY
9031 selector: @selector (repeatScroll:)
9037 [self sendScrollEventAtLoc: 0 fromEvent: e];
9042 /* Asynchronous mouse tracking for scroller. This allows us to dispatch
9043 mouseDragged events without going into a modal loop. */
9044 - (void)mouseDown: (NSEvent *)e
9047 /* hitPart is only updated AFTER event is passed on. */
9048 NSScrollerPart part = [self testPart: [e locationInWindow]];
9049 CGFloat loc, kloc, pos UNINIT;
9052 NSTRACE ("[EmacsScroller mouseDown:]");
9056 case NSScrollerDecrementPage:
9057 last_hit_part = horizontal ? scroll_bar_before_handle : scroll_bar_above_handle; break;
9058 case NSScrollerIncrementPage:
9059 last_hit_part = horizontal ? scroll_bar_after_handle : scroll_bar_below_handle; break;
9060 case NSScrollerDecrementLine:
9061 last_hit_part = horizontal ? scroll_bar_left_arrow : scroll_bar_up_arrow; break;
9062 case NSScrollerIncrementLine:
9063 last_hit_part = horizontal ? scroll_bar_right_arrow : scroll_bar_down_arrow; break;
9064 case NSScrollerKnob:
9065 last_hit_part = horizontal ? scroll_bar_horizontal_handle : scroll_bar_handle; break;
9066 case NSScrollerKnobSlot: /* GNUstep-only */
9067 last_hit_part = scroll_bar_move_ratio; break;
9068 default: /* NSScrollerNoPart? */
9069 fprintf (stderr, "EmacsScroller-mouseDown: unexpected part %ld\n",
9074 if (part == NSScrollerKnob || part == NSScrollerKnobSlot)
9076 /* handle, or on GNUstep possibly slot */
9077 NSEvent *fake_event;
9080 /* compute float loc in slot and mouse offset on knob */
9081 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
9085 length = NSWidth (sr);
9086 loc = ([e locationInWindow].x - NSMinX (sr));
9090 length = NSHeight (sr);
9091 loc = length - ([e locationInWindow].y - NSMinY (sr));
9099 else if (loc >= length)
9109 kr = [self convertRect: [self rectForPart: NSScrollerKnob]
9112 kloc = ([e locationInWindow].x - NSMinX (kr));
9114 kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
9116 last_mouse_offset = kloc;
9118 /* if knob, tell emacs a location offset by knob pos
9119 (to indicate top of handle) */
9120 if (part == NSScrollerKnob)
9121 pos = (loc - last_mouse_offset);
9123 /* else this is a slot click on GNUstep: go straight there */
9126 /* If there are buttons in the scroller area, we need to
9127 recalculate pos as emacs expects the scroller slot to take up
9128 the entire available length. */
9129 if (length != pixel_length)
9130 pos = pos * pixel_length / length;
9132 /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
9133 fake_event = [NSEvent mouseEventWithType: NSEventTypeLeftMouseUp
9134 location: [e locationInWindow]
9135 modifierFlags: [e modifierFlags]
9136 timestamp: [e timestamp]
9137 windowNumber: [e windowNumber]
9139 eventNumber: [e eventNumber]
9140 clickCount: [e clickCount]
9141 pressure: [e pressure]];
9142 [super mouseUp: fake_event];
9146 pos = 0; /* ignored */
9148 /* Set a timer to repeat, as we can't let superclass do this modally. */
9150 = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
9152 selector: @selector (repeatScroll:)
9158 if (part != NSScrollerKnob)
9159 [self sendScrollEventAtLoc: pos fromEvent: e];
9163 /* Called as we manually track scroller drags, rather than superclass. */
9164 - (void)mouseDragged: (NSEvent *)e
9170 NSTRACE ("[EmacsScroller mouseDragged:]");
9172 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
9177 length = NSWidth (sr);
9178 loc = ([e locationInWindow].x - NSMinX (sr));
9182 length = NSHeight (sr);
9183 loc = length - ([e locationInWindow].y - NSMinY (sr));
9190 else if (loc >= length + last_mouse_offset)
9192 loc = length + last_mouse_offset;
9195 pos = (loc - last_mouse_offset);
9197 /* If there are buttons in the scroller area, we need to
9198 recalculate pos as emacs expects the scroller slot to take up
9199 the entire available length. */
9200 if (length != pixel_length)
9201 pos = pos * pixel_length / length;
9203 [self sendScrollEventAtLoc: pos fromEvent: e];
9207 - (void)mouseUp: (NSEvent *)e
9209 NSTRACE ("[EmacsScroller mouseUp:]");
9211 if (scroll_repeat_entry)
9213 [scroll_repeat_entry invalidate];
9214 [scroll_repeat_entry release];
9215 scroll_repeat_entry = nil;
9217 last_hit_part = scroll_bar_above_handle;
9221 /* Treat scrollwheel events in the bar as though they were in the main window. */
9222 - (void) scrollWheel: (NSEvent *)theEvent
9224 NSTRACE ("[EmacsScroller scrollWheel:]");
9226 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
9227 [view mouseDown: theEvent];
9230 @end /* EmacsScroller */
9233 #ifdef NS_IMPL_GNUSTEP
9234 /* Dummy class to get rid of startup warnings. */
9235 @implementation EmacsDocument
9241 /* ==========================================================================
9243 Font-related functions; these used to be in nsfaces.m
9245 ========================================================================== */
9249 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
9251 struct font *font = XFONT_OBJECT (font_object);
9252 EmacsView *view = FRAME_NS_VIEW (f);
9253 int font_ascent, font_descent;
9256 fontset = fontset_from_font (font_object);
9257 FRAME_FONTSET (f) = fontset;
9259 if (FRAME_FONT (f) == font)
9260 /* This font is already set in frame F. There's nothing more to
9264 FRAME_FONT (f) = font;
9266 FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
9267 FRAME_COLUMN_WIDTH (f) = font->average_width;
9268 get_font_ascent_descent (font, &font_ascent, &font_descent);
9269 FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
9271 /* Compute the scroll bar width in character columns. */
9272 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
9274 int wid = FRAME_COLUMN_WIDTH (f);
9275 FRAME_CONFIG_SCROLL_BAR_COLS (f)
9276 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
9280 int wid = FRAME_COLUMN_WIDTH (f);
9281 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
9284 /* Compute the scroll bar height in character lines. */
9285 if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0)
9287 int height = FRAME_LINE_HEIGHT (f);
9288 FRAME_CONFIG_SCROLL_BAR_LINES (f)
9289 = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
9293 int height = FRAME_LINE_HEIGHT (f);
9294 FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
9297 /* Now make the frame display the given font. */
9298 if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
9299 adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
9300 FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
9307 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
9308 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
9312 ns_xlfd_to_fontname (const char *xlfd)
9313 /* --------------------------------------------------------------------------
9314 Convert an X font name (XLFD) to an NS font name.
9315 Only family is used.
9316 The string returned is temporarily allocated.
9317 -------------------------------------------------------------------------- */
9319 char *name = xmalloc (180);
9323 if (!strncmp (xlfd, "--", 2))
9324 sscanf (xlfd, "--%*[^-]-%179[^-]-", name);
9326 sscanf (xlfd, "-%*[^-]-%179[^-]-", name);
9328 /* stopgap for malformed XLFD input */
9329 if (strlen (name) == 0)
9330 strcpy (name, "Monaco");
9332 /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
9333 also uppercase after '-' or ' ' */
9334 name[0] = c_toupper (name[0]);
9335 for (len =strlen (name), i =0; i<len; i++)
9341 name[i+1] = c_toupper (name[i+1]);
9343 else if (name[i] == '_')
9347 name[i+1] = c_toupper (name[i+1]);
9350 /* fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name); */
9351 ret = [[NSString stringWithUTF8String: name] UTF8String];
9358 syms_of_nsterm (void)
9360 NSTRACE ("syms_of_nsterm");
9362 ns_antialias_threshold = 10.0;
9364 /* From 23+ we need to tell emacs what modifiers there are. */
9365 DEFSYM (Qmodifier_value, "modifier-value");
9366 DEFSYM (Qalt, "alt");
9367 DEFSYM (Qhyper, "hyper");
9368 DEFSYM (Qmeta, "meta");
9369 DEFSYM (Qsuper, "super");
9370 DEFSYM (Qcontrol, "control");
9371 DEFSYM (QUTF8_STRING, "UTF8_STRING");
9373 DEFSYM (Qfile, "file");
9374 DEFSYM (Qurl, "url");
9376 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
9377 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
9378 Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
9379 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
9380 Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
9382 DEFVAR_LISP ("ns-input-file", ns_input_file,
9383 "The file specified in the last NS event.");
9384 ns_input_file =Qnil;
9386 DEFVAR_LISP ("ns-working-text", ns_working_text,
9387 "String for visualizing working composition sequence.");
9388 ns_working_text =Qnil;
9390 DEFVAR_LISP ("ns-input-font", ns_input_font,
9391 "The font specified in the last NS event.");
9392 ns_input_font =Qnil;
9394 DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
9395 "The fontsize specified in the last NS event.");
9396 ns_input_fontsize =Qnil;
9398 DEFVAR_LISP ("ns-input-line", ns_input_line,
9399 "The line specified in the last NS event.");
9400 ns_input_line =Qnil;
9402 DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
9403 "The service name specified in the last NS event.");
9404 ns_input_spi_name =Qnil;
9406 DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
9407 "The service argument specified in the last NS event.");
9408 ns_input_spi_arg =Qnil;
9410 DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
9411 "This variable describes the behavior of the alternate or option key.\n\
9412 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9414 Set to none means that the alternate / option key is not interpreted by Emacs\n\
9415 at all, allowing it to be used at a lower level for accented character entry.");
9416 ns_alternate_modifier = Qmeta;
9418 DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
9419 "This variable describes the behavior of the right alternate or option key.\n\
9420 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9422 Set to left means be the same key as `ns-alternate-modifier'.\n\
9423 Set to none means that the alternate / option key is not interpreted by Emacs\n\
9424 at all, allowing it to be used at a lower level for accented character entry.");
9425 ns_right_alternate_modifier = Qleft;
9427 DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
9428 "This variable describes the behavior of the command key.\n\
9429 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9431 ns_command_modifier = Qsuper;
9433 DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
9434 "This variable describes the behavior of the right command key.\n\
9435 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9437 Set to left means be the same key as `ns-command-modifier'.\n\
9438 Set to none means that the command / option key is not interpreted by Emacs\n\
9439 at all, allowing it to be used at a lower level for accented character entry.");
9440 ns_right_command_modifier = Qleft;
9442 DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
9443 "This variable describes the behavior of the control key.\n\
9444 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9446 ns_control_modifier = Qcontrol;
9448 DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
9449 "This variable describes the behavior of the right control key.\n\
9450 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9452 Set to left means be the same key as `ns-control-modifier'.\n\
9453 Set to none means that the control / option key is not interpreted by Emacs\n\
9454 at all, allowing it to be used at a lower level for accented character entry.");
9455 ns_right_control_modifier = Qleft;
9457 DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
9458 "This variable describes the behavior of the function key (on laptops).\n\
9459 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9461 Set to none means that the function key is not interpreted by Emacs at all,\n\
9462 allowing it to be used at a lower level for accented character entry.");
9463 ns_function_modifier = Qnone;
9465 DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
9466 "Non-nil (the default) means to render text antialiased.");
9467 ns_antialias_text = Qt;
9469 DEFVAR_LISP ("ns-use-thin-smoothing", ns_use_thin_smoothing,
9470 "Non-nil turns on a font smoothing method that produces thinner strokes.");
9471 ns_use_thin_smoothing = Qnil;
9473 DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
9474 "Whether to confirm application quit using dialog.");
9475 ns_confirm_quit = Qnil;
9477 DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
9478 doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
9479 Only works on Mac OS X. */);
9480 ns_auto_hide_menu_bar = Qnil;
9482 DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
9483 doc: /* Non-nil means to use native fullscreen on Mac OS X 10.7 and later.
9484 Nil means use fullscreen the old (< 10.7) way. The old way works better with
9485 multiple monitors, but lacks tool bar. This variable is ignored on
9486 Mac OS X < 10.7. Default is t. */);
9487 ns_use_native_fullscreen = YES;
9488 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
9490 DEFVAR_BOOL ("ns-use-fullscreen-animation", ns_use_fullscreen_animation,
9491 doc: /* Non-nil means use animation on non-native fullscreen.
9492 For native fullscreen, this does nothing.
9493 Default is nil. */);
9494 ns_use_fullscreen_animation = NO;
9496 DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
9497 doc: /* Non-nil means to use sRGB colorspace on Mac OS X 10.7 and later.
9498 Note that this does not apply to images.
9499 This variable is ignored on Mac OS X < 10.7 and GNUstep. */);
9500 ns_use_srgb_colorspace = YES;
9502 DEFVAR_BOOL ("ns-use-mwheel-acceleration",
9503 ns_use_mwheel_acceleration,
9504 doc: /* Non-nil means use macOS's standard mouse wheel acceleration.
9505 This variable is ignored on macOS < 10.7 and GNUstep. Default is t. */);
9506 ns_use_mwheel_acceleration = YES;
9508 DEFVAR_LISP ("ns-mwheel-line-height", ns_mwheel_line_height,
9509 doc: /* The number of pixels touchpad scrolling considers one line.
9510 Nil or a non-number means use the default frame line height.
9511 This variable is ignored on macOS < 10.7 and GNUstep. Default is nil. */);
9512 ns_mwheel_line_height = Qnil;
9514 DEFVAR_BOOL ("ns-use-mwheel-momentum", ns_use_mwheel_momentum,
9515 doc: /* Non-nil means mouse wheel scrolling uses momentum.
9516 This variable is ignored on macOS < 10.7 and GNUstep. Default is t. */);
9517 ns_use_mwheel_momentum = YES;
9519 /* TODO: Move to common code. */
9520 DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
9521 doc: /* SKIP: real doc in xterm.c. */);
9522 Vx_toolkit_scroll_bars = Qt;
9524 DEFVAR_BOOL ("x-use-underline-position-properties",
9525 x_use_underline_position_properties,
9526 doc: /* SKIP: real doc in xterm.c. */);
9527 x_use_underline_position_properties = 0;
9528 DEFSYM (Qx_use_underline_position_properties,
9529 "x-use-underline-position-properties");
9531 DEFVAR_BOOL ("x-underline-at-descent-line",
9532 x_underline_at_descent_line,
9533 doc: /* SKIP: real doc in xterm.c. */);
9534 x_underline_at_descent_line = 0;
9535 DEFSYM (Qx_underline_at_descent_line, "x-underline-at-descent-line");
9537 /* Tell Emacs about this window system. */
9538 Fprovide (Qns, Qnil);
9540 DEFSYM (Qcocoa, "cocoa");
9541 DEFSYM (Qgnustep, "gnustep");
9543 #ifdef NS_IMPL_COCOA
9544 Fprovide (Qcocoa, Qnil);
9547 Fprovide (Qgnustep, Qnil);