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;
332 * State for pending menu activation:
333 * MENU_NONE Normal state
334 * MENU_PENDING A menu has been clicked on, but has been canceled so we can
335 * run lisp to update the menu.
336 * MENU_OPENING Menu is up to date, and the click event is redone so the menu
340 #define MENU_PENDING 1
341 #define MENU_OPENING 2
342 static int menu_will_open_state = MENU_NONE;
344 /* Saved position for menu click. */
345 static CGPoint menu_mouse_point;
348 /* Convert modifiers in a NeXTstep event to emacs style modifiers. */
349 #define NS_FUNCTION_KEY_MASK 0x800000
350 #define NSLeftControlKeyMask (0x000001 | NSEventModifierFlagControl)
351 #define NSRightControlKeyMask (0x002000 | NSEventModifierFlagControl)
352 #define NSLeftCommandKeyMask (0x000008 | NSEventModifierFlagCommand)
353 #define NSRightCommandKeyMask (0x000010 | NSEventModifierFlagCommand)
354 #define NSLeftAlternateKeyMask (0x000020 | NSEventModifierFlagOption)
355 #define NSRightAlternateKeyMask (0x000040 | NSEventModifierFlagOption)
358 ev_modifiers_helper (unsigned int flags, unsigned int left_mask,
359 unsigned int right_mask, unsigned int either_mask,
360 Lisp_Object left_modifier, Lisp_Object right_modifier)
362 unsigned int modifiers = 0;
364 if (flags & either_mask)
366 BOOL left_key = (flags & left_mask) == left_mask;
367 BOOL right_key = (flags & right_mask) == right_mask
368 && ! EQ (right_modifier, Qleft);
371 modifiers |= parse_solitary_modifier (right_modifier);
373 /* GNUstep (and possibly macOS in certain circumstances) doesn't
374 differentiate between the left and right keys, so if we can't
375 identify which key it is, we use the left key setting. */
376 if (left_key || ! right_key)
377 modifiers |= parse_solitary_modifier (left_modifier);
383 #define EV_MODIFIERS2(flags) \
384 (((flags & NSEventModifierFlagHelp) ? \
385 hyper_modifier : 0) \
386 | ((flags & NSEventModifierFlagShift) ? \
387 shift_modifier : 0) \
388 | ((flags & NS_FUNCTION_KEY_MASK) ? \
389 parse_solitary_modifier (ns_function_modifier) : 0) \
390 | ev_modifiers_helper (flags, NSLeftControlKeyMask, \
391 NSRightControlKeyMask, \
392 NSEventModifierFlagControl, \
393 ns_control_modifier, \
394 ns_right_control_modifier) \
395 | ev_modifiers_helper (flags, NSLeftCommandKeyMask, \
396 NSRightCommandKeyMask, \
397 NSEventModifierFlagCommand, \
398 ns_command_modifier, \
399 ns_right_command_modifier) \
400 | ev_modifiers_helper (flags, NSLeftAlternateKeyMask, \
401 NSRightAlternateKeyMask, \
402 NSEventModifierFlagOption, \
403 ns_alternate_modifier, \
404 ns_right_alternate_modifier))
406 #define EV_MODIFIERS(e) EV_MODIFIERS2 ([e modifierFlags])
408 #define EV_UDMODIFIERS(e) \
409 ((([e type] == NSEventTypeLeftMouseDown) ? down_modifier : 0) \
410 | (([e type] == NSEventTypeRightMouseDown) ? down_modifier : 0) \
411 | (([e type] == NSEventTypeOtherMouseDown) ? down_modifier : 0) \
412 | (([e type] == NSEventTypeLeftMouseDragged) ? down_modifier : 0) \
413 | (([e type] == NSEventTypeRightMouseDragged) ? down_modifier : 0) \
414 | (([e type] == NSEventTypeOtherMouseDragged) ? down_modifier : 0) \
415 | (([e type] == NSEventTypeLeftMouseUp) ? up_modifier : 0) \
416 | (([e type] == NSEventTypeRightMouseUp) ? up_modifier : 0) \
417 | (([e type] == NSEventTypeOtherMouseUp) ? up_modifier : 0))
419 #define EV_BUTTON(e) \
420 ((([e type] == NSEventTypeLeftMouseDown) || ([e type] == NSEventTypeLeftMouseUp)) ? 0 : \
421 (([e type] == NSEventTypeRightMouseDown) || ([e type] == NSEventTypeRightMouseUp)) ? 2 : \
422 [e buttonNumber] - 1)
424 /* Convert the time field to a timestamp in milliseconds. */
425 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
427 /* This is a piece of code which is common to all the event handling
428 methods. Maybe it should even be a function. */
429 #define EV_TRAILER(e) \
431 XSETFRAME (emacs_event->frame_or_window, emacsframe); \
435 #define EV_TRAILER2(e) \
437 if (e) emacs_event->timestamp = EV_TIMESTAMP (e); \
440 Lisp_Object tem = Vinhibit_quit; \
441 Vinhibit_quit = Qt; \
442 n_emacs_events_pending++; \
443 kbd_buffer_store_event_hold (emacs_event, q_event_ptr); \
444 Vinhibit_quit = tem; \
447 hold_event (emacs_event); \
448 EVENT_INIT (*emacs_event); \
449 ns_send_appdefined (-1); \
453 /* These flags will be OR'd or XOR'd with the NSWindow's styleMask
454 property depending on what we're doing. */
455 #define FRAME_DECORATED_FLAGS (NSWindowStyleMaskTitled \
456 | NSWindowStyleMaskResizable \
457 | NSWindowStyleMaskMiniaturizable \
458 | NSWindowStyleMaskClosable)
459 #define FRAME_UNDECORATED_FLAGS NSWindowStyleMaskBorderless
461 /* TODO: Get rid of need for these forward declarations. */
462 static void ns_condemn_scroll_bars (struct frame *f);
463 static void ns_judge_scroll_bars (struct frame *f);
466 /* ==========================================================================
470 ========================================================================== */
473 ns_init_events (struct input_event *ev)
480 ns_finish_events (void)
486 hold_event (struct input_event *event)
488 if (hold_event_q.nr == hold_event_q.cap)
490 if (hold_event_q.cap == 0) hold_event_q.cap = 10;
491 else hold_event_q.cap *= 2;
493 xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
496 hold_event_q.q[hold_event_q.nr++] = *event;
497 /* Make sure ns_read_socket is called, i.e. we have input. */
499 send_appdefined = YES;
503 append2 (Lisp_Object list, Lisp_Object item)
504 /* --------------------------------------------------------------------------
505 Utility to append to a list
506 -------------------------------------------------------------------------- */
508 return CALLN (Fnconc, list, list1 (item));
513 ns_etc_directory (void)
514 /* If running as a self-contained app bundle, return as a string the
515 filename of the etc directory, if present; else nil. */
517 NSBundle *bundle = [NSBundle mainBundle];
518 NSString *resourceDir = [bundle resourcePath];
519 NSString *resourcePath;
520 NSFileManager *fileManager = [NSFileManager defaultManager];
523 resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
524 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
526 if (isDir) return [resourcePath UTF8String];
534 /* If running as a self-contained app bundle, return as a path string
535 the filenames of the libexec and bin directories, ie libexec:bin.
536 Otherwise, return nil.
537 Normally, Emacs does not add its own bin/ directory to the PATH.
538 However, a self-contained NS build has a different layout, with
539 bin/ and libexec/ subdirectories in the directory that contains
541 We put libexec first, because init_callproc_1 uses the first
542 element to initialize exec-directory. An alternative would be
543 for init_callproc to check for invocation-directory/libexec.
546 NSBundle *bundle = [NSBundle mainBundle];
547 NSString *resourceDir = [bundle resourcePath];
548 NSString *binDir = [bundle bundlePath];
549 NSString *resourcePath, *resourcePaths;
551 NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
552 NSFileManager *fileManager = [NSFileManager defaultManager];
554 NSEnumerator *pathEnum;
557 range = [resourceDir rangeOfString: @"Contents"];
558 if (range.location != NSNotFound)
560 binDir = [binDir stringByAppendingPathComponent: @"Contents"];
562 binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
566 paths = [binDir stringsByAppendingPaths:
567 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
568 pathEnum = [paths objectEnumerator];
571 while ((resourcePath = [pathEnum nextObject]))
573 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
576 if ([resourcePaths length] > 0)
578 = [resourcePaths stringByAppendingString: pathSeparator];
580 = [resourcePaths stringByAppendingString: resourcePath];
583 if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
591 /* If running as a self-contained app bundle, return as a path string
592 the filenames of the site-lisp and lisp directories.
593 Ie, site-lisp:lisp. Otherwise, return nil. */
595 NSBundle *bundle = [NSBundle mainBundle];
596 NSString *resourceDir = [bundle resourcePath];
597 NSString *resourcePath, *resourcePaths;
598 NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
599 NSFileManager *fileManager = [NSFileManager defaultManager];
601 NSArray *paths = [resourceDir stringsByAppendingPaths:
602 [NSArray arrayWithObjects:
603 @"site-lisp", @"lisp", nil]];
604 NSEnumerator *pathEnum = [paths objectEnumerator];
607 /* Hack to skip site-lisp. */
608 if (no_site_lisp) resourcePath = [pathEnum nextObject];
610 while ((resourcePath = [pathEnum nextObject]))
612 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
615 if ([resourcePaths length] > 0)
617 = [resourcePaths stringByAppendingString: pathSeparator];
619 = [resourcePaths stringByAppendingString: resourcePath];
622 if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
629 ns_init_locale (void)
630 /* macOS doesn't set any environment variables for the locale when run
631 from the GUI. Get the locale from the OS and set LANG. */
633 NSLocale *locale = [NSLocale currentLocale];
635 NSTRACE ("ns_init_locale");
639 /* It seems macOS should probably use UTF-8 everywhere.
640 'localeIdentifier' does not specify the encoding, and I can't
641 find any way to get the OS to tell us which encoding to use,
642 so hard-code '.UTF-8'. */
643 NSString *localeID = [NSString stringWithFormat:@"%@.UTF-8",
644 [locale localeIdentifier]];
646 /* Set LANG to locale, but not if LANG is already set. */
647 setenv("LANG", [localeID UTF8String], 0);
649 @catch (NSException *e)
651 NSLog (@"Locale detection failed: %@: %@", [e name], [e reason]);
657 ns_release_object (void *obj)
658 /* --------------------------------------------------------------------------
659 Release an object (callable from C)
660 -------------------------------------------------------------------------- */
667 ns_retain_object (void *obj)
668 /* --------------------------------------------------------------------------
669 Retain an object (callable from C)
670 -------------------------------------------------------------------------- */
677 ns_alloc_autorelease_pool (void)
678 /* --------------------------------------------------------------------------
679 Allocate a pool for temporary objects (callable from C)
680 -------------------------------------------------------------------------- */
682 return [[NSAutoreleasePool alloc] init];
687 ns_release_autorelease_pool (void *pool)
688 /* --------------------------------------------------------------------------
689 Free a pool and temporary objects it refers to (callable from C)
690 -------------------------------------------------------------------------- */
692 ns_release_object (pool);
697 /* Disabling screen updates can be used to make several actions appear
698 "atomic" to the end user. It seems some actions can still update
701 When we re-enable screen updates the number of calls to
702 NSEnableScreenUpdates should match the number to
703 NSDisableScreenUpdates.
705 We use these functions to prevent the user seeing a blank frame
706 after it has been resized. x_set_window_size disables updates and
707 when redisplay completes unwind_redisplay enables them again
711 ns_disable_screen_updates (void)
713 NSDisableScreenUpdates ();
714 disable_screen_updates_count++;
718 ns_enable_screen_updates (void)
719 /* Re-enable screen updates. Called from unwind_redisplay. */
721 while (disable_screen_updates_count > 0)
723 NSEnableScreenUpdates ();
724 disable_screen_updates_count--;
731 ns_menu_bar_should_be_hidden (void)
732 /* True, if the menu bar should be hidden. */
734 return !NILP (ns_auto_hide_menu_bar)
735 && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
748 static struct EmacsMargins
749 ns_screen_margins (NSScreen *screen)
750 /* The parts of SCREEN used by the operating system. */
752 NSTRACE ("ns_screen_margins");
754 struct EmacsMargins margins;
756 NSRect screenFrame = [screen frame];
757 NSRect screenVisibleFrame = [screen visibleFrame];
759 /* Sometimes, visibleFrame isn't up-to-date with respect to a hidden
760 menu bar, check this explicitly. */
761 if (ns_menu_bar_should_be_hidden())
767 CGFloat frameTop = screenFrame.origin.y + screenFrame.size.height;
768 CGFloat visibleFrameTop = (screenVisibleFrame.origin.y
769 + screenVisibleFrame.size.height);
771 margins.top = frameTop - visibleFrameTop;
775 CGFloat frameRight = screenFrame.origin.x + screenFrame.size.width;
776 CGFloat visibleFrameRight = (screenVisibleFrame.origin.x
777 + screenVisibleFrame.size.width);
778 margins.right = frameRight - visibleFrameRight;
781 margins.bottom = screenVisibleFrame.origin.y - screenFrame.origin.y;
782 margins.left = screenVisibleFrame.origin.x - screenFrame.origin.x;
784 NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
794 /* A screen margin between 1 and DOCK_IGNORE_LIMIT (inclusive) is
795 assumed to contain a hidden dock. macOS currently use 4 pixels for
796 this, however, to be future compatible, a larger value is used. */
797 #define DOCK_IGNORE_LIMIT 6
799 static struct EmacsMargins
800 ns_screen_margins_ignoring_hidden_dock (NSScreen *screen)
801 /* The parts of SCREEN used by the operating system, excluding the parts
802 reserved for a hidden dock. */
804 NSTRACE ("ns_screen_margins_ignoring_hidden_dock");
806 struct EmacsMargins margins = ns_screen_margins(screen);
808 /* macOS (currently) reserved 4 pixels along the edge where a hidden
809 dock is located. Unfortunately, it's not possible to find the
810 location and information about if the dock is hidden. Instead,
811 it is assumed that if the margin of an edge is less than
812 DOCK_IGNORE_LIMIT, it contains a hidden dock. */
813 if (margins.left <= DOCK_IGNORE_LIMIT)
817 if (margins.right <= DOCK_IGNORE_LIMIT)
821 if (margins.top <= DOCK_IGNORE_LIMIT)
825 /* Note: This doesn't occur in current versions of macOS, but
826 included for completeness and future compatibility. */
827 if (margins.bottom <= DOCK_IGNORE_LIMIT)
832 NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
843 ns_menu_bar_height (NSScreen *screen)
844 /* The height of the menu bar, if visible.
846 Note: Don't use this when fullscreen is enabled -- the screen
847 sometimes includes, sometimes excludes the menu bar area. */
849 struct EmacsMargins margins = ns_screen_margins(screen);
851 CGFloat res = margins.top;
853 NSTRACE ("ns_menu_bar_height " NSTRACE_FMT_RETURN " %.0f", res);
859 /* ==========================================================================
861 Focus (clipping) and screen update
863 ========================================================================== */
866 // Window constraining
867 // -------------------
869 // To ensure that the windows are not placed under the menu bar, they
870 // are typically moved by the call-back constrainFrameRect. However,
871 // by overriding it, it's possible to inhibit this, leaving the window
872 // in it's original position.
874 // It's possible to hide the menu bar. However, technically, it's only
875 // possible to hide it when the application is active. To ensure that
876 // this work properly, the menu bar and window constraining are
877 // deferred until the application becomes active.
879 // Even though it's not possible to manually move a window above the
880 // top of the screen, it is allowed if it's done programmatically,
881 // when the menu is hidden. This allows the editable area to cover the
882 // full screen height.
887 // Use the following extra files:
890 // ;; Hide menu and place frame slightly above the top of the screen.
891 // (setq ns-auto-hide-menu-bar t)
892 // (set-frame-position (selected-frame) 0 -20)
896 // emacs -Q -l init.el
898 // Result: No menu bar, and the title bar should be above the screen.
904 // Result: Menu bar visible, frame placed immediately below the menu.
907 static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
909 NSTRACE ("constrain_frame_rect(" NSTRACE_FMT_RECT ")",
910 NSTRACE_ARG_RECT (frameRect));
912 // --------------------
913 // Collect information about the screen the frame is covering.
916 NSArray *screens = [NSScreen screens];
917 NSUInteger nr_screens = [screens count];
921 // The height of the menu bar, if present in any screen the frame is
923 int menu_bar_height = 0;
925 // A rectangle covering all the screen the frame is displayed in.
926 NSRect multiscreenRect = NSMakeRect(0, 0, 0, 0);
927 for (i = 0; i < nr_screens; ++i )
929 NSScreen *s = [screens objectAtIndex: i];
930 NSRect scrRect = [s frame];
932 NSTRACE_MSG ("Screen %d: " NSTRACE_FMT_RECT,
933 i, NSTRACE_ARG_RECT (scrRect));
935 if (NSIntersectionRect (frameRect, scrRect).size.height != 0)
937 multiscreenRect = NSUnionRect (multiscreenRect, scrRect);
941 CGFloat screen_menu_bar_height = ns_menu_bar_height (s);
942 menu_bar_height = max(menu_bar_height, screen_menu_bar_height);
947 NSTRACE_RECT ("multiscreenRect", multiscreenRect);
949 NSTRACE_MSG ("menu_bar_height: %d", menu_bar_height);
951 if (multiscreenRect.size.width == 0
952 || multiscreenRect.size.height == 0)
954 // Failed to find any monitor, give up.
955 NSTRACE_MSG ("multiscreenRect empty");
956 NSTRACE_RETURN_RECT (frameRect);
961 // --------------------
962 // Find a suitable placement.
965 if (ns_menu_bar_should_be_hidden())
967 // When the menu bar is hidden, the user may place part of the
968 // frame above the top of the screen, for example to hide the
971 // Hence, keep the original position.
975 // Ensure that the frame is below the menu bar, or below the top
978 // This assume that the menu bar is placed at the top in the
979 // rectangle that covers the monitors. (It doesn't have to be,
980 // but if it's not it's hard to do anything useful.)
981 CGFloat topOfWorkArea = (multiscreenRect.origin.y
982 + multiscreenRect.size.height
985 CGFloat topOfFrame = frameRect.origin.y + frameRect.size.height;
986 if (topOfFrame > topOfWorkArea)
988 frameRect.origin.y -= topOfFrame - topOfWorkArea;
989 NSTRACE_RECT ("After placement adjust", frameRect);
993 // Include the following section to restrict frame to the screens.
994 // (If so, update it to allow the frame to stretch down below the
997 // --------------------
998 // Ensure frame doesn't stretch below the screens.
1001 CGFloat diff = multiscreenRect.origin.y - frameRect.origin.y;
1005 frameRect.origin.y = multiscreenRect.origin.y;
1006 frameRect.size.height -= diff;
1010 NSTRACE_RETURN_RECT (frameRect);
1016 ns_constrain_all_frames (void)
1017 /* --------------------------------------------------------------------------
1018 Ensure that the menu bar doesn't cover any frames.
1019 -------------------------------------------------------------------------- */
1021 Lisp_Object tail, frame;
1023 NSTRACE ("ns_constrain_all_frames");
1027 FOR_EACH_FRAME (tail, frame)
1029 struct frame *f = XFRAME (frame);
1032 EmacsView *view = FRAME_NS_VIEW (f);
1034 if (![view isFullscreen])
1037 setFrame:constrain_frame_rect([[view window] frame], false)
1048 ns_update_auto_hide_menu_bar (void)
1049 /* --------------------------------------------------------------------------
1050 Show or hide the menu bar, based on user setting.
1051 -------------------------------------------------------------------------- */
1053 #ifdef NS_IMPL_COCOA
1054 NSTRACE ("ns_update_auto_hide_menu_bar");
1058 if (NSApp != nil && [NSApp isActive])
1060 // Note, "setPresentationOptions" triggers an error unless the
1061 // application is active.
1062 BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
1064 if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
1066 NSApplicationPresentationOptions options
1067 = NSApplicationPresentationDefault;
1069 if (menu_bar_should_be_hidden)
1070 options |= NSApplicationPresentationAutoHideMenuBar
1071 | NSApplicationPresentationAutoHideDock;
1073 [NSApp setPresentationOptions: options];
1075 ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
1077 if (!ns_menu_bar_is_hidden)
1079 ns_constrain_all_frames ();
1090 ns_update_begin (struct frame *f)
1091 /* --------------------------------------------------------------------------
1092 Prepare for a grouped sequence of drawing calls
1093 external (RIF) call; whole frame, called before update_window_begin
1094 -------------------------------------------------------------------------- */
1096 EmacsView *view = FRAME_NS_VIEW (f);
1097 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_begin");
1099 ns_update_auto_hide_menu_bar ();
1101 #ifdef NS_IMPL_COCOA
1102 if ([view isFullscreen] && [view fsIsNative])
1104 // Fix reappearing tool bar in fullscreen for Mac OS X 10.7
1105 BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
1106 NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
1107 if (! tbar_visible != ! [toolbar isVisible])
1108 [toolbar setVisible: tbar_visible];
1112 ns_updating_frame = f;
1115 /* drawRect may have been called for say the minibuffer, and then clip path
1116 is for the minibuffer. But the display engine may draw more because
1117 we have set the frame as garbaged. So reset clip path to the whole
1119 #ifdef NS_IMPL_COCOA
1122 NSRect r = [view frame];
1123 NSRect cr = [[view window] frame];
1124 /* If a large frame size is set, r may be larger than the window frame
1125 before constrained. In that case don't change the clip path, as we
1126 will clear in to the tool bar and title bar. */
1128 + FRAME_NS_TITLEBAR_HEIGHT (f)
1129 + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
1131 bp = [[NSBezierPath bezierPathWithRect: r] retain];
1138 #ifdef NS_IMPL_GNUSTEP
1139 uRect = NSMakeRect (0, 0, 0, 0);
1145 ns_update_window_begin (struct window *w)
1146 /* --------------------------------------------------------------------------
1147 Prepare for a grouped sequence of drawing calls
1148 external (RIF) call; for one window, called after update_begin
1149 -------------------------------------------------------------------------- */
1151 struct frame *f = XFRAME (WINDOW_FRAME (w));
1152 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1154 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_begin");
1155 w->output_cursor = w->cursor;
1159 if (f == hlinfo->mouse_face_mouse_frame)
1161 /* Don't do highlighting for mouse motion during the update. */
1162 hlinfo->mouse_face_defer = 1;
1164 /* If the frame needs to be redrawn,
1165 simply forget about any prior mouse highlighting. */
1166 if (FRAME_GARBAGED_P (f))
1167 hlinfo->mouse_face_window = Qnil;
1169 /* (further code for mouse faces ifdef'd out in other terms elided) */
1177 ns_update_window_end (struct window *w, bool cursor_on_p,
1178 bool mouse_face_overwritten_p)
1179 /* --------------------------------------------------------------------------
1180 Finished a grouped sequence of drawing calls
1181 external (RIF) call; for one window called before update_end
1182 -------------------------------------------------------------------------- */
1184 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_end");
1186 /* note: this fn is nearly identical in all terms */
1187 if (!w->pseudo_window_p)
1192 display_and_set_cursor (w, 1,
1193 w->output_cursor.hpos, w->output_cursor.vpos,
1194 w->output_cursor.x, w->output_cursor.y);
1196 if (draw_window_fringes (w, 1))
1198 if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
1199 x_draw_right_divider (w);
1201 x_draw_vertical_border (w);
1207 /* If a row with mouse-face was overwritten, arrange for
1208 frame_up_to_date to redisplay the mouse highlight. */
1209 if (mouse_face_overwritten_p)
1210 reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
1215 ns_update_end (struct frame *f)
1216 /* --------------------------------------------------------------------------
1217 Finished a grouped sequence of drawing calls
1218 external (RIF) call; for whole frame, called after update_window_end
1219 -------------------------------------------------------------------------- */
1221 EmacsView *view = FRAME_NS_VIEW (f);
1223 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_end");
1225 /* if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
1226 MOUSE_HL_INFO (f)->mouse_face_defer = 0;
1231 [[view window] flushWindow];
1234 ns_updating_frame = NULL;
1238 ns_focus (struct frame *f, NSRect *r, int n)
1239 /* --------------------------------------------------------------------------
1240 Internal: Focus on given frame. During small local updates this is used to
1241 draw, however during large updates, ns_update_begin and ns_update_end are
1242 called to wrap the whole thing, in which case these calls are stubbed out.
1243 Except, on GNUstep, we accumulate the rectangle being drawn into, because
1244 the back end won't do this automatically, and will just end up flushing
1246 -------------------------------------------------------------------------- */
1248 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_focus");
1251 NSTRACE_RECT ("r", *r);
1254 if (f != ns_updating_frame)
1256 NSView *view = FRAME_NS_VIEW (f);
1257 if (view != focus_view)
1259 if (focus_view != NULL)
1261 [focus_view unlockFocus];
1262 [[focus_view window] flushWindow];
1269 /* if (view) debug_lock++; */
1276 [[NSGraphicsContext currentContext] saveGraphicsState];
1278 NSRectClipList (r, 2);
1287 ns_unfocus (struct frame *f)
1288 /* --------------------------------------------------------------------------
1289 Internal: Remove focus on given frame
1290 -------------------------------------------------------------------------- */
1292 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_unfocus");
1296 [[NSGraphicsContext currentContext] restoreGraphicsState];
1300 if (f != ns_updating_frame)
1302 if (focus_view != NULL)
1304 [focus_view unlockFocus];
1305 [[focus_view window] flushWindow];
1314 ns_clip_to_row (struct window *w, struct glyph_row *row,
1315 enum glyph_row_area area, BOOL gc)
1316 /* --------------------------------------------------------------------------
1317 Internal (but parallels other terms): Focus drawing on given row
1318 -------------------------------------------------------------------------- */
1320 struct frame *f = XFRAME (WINDOW_FRAME (w));
1322 int window_x, window_y, window_width;
1324 window_box (w, area, &window_x, &window_y, &window_width, 0);
1326 clip_rect.origin.x = window_x;
1327 clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
1328 clip_rect.origin.y = max (clip_rect.origin.y, window_y);
1329 clip_rect.size.width = window_width;
1330 clip_rect.size.height = row->visible_height;
1332 ns_focus (f, &clip_rect, 1);
1336 /* ==========================================================================
1338 Visible bell and beep.
1340 ========================================================================== */
1343 // This bell implementation shows the visual bell image asynchronously
1344 // from the rest of Emacs. This is done by adding a NSView to the
1345 // superview of the Emacs window and removing it using a timer.
1347 // Unfortunately, some Emacs operations, like scrolling, is done using
1348 // low-level primitives that copy the content of the window, including
1349 // the bell image. To some extent, this is handled by removing the
1350 // image prior to scrolling and marking that the window is in need for
1353 // To test this code, make sure that there is no artifacts of the bell
1354 // image in the following situations. Use a non-empty buffer (like the
1355 // tutorial) to ensure that a scroll is performed:
1357 // * Single-window: C-g C-v
1359 // * Side-by-windows: C-x 3 C-g C-v
1361 // * Windows above each other: C-x 2 C-g C-v
1363 @interface EmacsBell : NSImageView
1365 // Number of currently active bells.
1366 unsigned int nestCount;
1370 - (void)show:(NSView *)view;
1375 @implementation EmacsBell
1379 NSTRACE ("[EmacsBell init]");
1380 if ((self = [super init]))
1384 #ifdef NS_IMPL_GNUSTEP
1385 // GNUstep doesn't provide named images. This was reported in
1386 // 2011, see https://savannah.gnu.org/bugs/?33396
1388 // As a drop in replacement, a semitransparent gray square is used.
1389 self.image = [[NSImage alloc] initWithSize:NSMakeSize(32 * 5, 32 * 5)];
1390 [self.image lockFocus];
1391 [[NSColor colorForEmacsRed:0.5 green:0.5 blue:0.5 alpha:0.5] set];
1392 NSRectFill(NSMakeRect(0, 0, 32, 32));
1393 [self.image unlockFocus];
1395 self.image = [NSImage imageNamed:NSImageNameCaution];
1396 [self.image setSize:NSMakeSize(self.image.size.width * 5,
1397 self.image.size.height * 5)];
1403 - (void)show:(NSView *)view
1405 NSTRACE ("[EmacsBell show:]");
1406 NSTRACE_MSG ("nestCount: %u", nestCount);
1408 // Show the image, unless it's already shown.
1411 NSRect rect = [view bounds];
1413 pos.x = rect.origin.x + (rect.size.width - self.image.size.width )/2;
1414 pos.y = rect.origin.y + (rect.size.height - self.image.size.height)/2;
1416 [self setFrameOrigin:pos];
1417 [self setFrameSize:self.image.size];
1421 [[[view window] contentView] addSubview:self
1422 positioned:NSWindowAbove
1428 [self performSelector:@selector(hide) withObject:self afterDelay:0.5];
1434 // Note: Trace output from this method isn't shown, reason unknown.
1435 // NSTRACE ("[EmacsBell hide]");
1440 // Remove the image once the last bell became inactive.
1450 NSTRACE ("[EmacsBell remove]");
1453 NSTRACE_MSG ("removeFromSuperview");
1454 [self removeFromSuperview];
1455 mView.needsDisplay = YES;
1463 static EmacsBell * bell_view = nil;
1466 ns_ring_bell (struct frame *f)
1467 /* --------------------------------------------------------------------------
1469 -------------------------------------------------------------------------- */
1471 NSTRACE ("ns_ring_bell");
1474 struct frame *frame = SELECTED_FRAME ();
1477 if (bell_view == nil)
1479 bell_view = [[EmacsBell alloc] init];
1485 view = FRAME_NS_VIEW (frame);
1488 [bell_view show:view];
1502 /* --------------------------------------------------------------------------
1503 Ensure the bell is hidden.
1504 -------------------------------------------------------------------------- */
1506 NSTRACE ("hide_bell");
1508 if (bell_view != nil)
1515 /* ==========================================================================
1517 Frame / window manager related functions
1519 ========================================================================== */
1523 ns_raise_frame (struct frame *f, BOOL make_key)
1524 /* --------------------------------------------------------------------------
1525 Bring window to foreground and if make_key is YES, give it focus.
1526 -------------------------------------------------------------------------- */
1530 check_window_system (f);
1531 view = FRAME_NS_VIEW (f);
1533 if (FRAME_VISIBLE_P (f))
1536 [[view window] makeKeyAndOrderFront: NSApp];
1538 [[view window] orderFront: NSApp];
1545 ns_lower_frame (struct frame *f)
1546 /* --------------------------------------------------------------------------
1548 -------------------------------------------------------------------------- */
1552 check_window_system (f);
1553 view = FRAME_NS_VIEW (f);
1555 [[view window] orderBack: NSApp];
1561 ns_frame_raise_lower (struct frame *f, bool raise)
1562 /* --------------------------------------------------------------------------
1564 -------------------------------------------------------------------------- */
1566 NSTRACE ("ns_frame_raise_lower");
1569 ns_raise_frame (f, YES);
1576 ns_frame_rehighlight (struct frame *frame)
1577 /* --------------------------------------------------------------------------
1578 External (hook): called on things like window switching within frame
1579 -------------------------------------------------------------------------- */
1581 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1582 struct frame *old_highlight = dpyinfo->x_highlight_frame;
1584 NSTRACE ("ns_frame_rehighlight");
1585 if (dpyinfo->x_focus_frame)
1587 dpyinfo->x_highlight_frame
1588 = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1589 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1590 : dpyinfo->x_focus_frame);
1591 if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1593 fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1594 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1598 dpyinfo->x_highlight_frame = 0;
1600 if (dpyinfo->x_highlight_frame &&
1601 dpyinfo->x_highlight_frame != old_highlight)
1605 x_update_cursor (old_highlight, 1);
1606 x_set_frame_alpha (old_highlight);
1608 if (dpyinfo->x_highlight_frame)
1610 x_update_cursor (dpyinfo->x_highlight_frame, 1);
1611 x_set_frame_alpha (dpyinfo->x_highlight_frame);
1618 x_make_frame_visible (struct frame *f)
1619 /* --------------------------------------------------------------------------
1620 External: Show the window (X11 semantics)
1621 -------------------------------------------------------------------------- */
1623 NSTRACE ("x_make_frame_visible");
1624 /* XXX: at some points in past this was not needed, as the only place that
1625 called this (frame.c:Fraise_frame ()) also called raise_lower;
1626 if this ends up the case again, comment this out again. */
1627 if (!FRAME_VISIBLE_P (f))
1629 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1630 NSWindow *window = [view window];
1632 SET_FRAME_VISIBLE (f, 1);
1633 ns_raise_frame (f, ! FRAME_NO_FOCUS_ON_MAP (f));
1635 /* Making a new frame from a fullscreen frame will make the new frame
1636 fullscreen also. So skip handleFS as this will print an error. */
1637 if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1638 && [view isFullscreen])
1641 if (f->want_fullscreen != FULLSCREEN_NONE)
1648 /* Making a frame invisible seems to break the parent->child
1649 relationship, so reinstate it. */
1650 if ([window parentWindow] == nil && FRAME_PARENT_FRAME (f) != NULL)
1652 NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
1655 [parent addChildWindow: window
1656 ordered: NSWindowAbove];
1659 /* If the parent frame moved while the child frame was
1660 invisible, the child frame's position won't have been
1661 updated. Make sure it's in the right place now. */
1662 x_set_offset(f, f->left_pos, f->top_pos, 0);
1669 x_make_frame_invisible (struct frame *f)
1670 /* --------------------------------------------------------------------------
1671 External: Hide the window (X11 semantics)
1672 -------------------------------------------------------------------------- */
1675 NSTRACE ("x_make_frame_invisible");
1676 check_window_system (f);
1677 view = FRAME_NS_VIEW (f);
1678 [[view window] orderOut: NSApp];
1679 SET_FRAME_VISIBLE (f, 0);
1680 SET_FRAME_ICONIFIED (f, 0);
1685 x_iconify_frame (struct frame *f)
1686 /* --------------------------------------------------------------------------
1687 External: Iconify window
1688 -------------------------------------------------------------------------- */
1691 struct ns_display_info *dpyinfo;
1693 NSTRACE ("x_iconify_frame");
1694 check_window_system (f);
1695 view = FRAME_NS_VIEW (f);
1696 dpyinfo = FRAME_DISPLAY_INFO (f);
1698 if (dpyinfo->x_highlight_frame == f)
1699 dpyinfo->x_highlight_frame = 0;
1701 if ([[view window] windowNumber] <= 0)
1703 /* The window is still deferred. Make it very small, bring it
1704 on screen and order it out. */
1705 NSRect s = { { 100, 100}, {0, 0} };
1707 t = [[view window] frame];
1708 [[view window] setFrame: s display: NO];
1709 [[view window] orderBack: NSApp];
1710 [[view window] orderOut: NSApp];
1711 [[view window] setFrame: t display: NO];
1714 /* Processing input while Emacs is being minimized can cause a
1715 crash, so block it for the duration. */
1717 [[view window] miniaturize: NSApp];
1721 /* Free X resources of frame F. */
1724 x_free_frame_resources (struct frame *f)
1727 struct ns_display_info *dpyinfo;
1728 Mouse_HLInfo *hlinfo;
1730 NSTRACE ("x_free_frame_resources");
1731 check_window_system (f);
1732 view = FRAME_NS_VIEW (f);
1733 dpyinfo = FRAME_DISPLAY_INFO (f);
1734 hlinfo = MOUSE_HL_INFO (f);
1736 [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1740 free_frame_menubar (f);
1741 free_frame_faces (f);
1743 if (f == dpyinfo->x_focus_frame)
1744 dpyinfo->x_focus_frame = 0;
1745 if (f == dpyinfo->x_highlight_frame)
1746 dpyinfo->x_highlight_frame = 0;
1747 if (f == hlinfo->mouse_face_mouse_frame)
1748 reset_mouse_highlight (hlinfo);
1750 if (f->output_data.ns->miniimage != nil)
1751 [f->output_data.ns->miniimage release];
1753 [[view window] close];
1756 xfree (f->output_data.ns);
1762 x_destroy_window (struct frame *f)
1763 /* --------------------------------------------------------------------------
1764 External: Delete the window
1765 -------------------------------------------------------------------------- */
1767 NSTRACE ("x_destroy_window");
1769 /* If this frame has a parent window, detach it as not doing so can
1770 cause a crash in GNUStep. */
1771 if (FRAME_PARENT_FRAME (f) != NULL)
1773 NSWindow *child = [FRAME_NS_VIEW (f) window];
1774 NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
1776 [parent removeChildWindow: child];
1779 check_window_system (f);
1780 x_free_frame_resources (f);
1786 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1787 /* --------------------------------------------------------------------------
1788 External: Position the window
1789 -------------------------------------------------------------------------- */
1791 NSView *view = FRAME_NS_VIEW (f);
1792 NSScreen *screen = [[view window] screen];
1794 NSTRACE ("x_set_offset");
1803 if (FRAME_PARENT_FRAME (f) == NULL && screen)
1805 f->left_pos = f->size_hint_flags & XNegative
1806 ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1808 /* We use visibleFrame here to take menu bar into account.
1809 Ideally we should also adjust left/top with visibleFrame.origin. */
1811 f->top_pos = f->size_hint_flags & YNegative
1812 ? ([screen visibleFrame].size.height + f->top_pos
1813 - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1814 - FRAME_TOOLBAR_HEIGHT (f))
1816 #ifdef NS_IMPL_GNUSTEP
1817 if (f->left_pos < 100)
1818 f->left_pos = 100; /* don't overlap menu */
1821 else if (FRAME_PARENT_FRAME (f) != NULL)
1823 struct frame *parent = FRAME_PARENT_FRAME (f);
1825 /* On X negative values for child frames always result in
1826 positioning relative to the bottom right corner of the
1828 if (f->left_pos < 0)
1829 f->left_pos = FRAME_PIXEL_WIDTH (parent) - FRAME_PIXEL_WIDTH (f) + f->left_pos;
1832 f->top_pos = FRAME_PIXEL_HEIGHT (parent) + FRAME_TOOLBAR_HEIGHT (parent)
1833 - FRAME_PIXEL_HEIGHT (f) + f->top_pos;
1836 /* Constrain the setFrameTopLeftPoint so we don't move behind the
1838 NSPoint pt = NSMakePoint (SCREENMAXBOUND (f->left_pos
1839 + NS_PARENT_WINDOW_LEFT_POS (f)),
1840 SCREENMAXBOUND (NS_PARENT_WINDOW_TOP_POS (f)
1842 NSTRACE_POINT ("setFrameTopLeftPoint", pt);
1843 [[view window] setFrameTopLeftPoint: pt];
1844 f->size_hint_flags &= ~(XNegative|YNegative);
1852 x_set_window_size (struct frame *f,
1853 bool change_gravity,
1857 /* --------------------------------------------------------------------------
1858 Adjust window pixel size based on given character grid size
1859 Impl is a bit more complex than other terms, need to do some
1861 -------------------------------------------------------------------------- */
1863 EmacsView *view = FRAME_NS_VIEW (f);
1864 NSWindow *window = [view window];
1865 NSRect wr = [window frame];
1866 int pixelwidth, pixelheight;
1867 int orig_height = wr.size.height;
1869 NSTRACE ("x_set_window_size");
1874 NSTRACE_RECT ("current", wr);
1875 NSTRACE_MSG ("Width:%d Height:%d Pixelwise:%d", width, height, pixelwise);
1876 NSTRACE_MSG ("Font %d x %d", FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f));
1880 #ifdef NS_IMPL_COCOA
1881 /* To prevent showing the user a blank frame, stop updates being
1882 flushed to the screen until after redisplay has completed. This
1883 breaks live resize (resizing with a mouse), so don't do it if
1884 we're in a live resize loop. */
1885 if (![view inLiveResize])
1886 ns_disable_screen_updates ();
1891 pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1892 pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1896 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, width);
1897 pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1900 wr.size.width = pixelwidth + f->border_width;
1901 wr.size.height = pixelheight;
1902 if (! [view isFullscreen])
1903 wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1904 + FRAME_TOOLBAR_HEIGHT (f);
1906 /* Do not try to constrain to this screen. We may have multiple
1907 screens, and want Emacs to span those. Constraining to screen
1908 prevents that, and that is not nice to the user. */
1909 if (f->output_data.ns->zooming)
1910 f->output_data.ns->zooming = 0;
1912 wr.origin.y += orig_height - wr.size.height;
1914 frame_size_history_add
1915 (f, Qx_set_window_size_1, width, height,
1916 list5 (Fcons (make_number (pixelwidth), make_number (pixelheight)),
1917 Fcons (make_number (wr.size.width), make_number (wr.size.height)),
1918 make_number (f->border_width),
1919 make_number (FRAME_NS_TITLEBAR_HEIGHT (f)),
1920 make_number (FRAME_TOOLBAR_HEIGHT (f))));
1922 [window setFrame: wr display: YES];
1924 [view updateFrameSize: NO];
1928 #ifdef NS_IMPL_COCOA
1930 x_set_undecorated (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1931 /* --------------------------------------------------------------------------
1932 Set frame F's `undecorated' parameter. If non-nil, F's window-system
1933 window is drawn without decorations, title, minimize/maximize boxes
1934 and external borders. This usually means that the window cannot be
1935 dragged, resized, iconified, maximized or deleted with the mouse. If
1936 nil, draw the frame with all the elements listed above unless these
1937 have been suspended via window manager settings.
1939 GNUStep cannot change an existing window's style.
1940 -------------------------------------------------------------------------- */
1942 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1943 NSWindow *window = [view window];
1945 NSTRACE ("x_set_undecorated");
1947 if (!EQ (new_value, old_value))
1951 if (NILP (new_value))
1953 FRAME_UNDECORATED (f) = false;
1954 [window setStyleMask: ((window.styleMask | FRAME_DECORATED_FLAGS)
1955 ^ FRAME_UNDECORATED_FLAGS)];
1957 [view createToolbar: f];
1961 [window setToolbar: nil];
1962 /* Do I need to release the toolbar here? */
1964 FRAME_UNDECORATED (f) = true;
1965 [window setStyleMask: ((window.styleMask | FRAME_UNDECORATED_FLAGS)
1966 ^ FRAME_DECORATED_FLAGS)];
1969 /* At this point it seems we don't have an active NSResponder,
1970 so some key presses (TAB) are swallowed by the system. */
1971 [window makeFirstResponder: view];
1973 [view updateFrameSize: NO];
1977 #endif /* NS_IMPL_COCOA */
1980 x_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1981 /* --------------------------------------------------------------------------
1982 Set frame F's `parent-frame' parameter. If non-nil, make F a child
1983 frame of the frame specified by that parameter. Technically, this
1984 makes F's window-system window a child window of the parent frame's
1985 window-system window. If nil, make F's window-system window a
1986 top-level window--a child of its display's root window.
1988 A child frame's `left' and `top' parameters specify positions
1989 relative to the top-left corner of its parent frame's native
1990 rectangle. On macOS moving a parent frame moves all its child
1991 frames too, keeping their position relative to the parent
1992 unaltered. When a parent frame is iconified or made invisible, its
1993 child frames are made invisible. When a parent frame is deleted,
1994 its child frames are deleted too.
1996 Whether a child frame has a tool bar may be window-system or window
1997 manager dependent. It's advisable to disable it via the frame
2000 Some window managers may not honor this parameter.
2001 -------------------------------------------------------------------------- */
2003 struct frame *p = NULL;
2004 NSWindow *parent, *child;
2006 NSTRACE ("x_set_parent_frame");
2008 if (!NILP (new_value)
2009 && (!FRAMEP (new_value)
2010 || !FRAME_LIVE_P (p = XFRAME (new_value))
2011 || !FRAME_NS_P (p)))
2013 store_frame_param (f, Qparent_frame, old_value);
2014 error ("Invalid specification of `parent-frame'");
2017 if (p != FRAME_PARENT_FRAME (f))
2019 parent = [FRAME_NS_VIEW (p) window];
2020 child = [FRAME_NS_VIEW (f) window];
2023 [parent addChildWindow: child
2024 ordered: NSWindowAbove];
2027 fset_parent_frame (f, new_value);
2032 x_set_no_focus_on_map (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
2033 /* Set frame F's `no-focus-on-map' parameter which, if non-nil, means
2034 * that F's window-system window does not want to receive input focus
2035 * when it is mapped. (A frame's window is mapped when the frame is
2036 * displayed for the first time and when the frame changes its state
2037 * from `iconified' or `invisible' to `visible'.)
2039 * Some window managers may not honor this parameter. */
2041 NSTRACE ("x_set_no_focus_on_map");
2043 if (!EQ (new_value, old_value))
2045 FRAME_NO_FOCUS_ON_MAP (f) = !NILP (new_value);
2050 x_set_no_accept_focus (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
2051 /* Set frame F's `no-accept-focus' parameter which, if non-nil, hints
2052 * that F's window-system window does not want to receive input focus
2053 * via mouse clicks or by moving the mouse into it.
2055 * If non-nil, this may have the unwanted side-effect that a user cannot
2056 * scroll a non-selected frame with the mouse.
2058 * Some window managers may not honor this parameter. */
2060 NSTRACE ("x_set_no_accept_focus");
2062 if (!EQ (new_value, old_value))
2063 FRAME_NO_ACCEPT_FOCUS (f) = !NILP (new_value);
2067 x_set_z_group (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
2068 /* Set frame F's `z-group' parameter. If `above', F's window-system
2069 window is displayed above all windows that do not have the `above'
2070 property set. If nil, F's window is shown below all windows that
2071 have the `above' property set and above all windows that have the
2072 `below' property set. If `below', F's window is displayed below
2073 all windows that do.
2075 Some window managers may not honor this parameter. */
2077 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2078 NSWindow *window = [view window];
2080 NSTRACE ("x_set_z_group");
2082 if (NILP (new_value))
2084 window.level = NSNormalWindowLevel;
2085 FRAME_Z_GROUP (f) = z_group_none;
2087 else if (EQ (new_value, Qabove))
2089 window.level = NSNormalWindowLevel + 1;
2090 FRAME_Z_GROUP (f) = z_group_above;
2092 else if (EQ (new_value, Qabove_suspended))
2094 /* Not sure what level this should be. */
2095 window.level = NSNormalWindowLevel + 1;
2096 FRAME_Z_GROUP (f) = z_group_above_suspended;
2098 else if (EQ (new_value, Qbelow))
2100 window.level = NSNormalWindowLevel - 1;
2101 FRAME_Z_GROUP (f) = z_group_below;
2104 error ("Invalid z-group specification");
2107 #ifdef NS_IMPL_COCOA
2109 ns_set_appearance (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
2111 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
2112 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2113 NSWindow *window = [view window];
2115 NSTRACE ("ns_set_appearance");
2117 #ifndef NSAppKitVersionNumber10_10
2118 #define NSAppKitVersionNumber10_10 1343
2121 if (NSAppKitVersionNumber < NSAppKitVersionNumber10_10)
2124 if (EQ (new_value, Qdark))
2126 window.appearance = [NSAppearance
2127 appearanceNamed: NSAppearanceNameVibrantDark];
2128 FRAME_NS_APPEARANCE (f) = ns_appearance_vibrant_dark;
2132 window.appearance = [NSAppearance
2133 appearanceNamed: NSAppearanceNameAqua];
2134 FRAME_NS_APPEARANCE (f) = ns_appearance_aqua;
2136 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 */
2140 ns_set_transparent_titlebar (struct frame *f, Lisp_Object new_value,
2141 Lisp_Object old_value)
2143 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
2144 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2145 NSWindow *window = [view window];
2147 NSTRACE ("ns_set_transparent_titlebar");
2149 if ([window respondsToSelector: @selector(titlebarAppearsTransparent)]
2150 && !EQ (new_value, old_value))
2152 window.titlebarAppearsTransparent = !NILP (new_value);
2153 FRAME_NS_TRANSPARENT_TITLEBAR (f) = !NILP (new_value);
2155 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 */
2157 #endif /* NS_IMPL_COCOA */
2160 ns_fullscreen_hook (struct frame *f)
2162 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2164 NSTRACE ("ns_fullscreen_hook");
2166 if (!FRAME_VISIBLE_P (f))
2169 if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
2171 /* Old style fs don't initiate correctly if created from
2172 init/default-frame alist, so use a timer (not nice...). */
2173 [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
2174 selector: @selector (handleFS)
2175 userInfo: nil repeats: NO];
2184 /* ==========================================================================
2188 ========================================================================== */
2192 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
2194 struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
2195 if (idx < 1 || idx >= color_table->avail)
2197 return color_table->colors[idx];
2202 ns_index_color (NSColor *color, struct frame *f)
2204 struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
2208 if (!color_table->colors)
2210 color_table->size = NS_COLOR_CAPACITY;
2211 color_table->avail = 1; /* skip idx=0 as marker */
2212 color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
2213 color_table->colors[0] = nil;
2214 color_table->empty_indices = [[NSMutableSet alloc] init];
2217 /* Do we already have this color? */
2218 for (i = 1; i < color_table->avail; i++)
2219 if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
2222 if ([color_table->empty_indices count] > 0)
2224 NSNumber *index = [color_table->empty_indices anyObject];
2225 [color_table->empty_indices removeObject: index];
2226 idx = [index unsignedLongValue];
2230 if (color_table->avail == color_table->size)
2231 color_table->colors =
2232 xpalloc (color_table->colors, &color_table->size, 1,
2233 min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
2234 idx = color_table->avail++;
2237 color_table->colors[idx] = color;
2239 /* fprintf(stderr, "color_table: allocated %d\n",idx); */
2245 ns_get_color (const char *name, NSColor **col)
2246 /* --------------------------------------------------------------------------
2248 -------------------------------------------------------------------------- */
2249 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
2250 X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
2251 See https://lists.gnu.org/r/emacs-devel/2009-07/msg01203.html. */
2254 static char hex[20];
2256 float r = -1.0, g, b;
2257 NSString *nsname = [NSString stringWithUTF8String: name];
2259 NSTRACE ("ns_get_color(%s, **)", name);
2263 if ([nsname isEqualToString: @"ns_selection_bg_color"])
2265 #ifdef NS_IMPL_COCOA
2266 NSString *defname = [[NSUserDefaults standardUserDefaults]
2267 stringForKey: @"AppleHighlightColor"];
2272 if ((new = [NSColor selectedTextBackgroundColor]) != nil)
2274 *col = [new colorUsingDefaultColorSpace];
2279 nsname = NS_SELECTION_BG_COLOR_DEFAULT;
2281 name = [nsname UTF8String];
2283 else if ([nsname isEqualToString: @"ns_selection_fg_color"])
2285 /* NOTE: macOS applications normally don't set foreground
2286 selection, but text may be unreadable if we don't. */
2287 if ((new = [NSColor selectedTextColor]) != nil)
2289 *col = [new colorUsingDefaultColorSpace];
2294 nsname = NS_SELECTION_FG_COLOR_DEFAULT;
2295 name = [nsname UTF8String];
2298 /* First, check for some sort of numeric specification. */
2301 if (name[0] == '0' || name[0] == '1' || name[0] == '.') /* RGB decimal */
2303 NSScanner *scanner = [NSScanner scannerWithString: nsname];
2304 [scanner scanFloat: &r];
2305 [scanner scanFloat: &g];
2306 [scanner scanFloat: &b];
2308 else if (!strncmp(name, "rgb:", 4)) /* A newer X11 format -- rgb:r/g/b */
2309 scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
2310 else if (name[0] == '#') /* An old X11 format; convert to newer */
2312 int len = (strlen(name) - 1);
2313 int start = (len % 3 == 0) ? 1 : len / 4 + 1;
2315 scaling = strlen(name+start) / 3;
2316 for (i = 0; i < 3; i++)
2317 sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
2318 name + start + i * scaling);
2319 hex[3 * (scaling + 1) - 1] = '\0';
2324 unsigned int rr, gg, bb;
2325 float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
2326 if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
2336 *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
2341 /* Otherwise, color is expected to be from a list */
2343 NSEnumerator *lenum, *cenum;
2347 #ifdef NS_IMPL_GNUSTEP
2348 /* XXX: who is wrong, the requestor or the implementation? */
2349 if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
2351 nsname = @"highlightColor";
2354 lenum = [[NSColorList availableColorLists] objectEnumerator];
2355 while ( (clist = [lenum nextObject]) && new == nil)
2357 cenum = [[clist allKeys] objectEnumerator];
2358 while ( (name = [cenum nextObject]) && new == nil )
2360 if ([name compare: nsname
2361 options: NSCaseInsensitiveSearch] == NSOrderedSame )
2362 new = [clist colorWithKey: name];
2368 *col = [new colorUsingDefaultColorSpace];
2375 ns_lisp_to_color (Lisp_Object color, NSColor **col)
2376 /* --------------------------------------------------------------------------
2377 Convert a Lisp string object to a NS color.
2378 -------------------------------------------------------------------------- */
2380 NSTRACE ("ns_lisp_to_color");
2381 if (STRINGP (color))
2382 return ns_get_color (SSDATA (color), col);
2383 else if (SYMBOLP (color))
2384 return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
2390 ns_query_color(void *col, XColor *color_def, int setPixel)
2391 /* --------------------------------------------------------------------------
2392 Get ARGB values out of NSColor col and put them into color_def.
2393 If setPixel, set the pixel to a concatenated version.
2394 and set color_def pixel to the resulting index.
2395 -------------------------------------------------------------------------- */
2397 EmacsCGFloat r, g, b, a;
2399 [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
2400 color_def->red = r * 65535;
2401 color_def->green = g * 65535;
2402 color_def->blue = b * 65535;
2404 if (setPixel == YES)
2406 = ARGB_TO_ULONG((int)(a*255),
2407 (int)(r*255), (int)(g*255), (int)(b*255));
2412 ns_defined_color (struct frame *f,
2417 /* --------------------------------------------------------------------------
2418 Return true if named color found, and set color_def rgb accordingly.
2419 If makeIndex and alloc are nonzero put the color in the color_table,
2420 and set color_def pixel to the resulting index.
2421 If makeIndex is zero, set color_def pixel to ARGB.
2422 Return false if not found.
2423 -------------------------------------------------------------------------- */
2426 NSTRACE_WHEN (NSTRACE_GROUP_COLOR, "ns_defined_color");
2429 if (ns_get_color (name, &col) != 0) /* Color not found */
2434 if (makeIndex && alloc)
2435 color_def->pixel = ns_index_color (col, f);
2436 ns_query_color (col, color_def, !makeIndex);
2443 x_set_frame_alpha (struct frame *f)
2444 /* --------------------------------------------------------------------------
2445 change the entire-frame transparency
2446 -------------------------------------------------------------------------- */
2448 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2450 double alpha_min = 1.0;
2452 NSTRACE ("x_set_frame_alpha");
2454 if (dpyinfo->x_highlight_frame == f)
2455 alpha = f->alpha[0];
2457 alpha = f->alpha[1];
2459 if (FLOATP (Vframe_alpha_lower_limit))
2460 alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
2461 else if (INTEGERP (Vframe_alpha_lower_limit))
2462 alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
2466 else if (1.0 < alpha)
2468 else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
2471 #ifdef NS_IMPL_COCOA
2473 EmacsView *view = FRAME_NS_VIEW (f);
2474 [[view window] setAlphaValue: alpha];
2480 /* ==========================================================================
2484 ========================================================================== */
2488 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
2489 /* --------------------------------------------------------------------------
2490 Programmatically reposition mouse pointer in pixel coordinates
2491 -------------------------------------------------------------------------- */
2493 NSTRACE ("frame_set_mouse_pixel_position");
2495 /* FIXME: what about GNUstep? */
2496 #ifdef NS_IMPL_COCOA
2498 CGPointMake(f->left_pos + pix_x,
2499 f->top_pos + pix_y +
2500 FRAME_NS_TITLEBAR_HEIGHT(f) + FRAME_TOOLBAR_HEIGHT(f));
2501 CGWarpMouseCursorPosition (mouse_pos);
2506 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
2507 /* ------------------------------------------------------------------------
2508 Called by EmacsView on mouseMovement events. Passes on
2509 to emacs mainstream code if we moved off of a rect of interest
2510 known as last_mouse_glyph.
2511 ------------------------------------------------------------------------ */
2513 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
2516 // NSTRACE ("note_mouse_movement");
2518 dpyinfo->last_mouse_motion_frame = frame;
2519 r = &dpyinfo->last_mouse_glyph;
2521 /* Note, this doesn't get called for enter/leave, since we don't have a
2522 position. Those are taken care of in the corresponding NSView methods. */
2524 /* Has movement gone beyond last rect we were tracking? */
2525 if (x < r->origin.x || x >= r->origin.x + r->size.width
2526 || y < r->origin.y || y >= r->origin.y + r->size.height)
2528 ns_update_begin (frame);
2529 frame->mouse_moved = 1;
2530 note_mouse_highlight (frame, x, y);
2531 remember_mouse_glyph (frame, x, y, r);
2532 ns_update_end (frame);
2541 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
2542 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
2544 /* --------------------------------------------------------------------------
2545 External (hook): inform emacs about mouse position and hit parts.
2546 If a scrollbar is being dragged, set bar_window, part, x, y, time.
2547 x & y should be position in the scrollbar (the whole bar, not the handle)
2548 and length of scrollbar respectively.
2549 -------------------------------------------------------------------------- */
2553 Lisp_Object frame, tail;
2555 struct ns_display_info *dpyinfo;
2557 NSTRACE ("ns_mouse_position");
2561 fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
2565 dpyinfo = FRAME_DISPLAY_INFO (*fp);
2569 /* Clear the mouse-moved flag for every frame on this display. */
2570 FOR_EACH_FRAME (tail, frame)
2571 if (FRAME_NS_P (XFRAME (frame))
2572 && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
2573 XFRAME (frame)->mouse_moved = 0;
2575 dpyinfo->last_mouse_scroll_bar = nil;
2576 if (dpyinfo->last_mouse_frame
2577 && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
2578 f = dpyinfo->last_mouse_frame;
2580 f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame : SELECTED_FRAME ();
2582 if (f && FRAME_NS_P (f))
2584 view = FRAME_NS_VIEW (*fp);
2586 position = [[view window] mouseLocationOutsideOfEventStream];
2587 position = [view convertPoint: position fromView: nil];
2588 remember_mouse_glyph (f, position.x, position.y,
2589 &dpyinfo->last_mouse_glyph);
2590 NSTRACE_POINT ("position", position);
2592 if (bar_window) *bar_window = Qnil;
2593 if (part) *part = scroll_bar_above_handle;
2595 if (x) XSETINT (*x, lrint (position.x));
2596 if (y) XSETINT (*y, lrint (position.y));
2598 *time = dpyinfo->last_mouse_movement_time;
2607 ns_frame_up_to_date (struct frame *f)
2608 /* --------------------------------------------------------------------------
2609 External (hook): Fix up mouse highlighting right after a full update.
2610 Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
2611 -------------------------------------------------------------------------- */
2613 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_frame_up_to_date");
2617 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
2618 if (f == hlinfo->mouse_face_mouse_frame)
2622 note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
2623 hlinfo->mouse_face_mouse_x,
2624 hlinfo->mouse_face_mouse_y);
2633 ns_define_frame_cursor (struct frame *f, Cursor cursor)
2634 /* --------------------------------------------------------------------------
2635 External (RIF): set frame mouse pointer type.
2636 -------------------------------------------------------------------------- */
2638 NSTRACE ("ns_define_frame_cursor");
2639 if (FRAME_POINTER_TYPE (f) != cursor)
2641 EmacsView *view = FRAME_NS_VIEW (f);
2642 FRAME_POINTER_TYPE (f) = cursor;
2643 [[view window] invalidateCursorRectsForView: view];
2644 /* Redisplay assumes this function also draws the changed frame
2645 cursor, but this function doesn't, so do it explicitly. */
2646 x_update_cursor (f, 1);
2652 /* ==========================================================================
2656 ========================================================================== */
2660 ns_convert_key (unsigned code)
2661 /* --------------------------------------------------------------------------
2662 Internal call used by NSView-keyDown.
2663 -------------------------------------------------------------------------- */
2665 const unsigned last_keysym = ARRAYELTS (convert_ns_to_X_keysym);
2667 /* An array would be faster, but less easy to read. */
2668 for (keysym = 0; keysym < last_keysym; keysym += 2)
2669 if (code == convert_ns_to_X_keysym[keysym])
2670 return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
2672 /* if decide to use keyCode and Carbon table, use this line:
2673 return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
2678 x_get_keysym_name (int keysym)
2679 /* --------------------------------------------------------------------------
2680 Called by keyboard.c. Not sure if the return val is important, except
2682 -------------------------------------------------------------------------- */
2684 static char value[16];
2685 NSTRACE ("x_get_keysym_name");
2686 sprintf (value, "%d", keysym);
2690 #ifdef NS_IMPL_COCOA
2692 ns_get_shifted_character (NSEvent *event)
2693 /* Look up the character corresponding to the key pressed on the
2694 current keyboard layout and the currently configured shift-like
2695 modifiers. This ignores the control-like modifiers that cause
2696 [event characters] to give us the wrong result.
2698 Although UCKeyTranslate doesn't require the Carbon framework, some
2699 of the surrounding paraphernalia does, so this function makes
2700 Carbon a requirement. */
2702 static UInt32 dead_key_state;
2704 /* UCKeyTranslate may return up to 255 characters. If the buffer
2705 isn't large enough then it produces an error. What kind of
2706 keyboard inputs 255 characters in a single keypress? */
2708 UniCharCount max_string_length = 255;
2709 UniCharCount actual_string_length = 0;
2712 CFDataRef layout_ref = (CFDataRef) TISGetInputSourceProperty
2713 (TISCopyCurrentKeyboardLayoutInputSource (), kTISPropertyUnicodeKeyLayoutData);
2714 UCKeyboardLayout* layout = (UCKeyboardLayout*) CFDataGetBytePtr (layout_ref);
2716 UInt32 flags = [event modifierFlags];
2717 UInt32 modifiers = (flags & NSEventModifierFlagShift) ? shiftKey : 0;
2719 NSTRACE ("ns_get_shifted_character");
2721 if ((flags & NSRightAlternateKeyMask) == NSRightAlternateKeyMask
2722 && (EQ (ns_right_alternate_modifier, Qnone)
2723 || (EQ (ns_right_alternate_modifier, Qleft)
2724 && EQ (ns_alternate_modifier, Qnone))))
2725 modifiers |= rightOptionKey;
2727 if ((flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
2728 && EQ (ns_alternate_modifier, Qnone))
2729 modifiers |= optionKey;
2731 if ((flags & NSRightCommandKeyMask) == NSRightCommandKeyMask
2732 && (EQ (ns_right_command_modifier, Qnone)
2733 || (EQ (ns_right_command_modifier, Qleft)
2734 && EQ (ns_command_modifier, Qnone))))
2735 /* Carbon doesn't differentiate between left and right command
2737 modifiers |= cmdKey;
2739 if ((flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
2740 && EQ (ns_command_modifier, Qnone))
2741 modifiers |= cmdKey;
2743 result = UCKeyTranslate (layout, [event keyCode], kUCKeyActionDown,
2744 (modifiers >> 8) & 0xFF, LMGetKbdType (),
2745 kUCKeyTranslateNoDeadKeysBit, &dead_key_state,
2746 max_string_length, &actual_string_length, buf);
2750 NSLog(@"Failed to translate character '%@' with modifiers %x",
2751 [event characters], modifiers);
2755 /* FIXME: What do we do if more than one code unit is returned? */
2756 if (actual_string_length > 0)
2761 #endif /* NS_IMPL_COCOA */
2763 /* ==========================================================================
2765 Block drawing operations
2767 ========================================================================== */
2771 ns_redraw_scroll_bars (struct frame *f)
2775 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2776 NSTRACE ("ns_redraw_scroll_bars");
2777 for (i =[subviews count]-1; i >= 0; i--)
2779 view = [subviews objectAtIndex: i];
2780 if (![view isKindOfClass: [EmacsScroller class]]) continue;
2787 ns_clear_frame (struct frame *f)
2788 /* --------------------------------------------------------------------------
2789 External (hook): Erase the entire frame
2790 -------------------------------------------------------------------------- */
2792 NSView *view = FRAME_NS_VIEW (f);
2795 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame");
2797 /* comes on initial frame because we have
2798 after-make-frame-functions = select-frame */
2799 if (!FRAME_DEFAULT_FACE (f))
2802 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2807 ns_focus (f, &r, 1);
2808 [ns_lookup_indexed_color (NS_FACE_BACKGROUND
2809 (FACE_FROM_ID (f, DEFAULT_FACE_ID)), f) set];
2813 /* as of 2006/11 or so this is now needed */
2814 ns_redraw_scroll_bars (f);
2820 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2821 /* --------------------------------------------------------------------------
2822 External (RIF): Clear section of frame
2823 -------------------------------------------------------------------------- */
2825 NSRect r = NSMakeRect (x, y, width, height);
2826 NSView *view = FRAME_NS_VIEW (f);
2827 struct face *face = FRAME_DEFAULT_FACE (f);
2832 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame_area");
2834 r = NSIntersectionRect (r, [view frame]);
2835 ns_focus (f, &r, 1);
2836 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2845 ns_copy_bits (struct frame *f, NSRect src, NSRect dest)
2847 NSTRACE ("ns_copy_bits");
2849 if (FRAME_NS_VIEW (f))
2851 hide_bell(); // Ensure the bell image isn't scrolled.
2853 ns_focus (f, &dest, 1);
2854 [FRAME_NS_VIEW (f) scrollRect: src
2855 by: NSMakeSize (dest.origin.x - src.origin.x,
2856 dest.origin.y - src.origin.y)];
2862 ns_scroll_run (struct window *w, struct run *run)
2863 /* --------------------------------------------------------------------------
2864 External (RIF): Insert or delete n lines at line vpos.
2865 -------------------------------------------------------------------------- */
2867 struct frame *f = XFRAME (w->frame);
2868 int x, y, width, height, from_y, to_y, bottom_y;
2870 NSTRACE ("ns_scroll_run");
2872 /* begin copy from other terms */
2873 /* Get frame-relative bounding box of the text display area of W,
2874 without mode lines. Include in this box the left and right
2876 window_box (w, ANY_AREA, &x, &y, &width, &height);
2878 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2879 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2880 bottom_y = y + height;
2884 /* Scrolling up. Make sure we don't copy part of the mode
2885 line at the bottom. */
2886 if (from_y + run->height > bottom_y)
2887 height = bottom_y - from_y;
2889 height = run->height;
2893 /* Scrolling down. Make sure we don't copy over the mode line.
2895 if (to_y + run->height > bottom_y)
2896 height = bottom_y - to_y;
2898 height = run->height;
2900 /* end copy from other terms */
2910 NSRect srcRect = NSMakeRect (x, from_y, width, height);
2911 NSRect dstRect = NSMakeRect (x, to_y, width, height);
2913 ns_copy_bits (f, srcRect , dstRect);
2921 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2922 /* --------------------------------------------------------------------------
2923 External (RIF): preparatory to fringe update after text was updated
2924 -------------------------------------------------------------------------- */
2929 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_after_update_window_line");
2931 /* begin copy from other terms */
2934 if (!desired_row->mode_line_p && !w->pseudo_window_p)
2935 desired_row->redraw_fringe_bitmaps_p = 1;
2937 /* When a window has disappeared, make sure that no rest of
2938 full-width rows stays visible in the internal border. */
2939 if (windows_or_buffers_changed
2940 && desired_row->full_width_p
2941 && (f = XFRAME (w->frame),
2942 width = FRAME_INTERNAL_BORDER_WIDTH (f),
2944 && (height = desired_row->visible_height,
2947 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2950 ns_clear_frame_area (f, 0, y, width, height);
2951 ns_clear_frame_area (f,
2952 FRAME_PIXEL_WIDTH (f) - width,
2960 ns_shift_glyphs_for_insert (struct frame *f,
2961 int x, int y, int width, int height,
2963 /* --------------------------------------------------------------------------
2964 External (RIF): copy an area horizontally, don't worry about clearing src
2965 -------------------------------------------------------------------------- */
2967 NSRect srcRect = NSMakeRect (x, y, width, height);
2968 NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2970 NSTRACE ("ns_shift_glyphs_for_insert");
2972 ns_copy_bits (f, srcRect, dstRect);
2977 /* ==========================================================================
2979 Character encoding and metrics
2981 ========================================================================== */
2985 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2986 /* --------------------------------------------------------------------------
2987 External (RIF); compute left/right overhang of whole string and set in s
2988 -------------------------------------------------------------------------- */
2990 struct font *font = s->font;
2994 struct font_metrics metrics;
2995 unsigned int codes[2];
2996 codes[0] = *(s->char2b);
2997 codes[1] = *(s->char2b + s->nchars - 1);
2999 font->driver->text_extents (font, codes, 2, &metrics);
3000 s->left_overhang = -metrics.lbearing;
3002 = metrics.rbearing > metrics.width
3003 ? metrics.rbearing - metrics.width : 0;
3007 s->left_overhang = 0;
3008 if (EQ (font->driver->type, Qns))
3009 s->right_overhang = ((struct nsfont_info *)font)->ital ?
3010 FONT_HEIGHT (font) * 0.2 : 0;
3012 s->right_overhang = 0;
3018 /* ==========================================================================
3020 Fringe and cursor drawing
3022 ========================================================================== */
3025 extern int max_used_fringe_bitmap;
3027 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
3028 struct draw_fringe_bitmap_params *p)
3029 /* --------------------------------------------------------------------------
3030 External (RIF); fringe-related
3031 -------------------------------------------------------------------------- */
3033 /* Fringe bitmaps comes in two variants, normal and periodic. A
3034 periodic bitmap is used to create a continuous pattern. Since a
3035 bitmap is rendered one text line at a time, the start offset (dh)
3036 of the bitmap varies. Concretely, this is used for the empty
3039 For a bitmap, "h + dh" is the full height and is always
3040 invariant. For a normal bitmap "dh" is zero.
3042 For example, when the period is three and the full height is 72
3043 the following combinations exists:
3049 struct frame *f = XFRAME (WINDOW_FRAME (w));
3050 struct face *face = p->face;
3051 static EmacsImage **bimgs = NULL;
3052 static int nBimgs = 0;
3054 NSTRACE_WHEN (NSTRACE_GROUP_FRINGE, "ns_draw_fringe_bitmap");
3055 NSTRACE_MSG ("which:%d cursor:%d overlay:%d width:%d height:%d period:%d",
3056 p->which, p->cursor_p, p->overlay_p, p->wd, p->h, p->dh);
3058 /* grow bimgs if needed */
3059 if (nBimgs < max_used_fringe_bitmap)
3061 bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
3062 memset (bimgs + nBimgs, 0,
3063 (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
3064 nBimgs = max_used_fringe_bitmap;
3067 /* Must clip because of partially visible lines. */
3068 ns_clip_to_row (w, row, ANY_AREA, YES);
3072 int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
3074 if (bx >= 0 && nx > 0)
3076 NSRect r = NSMakeRect (bx, by, nx, ny);
3078 [ns_lookup_indexed_color (face->background, f) set];
3085 NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
3086 EmacsImage *img = bimgs[p->which - 1];
3090 // Note: For "periodic" images, allocate one EmacsImage for
3091 // the base image, and use it for all dh:s.
3092 unsigned short *bits = p->bits;
3093 int full_height = p->h + p->dh;
3095 unsigned char *cbits = xmalloc (full_height);
3097 for (i = 0; i < full_height; i++)
3099 img = [[EmacsImage alloc] initFromXBM: cbits width: 8
3102 bimgs[p->which - 1] = img;
3106 NSTRACE_RECT ("r", r);
3109 /* Since we composite the bitmap instead of just blitting it, we need
3110 to erase the whole background. */
3111 [ns_lookup_indexed_color(face->background, f) set];
3117 bm_color = ns_lookup_indexed_color(face->foreground, f);
3118 else if (p->overlay_p)
3119 bm_color = ns_lookup_indexed_color(face->background, f);
3121 bm_color = f->output_data.ns->cursor_color;
3122 [img setXBMColor: bm_color];
3125 #ifdef NS_IMPL_COCOA
3126 // Note: For periodic images, the full image height is "h + hd".
3127 // By using the height h, a suitable part of the image is used.
3128 NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h);
3130 NSTRACE_RECT ("fromRect", fromRect);
3134 operation: NSCompositingOperationSourceOver
3140 NSPoint pt = r.origin;
3142 [img compositeToPoint: pt operation: NSCompositingOperationSourceOver];
3151 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
3152 int x, int y, enum text_cursor_kinds cursor_type,
3153 int cursor_width, bool on_p, bool active_p)
3154 /* --------------------------------------------------------------------------
3155 External call (RIF): draw cursor.
3156 Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
3157 -------------------------------------------------------------------------- */
3160 int fx, fy, h, cursor_height;
3161 struct frame *f = WINDOW_XFRAME (w);
3162 struct glyph *phys_cursor_glyph;
3163 struct glyph *cursor_glyph;
3165 NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
3167 /* If cursor is out of bounds, don't draw garbage. This can happen
3168 in mini-buffer windows when switching between echo area glyphs
3171 NSTRACE ("ns_draw_window_cursor");
3176 w->phys_cursor_type = cursor_type;
3177 w->phys_cursor_on_p = on_p;
3179 if (cursor_type == NO_CURSOR)
3181 w->phys_cursor_width = 0;
3185 if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
3187 if (glyph_row->exact_window_width_line_p
3188 && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
3190 glyph_row->cursor_in_fringe_p = 1;
3191 draw_fringe_bitmap (w, glyph_row, 0);
3196 /* We draw the cursor (with NSRectFill), then draw the glyph on top
3197 (other terminals do it the other way round). We must set
3198 w->phys_cursor_width to the cursor width. For bar cursors, that
3199 is CURSOR_WIDTH; for box cursors, it is the glyph width. */
3200 get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
3202 /* The above get_phys_cursor_geometry call set w->phys_cursor_width
3203 to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
3204 if (cursor_type == BAR_CURSOR)
3206 if (cursor_width < 1)
3207 cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
3209 /* The bar cursor should never be wider than the glyph. */
3210 if (cursor_width < w->phys_cursor_width)
3211 w->phys_cursor_width = cursor_width;
3213 /* If we have an HBAR, "cursor_width" MAY specify height. */
3214 else if (cursor_type == HBAR_CURSOR)
3216 cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
3217 if (cursor_height > glyph_row->height)
3218 cursor_height = glyph_row->height;
3219 if (h > cursor_height) // Cursor smaller than line height, move down
3220 fy += h - cursor_height;
3224 r.origin.x = fx, r.origin.y = fy;
3226 r.size.width = w->phys_cursor_width;
3228 /* Prevent the cursor from being drawn outside the text area. */
3229 ns_clip_to_row (w, glyph_row, TEXT_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
3232 face = FACE_FROM_ID_OR_NULL (f, phys_cursor_glyph->face_id);
3233 if (face && NS_FACE_BACKGROUND (face)
3234 == ns_index_color (FRAME_CURSOR_COLOR (f), f))
3236 [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
3237 hollow_color = FRAME_CURSOR_COLOR (f);
3240 [FRAME_CURSOR_COLOR (f) set];
3242 #ifdef NS_IMPL_COCOA
3243 /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
3244 atomic. Cleaner ways of doing this should be investigated.
3245 One way would be to set a global variable DRAWING_CURSOR
3246 when making the call to draw_phys..(), don't focus in that
3247 case, then move the ns_unfocus() here after that call. */
3248 NSDisableScreenUpdates ();
3251 switch (cursor_type)
3253 case DEFAULT_CURSOR:
3256 case FILLED_BOX_CURSOR:
3259 case HOLLOW_BOX_CURSOR:
3262 NSRectFill (NSInsetRect (r, 1, 1));
3263 [FRAME_CURSOR_COLOR (f) set];
3270 /* If the character under cursor is R2L, draw the bar cursor
3271 on the right of its glyph, rather than on the left. */
3272 cursor_glyph = get_phys_cursor_glyph (w);
3273 if ((cursor_glyph->resolved_level & 1) != 0)
3274 s.origin.x += cursor_glyph->pixel_width - s.size.width;
3281 /* draw the character under the cursor */
3282 if (cursor_type != NO_CURSOR)
3283 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
3285 #ifdef NS_IMPL_COCOA
3286 NSEnableScreenUpdates ();
3293 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
3294 /* --------------------------------------------------------------------------
3295 External (RIF): Draw a vertical line.
3296 -------------------------------------------------------------------------- */
3298 struct frame *f = XFRAME (WINDOW_FRAME (w));
3300 NSRect r = NSMakeRect (x, y0, 1, y1-y0);
3302 NSTRACE ("ns_draw_vertical_window_border");
3304 face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID);
3306 ns_focus (f, &r, 1);
3308 [ns_lookup_indexed_color(face->foreground, f) set];
3316 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
3317 /* --------------------------------------------------------------------------
3318 External (RIF): Draw a window divider.
3319 -------------------------------------------------------------------------- */
3321 struct frame *f = XFRAME (WINDOW_FRAME (w));
3322 struct face *face = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FACE_ID);
3323 struct face *face_first
3324 = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID);
3325 struct face *face_last
3326 = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_LAST_PIXEL_FACE_ID);
3327 unsigned long color = face ? face->foreground : FRAME_FOREGROUND_PIXEL (f);
3328 unsigned long color_first = (face_first
3329 ? face_first->foreground
3330 : FRAME_FOREGROUND_PIXEL (f));
3331 unsigned long color_last = (face_last
3332 ? face_last->foreground
3333 : FRAME_FOREGROUND_PIXEL (f));
3334 NSRect divider = NSMakeRect (x0, y0, x1-x0, y1-y0);
3336 NSTRACE ("ns_draw_window_divider");
3338 ns_focus (f, ÷r, 1);
3340 if ((y1 - y0 > x1 - x0) && (x1 - x0 >= 3))
3341 /* A vertical divider, at least three pixels wide: Draw first and
3342 last pixels differently. */
3344 [ns_lookup_indexed_color(color_first, f) set];
3345 NSRectFill(NSMakeRect (x0, y0, 1, y1 - y0));
3346 [ns_lookup_indexed_color(color, f) set];
3347 NSRectFill(NSMakeRect (x0 + 1, y0, x1 - x0 - 2, y1 - y0));
3348 [ns_lookup_indexed_color(color_last, f) set];
3349 NSRectFill(NSMakeRect (x1 - 1, y0, 1, y1 - y0));
3351 else if ((x1 - x0 > y1 - y0) && (y1 - y0 >= 3))
3352 /* A horizontal divider, at least three pixels high: Draw first and
3353 last pixels differently. */
3355 [ns_lookup_indexed_color(color_first, f) set];
3356 NSRectFill(NSMakeRect (x0, y0, x1 - x0, 1));
3357 [ns_lookup_indexed_color(color, f) set];
3358 NSRectFill(NSMakeRect (x0, y0 + 1, x1 - x0, y1 - y0 - 2));
3359 [ns_lookup_indexed_color(color_last, f) set];
3360 NSRectFill(NSMakeRect (x0, y1 - 1, x1 - x0, 1));
3364 /* In any other case do not draw the first and last pixels
3366 [ns_lookup_indexed_color(color, f) set];
3367 NSRectFill(divider);
3374 ns_show_hourglass (struct frame *f)
3376 /* TODO: add NSProgressIndicator to all frames. */
3380 ns_hide_hourglass (struct frame *f)
3382 /* TODO: remove NSProgressIndicator from all frames. */
3385 /* ==========================================================================
3387 Glyph drawing operations
3389 ========================================================================== */
3392 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
3393 /* --------------------------------------------------------------------------
3394 Wrapper utility to account for internal border width on full-width lines,
3395 and allow top full-width rows to hit the frame top. nr should be pointer
3396 to two successive NSRects. Number of rects actually used is returned.
3397 -------------------------------------------------------------------------- */
3399 int n = get_glyph_string_clip_rects (s, nr, 2);
3403 /* --------------------------------------------------------------------
3404 Draw a wavy line under glyph string s. The wave fills wave_height
3411 wave_height = 3 | * * * *
3412 --------------------------------------------------------------------- */
3415 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
3417 int wave_height = 3, wave_length = 2;
3418 int y, dx, dy, odd, xmax;
3423 dy = wave_height - 1;
3424 y = s->ybase - wave_height + 3;
3427 /* Find and set clipping rectangle */
3428 waveClip = NSMakeRect (x, y, width, wave_height);
3429 [[NSGraphicsContext currentContext] saveGraphicsState];
3430 NSRectClip (waveClip);
3432 /* Draw the waves */
3433 a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
3435 odd = (int)(a.x/dx) % 2;
3436 a.y = b.y = y + 0.5;
3445 [NSBezierPath strokeLineFromPoint:a toPoint:b];
3446 a.x = b.x, a.y = b.y;
3447 b.x += dx, b.y = y + 0.5 + odd*dy;
3451 /* Restore previous clipping rectangle(s) */
3452 [[NSGraphicsContext currentContext] restoreGraphicsState];
3458 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
3459 NSColor *defaultCol, CGFloat width, CGFloat x)
3460 /* --------------------------------------------------------------------------
3461 Draw underline, overline, and strike-through on glyph string s.
3462 -------------------------------------------------------------------------- */
3464 if (s->for_overlaps)
3468 if (face->underline_p)
3470 if (s->face->underline_type == FACE_UNDER_WAVE)
3472 if (face->underline_defaulted_p)
3475 [ns_lookup_indexed_color (face->underline_color, s->f) set];
3477 ns_draw_underwave (s, width, x);
3479 else if (s->face->underline_type == FACE_UNDER_LINE)
3483 unsigned long thickness, position;
3485 /* If the prev was underlined, match its appearance. */
3486 if (s->prev && s->prev->face->underline_p
3487 && s->prev->face->underline_type == FACE_UNDER_LINE
3488 && s->prev->underline_thickness > 0)
3490 thickness = s->prev->underline_thickness;
3491 position = s->prev->underline_position;
3495 struct font *font = font_for_underline_metrics (s);
3496 unsigned long descent = s->y + s->height - s->ybase;
3497 unsigned long minimum_offset;
3498 BOOL underline_at_descent_line, use_underline_position_properties;
3499 Lisp_Object val = buffer_local_value (Qunderline_minimum_offset,
3502 minimum_offset = XFASTINT (val);
3505 val = buffer_local_value (Qx_underline_at_descent_line,
3507 underline_at_descent_line = !(NILP (val) || EQ (val, Qunbound));
3508 val = buffer_local_value (Qx_use_underline_position_properties,
3510 use_underline_position_properties =
3511 !(NILP (val) || EQ (val, Qunbound));
3513 /* Use underline thickness of font, defaulting to 1. */
3514 thickness = (font && font->underline_thickness > 0)
3515 ? font->underline_thickness : 1;
3517 /* Determine the offset of underlining from the baseline. */
3518 if (underline_at_descent_line)
3519 position = descent - thickness;
3520 else if (use_underline_position_properties
3521 && font && font->underline_position >= 0)
3522 position = font->underline_position;
3524 position = lround (font->descent / 2);
3526 position = minimum_offset;
3528 position = max (position, minimum_offset);
3530 /* Ensure underlining is not cropped. */
3531 if (descent <= position)
3533 position = descent - 1;
3536 else if (descent < position + thickness)
3540 s->underline_thickness = thickness;
3541 s->underline_position = position;
3543 r = NSMakeRect (x, s->ybase + position, width, thickness);
3545 if (face->underline_defaulted_p)
3548 [ns_lookup_indexed_color (face->underline_color, s->f) set];
3552 /* Do overline. We follow other terms in using a thickness of 1
3553 and ignoring overline_margin. */
3554 if (face->overline_p)
3557 r = NSMakeRect (x, s->y, width, 1);
3559 if (face->overline_color_defaulted_p)
3562 [ns_lookup_indexed_color (face->overline_color, s->f) set];
3566 /* Do strike-through. We follow other terms for thickness and
3567 vertical position. */
3568 if (face->strike_through_p)
3571 /* Y-coordinate and height of the glyph string's first glyph.
3572 We cannot use s->y and s->height because those could be
3573 larger if there are taller display elements (e.g., characters
3574 displayed with a larger font) in the same glyph row. */
3575 int glyph_y = s->ybase - s->first_glyph->ascent;
3576 int glyph_height = s->first_glyph->ascent + s->first_glyph->descent;
3577 /* Strike-through width and offset from the glyph string's
3579 unsigned long h = 1;
3582 dy = lrint ((glyph_height - h) / 2);
3583 r = NSMakeRect (x, glyph_y + dy, width, 1);
3585 if (face->strike_through_color_defaulted_p)
3588 [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
3594 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
3595 char left_p, char right_p)
3596 /* --------------------------------------------------------------------------
3597 Draw an unfilled rect inside r, optionally leaving left and/or right open.
3598 Note we can't just use an NSDrawRect command, because of the possibility
3599 of some sides not being drawn, and because the rect will be filled.
3600 -------------------------------------------------------------------------- */
3606 s.size.height = thickness;
3608 s.origin.y += r.size.height - thickness;
3611 s.size.height = r.size.height;
3612 s.origin.y = r.origin.y;
3614 /* left, right (optional) */
3615 s.size.width = thickness;
3620 s.origin.x += r.size.width - thickness;
3627 ns_draw_relief (NSRect r, int thickness, char raised_p,
3628 char top_p, char bottom_p, char left_p, char right_p,
3629 struct glyph_string *s)
3630 /* --------------------------------------------------------------------------
3631 Draw a relief rect inside r, optionally leaving some sides open.
3632 Note we can't just use an NSDrawBezel command, because of the possibility
3633 of some sides not being drawn, and because the rect will be filled.
3634 -------------------------------------------------------------------------- */
3636 static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
3637 NSColor *newBaseCol = nil;
3640 NSTRACE ("ns_draw_relief");
3644 if (s->face->use_box_color_for_shadows_p)
3646 newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
3648 /* else if (s->first_glyph->type == IMAGE_GLYPH
3650 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3652 newBaseCol = IMAGE_BACKGROUND (s->img, s->f, 0);
3656 newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
3659 if (newBaseCol == nil)
3660 newBaseCol = [NSColor grayColor];
3662 if (newBaseCol != baseCol) /* TODO: better check */
3665 baseCol = [newBaseCol retain];
3667 lightCol = [[baseCol highlightWithLevel: 0.2] retain];
3669 darkCol = [[baseCol shadowWithLevel: 0.3] retain];
3672 [(raised_p ? lightCol : darkCol) set];
3674 /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
3677 sr.size.height = thickness;
3678 if (top_p) NSRectFill (sr);
3681 sr.size.height = r.size.height;
3682 sr.size.width = thickness;
3683 if (left_p) NSRectFill (sr);
3685 [(raised_p ? darkCol : lightCol) set];
3688 sr.size.width = r.size.width;
3689 sr.size.height = thickness;
3690 sr.origin.y += r.size.height - thickness;
3691 if (bottom_p) NSRectFill (sr);
3694 sr.size.height = r.size.height;
3695 sr.origin.y = r.origin.y;
3696 sr.size.width = thickness;
3697 sr.origin.x += r.size.width - thickness;
3698 if (right_p) NSRectFill (sr);
3703 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
3704 /* --------------------------------------------------------------------------
3705 Function modeled after x_draw_glyph_string_box ().
3706 Sets up parameters for drawing.
3707 -------------------------------------------------------------------------- */
3709 int right_x, last_x;
3710 char left_p, right_p;
3711 struct glyph *last_glyph;
3716 if (s->hl == DRAW_MOUSE_FACE)
3718 face = FACE_FROM_ID_OR_NULL (s->f,
3719 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3721 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3726 thickness = face->box_line_width;
3728 NSTRACE ("ns_dumpglyphs_box_or_relief");
3730 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
3731 ? WINDOW_RIGHT_EDGE_X (s->w)
3732 : window_box_right (s->w, s->area));
3733 last_glyph = (s->cmp || s->img
3734 ? s->first_glyph : s->first_glyph + s->nchars-1);
3736 right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
3737 ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
3739 left_p = (s->first_glyph->left_box_line_p
3740 || (s->hl == DRAW_MOUSE_FACE
3741 && (s->prev == NULL || s->prev->hl != s->hl)));
3742 right_p = (last_glyph->right_box_line_p
3743 || (s->hl == DRAW_MOUSE_FACE
3744 && (s->next == NULL || s->next->hl != s->hl)));
3746 r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
3748 /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
3749 if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
3751 ns_draw_box (r, abs (thickness),
3752 ns_lookup_indexed_color (face->box_color, s->f),
3757 ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
3758 1, 1, left_p, right_p, s);
3764 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
3765 /* --------------------------------------------------------------------------
3766 Modeled after x_draw_glyph_string_background, which draws BG in
3767 certain cases. Others are left to the text rendering routine.
3768 -------------------------------------------------------------------------- */
3770 NSTRACE ("ns_maybe_dumpglyphs_background");
3772 if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
3774 int box_line_width = max (s->face->box_line_width, 0);
3775 if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
3776 /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font
3777 dimensions, since the actual glyphs might be much
3778 smaller. So in that case we always clear the rectangle
3779 with background color. */
3780 || FONT_TOO_HIGH (s->font)
3781 || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
3784 if (s->hl == DRAW_MOUSE_FACE)
3787 = FACE_FROM_ID_OR_NULL (s->f,
3788 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3790 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3793 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3795 [(NS_FACE_BACKGROUND (face) != 0
3796 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
3797 : FRAME_BACKGROUND_COLOR (s->f)) set];
3800 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
3801 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
3804 if (s->hl != DRAW_CURSOR)
3806 NSRect r = NSMakeRect (s->x, s->y + box_line_width,
3807 s->background_width,
3808 s->height-2*box_line_width);
3812 s->background_filled_p = 1;
3819 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3820 /* --------------------------------------------------------------------------
3821 Renders an image and associated borders.
3822 -------------------------------------------------------------------------- */
3824 EmacsImage *img = s->img->pixmap;
3825 int box_line_vwidth = max (s->face->box_line_width, 0);
3826 int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3827 int bg_x, bg_y, bg_height;
3834 NSTRACE ("ns_dumpglyphs_image");
3836 if (s->face->box != FACE_NO_BOX
3837 && s->first_glyph->left_box_line_p && s->slice.x == 0)
3838 x += abs (s->face->box_line_width);
3841 bg_y = s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
3842 bg_height = s->height;
3843 /* other terms have this, but was causing problems w/tabbar mode */
3844 /* - 2 * box_line_vwidth; */
3846 if (s->slice.x == 0) x += s->img->hmargin;
3847 if (s->slice.y == 0) y += s->img->vmargin;
3849 /* Draw BG: if we need larger area than image itself cleared, do that,
3850 otherwise, since we composite the image under NS (instead of mucking
3851 with its background color), we must clear just the image area. */
3852 if (s->hl == DRAW_MOUSE_FACE)
3854 face = FACE_FROM_ID_OR_NULL (s->f,
3855 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3857 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3860 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3862 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3864 if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3865 || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3867 br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3868 s->background_filled_p = 1;
3872 br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3877 /* Draw the image... do we need to draw placeholder if img == nil? */
3880 #ifdef NS_IMPL_COCOA
3881 NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3882 NSRect ir = NSMakeRect (s->slice.x,
3883 s->img->height - s->slice.y - s->slice.height,
3884 s->slice.width, s->slice.height);
3887 operation: NSCompositingOperationSourceOver
3892 [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3893 operation: NSCompositingOperationSourceOver];
3897 if (s->hl == DRAW_CURSOR)
3899 [FRAME_CURSOR_COLOR (s->f) set];
3900 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3901 tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3903 /* Currently on NS img->mask is always 0. Since
3904 get_window_cursor_type specifies a hollow box cursor when on
3905 a non-masked image we never reach this clause. But we put it
3906 in, in anticipation of better support for image masks on
3908 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3912 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3915 /* Draw underline, overline, strike-through. */
3916 ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3918 /* Draw relief, if requested */
3919 if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3921 if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3923 th = tool_bar_button_relief >= 0 ?
3924 tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3925 raised_p = (s->hl == DRAW_IMAGE_RAISED);
3929 th = abs (s->img->relief);
3930 raised_p = (s->img->relief > 0);
3933 r.origin.x = x - th;
3934 r.origin.y = y - th;
3935 r.size.width = s->slice.width + 2*th-1;
3936 r.size.height = s->slice.height + 2*th-1;
3937 ns_draw_relief (r, th, raised_p,
3939 s->slice.y + s->slice.height == s->img->height,
3941 s->slice.x + s->slice.width == s->img->width, s);
3944 /* If there is no mask, the background won't be seen,
3945 so draw a rectangle on the image for the cursor.
3946 Do this for all images, getting transparency right is not reliable. */
3947 if (s->hl == DRAW_CURSOR)
3949 int thickness = abs (s->img->relief);
3950 if (thickness == 0) thickness = 1;
3951 ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3957 ns_dumpglyphs_stretch (struct glyph_string *s)
3962 NSColor *fgCol, *bgCol;
3964 if (!s->background_filled_p)
3966 n = ns_get_glyph_string_clip_rect (s, r);
3967 *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3969 ns_focus (s->f, r, n);
3971 if (s->hl == DRAW_MOUSE_FACE)
3973 face = FACE_FROM_ID_OR_NULL (s->f,
3974 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3976 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3979 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3981 bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3982 fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3984 for (i = 0; i < n; ++i)
3986 if (!s->row->full_width_p)
3988 int overrun, leftoverrun;
3990 /* truncate to avoid overwriting fringe and/or scrollbar */
3991 overrun = max (0, (s->x + s->background_width)
3992 - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3993 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3994 r[i].size.width -= overrun;
3996 /* truncate to avoid overwriting to left of the window box */
3997 leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3998 + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
4000 if (leftoverrun > 0)
4002 r[i].origin.x += leftoverrun;
4003 r[i].size.width -= leftoverrun;
4006 /* XXX: Try to work between problem where a stretch glyph on
4007 a partially-visible bottom row will clear part of the
4008 modeline, and another where list-buffers headers and similar
4009 rows erroneously have visible_height set to 0. Not sure
4010 where this is coming from as other terms seem not to show. */
4011 r[i].size.height = min (s->height, s->row->visible_height);
4016 /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
4017 overwriting cursor (usually when cursor on a tab). */
4018 if (s->hl == DRAW_CURSOR)
4023 width = s->w->phys_cursor_width;
4024 r[i].size.width -= width;
4025 r[i].origin.x += width;
4029 /* Draw overlining, etc. on the cursor. */
4030 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
4031 ns_draw_text_decoration (s, face, bgCol, width, x);
4033 ns_draw_text_decoration (s, face, fgCol, width, x);
4040 /* Draw overlining, etc. on the stretch glyph (or the part
4041 of the stretch glyph after the cursor). */
4042 ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
4046 s->background_filled_p = 1;
4052 ns_draw_glyph_string_foreground (struct glyph_string *s)
4055 struct font *font = s->font;
4057 /* If first glyph of S has a left box line, start drawing the text
4058 of S to the right of that box line. */
4059 if (s->face && s->face->box != FACE_NO_BOX
4060 && s->first_glyph->left_box_line_p)
4061 x = s->x + eabs (s->face->box_line_width);
4065 flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
4066 (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
4067 (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
4068 NS_DUMPGLYPH_NORMAL));
4071 (s, s->cmp_from, s->nchars, x, s->ybase,
4072 (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
4073 || flags == NS_DUMPGLYPH_MOUSEFACE);
4078 ns_draw_composite_glyph_string_foreground (struct glyph_string *s)
4081 struct font *font = s->font;
4083 /* If first glyph of S has a left box line, start drawing the text
4084 of S to the right of that box line. */
4085 if (s->face && s->face->box != FACE_NO_BOX
4086 && s->first_glyph->left_box_line_p)
4087 x = s->x + eabs (s->face->box_line_width);
4091 /* S is a glyph string for a composition. S->cmp_from is the index
4092 of the first character drawn for glyphs of this composition.
4093 S->cmp_from == 0 means we are drawing the very first character of
4094 this composition. */
4096 /* Draw a rectangle for the composition if the font for the very
4097 first character of the composition could not be loaded. */
4098 if (s->font_not_found_p)
4100 if (s->cmp_from == 0)
4102 NSRect r = NSMakeRect (s->x, s->y, s->width-1, s->height -1);
4103 ns_draw_box (r, 1, FRAME_CURSOR_COLOR (s->f), 1, 1);
4106 else if (! s->first_glyph->u.cmp.automatic)
4110 for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
4111 /* TAB in a composition means display glyphs with padding
4112 space on the left or right. */
4113 if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
4115 int xx = x + s->cmp->offsets[j * 2];
4116 int yy = y - s->cmp->offsets[j * 2 + 1];
4118 font->driver->draw (s, j, j + 1, xx, yy, false);
4119 if (s->face->overstrike)
4120 font->driver->draw (s, j, j + 1, xx + 1, yy, false);
4125 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
4130 for (i = j = s->cmp_from; i < s->cmp_to; i++)
4132 glyph = LGSTRING_GLYPH (gstring, i);
4133 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
4134 width += LGLYPH_WIDTH (glyph);
4137 int xoff, yoff, wadjust;
4141 font->driver->draw (s, j, i, x, y, false);
4142 if (s->face->overstrike)
4143 font->driver->draw (s, j, i, x + 1, y, false);
4146 xoff = LGLYPH_XOFF (glyph);
4147 yoff = LGLYPH_YOFF (glyph);
4148 wadjust = LGLYPH_WADJUST (glyph);
4149 font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
4150 if (s->face->overstrike)
4151 font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
4160 font->driver->draw (s, j, i, x, y, false);
4161 if (s->face->overstrike)
4162 font->driver->draw (s, j, i, x + 1, y, false);
4168 ns_draw_glyph_string (struct glyph_string *s)
4169 /* --------------------------------------------------------------------------
4170 External (RIF): Main draw-text call.
4171 -------------------------------------------------------------------------- */
4173 /* TODO (optimize): focus for box and contents draw */
4176 char box_drawn_p = 0;
4177 struct font *font = s->face->font;
4178 if (! font) font = FRAME_FONT (s->f);
4180 NSTRACE_WHEN (NSTRACE_GROUP_GLYPHS, "ns_draw_glyph_string");
4182 if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
4185 struct glyph_string *next;
4187 for (width = 0, next = s->next;
4188 next && width < s->right_overhang;
4189 width += next->width, next = next->next)
4190 if (next->first_glyph->type != IMAGE_GLYPH)
4192 if (next->first_glyph->type != STRETCH_GLYPH)
4194 n = ns_get_glyph_string_clip_rect (s->next, r);
4195 ns_focus (s->f, r, n);
4196 ns_maybe_dumpglyphs_background (s->next, 1);
4201 ns_dumpglyphs_stretch (s->next);
4203 next->num_clips = 0;
4207 if (!s->for_overlaps && s->face->box != FACE_NO_BOX
4208 && (s->first_glyph->type == CHAR_GLYPH
4209 || s->first_glyph->type == COMPOSITE_GLYPH))
4211 n = ns_get_glyph_string_clip_rect (s, r);
4212 ns_focus (s->f, r, n);
4213 ns_maybe_dumpglyphs_background (s, 1);
4214 ns_dumpglyphs_box_or_relief (s);
4219 switch (s->first_glyph->type)
4223 n = ns_get_glyph_string_clip_rect (s, r);
4224 ns_focus (s->f, r, n);
4225 ns_dumpglyphs_image (s, r[0]);
4230 ns_dumpglyphs_stretch (s);
4234 case COMPOSITE_GLYPH:
4235 n = ns_get_glyph_string_clip_rect (s, r);
4236 ns_focus (s->f, r, n);
4238 if (s->for_overlaps || (s->cmp_from > 0
4239 && ! s->first_glyph->u.cmp.automatic))
4240 s->background_filled_p = 1;
4242 ns_maybe_dumpglyphs_background
4243 (s, s->first_glyph->type == COMPOSITE_GLYPH);
4245 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
4247 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
4248 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
4249 NS_FACE_FOREGROUND (s->face) = tmp;
4253 BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
4256 ns_draw_composite_glyph_string_foreground (s);
4258 ns_draw_glyph_string_foreground (s);
4262 NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
4263 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
4265 : FRAME_FOREGROUND_COLOR (s->f));
4268 /* Draw underline, overline, strike-through. */
4269 ns_draw_text_decoration (s, s->face, col, s->width, s->x);
4272 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
4274 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
4275 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
4276 NS_FACE_FOREGROUND (s->face) = tmp;
4282 case GLYPHLESS_GLYPH:
4283 n = ns_get_glyph_string_clip_rect (s, r);
4284 ns_focus (s->f, r, n);
4286 if (s->for_overlaps || (s->cmp_from > 0
4287 && ! s->first_glyph->u.cmp.automatic))
4288 s->background_filled_p = 1;
4290 ns_maybe_dumpglyphs_background
4291 (s, s->first_glyph->type == COMPOSITE_GLYPH);
4293 /* Not yet implemented. */
4302 /* Draw box if not done already. */
4303 if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
4305 n = ns_get_glyph_string_clip_rect (s, r);
4306 ns_focus (s->f, r, n);
4307 ns_dumpglyphs_box_or_relief (s);
4316 /* ==========================================================================
4320 ========================================================================== */
4324 ns_send_appdefined (int value)
4325 /* --------------------------------------------------------------------------
4326 Internal: post an appdefined event which EmacsApp-sendEvent will
4327 recognize and take as a command to halt the event loop.
4328 -------------------------------------------------------------------------- */
4330 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_send_appdefined(%d)", value);
4332 // GNUstep needs postEvent to happen on the main thread.
4333 // Cocoa needs nextEventMatchingMask to happen on the main thread too.
4334 if (! [[NSThread currentThread] isMainThread])
4336 EmacsApp *app = (EmacsApp *)NSApp;
4337 app->nextappdefined = value;
4338 [app performSelectorOnMainThread:@selector (sendFromMainThread:)
4344 /* Only post this event if we haven't already posted one. This will end
4345 the [NXApp run] main loop after having processed all events queued at
4348 #ifdef NS_IMPL_COCOA
4349 if (! send_appdefined)
4351 /* OS X 10.10.1 swallows the AppDefined event we are sending ourselves
4352 in certain situations (rapid incoming events).
4353 So check if we have one, if not add one. */
4354 NSEvent *appev = [NSApp nextEventMatchingMask:NSEventMaskApplicationDefined
4355 untilDate:[NSDate distantPast]
4356 inMode:NSDefaultRunLoopMode
4358 if (! appev) send_appdefined = YES;
4362 if (send_appdefined)
4366 /* We only need one NX_APPDEFINED event to stop NXApp from running. */
4367 send_appdefined = NO;
4369 /* Don't need wakeup timer any more. */
4372 [timed_entry invalidate];
4373 [timed_entry release];
4377 nxev = [NSEvent otherEventWithType: NSEventTypeApplicationDefined
4378 location: NSMakePoint (0, 0)
4381 windowNumber: [[NSApp mainWindow] windowNumber]
4382 context: [NSApp context]
4387 /* Post an application defined event on the event queue. When this is
4388 received the [NXApp run] will return, thus having processed all
4389 events which are currently queued. */
4390 [NSApp postEvent: nxev atStart: NO];
4394 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
4398 Lisp_Object frame, tail;
4400 if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
4403 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
4405 FOR_EACH_FRAME (tail, frame)
4407 struct frame *f = XFRAME (frame);
4410 EmacsView *view = FRAME_NS_VIEW (f);
4411 [view updateCollectionBehavior];
4417 /* GNUstep does not have cancelTracking. */
4418 #ifdef NS_IMPL_COCOA
4419 /* Check if menu open should be canceled or continued as normal. */
4421 ns_check_menu_open (NSMenu *menu)
4423 /* Click in menu bar? */
4424 NSArray *a = [[NSApp mainMenu] itemArray];
4428 if (menu == nil) // Menu tracking ended.
4430 if (menu_will_open_state == MENU_OPENING)
4431 menu_will_open_state = MENU_NONE;
4435 for (i = 0; ! found && i < [a count]; i++)
4436 found = menu == [[a objectAtIndex:i] submenu];
4439 if (menu_will_open_state == MENU_NONE && emacs_event)
4441 NSEvent *theEvent = [NSApp currentEvent];
4442 struct frame *emacsframe = SELECTED_FRAME ();
4444 [menu cancelTracking];
4445 menu_will_open_state = MENU_PENDING;
4446 emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
4447 EV_TRAILER (theEvent);
4449 CGEventRef ourEvent = CGEventCreate (NULL);
4450 menu_mouse_point = CGEventGetLocation (ourEvent);
4451 CFRelease (ourEvent);
4453 else if (menu_will_open_state == MENU_OPENING)
4455 menu_will_open_state = MENU_NONE;
4460 /* Redo saved menu click if state is MENU_PENDING. */
4462 ns_check_pending_open_menu ()
4464 if (menu_will_open_state == MENU_PENDING)
4466 CGEventSourceRef source
4467 = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
4469 CGEventRef event = CGEventCreateMouseEvent (source,
4470 kCGEventLeftMouseDown,
4472 kCGMouseButtonLeft);
4473 CGEventSetType (event, kCGEventLeftMouseDown);
4474 CGEventPost (kCGHIDEventTap, event);
4478 menu_will_open_state = MENU_OPENING;
4481 #endif /* NS_IMPL_COCOA */
4484 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
4485 /* --------------------------------------------------------------------------
4486 External (hook): Post an event to ourself and keep reading events until
4487 we read it back again. In effect process all events which were waiting.
4488 From 21+ we have to manage the event buffer ourselves.
4489 -------------------------------------------------------------------------- */
4491 struct input_event ev;
4494 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_read_socket");
4496 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
4500 if ([NSApp modalWindow] != nil)
4503 if (hold_event_q.nr > 0)
4506 for (i = 0; i < hold_event_q.nr; ++i)
4507 kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
4508 hold_event_q.nr = 0;
4512 if ([NSThread isMainThread])
4515 n_emacs_events_pending = 0;
4516 ns_init_events (&ev);
4517 q_event_ptr = hold_quit;
4519 /* We manage autorelease pools by allocate/reallocate each time around
4520 the loop; strict nesting is occasionally violated but seems not to
4521 matter... earlier methods using full nesting caused major memory leaks. */
4522 [outerpool release];
4523 outerpool = [[NSAutoreleasePool alloc] init];
4525 /* If have pending open-file requests, attend to the next one of those. */
4526 if (ns_pending_files && [ns_pending_files count] != 0
4527 && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
4529 [ns_pending_files removeObjectAtIndex: 0];
4531 /* Deal with pending service requests. */
4532 else if (ns_pending_service_names && [ns_pending_service_names count] != 0
4534 NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
4535 withArg: [ns_pending_service_args objectAtIndex: 0]])
4537 [ns_pending_service_names removeObjectAtIndex: 0];
4538 [ns_pending_service_args removeObjectAtIndex: 0];
4542 /* Run and wait for events. We must always send one NX_APPDEFINED event
4543 to ourself, otherwise [NXApp run] will never exit. */
4544 send_appdefined = YES;
4545 ns_send_appdefined (-1);
4550 nevents = n_emacs_events_pending;
4551 n_emacs_events_pending = 0;
4552 ns_finish_events ();
4564 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
4565 fd_set *exceptfds, struct timespec *timeout,
4567 /* --------------------------------------------------------------------------
4568 Replacement for select, checking for events
4569 -------------------------------------------------------------------------- */
4573 struct input_event event;
4576 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_select");
4578 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
4582 if (hold_event_q.nr > 0)
4584 /* We already have events pending. */
4590 for (k = 0; k < nfds+1; k++)
4592 if (readfds && FD_ISSET(k, readfds)) ++nr;
4593 if (writefds && FD_ISSET(k, writefds)) ++nr;
4597 || ![NSThread isMainThread]
4598 || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
4599 return thread_select(pselect, nfds, readfds, writefds,
4600 exceptfds, timeout, sigmask);
4603 struct timespec t = {0, 0};
4604 thread_select(pselect, 0, NULL, NULL, NULL, &t, sigmask);
4607 [outerpool release];
4608 outerpool = [[NSAutoreleasePool alloc] init];
4611 send_appdefined = YES;
4614 pthread_mutex_lock (&select_mutex);
4619 select_readfds = *readfds;
4620 select_valid += SELECT_HAVE_READ;
4624 select_writefds = *writefds;
4625 select_valid += SELECT_HAVE_WRITE;
4630 select_timeout = *timeout;
4631 select_valid += SELECT_HAVE_TMO;
4634 pthread_mutex_unlock (&select_mutex);
4636 /* Inform fd_handler that select should be called. */
4638 emacs_write_sig (selfds[1], &c, 1);
4640 else if (nr == 0 && timeout)
4642 /* No file descriptor, just a timeout, no need to wake fd_handler. */
4643 double time = timespectod (*timeout);
4644 timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
4647 @selector (timeout_handler:)
4652 else /* No timeout and no file descriptors, can this happen? */
4654 /* Send appdefined so we exit from the loop. */
4655 ns_send_appdefined (-1);
4659 ns_init_events (&event);
4663 ns_finish_events ();
4664 if (nr > 0 && readfds)
4667 emacs_write_sig (selfds[1], &c, 1);
4671 t = last_appdefined_event_data;
4673 if (t != NO_APPDEFINED_DATA)
4675 last_appdefined_event_data = NO_APPDEFINED_DATA;
4679 /* The NX_APPDEFINED event we received was a timeout. */
4684 /* The NX_APPDEFINED event we received was the result of
4685 at least one real input event arriving. */
4691 /* Received back from select () in fd_handler; copy the results. */
4692 pthread_mutex_lock (&select_mutex);
4693 if (readfds) *readfds = select_readfds;
4694 if (writefds) *writefds = select_writefds;
4695 pthread_mutex_unlock (&select_mutex);
4710 ns_run_loop_break ()
4711 /* Break out of the NS run loop in ns_select or ns_read_socket. */
4713 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_run_loop_break");
4715 /* If we don't have a GUI, don't send the event. */
4717 ns_send_appdefined(-1);
4722 /* ==========================================================================
4726 ========================================================================== */
4730 ns_set_vertical_scroll_bar (struct window *window,
4731 int portion, int whole, int position)
4732 /* --------------------------------------------------------------------------
4733 External (hook): Update or add scrollbar
4734 -------------------------------------------------------------------------- */
4738 struct frame *f = XFRAME (WINDOW_FRAME (window));
4739 EmacsView *view = FRAME_NS_VIEW (f);
4741 int window_y, window_height;
4742 int top, left, height, width;
4743 BOOL update_p = YES;
4745 /* Optimization; display engine sends WAY too many of these. */
4746 if (!NILP (window->vertical_scroll_bar))
4748 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4749 if ([bar checkSamePosition: position portion: portion whole: whole])
4751 if (view->scrollbarsNeedingUpdate == 0)
4753 if (!windows_or_buffers_changed)
4757 view->scrollbarsNeedingUpdate--;
4762 NSTRACE ("ns_set_vertical_scroll_bar");
4764 /* Get dimensions. */
4765 window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
4767 height = window_height;
4768 width = NS_SCROLL_BAR_WIDTH (f);
4769 left = WINDOW_SCROLL_BAR_AREA_X (window);
4771 r = NSMakeRect (left, top, width, height);
4772 /* The parent view is flipped, so we need to flip y value. */
4774 r.origin.y = (v.size.height - r.size.height - r.origin.y);
4776 XSETWINDOW (win, window);
4779 /* We want at least 5 lines to display a scrollbar. */
4780 if (WINDOW_TOTAL_LINES (window) < 5)
4782 if (!NILP (window->vertical_scroll_bar))
4784 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4785 [bar removeFromSuperview];
4786 wset_vertical_scroll_bar (window, Qnil);
4789 ns_clear_frame_area (f, left, top, width, height);
4794 if (NILP (window->vertical_scroll_bar))
4796 if (width > 0 && height > 0)
4797 ns_clear_frame_area (f, left, top, width, height);
4799 bar = [[EmacsScroller alloc] initFrame: r window: win];
4800 wset_vertical_scroll_bar (window, make_save_ptr (bar));
4806 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4807 oldRect = [bar frame];
4808 r.size.width = oldRect.size.width;
4809 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4811 if (oldRect.origin.x != r.origin.x)
4812 ns_clear_frame_area (f, left, top, width, height);
4818 [bar setPosition: position portion: portion whole: whole];
4824 ns_set_horizontal_scroll_bar (struct window *window,
4825 int portion, int whole, int position)
4826 /* --------------------------------------------------------------------------
4827 External (hook): Update or add scrollbar.
4828 -------------------------------------------------------------------------- */
4832 struct frame *f = XFRAME (WINDOW_FRAME (window));
4833 EmacsView *view = FRAME_NS_VIEW (f);
4835 int top, height, left, width;
4836 int window_x, window_width;
4837 BOOL update_p = YES;
4839 /* Optimization; display engine sends WAY too many of these. */
4840 if (!NILP (window->horizontal_scroll_bar))
4842 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4843 if ([bar checkSamePosition: position portion: portion whole: whole])
4845 if (view->scrollbarsNeedingUpdate == 0)
4847 if (!windows_or_buffers_changed)
4851 view->scrollbarsNeedingUpdate--;
4856 NSTRACE ("ns_set_horizontal_scroll_bar");
4858 /* Get dimensions. */
4859 window_box (window, ANY_AREA, &window_x, 0, &window_width, 0);
4861 width = window_width;
4862 height = NS_SCROLL_BAR_HEIGHT (f);
4863 top = WINDOW_SCROLL_BAR_AREA_Y (window);
4865 r = NSMakeRect (left, top, width, height);
4866 /* The parent view is flipped, so we need to flip y value. */
4868 r.origin.y = (v.size.height - r.size.height - r.origin.y);
4870 XSETWINDOW (win, window);
4873 if (NILP (window->horizontal_scroll_bar))
4875 if (width > 0 && height > 0)
4876 ns_clear_frame_area (f, left, top, width, height);
4878 bar = [[EmacsScroller alloc] initFrame: r window: win];
4879 wset_horizontal_scroll_bar (window, make_save_ptr (bar));
4885 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4886 oldRect = [bar frame];
4887 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4889 if (oldRect.origin.y != r.origin.y)
4890 ns_clear_frame_area (f, left, top, width, height);
4896 /* If there are both horizontal and vertical scroll-bars they leave
4897 a square that belongs to neither. We need to clear it otherwise
4898 it fills with junk. */
4899 if (!NILP (window->vertical_scroll_bar))
4900 ns_clear_frame_area (f, WINDOW_SCROLL_BAR_AREA_X (window), top,
4901 NS_SCROLL_BAR_HEIGHT (f), height);
4904 [bar setPosition: position portion: portion whole: whole];
4910 ns_condemn_scroll_bars (struct frame *f)
4911 /* --------------------------------------------------------------------------
4912 External (hook): arrange for all frame's scrollbars to be removed
4913 at next call to judge_scroll_bars, except for those redeemed.
4914 -------------------------------------------------------------------------- */
4918 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
4920 NSTRACE ("ns_condemn_scroll_bars");
4922 for (i =[subviews count]-1; i >= 0; i--)
4924 view = [subviews objectAtIndex: i];
4925 if ([view isKindOfClass: [EmacsScroller class]])
4932 ns_redeem_scroll_bar (struct window *window)
4933 /* --------------------------------------------------------------------------
4934 External (hook): arrange to spare this window's scrollbar
4935 at next call to judge_scroll_bars.
4936 -------------------------------------------------------------------------- */
4939 NSTRACE ("ns_redeem_scroll_bar");
4940 if (!NILP (window->vertical_scroll_bar)
4941 && WINDOW_HAS_VERTICAL_SCROLL_BAR (window))
4943 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4947 if (!NILP (window->horizontal_scroll_bar)
4948 && WINDOW_HAS_HORIZONTAL_SCROLL_BAR (window))
4950 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4957 ns_judge_scroll_bars (struct frame *f)
4958 /* --------------------------------------------------------------------------
4959 External (hook): destroy all scrollbars on frame that weren't
4960 redeemed after call to condemn_scroll_bars.
4961 -------------------------------------------------------------------------- */
4965 EmacsView *eview = FRAME_NS_VIEW (f);
4966 NSArray *subviews = [[eview superview] subviews];
4969 NSTRACE ("ns_judge_scroll_bars");
4970 for (i = [subviews count]-1; i >= 0; --i)
4972 view = [subviews objectAtIndex: i];
4973 if (![view isKindOfClass: [EmacsScroller class]]) continue;
4979 [eview updateFrameSize: NO];
4982 /* ==========================================================================
4986 ========================================================================== */
4989 x_display_pixel_height (struct ns_display_info *dpyinfo)
4991 NSArray *screens = [NSScreen screens];
4992 NSEnumerator *enumerator = [screens objectEnumerator];
4997 while ((screen = [enumerator nextObject]) != nil)
4998 frame = NSUnionRect (frame, [screen frame]);
5000 return NSHeight (frame);
5004 x_display_pixel_width (struct ns_display_info *dpyinfo)
5006 NSArray *screens = [NSScreen screens];
5007 NSEnumerator *enumerator = [screens objectEnumerator];
5012 while ((screen = [enumerator nextObject]) != nil)
5013 frame = NSUnionRect (frame, [screen frame]);
5015 return NSWidth (frame);
5019 static Lisp_Object ns_string_to_lispmod (const char *s)
5020 /* --------------------------------------------------------------------------
5021 Convert modifier name to lisp symbol.
5022 -------------------------------------------------------------------------- */
5024 if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
5026 else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
5028 else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
5030 else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
5032 else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
5034 else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
5042 ns_default (const char *parameter, Lisp_Object *result,
5043 Lisp_Object yesval, Lisp_Object noval,
5044 BOOL is_float, BOOL is_modstring)
5045 /* --------------------------------------------------------------------------
5046 Check a parameter value in user's preferences.
5047 -------------------------------------------------------------------------- */
5049 const char *value = ns_get_defaults_value (parameter);
5055 if (c_strcasecmp (value, "YES") == 0)
5057 else if (c_strcasecmp (value, "NO") == 0)
5059 else if (is_float && (f = strtod (value, &pos), pos != value))
5060 *result = make_float (f);
5061 else if (is_modstring && value)
5062 *result = ns_string_to_lispmod (value);
5063 else fprintf (stderr,
5064 "Bad value for default \"%s\": \"%s\"\n", parameter, value);
5070 ns_initialize_display_info (struct ns_display_info *dpyinfo)
5071 /* --------------------------------------------------------------------------
5072 Initialize global info and storage for display.
5073 -------------------------------------------------------------------------- */
5075 NSScreen *screen = [NSScreen mainScreen];
5076 NSWindowDepth depth = [screen depth];
5078 dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
5079 dpyinfo->resy = 72.27;
5080 dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
5081 NSColorSpaceFromDepth (depth)]
5082 && ![NSCalibratedWhiteColorSpace isEqualToString:
5083 NSColorSpaceFromDepth (depth)];
5084 dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
5085 dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
5086 dpyinfo->color_table->colors = NULL;
5087 dpyinfo->root_window = 42; /* A placeholder. */
5088 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
5089 dpyinfo->n_fonts = 0;
5090 dpyinfo->smallest_font_height = 1;
5091 dpyinfo->smallest_char_width = 1;
5093 reset_mouse_highlight (&dpyinfo->mouse_highlight);
5097 /* This and next define (many of the) public functions in this file. */
5098 /* x_... are generic versions in xdisp.c that we, and other terms, get away
5099 with using despite presence in the "system dependent" redisplay
5100 interface. In addition, many of the ns_ methods have code that is
5101 shared with all terms, indicating need for further refactoring. */
5102 extern frame_parm_handler ns_frame_parm_handlers[];
5103 static struct redisplay_interface ns_redisplay_interface =
5105 ns_frame_parm_handlers,
5109 x_clear_end_of_line,
5111 ns_after_update_window_line,
5112 ns_update_window_begin,
5113 ns_update_window_end,
5114 0, /* flush_display */
5115 x_clear_window_mouse_face,
5116 x_get_glyph_overhangs,
5117 x_fix_overlapping_area,
5118 ns_draw_fringe_bitmap,
5119 0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
5120 0, /* destroy_fringe_bitmap */
5121 ns_compute_glyph_string_overhangs,
5122 ns_draw_glyph_string,
5123 ns_define_frame_cursor,
5124 ns_clear_frame_area,
5125 ns_draw_window_cursor,
5126 ns_draw_vertical_window_border,
5127 ns_draw_window_divider,
5128 ns_shift_glyphs_for_insert,
5135 ns_delete_display (struct ns_display_info *dpyinfo)
5141 /* This function is called when the last frame on a display is deleted. */
5143 ns_delete_terminal (struct terminal *terminal)
5145 struct ns_display_info *dpyinfo = terminal->display_info.ns;
5147 NSTRACE ("ns_delete_terminal");
5149 /* Protect against recursive calls. delete_frame in
5150 delete_terminal calls us back when it deletes our last frame. */
5151 if (!terminal->name)
5156 x_destroy_all_bitmaps (dpyinfo);
5157 ns_delete_display (dpyinfo);
5162 static struct terminal *
5163 ns_create_terminal (struct ns_display_info *dpyinfo)
5164 /* --------------------------------------------------------------------------
5165 Set up use of NS before we make the first connection.
5166 -------------------------------------------------------------------------- */
5168 struct terminal *terminal;
5170 NSTRACE ("ns_create_terminal");
5172 terminal = create_terminal (output_ns, &ns_redisplay_interface);
5174 terminal->display_info.ns = dpyinfo;
5175 dpyinfo->terminal = terminal;
5177 terminal->clear_frame_hook = ns_clear_frame;
5178 terminal->ring_bell_hook = ns_ring_bell;
5179 terminal->update_begin_hook = ns_update_begin;
5180 terminal->update_end_hook = ns_update_end;
5181 terminal->read_socket_hook = ns_read_socket;
5182 terminal->frame_up_to_date_hook = ns_frame_up_to_date;
5183 terminal->mouse_position_hook = ns_mouse_position;
5184 terminal->frame_rehighlight_hook = ns_frame_rehighlight;
5185 terminal->frame_raise_lower_hook = ns_frame_raise_lower;
5186 terminal->fullscreen_hook = ns_fullscreen_hook;
5187 terminal->menu_show_hook = ns_menu_show;
5188 terminal->popup_dialog_hook = ns_popup_dialog;
5189 terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
5190 terminal->set_horizontal_scroll_bar_hook = ns_set_horizontal_scroll_bar;
5191 terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
5192 terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
5193 terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
5194 terminal->delete_frame_hook = x_destroy_window;
5195 terminal->delete_terminal_hook = ns_delete_terminal;
5196 /* Other hooks are NULL by default. */
5202 struct ns_display_info *
5203 ns_term_init (Lisp_Object display_name)
5204 /* --------------------------------------------------------------------------
5205 Start the Application and get things rolling.
5206 -------------------------------------------------------------------------- */
5208 struct terminal *terminal;
5209 struct ns_display_info *dpyinfo;
5210 static int ns_initialized = 0;
5213 if (ns_initialized) return x_display_list;
5218 NSTRACE ("ns_term_init");
5220 [outerpool release];
5221 outerpool = [[NSAutoreleasePool alloc] init];
5223 /* count object allocs (About, click icon); on macOS use ObjectAlloc tool */
5224 /*GSDebugAllocationActive (YES); */
5228 Fset_input_interrupt_mode (Qnil);
5230 if (selfds[0] == -1)
5232 if (emacs_pipe (selfds) != 0)
5234 fprintf (stderr, "Failed to create pipe: %s\n",
5235 emacs_strerror (errno));
5239 fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
5240 FD_ZERO (&select_readfds);
5241 FD_ZERO (&select_writefds);
5242 pthread_mutex_init (&select_mutex, NULL);
5245 ns_pending_files = [[NSMutableArray alloc] init];
5246 ns_pending_service_names = [[NSMutableArray alloc] init];
5247 ns_pending_service_args = [[NSMutableArray alloc] init];
5249 /* Start app and create the main menu, window, view.
5250 Needs to be here because ns_initialize_display_info () uses AppKit classes.
5251 The view will then ask the NSApp to stop and return to Emacs. */
5252 [EmacsApp sharedApplication];
5255 [NSApp setDelegate: NSApp];
5257 /* Start the select thread. */
5258 [NSThread detachNewThreadSelector:@selector (fd_handler:)
5262 /* debugging: log all notifications */
5263 /* [[NSNotificationCenter defaultCenter] addObserver: NSApp
5264 selector: @selector (logNotification:)
5265 name: nil object: nil]; */
5267 dpyinfo = xzalloc (sizeof *dpyinfo);
5269 ns_initialize_display_info (dpyinfo);
5270 terminal = ns_create_terminal (dpyinfo);
5272 terminal->kboard = allocate_kboard (Qns);
5273 /* Don't let the initial kboard remain current longer than necessary.
5274 That would cause problems if a file loaded on startup tries to
5275 prompt in the mini-buffer. */
5276 if (current_kboard == initial_kboard)
5277 current_kboard = terminal->kboard;
5278 terminal->kboard->reference_count++;
5280 dpyinfo->next = x_display_list;
5281 x_display_list = dpyinfo;
5283 dpyinfo->name_list_element = Fcons (display_name, Qnil);
5285 terminal->name = xlispstrdup (display_name);
5289 if (!inhibit_x_resources)
5291 ns_default ("GSFontAntiAlias", &ns_antialias_text,
5294 /* this is a standard variable */
5295 ns_default ("AppleAntiAliasingThreshold", &tmp,
5296 make_float (10.0), make_float (6.0), YES, NO);
5297 ns_antialias_threshold = NILP (tmp) ? 10.0 : extract_float (tmp);
5300 NSTRACE_MSG ("Colors");
5303 NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
5307 Lisp_Object color_file, color_map, color;
5311 color_file = Fexpand_file_name (build_string ("rgb.txt"),
5312 Fsymbol_value (intern ("data-directory")));
5314 color_map = Fx_load_color_file (color_file);
5315 if (NILP (color_map))
5316 fatal ("Could not read %s.\n", SDATA (color_file));
5318 cl = [[NSColorList alloc] initWithName: @"Emacs"];
5319 for ( ; CONSP (color_map); color_map = XCDR (color_map))
5321 color = XCAR (color_map);
5322 name = SSDATA (XCAR (color));
5323 c = XINT (XCDR (color));
5325 [NSColor colorForEmacsRed: RED_FROM_ULONG (c) / 255.0
5326 green: GREEN_FROM_ULONG (c) / 255.0
5327 blue: BLUE_FROM_ULONG (c) / 255.0
5329 forKey: [NSString stringWithUTF8String: name]];
5331 [cl writeToFile: nil];
5335 NSTRACE_MSG ("Versions");
5338 #ifdef NS_IMPL_GNUSTEP
5339 Vwindow_system_version = build_string (gnustep_base_version);
5341 /* PSnextrelease (128, c); */
5342 char c[DBL_BUFSIZE_BOUND];
5343 int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
5344 Vwindow_system_version = make_unibyte_string (c, len);
5348 delete_keyboard_wait_descriptor (0);
5350 ns_app_name = [[NSProcessInfo processInfo] processName];
5352 /* Set up macOS app menu */
5354 NSTRACE_MSG ("Menu init");
5356 #ifdef NS_IMPL_COCOA
5360 /* set up the application menu */
5361 svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
5362 [svcsMenu setAutoenablesItems: NO];
5363 appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
5364 [appMenu setAutoenablesItems: NO];
5365 mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
5366 dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
5368 [appMenu insertItemWithTitle: @"About Emacs"
5369 action: @selector (orderFrontStandardAboutPanel:)
5372 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
5373 [appMenu insertItemWithTitle: @"Preferences..."
5374 action: @selector (showPreferencesWindow:)
5377 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
5378 item = [appMenu insertItemWithTitle: @"Services"
5379 action: @selector (menuDown:)
5382 [appMenu setSubmenu: svcsMenu forItem: item];
5383 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
5384 [appMenu insertItemWithTitle: @"Hide Emacs"
5385 action: @selector (hide:)
5388 item = [appMenu insertItemWithTitle: @"Hide Others"
5389 action: @selector (hideOtherApplications:)
5392 [item setKeyEquivalentModifierMask: NSEventModifierFlagCommand | NSEventModifierFlagOption];
5393 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
5394 [appMenu insertItemWithTitle: @"Quit Emacs"
5395 action: @selector (terminate:)
5399 item = [mainMenu insertItemWithTitle: ns_app_name
5400 action: @selector (menuDown:)
5403 [mainMenu setSubmenu: appMenu forItem: item];
5404 [dockMenu insertItemWithTitle: @"New Frame"
5405 action: @selector (newFrame:)
5409 [NSApp setMainMenu: mainMenu];
5410 [NSApp setAppleMenu: appMenu];
5411 [NSApp setServicesMenu: svcsMenu];
5412 /* Needed at least on Cocoa, to get dock menu to show windows */
5413 [NSApp setWindowsMenu: [[NSMenu alloc] init]];
5415 [[NSNotificationCenter defaultCenter]
5416 addObserver: mainMenu
5417 selector: @selector (trackingNotification:)
5418 name: NSMenuDidBeginTrackingNotification object: mainMenu];
5419 [[NSNotificationCenter defaultCenter]
5420 addObserver: mainMenu
5421 selector: @selector (trackingNotification:)
5422 name: NSMenuDidEndTrackingNotification object: mainMenu];
5424 #endif /* macOS menu setup */
5426 /* Register our external input/output types, used for determining
5427 applicable services and also drag/drop eligibility. */
5429 NSTRACE_MSG ("Input/output types");
5431 ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
5432 ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
5434 ns_drag_types = [[NSArray arrayWithObjects:
5436 NSTabularTextPboardType,
5437 NSFilenamesPboardType,
5438 NSURLPboardType, nil] retain];
5440 /* If fullscreen is in init/default-frame-alist, focus isn't set
5441 right for fullscreen windows, so set this. */
5442 [NSApp activateIgnoringOtherApps:YES];
5444 NSTRACE_MSG ("Call NSApp run");
5447 ns_do_open_file = YES;
5449 #ifdef NS_IMPL_GNUSTEP
5450 /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
5451 We must re-catch it so subprocess works. */
5452 catch_child_signal ();
5455 NSTRACE_MSG ("ns_term_init done");
5464 ns_term_shutdown (int sig)
5466 [[NSUserDefaults standardUserDefaults] synchronize];
5468 /* code not reached in emacs.c after this is called by shut_down_emacs: */
5469 if (STRINGP (Vauto_save_list_file_name))
5470 unlink (SSDATA (Vauto_save_list_file_name));
5472 if (sig == 0 || sig == SIGTERM)
5474 [NSApp terminate: NSApp];
5476 else // force a stack trace to happen
5483 /* ==========================================================================
5485 EmacsApp implementation
5487 ========================================================================== */
5490 @implementation EmacsApp
5494 NSTRACE ("[EmacsApp init]");
5496 if ((self = [super init]))
5498 #ifdef NS_IMPL_COCOA
5499 self->isFirst = YES;
5501 #ifdef NS_IMPL_GNUSTEP
5502 self->applicationDidFinishLaunchingCalled = NO;
5509 #ifdef NS_IMPL_COCOA
5512 NSTRACE ("[EmacsApp run]");
5514 #ifndef NSAppKitVersionNumber10_9
5515 #define NSAppKitVersionNumber10_9 1265
5518 if ((int)NSAppKitVersionNumber != NSAppKitVersionNumber10_9)
5524 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5526 if (isFirst) [self finishLaunching];
5529 shouldKeepRunning = YES;
5533 pool = [[NSAutoreleasePool alloc] init];
5536 [self nextEventMatchingMask:NSEventMaskAny
5537 untilDate:[NSDate distantFuture]
5538 inMode:NSDefaultRunLoopMode
5541 [self sendEvent:event];
5542 [self updateWindows];
5543 } while (shouldKeepRunning);
5548 - (void)stop: (id)sender
5550 NSTRACE ("[EmacsApp stop:]");
5552 shouldKeepRunning = NO;
5553 // Stop possible dialog also. Noop if no dialog present.
5554 // The file dialog still leaks 7k - 10k on 10.9 though.
5555 [super stop:sender];
5557 #endif /* NS_IMPL_COCOA */
5559 - (void)logNotification: (NSNotification *)notification
5561 NSTRACE ("[EmacsApp logNotification:]");
5563 const char *name = [[notification name] UTF8String];
5564 if (!strstr (name, "Update") && !strstr (name, "NSMenu")
5565 && !strstr (name, "WindowNumber"))
5566 NSLog (@"notification: '%@'", [notification name]);
5570 - (void)sendEvent: (NSEvent *)theEvent
5571 /* --------------------------------------------------------------------------
5572 Called when NSApp is running for each event received. Used to stop
5573 the loop when we choose, since there's no way to just run one iteration.
5574 -------------------------------------------------------------------------- */
5576 int type = [theEvent type];
5577 NSWindow *window = [theEvent window];
5579 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsApp sendEvent:]");
5580 NSTRACE_MSG ("Type: %d", type);
5582 #ifdef NS_IMPL_GNUSTEP
5583 // Keyboard events aren't propagated to file dialogs for some reason.
5584 if ([NSApp modalWindow] != nil &&
5585 (type == NSEventTypeKeyDown || type == NSEventTypeKeyUp || type == NSEventTypeFlagsChanged))
5587 [[NSApp modalWindow] sendEvent: theEvent];
5592 if (type == NSEventTypeApplicationDefined)
5594 switch ([theEvent data2])
5596 #ifdef NS_IMPL_COCOA
5597 case NSAPP_DATA2_RUNASSCRIPT:
5602 case NSAPP_DATA2_RUNFILEDIALOG:
5603 ns_run_file_dialog ();
5609 if (type == NSEventTypeCursorUpdate && window == nil)
5611 fprintf (stderr, "Dropping external cursor update event.\n");
5615 if (type == NSEventTypeApplicationDefined)
5617 /* Events posted by ns_send_appdefined interrupt the run loop here.
5618 But, if a modal window is up, an appdefined can still come through,
5619 (e.g., from a makeKeyWindow event) but stopping self also stops the
5620 modal loop. Just defer it until later. */
5621 if ([NSApp modalWindow] == nil)
5623 last_appdefined_event_data = [theEvent data1];
5628 send_appdefined = YES;
5633 #ifdef NS_IMPL_COCOA
5634 /* If no dialog and none of our frames have focus and it is a move, skip it.
5635 It is a mouse move in an auxiliary menu, i.e. on the top right on macOS,
5636 such as Wifi, sound, date or similar.
5637 This prevents "spooky" highlighting in the frame under the menu. */
5638 if (type == NSEventTypeMouseMoved && [NSApp modalWindow] == nil)
5640 struct ns_display_info *di;
5641 BOOL has_focus = NO;
5642 for (di = x_display_list; ! has_focus && di; di = di->next)
5643 has_focus = di->x_focus_frame != 0;
5649 NSTRACE_UNSILENCE();
5651 [super sendEvent: theEvent];
5655 - (void)showPreferencesWindow: (id)sender
5657 struct frame *emacsframe = SELECTED_FRAME ();
5658 NSEvent *theEvent = [NSApp currentEvent];
5662 emacs_event->kind = NS_NONKEY_EVENT;
5663 emacs_event->code = KEY_NS_SHOW_PREFS;
5664 emacs_event->modifiers = 0;
5665 EV_TRAILER (theEvent);
5669 - (void)newFrame: (id)sender
5671 NSTRACE ("[EmacsApp newFrame:]");
5673 struct frame *emacsframe = SELECTED_FRAME ();
5674 NSEvent *theEvent = [NSApp currentEvent];
5678 emacs_event->kind = NS_NONKEY_EVENT;
5679 emacs_event->code = KEY_NS_NEW_FRAME;
5680 emacs_event->modifiers = 0;
5681 EV_TRAILER (theEvent);
5685 /* Open a file (used by below, after going into queue read by ns_read_socket). */
5686 - (BOOL) openFile: (NSString *)fileName
5688 NSTRACE ("[EmacsApp openFile:]");
5690 struct frame *emacsframe = SELECTED_FRAME ();
5691 NSEvent *theEvent = [NSApp currentEvent];
5696 emacs_event->kind = NS_NONKEY_EVENT;
5697 emacs_event->code = KEY_NS_OPEN_FILE_LINE;
5698 ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
5699 ns_input_line = Qnil; /* can be start or cons start,end */
5700 emacs_event->modifiers =0;
5701 EV_TRAILER (theEvent);
5707 /* **************************************************************************
5709 EmacsApp delegate implementation
5711 ************************************************************************** */
5713 - (void)applicationDidFinishLaunching: (NSNotification *)notification
5714 /* --------------------------------------------------------------------------
5715 When application is loaded, terminate event loop in ns_term_init.
5716 -------------------------------------------------------------------------- */
5718 NSTRACE ("[EmacsApp applicationDidFinishLaunching:]");
5720 #ifdef NS_IMPL_GNUSTEP
5721 ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
5723 [NSApp setServicesProvider: NSApp];
5725 [self antialiasThresholdDidChange:nil];
5726 #ifdef NS_IMPL_COCOA
5727 [[NSNotificationCenter defaultCenter]
5729 selector:@selector(antialiasThresholdDidChange:)
5730 name:NSAntialiasThresholdChangedNotification
5734 #ifdef NS_IMPL_COCOA
5735 if ([NSApp activationPolicy] == NSApplicationActivationPolicyProhibited) {
5736 /* Set the app's activation policy to regular when we run outside
5737 of a bundle. This is already done for us by Info.plist when we
5738 run inside a bundle. */
5739 [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
5740 [NSApp setApplicationIconImage:
5743 build_string("icons/hicolor/128x128/apps/emacs.png")]];
5747 ns_send_appdefined (-2);
5750 - (void)antialiasThresholdDidChange:(NSNotification *)notification
5752 #ifdef NS_IMPL_COCOA
5753 macfont_update_antialias_threshold ();
5758 /* Termination sequences:
5761 MenuBar | File | Exit:
5762 Select Quit from App menubar:
5764 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5767 Select Quit from Dock menu:
5770 Cancel -> Nothing else
5774 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5779 - (void) terminate: (id)sender
5781 NSTRACE ("[EmacsApp terminate:]");
5783 struct frame *emacsframe = SELECTED_FRAME ();
5788 emacs_event->kind = NS_NONKEY_EVENT;
5789 emacs_event->code = KEY_NS_POWER_OFF;
5790 emacs_event->arg = Qt; /* mark as non-key event */
5791 EV_TRAILER ((id)nil);
5795 runAlertPanel(NSString *title,
5796 NSString *msgFormat,
5797 NSString *defaultButton,
5798 NSString *alternateButton)
5800 #ifdef NS_IMPL_GNUSTEP
5801 return NSRunAlertPanel(title, msgFormat, defaultButton, alternateButton, nil)
5802 == NSAlertDefaultReturn;
5804 NSAlert *alert = [[NSAlert alloc] init];
5805 [alert setAlertStyle: NSAlertStyleCritical];
5806 [alert setMessageText: msgFormat];
5807 [alert addButtonWithTitle: defaultButton];
5808 [alert addButtonWithTitle: alternateButton];
5809 NSInteger ret = [alert runModal];
5811 return ret == NSAlertFirstButtonReturn;
5816 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
5818 NSTRACE ("[EmacsApp applicationShouldTerminate:]");
5822 if (NILP (ns_confirm_quit)) // || ns_shutdown_properly --> TO DO
5823 return NSTerminateNow;
5825 ret = runAlertPanel(ns_app_name,
5826 @"Exit requested. Would you like to Save Buffers and Exit, or Cancel the request?",
5827 @"Save Buffers and Exit", @"Cancel");
5829 return ret ? NSTerminateNow : NSTerminateCancel;
5833 not_in_argv (NSString *arg)
5836 const char *a = [arg UTF8String];
5837 for (k = 1; k < initial_argc; ++k)
5838 if (strcmp (a, initial_argv[k]) == 0) return 0;
5842 /* Notification from the Workspace to open a file. */
5843 - (BOOL)application: sender openFile: (NSString *)file
5845 if (ns_do_open_file || not_in_argv (file))
5846 [ns_pending_files addObject: file];
5851 /* Open a file as a temporary file. */
5852 - (BOOL)application: sender openTempFile: (NSString *)file
5854 if (ns_do_open_file || not_in_argv (file))
5855 [ns_pending_files addObject: file];
5860 /* Notification from the Workspace to open a file noninteractively (?). */
5861 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
5863 if (ns_do_open_file || not_in_argv (file))
5864 [ns_pending_files addObject: file];
5868 /* Notification from the Workspace to open multiple files. */
5869 - (void)application: sender openFiles: (NSArray *)fileList
5871 NSEnumerator *files = [fileList objectEnumerator];
5873 /* Don't open files from the command line unconditionally,
5874 Cocoa parses the command line wrong, --option value tries to open value
5875 if --option is the last option. */
5876 while ((file = [files nextObject]) != nil)
5877 if (ns_do_open_file || not_in_argv (file))
5878 [ns_pending_files addObject: file];
5880 [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
5885 /* Handle dock menu requests. */
5886 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
5892 /* TODO: these may help w/IO switching between terminal and NSApp. */
5893 - (void)applicationWillBecomeActive: (NSNotification *)notification
5895 NSTRACE ("[EmacsApp applicationWillBecomeActive:]");
5896 // ns_app_active=YES;
5899 - (void)applicationDidBecomeActive: (NSNotification *)notification
5901 NSTRACE ("[EmacsApp applicationDidBecomeActive:]");
5903 #ifdef NS_IMPL_GNUSTEP
5904 if (! applicationDidFinishLaunchingCalled)
5905 [self applicationDidFinishLaunching:notification];
5907 // ns_app_active=YES;
5909 ns_update_auto_hide_menu_bar ();
5910 // No constraining takes place when the application is not active.
5911 ns_constrain_all_frames ();
5913 - (void)applicationDidResignActive: (NSNotification *)notification
5915 NSTRACE ("[EmacsApp applicationDidResignActive:]");
5917 // ns_app_active=NO;
5918 ns_send_appdefined (-1);
5923 /* ==========================================================================
5925 EmacsApp aux handlers for managing event loop
5927 ========================================================================== */
5930 - (void)timeout_handler: (NSTimer *)timedEntry
5931 /* --------------------------------------------------------------------------
5932 The timeout specified to ns_select has passed.
5933 -------------------------------------------------------------------------- */
5935 /* NSTRACE ("timeout_handler"); */
5936 ns_send_appdefined (-2);
5939 - (void)sendFromMainThread:(id)unused
5941 ns_send_appdefined (nextappdefined);
5944 - (void)fd_handler:(id)unused
5945 /* --------------------------------------------------------------------------
5946 Check data waiting on file descriptors and terminate if so.
5947 -------------------------------------------------------------------------- */
5950 int waiting = 1, nfds;
5953 fd_set readfds, writefds, *wfds;
5954 struct timespec timeout, *tmo;
5955 NSAutoreleasePool *pool = nil;
5957 /* NSTRACE ("fd_handler"); */
5962 pool = [[NSAutoreleasePool alloc] init];
5968 FD_SET (selfds[0], &fds);
5969 result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
5970 if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
5975 pthread_mutex_lock (&select_mutex);
5978 if (select_valid & SELECT_HAVE_READ)
5979 readfds = select_readfds;
5983 if (select_valid & SELECT_HAVE_WRITE)
5985 writefds = select_writefds;
5990 if (select_valid & SELECT_HAVE_TMO)
5992 timeout = select_timeout;
5998 pthread_mutex_unlock (&select_mutex);
6000 FD_SET (selfds[0], &readfds);
6001 if (selfds[0] >= nfds) nfds = selfds[0]+1;
6003 result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
6006 ns_send_appdefined (-2);
6007 else if (result > 0)
6009 if (FD_ISSET (selfds[0], &readfds))
6011 if (read (selfds[0], &c, 1) == 1 && c == 's')
6016 pthread_mutex_lock (&select_mutex);
6017 if (select_valid & SELECT_HAVE_READ)
6018 select_readfds = readfds;
6019 if (select_valid & SELECT_HAVE_WRITE)
6020 select_writefds = writefds;
6021 if (select_valid & SELECT_HAVE_TMO)
6022 select_timeout = timeout;
6023 pthread_mutex_unlock (&select_mutex);
6025 ns_send_appdefined (result);
6035 /* ==========================================================================
6039 ========================================================================== */
6041 /* Called from system: queue for next pass through event loop. */
6042 - (void)requestService: (NSPasteboard *)pboard
6043 userData: (NSString *)userData
6044 error: (NSString **)error
6046 [ns_pending_service_names addObject: userData];
6047 [ns_pending_service_args addObject: [NSString stringWithUTF8String:
6048 SSDATA (ns_string_from_pasteboard (pboard))]];
6052 /* Called from ns_read_socket to clear queue. */
6053 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
6055 struct frame *emacsframe = SELECTED_FRAME ();
6056 NSEvent *theEvent = [NSApp currentEvent];
6058 NSTRACE ("[EmacsApp fulfillService:withArg:]");
6063 emacs_event->kind = NS_NONKEY_EVENT;
6064 emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
6065 ns_input_spi_name = build_string ([name UTF8String]);
6066 ns_input_spi_arg = build_string ([arg UTF8String]);
6067 emacs_event->modifiers = EV_MODIFIERS (theEvent);
6068 EV_TRAILER (theEvent);
6077 /* ==========================================================================
6079 EmacsView implementation
6081 ========================================================================== */
6084 @implementation EmacsView
6086 /* Needed to inform when window closed from lisp. */
6087 - (void) setWindowClosing: (BOOL)closing
6089 NSTRACE ("[EmacsView setWindowClosing:%d]", closing);
6091 windowClosing = closing;
6097 NSTRACE ("[EmacsView dealloc]");
6099 if (fs_state == FULLSCREEN_BOTH)
6100 [nonfs_window release];
6105 /* Called on font panel selection. */
6106 - (void)changeFont: (id)sender
6108 NSEvent *e = [[self window] currentEvent];
6109 struct face *face = FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID);
6110 struct font *font = face->font;
6115 NSTRACE ("[EmacsView changeFont:]");
6120 #ifdef NS_IMPL_GNUSTEP
6121 nsfont = ((struct nsfont_info *)font)->nsfont;
6123 #ifdef NS_IMPL_COCOA
6124 nsfont = (NSFont *) macfont_get_nsctfont (font);
6127 if ((newFont = [sender convertFont: nsfont]))
6129 SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
6131 emacs_event->kind = NS_NONKEY_EVENT;
6132 emacs_event->modifiers = 0;
6133 emacs_event->code = KEY_NS_CHANGE_FONT;
6135 size = [newFont pointSize];
6136 ns_input_fontsize = make_number (lrint (size));
6137 ns_input_font = build_string ([[newFont familyName] UTF8String]);
6143 - (BOOL)acceptsFirstResponder
6145 NSTRACE ("[EmacsView acceptsFirstResponder]");
6150 - (void)resetCursorRects
6152 NSRect visible = [self visibleRect];
6153 NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
6154 NSTRACE ("[EmacsView resetCursorRects]");
6156 if (currentCursor == nil)
6157 currentCursor = [NSCursor arrowCursor];
6159 if (!NSIsEmptyRect (visible))
6160 [self addCursorRect: visible cursor: currentCursor];
6162 #if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 101300
6163 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101300
6164 if ([currentCursor respondsToSelector: @selector(setOnMouseEntered)])
6166 [currentCursor setOnMouseEntered: YES];
6172 /*****************************************************************************/
6173 /* Keyboard handling. */
6176 - (void)keyDown: (NSEvent *)theEvent
6178 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
6180 unsigned fnKeysym = 0;
6181 static NSMutableArray *nsEvArray;
6182 unsigned int flags = [theEvent modifierFlags];
6184 NSTRACE ("[EmacsView keyDown:]");
6186 /* Rhapsody and macOS give up and down events for the arrow keys. */
6187 if (ns_fake_keydown == YES)
6188 ns_fake_keydown = NO;
6189 else if ([theEvent type] != NSEventTypeKeyDown)
6195 if (![[self window] isKeyWindow]
6196 && [[theEvent window] isKindOfClass: [EmacsWindow class]]
6197 /* We must avoid an infinite loop here. */
6198 && (EmacsView *)[[theEvent window] delegate] != self)
6200 /* XXX: There is an occasional condition in which, when Emacs display
6201 updates a different frame from the current one, and temporarily
6202 selects it, then processes some interrupt-driven input
6203 (dispnew.c:3878), OS will send the event to the correct NSWindow, but
6204 for some reason that window has its first responder set to the NSView
6205 most recently updated (I guess), which is not the correct one. */
6206 [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
6210 if (nsEvArray == nil)
6211 nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
6213 [NSCursor setHiddenUntilMouseMoves: YES];
6215 if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
6217 clear_mouse_face (hlinfo);
6218 hlinfo->mouse_face_hidden = 1;
6221 if (!processingCompose)
6223 /* FIXME: What should happen for key sequences with more than
6225 code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
6226 0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
6228 /* Is it a "function key"? */
6229 /* Note: Sometimes a plain key will have the NSEventModifierFlagNumericPad
6230 flag set (this is probably a bug in the OS). */
6231 if (code < 0x00ff && (flags&NSEventModifierFlagNumericPad))
6233 fnKeysym = ns_convert_key ([theEvent keyCode] | NSEventModifierFlagNumericPad);
6237 fnKeysym = ns_convert_key (code);
6242 /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
6243 because Emacs treats Delete and KP-Delete same (in simple.el). */
6244 if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
6245 #ifdef NS_IMPL_GNUSTEP
6246 /* GNUstep uses incompatible keycodes, even for those that are
6247 supposed to be hardware independent. Just check for delete.
6248 Keypad delete does not have keysym 0xFFFF.
6249 See https://savannah.gnu.org/bugs/?25395 */
6250 || (fnKeysym == 0xFFFF && code == 127)
6253 code = 0xFF08; /* backspace */
6258 /* The ⌘ and ⌥ modifiers can be either shift-like (for alternate
6259 character input) or control-like (as command prefix). If we
6260 have only shift-like modifiers, then we should use the
6261 translated characters (returned by the characters method); if
6262 we have only control-like modifiers, then we should use the
6263 untranslated characters (returned by the
6264 charactersIgnoringModifiers method). An annoyance happens if
6265 we have both shift-like and control-like modifiers because
6266 the NSEvent API doesn’t let us ignore only some modifiers.
6267 In that case we use UCKeyTranslate (ns_get_shifted_character)
6268 to look up the correct character. */
6270 /* EV_MODIFIERS2 uses parse_solitary_modifier on all known
6271 modifier keys, which returns 0 for shift-like modifiers.
6272 Therefore its return value is the set of control-like
6274 emacs_event->modifiers = EV_MODIFIERS2 (flags);
6276 /* Function keys (such as the F-keys, arrow keys, etc.) set
6277 modifiers as though the fn key has been pressed when it
6278 hasn't. Also some combinations of fn and a function key
6279 return a different key than was pressed (e.g. fn-<left> gives
6280 <home>). We need to unset the fn modifier in these cases.
6281 FIXME: Can we avoid setting it in the first place? */
6282 if (fnKeysym && (flags & NS_FUNCTION_KEY_MASK))
6283 emacs_event->modifiers ^= parse_solitary_modifier (ns_function_modifier);
6286 fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
6287 code, fnKeysym, flags, emacs_event->modifiers);
6289 /* If it was a function key or had control-like modifiers, pass
6290 it directly to Emacs. */
6291 if (fnKeysym || (emacs_event->modifiers
6292 && (emacs_event->modifiers != shift_modifier)
6293 && [[theEvent charactersIgnoringModifiers] length] > 0))
6295 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6296 /* FIXME: What are the next four lines supposed to do? */
6298 code |= (1<<28)|(3<<16);
6299 else if (code == 0x7f)
6300 code |= (1<<28)|(3<<16);
6303 #ifdef NS_IMPL_COCOA
6304 /* We potentially have both shift- and control-like
6305 modifiers in use, so find the correct character
6306 ignoring any control-like ones. */
6307 code = ns_get_shifted_character (theEvent);
6310 /* FIXME: This seems wrong, characters in the range
6311 [0x80, 0xFF] are not ASCII characters. Can’t we just
6312 use MULTIBYTE_CHAR_KEYSTROKE_EVENT here for all kinds
6314 emacs_event->kind = code > 0xFF
6315 ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6318 emacs_event->code = code;
6319 EV_TRAILER (theEvent);
6320 processingCompose = NO;
6325 /* If we get here, a non-function key without control-like modifiers
6326 was hit. Use interpretKeyEvents, which in turn will call
6328 https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/EventOverview/HandlingKeyEvents/HandlingKeyEvents.html. */
6330 if (NS_KEYLOG && !processingCompose)
6331 fprintf (stderr, "keyDown: Begin compose sequence.\n");
6333 /* FIXME: interpretKeyEvents doesn’t seem to send insertText if ⌘ is
6334 used as shift-like modifier, at least on El Capitan. Mask it
6335 out. This shouldn’t be needed though; we should figure out what
6336 the correct way of handling ⌘ is. */
6337 if ([theEvent modifierFlags] & NSEventModifierFlagCommand)
6338 theEvent = [NSEvent keyEventWithType:[theEvent type]
6339 location:[theEvent locationInWindow]
6340 modifierFlags:[theEvent modifierFlags] & ~NSEventModifierFlagCommand
6341 timestamp:[theEvent timestamp]
6342 windowNumber:[theEvent windowNumber]
6344 characters:[theEvent characters]
6345 charactersIgnoringModifiers:[theEvent charactersIgnoringModifiers]
6346 isARepeat:[theEvent isARepeat]
6347 keyCode:[theEvent keyCode]];
6349 processingCompose = YES;
6350 /* FIXME: Use [NSArray arrayWithObject:theEvent]? */
6351 [nsEvArray addObject: theEvent];
6352 [self interpretKeyEvents: nsEvArray];
6353 [nsEvArray removeObject: theEvent];
6357 /* <NSTextInput> implementation (called through [super interpretKeyEvents:]). */
6360 /* <NSTextInput>: called when done composing;
6361 NOTE: also called when we delete over working text, followed
6362 immediately by doCommandBySelector: deleteBackward: */
6363 - (void)insertText: (id)aString
6368 NSTRACE ("[EmacsView insertText:]");
6370 if ([aString isKindOfClass:[NSAttributedString class]])
6371 s = [aString string];
6378 NSLog (@"insertText '%@'\tlen = %lu", aString, (unsigned long) len);
6379 processingCompose = NO;
6384 /* First, clear any working text. */
6385 if (workingText != nil)
6386 [self deleteWorkingText];
6388 /* It might be preferable to use getCharacters:range: below,
6389 cf. https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CocoaPerformance/Articles/StringDrawing.html#//apple_ref/doc/uid/TP40001445-112378.
6390 However, we probably can't use SAFE_NALLOCA here because it might
6393 /* Now insert the string as keystrokes. */
6394 for (NSUInteger i = 0; i < len; i++)
6396 NSUInteger code = [s characterAtIndex:i];
6397 if (UTF_16_HIGH_SURROGATE_P (code) && i < len - 1)
6399 unichar low = [s characterAtIndex:i + 1];
6400 if (UTF_16_LOW_SURROGATE_P (low))
6402 code = surrogates_to_codepoint (low, code);
6406 /* TODO: still need this? */
6408 code = '~'; /* 0x7E */
6409 if (code != 32) /* Space */
6410 emacs_event->modifiers = 0;
6412 = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6413 emacs_event->code = code;
6414 EV_TRAILER ((id)nil);
6419 /* <NSTextInput>: inserts display of composing characters. */
6420 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
6422 NSString *str = [aString respondsToSelector: @selector (string)] ?
6423 [aString string] : aString;
6425 NSTRACE ("[EmacsView setMarkedText:selectedRange:]");
6428 NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
6429 str, (unsigned long)[str length],
6430 (unsigned long)selRange.length,
6431 (unsigned long)selRange.location);
6433 if (workingText != nil)
6434 [self deleteWorkingText];
6435 if ([str length] == 0)
6441 processingCompose = YES;
6442 workingText = [str copy];
6443 ns_working_text = build_string ([workingText UTF8String]);
6445 emacs_event->kind = NS_TEXT_EVENT;
6446 emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
6447 EV_TRAILER ((id)nil);
6451 /* Delete display of composing characters [not in <NSTextInput>]. */
6452 - (void)deleteWorkingText
6454 NSTRACE ("[EmacsView deleteWorkingText]");
6456 if (workingText == nil)
6459 NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
6460 [workingText release];
6462 processingCompose = NO;
6467 emacs_event->kind = NS_TEXT_EVENT;
6468 emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
6469 EV_TRAILER ((id)nil);
6473 - (BOOL)hasMarkedText
6475 NSTRACE ("[EmacsView hasMarkedText]");
6477 return workingText != nil;
6481 - (NSRange)markedRange
6483 NSTRACE ("[EmacsView markedRange]");
6485 NSRange rng = workingText != nil
6486 ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
6488 NSLog (@"markedRange request");
6495 NSTRACE ("[EmacsView unmarkText]");
6498 NSLog (@"unmark (accept) text");
6499 [self deleteWorkingText];
6500 processingCompose = NO;
6504 /* Used to position char selection windows, etc. */
6505 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
6509 struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
6511 NSTRACE ("[EmacsView firstRectForCharacterRange:]");
6514 NSLog (@"firstRectForCharRange request");
6516 rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
6517 rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
6518 pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
6519 pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
6520 +FRAME_LINE_HEIGHT (emacsframe));
6522 pt = [self convertPoint: pt toView: nil];
6524 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
6525 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6526 if ([[self window] respondsToSelector: @selector(convertRectToScreen:)])
6530 rect = [(EmacsWindow *) [self window] convertRectToScreen: rect];
6531 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6535 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
6536 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 \
6537 || defined (NS_IMPL_GNUSTEP)
6539 pt = [[self window] convertBaseToScreen: pt];
6548 - (NSInteger)conversationIdentifier
6550 return (NSInteger)self;
6554 - (void)doCommandBySelector: (SEL)aSelector
6556 NSTRACE ("[EmacsView doCommandBySelector:]");
6559 NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
6561 processingCompose = NO;
6562 if (aSelector == @selector (deleteBackward:))
6564 /* Happens when user backspaces over an ongoing composition:
6565 throw a 'delete' into the event queue. */
6568 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6569 emacs_event->code = 0xFF08;
6570 EV_TRAILER ((id)nil);
6574 - (NSArray *)validAttributesForMarkedText
6576 static NSArray *arr = nil;
6577 if (arr == nil) arr = [NSArray new];
6578 /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
6582 - (NSRange)selectedRange
6585 NSLog (@"selectedRange request");
6586 return NSMakeRange (NSNotFound, 0);
6589 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
6590 GNUSTEP_GUI_MINOR_VERSION > 22
6591 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
6593 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
6597 NSLog (@"characterIndexForPoint request");
6601 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
6603 static NSAttributedString *str = nil;
6604 if (str == nil) str = [NSAttributedString new];
6606 NSLog (@"attributedSubstringFromRange request");
6610 /* End <NSTextInput> implementation. */
6611 /*****************************************************************************/
6614 /* This is what happens when the user presses a mouse button. */
6615 - (void)mouseDown: (NSEvent *)theEvent
6617 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6618 NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
6620 NSTRACE ("[EmacsView mouseDown:]");
6622 [self deleteWorkingText];
6627 dpyinfo->last_mouse_frame = emacsframe;
6628 /* Appears to be needed to prevent spurious movement events generated on
6630 emacsframe->mouse_moved = 0;
6632 if ([theEvent type] == NSEventTypeScrollWheel)
6634 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
6635 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6636 if ([theEvent respondsToSelector:@selector(hasPreciseScrollingDeltas)])
6639 /* If the input device is a touchpad or similar, use precise
6640 * scrolling deltas. These are measured in pixels, so we
6641 * have to add them up until they exceed one line height,
6642 * then we can send a scroll wheel event.
6644 * If the device only has coarse scrolling deltas, like a
6645 * real mousewheel, the deltas represent a ratio of whole
6646 * lines, so round up the number of lines. This means we
6647 * always send one scroll event per click, but can still
6648 * scroll more than one line if the OS tells us to.
6654 /* FIXME: At the top or bottom of the buffer we should
6655 * ignore momentum-phase events. */
6656 if (! ns_use_mwheel_momentum
6657 && [theEvent momentumPhase] != NSEventPhaseNone)
6660 if ([theEvent hasPreciseScrollingDeltas])
6662 static int totalDeltaX, totalDeltaY;
6665 if (NUMBERP (ns_mwheel_line_height))
6666 lineHeight = XINT (ns_mwheel_line_height);
6669 /* FIXME: Use actual line height instead of the default. */
6670 lineHeight = default_line_pixel_height
6671 (XWINDOW (FRAME_SELECTED_WINDOW (emacsframe)));
6674 if ([theEvent phase] == NSEventPhaseBegan)
6680 totalDeltaX += [theEvent scrollingDeltaX];
6681 totalDeltaY += [theEvent scrollingDeltaY];
6683 /* Calculate the number of lines, if any, to scroll, and
6684 * reset the total delta for the direction we're NOT
6685 * scrolling so that small movements don't add up. */
6686 if (abs (totalDeltaX) > abs (totalDeltaY)
6687 && abs (totalDeltaX) > lineHeight)
6690 scrollUp = totalDeltaX > 0;
6692 lines = abs (totalDeltaX / lineHeight);
6693 totalDeltaX = totalDeltaX % lineHeight;
6696 else if (abs (totalDeltaY) >= abs (totalDeltaX)
6697 && abs (totalDeltaY) > lineHeight)
6700 scrollUp = totalDeltaY > 0;
6702 lines = abs (totalDeltaY / lineHeight);
6703 totalDeltaY = totalDeltaY % lineHeight;
6707 if (lines > 1 && ! ns_use_mwheel_acceleration)
6714 if ([theEvent scrollingDeltaY] == 0)
6717 delta = [theEvent scrollingDeltaX];
6722 delta = [theEvent scrollingDeltaY];
6725 lines = (ns_use_mwheel_acceleration)
6726 ? ceil (fabs (delta)) : 1;
6728 scrollUp = delta > 0;
6734 emacs_event->kind = horizontal ? HORIZ_WHEEL_EVENT : WHEEL_EVENT;
6735 emacs_event->arg = (make_number (lines));
6737 emacs_event->code = 0;
6738 emacs_event->modifiers = EV_MODIFIERS (theEvent) |
6739 (scrollUp ? up_modifier : down_modifier);
6740 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6744 #endif /* defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
6745 #if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6747 CGFloat delta = [theEvent deltaY];
6748 /* Mac notebooks send wheel events with delta equal to 0
6749 when trackpad scrolling. */
6752 delta = [theEvent deltaX];
6755 NSTRACE_MSG ("deltaIsZero");
6758 emacs_event->kind = HORIZ_WHEEL_EVENT;
6761 emacs_event->kind = WHEEL_EVENT;
6763 emacs_event->code = 0;
6764 emacs_event->modifiers = EV_MODIFIERS (theEvent) |
6765 ((delta > 0) ? up_modifier : down_modifier);
6771 emacs_event->kind = MOUSE_CLICK_EVENT;
6772 emacs_event->code = EV_BUTTON (theEvent);
6773 emacs_event->modifiers = EV_MODIFIERS (theEvent)
6774 | EV_UDMODIFIERS (theEvent);
6777 XSETINT (emacs_event->x, lrint (p.x));
6778 XSETINT (emacs_event->y, lrint (p.y));
6779 EV_TRAILER (theEvent);
6784 - (void)rightMouseDown: (NSEvent *)theEvent
6786 NSTRACE ("[EmacsView rightMouseDown:]");
6787 [self mouseDown: theEvent];
6791 - (void)otherMouseDown: (NSEvent *)theEvent
6793 NSTRACE ("[EmacsView otherMouseDown:]");
6794 [self mouseDown: theEvent];
6798 - (void)mouseUp: (NSEvent *)theEvent
6800 NSTRACE ("[EmacsView mouseUp:]");
6801 [self mouseDown: theEvent];
6805 - (void)rightMouseUp: (NSEvent *)theEvent
6807 NSTRACE ("[EmacsView rightMouseUp:]");
6808 [self mouseDown: theEvent];
6812 - (void)otherMouseUp: (NSEvent *)theEvent
6814 NSTRACE ("[EmacsView otherMouseUp:]");
6815 [self mouseDown: theEvent];
6819 - (void) scrollWheel: (NSEvent *)theEvent
6821 NSTRACE ("[EmacsView scrollWheel:]");
6822 [self mouseDown: theEvent];
6826 /* Tell emacs the mouse has moved. */
6827 - (void)mouseMoved: (NSEvent *)e
6829 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
6830 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6834 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsView mouseMoved:]");
6836 dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
6837 pt = [self convertPoint: [e locationInWindow] fromView: nil];
6838 dpyinfo->last_mouse_motion_x = pt.x;
6839 dpyinfo->last_mouse_motion_y = pt.y;
6841 /* Update any mouse face. */
6842 if (hlinfo->mouse_face_hidden)
6844 hlinfo->mouse_face_hidden = 0;
6845 clear_mouse_face (hlinfo);
6848 /* Tooltip handling. */
6849 previous_help_echo_string = help_echo_string;
6850 help_echo_string = Qnil;
6852 if (!NILP (Vmouse_autoselect_window))
6854 NSTRACE_MSG ("mouse_autoselect_window");
6855 static Lisp_Object last_mouse_window;
6857 = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
6859 if (WINDOWP (window)
6860 && !EQ (window, last_mouse_window)
6861 && !EQ (window, selected_window)
6862 && (!NILP (focus_follows_mouse)
6863 || (EQ (XWINDOW (window)->frame,
6864 XWINDOW (selected_window)->frame))))
6866 NSTRACE_MSG ("in_window");
6867 emacs_event->kind = SELECT_WINDOW_EVENT;
6868 emacs_event->frame_or_window = window;
6871 /* Remember the last window where we saw the mouse. */
6872 last_mouse_window = window;
6875 if (!note_mouse_movement (emacsframe, pt.x, pt.y))
6876 help_echo_string = previous_help_echo_string;
6878 XSETFRAME (frame, emacsframe);
6879 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
6881 /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
6882 (note_mouse_highlight), which is called through the
6883 note_mouse_movement () call above. */
6884 any_help_event_p = YES;
6885 gen_help_event (help_echo_string, frame, help_echo_window,
6886 help_echo_object, help_echo_pos);
6889 if (emacsframe->mouse_moved && send_appdefined)
6890 ns_send_appdefined (-1);
6894 - (void)mouseDragged: (NSEvent *)e
6896 NSTRACE ("[EmacsView mouseDragged:]");
6897 [self mouseMoved: e];
6901 - (void)rightMouseDragged: (NSEvent *)e
6903 NSTRACE ("[EmacsView rightMouseDragged:]");
6904 [self mouseMoved: e];
6908 - (void)otherMouseDragged: (NSEvent *)e
6910 NSTRACE ("[EmacsView otherMouseDragged:]");
6911 [self mouseMoved: e];
6915 - (BOOL)windowShouldClose: (id)sender
6917 NSEvent *e =[[self window] currentEvent];
6919 NSTRACE ("[EmacsView windowShouldClose:]");
6920 windowClosing = YES;
6923 emacs_event->kind = DELETE_WINDOW_EVENT;
6924 emacs_event->modifiers = 0;
6925 emacs_event->code = 0;
6927 /* Don't close this window, let this be done from lisp code. */
6931 - (void) updateFrameSize: (BOOL) delay
6933 NSWindow *window = [self window];
6934 NSRect wr = [window frame];
6936 int oldc = cols, oldr = rows;
6937 int oldw = FRAME_PIXEL_WIDTH (emacsframe);
6938 int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
6941 NSTRACE ("[EmacsView updateFrameSize:]");
6942 NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
6943 NSTRACE_RECT ("Original frame", wr);
6944 NSTRACE_MSG ("Original columns: %d", cols);
6945 NSTRACE_MSG ("Original rows: %d", rows);
6947 if (! [self isFullscreen])
6950 #ifdef NS_IMPL_GNUSTEP
6951 // GNUstep does not always update the tool bar height. Force it.
6952 if (toolbar && [toolbar isVisible])
6953 update_frame_tool_bar (emacsframe);
6956 toolbar_height = FRAME_TOOLBAR_HEIGHT (emacsframe);
6957 if (toolbar_height < 0)
6958 toolbar_height = 35;
6960 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6964 if (wait_for_tool_bar)
6966 /* The toolbar height is always 0 in fullscreen and undecorated
6967 frames, so don't wait for it to become available. */
6968 if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0
6969 && FRAME_UNDECORATED (emacsframe) == false
6970 && ! [self isFullscreen])
6972 NSTRACE_MSG ("Waiting for toolbar");
6975 wait_for_tool_bar = NO;
6978 neww = (int)wr.size.width - emacsframe->border_width;
6979 newh = (int)wr.size.height - extra;
6981 NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
6982 NSTRACE_MSG ("FRAME_TOOLBAR_HEIGHT: %d", FRAME_TOOLBAR_HEIGHT (emacsframe));
6983 NSTRACE_MSG ("FRAME_NS_TITLEBAR_HEIGHT: %d", FRAME_NS_TITLEBAR_HEIGHT (emacsframe));
6985 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
6986 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
6988 if (cols < MINWIDTH)
6991 if (rows < MINHEIGHT)
6994 NSTRACE_MSG ("New columns: %d", cols);
6995 NSTRACE_MSG ("New rows: %d", rows);
6997 if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
6999 NSView *view = FRAME_NS_VIEW (emacsframe);
7001 change_frame_size (emacsframe,
7002 FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
7003 FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
7005 SET_FRAME_GARBAGED (emacsframe);
7006 cancel_mouse_face (emacsframe);
7008 /* The next two lines set the frame to the same size as we've
7009 already set above. We need to do this when we switch back
7010 from non-native fullscreen, in other circumstances it appears
7011 to be a noop. (bug#28872) */
7012 wr = NSMakeRect (0, 0, neww, newh);
7013 [view setFrame: wr];
7015 // To do: consider using [NSNotificationCenter postNotificationName:].
7016 [self windowDidMove: // Update top/left.
7017 [NSNotification notificationWithName:NSWindowDidMoveNotification
7018 object:[view window]]];
7022 NSTRACE_MSG ("No change");
7026 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
7027 /* Normalize frame to gridded text size. */
7031 NSTRACE ("[EmacsView windowWillResize:toSize: " NSTRACE_FMT_SIZE "]",
7032 NSTRACE_ARG_SIZE (frameSize));
7033 NSTRACE_RECT ("[sender frame]", [sender frame]);
7034 NSTRACE_FSTYPE ("fs_state", fs_state);
7036 if (!FRAME_LIVE_P (emacsframe))
7039 if (fs_state == FULLSCREEN_MAXIMIZED
7040 && (maximized_width != (int)frameSize.width
7041 || maximized_height != (int)frameSize.height))
7042 [self setFSValue: FULLSCREEN_NONE];
7043 else if (fs_state == FULLSCREEN_WIDTH
7044 && maximized_width != (int)frameSize.width)
7045 [self setFSValue: FULLSCREEN_NONE];
7046 else if (fs_state == FULLSCREEN_HEIGHT
7047 && maximized_height != (int)frameSize.height)
7048 [self setFSValue: FULLSCREEN_NONE];
7050 if (fs_state == FULLSCREEN_NONE)
7051 maximized_width = maximized_height = -1;
7053 if (! [self isFullscreen])
7055 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
7056 + FRAME_TOOLBAR_HEIGHT (emacsframe);
7059 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
7060 if (cols < MINWIDTH)
7063 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
7064 frameSize.height - extra);
7065 if (rows < MINHEIGHT)
7067 #ifdef NS_IMPL_COCOA
7069 /* This sets window title to have size in it; the wm does this under GS. */
7070 NSRect r = [[self window] frame];
7071 if (r.size.height == frameSize.height && r.size.width == frameSize.width)
7079 else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize
7080 && [[self window] title] != NULL)
7083 NSWindow *window = [self window];
7086 char *t = strdup ([[[self window] title] UTF8String]);
7087 char *pos = strstr (t, " — ");
7092 size_title = xmalloc (strlen (old_title) + 40);
7093 esprintf (size_title, "%s — (%d x %d)", old_title, cols, rows);
7094 [window setTitle: [NSString stringWithUTF8String: size_title]];
7099 #endif /* NS_IMPL_COCOA */
7101 NSTRACE_MSG ("cols: %d rows: %d", cols, rows);
7103 /* Restrict the new size to the text grid.
7105 Don't restrict the width if the user only adjusted the height, and
7106 vice versa. (Without this, the frame would shrink, and move
7107 slightly, if the window was resized by dragging one of its
7109 if (!frame_resize_pixelwise)
7111 NSRect r = [[self window] frame];
7113 if (r.size.width != frameSize.width)
7116 FRAME_TEXT_COLS_TO_PIXEL_WIDTH (emacsframe, cols);
7119 if (r.size.height != frameSize.height)
7122 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (emacsframe, rows) + extra;
7126 NSTRACE_RETURN_SIZE (frameSize);
7132 - (void)windowDidResize: (NSNotification *)notification
7134 NSTRACE ("[EmacsView windowDidResize:]");
7135 if (!FRAME_LIVE_P (emacsframe))
7137 NSTRACE_MSG ("Ignored (frame dead)");
7140 if (emacsframe->output_data.ns->in_animation)
7142 NSTRACE_MSG ("Ignored (in animation)");
7146 if (! [self fsIsNative])
7148 NSWindow *theWindow = [notification object];
7149 /* We can get notification on the non-FS window when in
7151 if ([self window] != theWindow) return;
7154 NSTRACE_RECT ("frame", [[notification object] frame]);
7156 #ifdef NS_IMPL_GNUSTEP
7157 NSWindow *theWindow = [notification object];
7159 /* In GNUstep, at least currently, it's possible to get a didResize
7160 without getting a willResize, therefore we need to act as if we got
7161 the willResize now. */
7162 NSSize sz = [theWindow frame].size;
7163 sz = [self windowWillResize: theWindow toSize: sz];
7164 #endif /* NS_IMPL_GNUSTEP */
7166 if (cols > 0 && rows > 0)
7168 [self updateFrameSize: YES];
7171 ns_send_appdefined (-1);
7174 #ifdef NS_IMPL_COCOA
7175 - (void)viewDidEndLiveResize
7177 NSTRACE ("[EmacsView viewDidEndLiveResize]");
7179 [super viewDidEndLiveResize];
7182 [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
7186 maximizing_resize = NO;
7188 #endif /* NS_IMPL_COCOA */
7191 - (void)windowDidBecomeKey: (NSNotification *)notification
7192 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
7194 [self windowDidBecomeKey];
7198 - (void)windowDidBecomeKey /* for direct calls */
7200 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
7201 struct frame *old_focus = dpyinfo->x_focus_frame;
7203 NSTRACE ("[EmacsView windowDidBecomeKey]");
7205 if (emacsframe != old_focus)
7206 dpyinfo->x_focus_frame = emacsframe;
7208 ns_frame_rehighlight (emacsframe);
7212 emacs_event->kind = FOCUS_IN_EVENT;
7213 EV_TRAILER ((id)nil);
7218 - (void)windowDidResignKey: (NSNotification *)notification
7219 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
7221 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
7222 BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
7223 NSTRACE ("[EmacsView windowDidResignKey:]");
7226 dpyinfo->x_focus_frame = 0;
7228 emacsframe->mouse_moved = 0;
7229 ns_frame_rehighlight (emacsframe);
7231 /* FIXME: for some reason needed on second and subsequent clicks away
7232 from sole-frame Emacs to get hollow box to show. */
7233 if (!windowClosing && [[self window] isVisible] == YES)
7235 x_update_cursor (emacsframe, 1);
7236 x_set_frame_alpha (emacsframe);
7239 if (any_help_event_p)
7242 XSETFRAME (frame, emacsframe);
7243 help_echo_string = Qnil;
7244 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
7247 if (emacs_event && is_focus_frame)
7249 [self deleteWorkingText];
7250 emacs_event->kind = FOCUS_OUT_EVENT;
7251 EV_TRAILER ((id)nil);
7256 - (void)windowWillMiniaturize: sender
7258 NSTRACE ("[EmacsView windowWillMiniaturize:]");
7262 - (void)setFrame:(NSRect)frameRect
7264 NSTRACE ("[EmacsView setFrame:" NSTRACE_FMT_RECT "]",
7265 NSTRACE_ARG_RECT (frameRect));
7267 [super setFrame:(NSRect)frameRect];
7283 - (void)createToolbar: (struct frame *)f
7285 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
7286 NSWindow *window = [view window];
7288 toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
7289 [NSString stringWithFormat: @"Emacs Frame %d",
7291 [toolbar setVisible: NO];
7292 [window setToolbar: toolbar];
7294 /* Don't set frame garbaged until tool bar is up to date?
7295 This avoids an extra clear and redraw (flicker) at frame creation. */
7296 if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
7297 else wait_for_tool_bar = NO;
7300 #ifdef NS_IMPL_COCOA
7302 NSButton *toggleButton;
7303 toggleButton = [window standardWindowButton: NSWindowToolbarButton];
7304 [toggleButton setTarget: self];
7305 [toggleButton setAction: @selector (toggleToolbar: )];
7311 - (instancetype) initFrameFromEmacs: (struct frame *)f
7319 NSTRACE ("[EmacsView initFrameFromEmacs:]");
7320 NSTRACE_MSG ("cols:%d lines:%d", f->text_cols, f->text_lines);
7323 processingCompose = NO;
7324 scrollbarsNeedingUpdate = 0;
7325 fs_state = FULLSCREEN_NONE;
7326 fs_before_fs = next_maximized = -1;
7329 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7330 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7331 if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7333 fs_is_native = ns_use_native_fullscreen;
7336 maximized_width = maximized_height = -1;
7339 ns_userRect = NSMakeRect (0, 0, 0, 0);
7340 r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
7341 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
7342 [self initWithFrame: r];
7343 [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
7345 FRAME_NS_VIEW (f) = self;
7347 #ifdef NS_IMPL_COCOA
7349 maximizing_resize = NO;
7352 win = [[EmacsWindow alloc]
7353 initWithContentRect: r
7354 styleMask: (FRAME_UNDECORATED (f)
7355 ? FRAME_UNDECORATED_FLAGS
7356 : FRAME_DECORATED_FLAGS)
7357 backing: NSBackingStoreBuffered
7360 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7361 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7362 if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7364 [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
7368 bwidth = f->border_width = wr.size.width - r.size.width;
7370 [win setAcceptsMouseMovedEvents: YES];
7371 [win setDelegate: self];
7372 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7373 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7374 if ([win respondsToSelector: @selector(useOptimizedDrawing:)])
7376 [win useOptimizedDrawing: YES];
7379 [[win contentView] addSubview: self];
7382 [self registerForDraggedTypes: ns_drag_types];
7385 name = [NSString stringWithUTF8String:
7386 NILP (tem) ? "Emacs" : SSDATA (tem)];
7387 [win setTitle: name];
7389 /* toolbar support */
7390 if (! FRAME_UNDECORATED (f))
7391 [self createToolbar: f];
7393 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
7394 #ifndef NSAppKitVersionNumber10_10
7395 #define NSAppKitVersionNumber10_10 1343
7398 if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_10
7399 && FRAME_NS_APPEARANCE (f) != ns_appearance_aqua)
7400 win.appearance = [NSAppearance
7401 appearanceNamed: NSAppearanceNameVibrantDark];
7404 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
7405 if ([win respondsToSelector: @selector(titlebarAppearsTransparent)])
7406 win.titlebarAppearsTransparent = FRAME_NS_TRANSPARENT_TITLEBAR (f);
7411 [win setMiniwindowTitle:
7412 [NSString stringWithUTF8String: SSDATA (tem)]];
7414 if (FRAME_PARENT_FRAME (f) != NULL)
7416 NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
7417 [parent addChildWindow: win
7418 ordered: NSWindowAbove];
7421 if (FRAME_Z_GROUP (f) != z_group_none)
7422 win.level = NSNormalWindowLevel
7423 + (FRAME_Z_GROUP_BELOW (f) ? -1 : 1);
7426 NSScreen *screen = [win screen];
7430 NSPoint pt = NSMakePoint
7431 (IN_BOUND (-SCREENMAX, f->left_pos
7432 + NS_PARENT_WINDOW_LEFT_POS (f), SCREENMAX),
7433 IN_BOUND (-SCREENMAX,
7434 NS_PARENT_WINDOW_TOP_POS (f) - f->top_pos,
7437 [win setFrameTopLeftPoint: pt];
7439 NSTRACE_RECT ("new frame", [win frame]);
7443 [win makeFirstResponder: self];
7445 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7446 (FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID)),
7448 [win setBackgroundColor: col];
7449 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7450 [win setOpaque: NO];
7452 #if !defined (NS_IMPL_COCOA) \
7453 || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7454 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7455 if ([self respondsToSelector: @selector(allocateGState)])
7457 [self allocateGState];
7459 [NSApp registerServicesMenuSendTypes: ns_send_types
7460 returnTypes: [NSArray array]];
7462 /* macOS Sierra automatically enables tabbed windows. We can't
7463 allow this to be enabled until it's available on a Free system.
7464 Currently it only happens by accident and is buggy anyway. */
7465 #if defined (NS_IMPL_COCOA) \
7466 && MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
7467 #if MAC_OS_X_VERSION_MIN_REQUIRED < 101200
7468 if ([win respondsToSelector: @selector(setTabbingMode:)])
7470 [win setTabbingMode: NSWindowTabbingModeDisallowed];
7478 - (void)windowDidMove: sender
7480 NSWindow *win = [self window];
7481 NSRect r = [win frame];
7482 NSArray *screens = [NSScreen screens];
7483 NSScreen *screen = [screens objectAtIndex: 0];
7485 NSTRACE ("[EmacsView windowDidMove:]");
7487 if (!emacsframe->output_data.ns)
7491 emacsframe->left_pos = r.origin.x - NS_PARENT_WINDOW_LEFT_POS (emacsframe);
7492 emacsframe->top_pos =
7493 NS_PARENT_WINDOW_TOP_POS (emacsframe) - (r.origin.y + r.size.height);
7497 emacs_event->kind = MOVE_FRAME_EVENT;
7498 EV_TRAILER ((id)nil);
7504 /* Called AFTER method below, but before our windowWillResize call there leads
7505 to windowDidResize -> x_set_window_size. Update emacs' notion of frame
7506 location so set_window_size moves the frame. */
7507 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
7509 NSTRACE (("[EmacsView windowShouldZoom:toFrame:" NSTRACE_FMT_RECT "]"
7510 NSTRACE_FMT_RETURN "YES"),
7511 NSTRACE_ARG_RECT (newFrame));
7513 emacsframe->output_data.ns->zooming = 1;
7518 /* Override to do something slightly nonstandard, but nice. First click on
7519 zoom button will zoom vertically. Second will zoom completely. Third
7520 returns to original. */
7521 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
7522 defaultFrame:(NSRect)defaultFrame
7524 // TODO: Rename to "currentFrame" and assign "result" properly in
7526 NSRect result = [sender frame];
7528 NSTRACE (("[EmacsView windowWillUseStandardFrame:defaultFrame:"
7529 NSTRACE_FMT_RECT "]"),
7530 NSTRACE_ARG_RECT (defaultFrame));
7531 NSTRACE_FSTYPE ("fs_state", fs_state);
7532 NSTRACE_FSTYPE ("fs_before_fs", fs_before_fs);
7533 NSTRACE_FSTYPE ("next_maximized", next_maximized);
7534 NSTRACE_RECT ("ns_userRect", ns_userRect);
7535 NSTRACE_RECT ("[sender frame]", [sender frame]);
7537 if (fs_before_fs != -1) /* Entering fullscreen */
7539 NSTRACE_MSG ("Entering fullscreen");
7540 result = defaultFrame;
7544 // Save the window size and position (frame) before the resize.
7545 if (fs_state != FULLSCREEN_MAXIMIZED
7546 && fs_state != FULLSCREEN_WIDTH)
7548 ns_userRect.size.width = result.size.width;
7549 ns_userRect.origin.x = result.origin.x;
7552 if (fs_state != FULLSCREEN_MAXIMIZED
7553 && fs_state != FULLSCREEN_HEIGHT)
7555 ns_userRect.size.height = result.size.height;
7556 ns_userRect.origin.y = result.origin.y;
7559 NSTRACE_RECT ("ns_userRect (2)", ns_userRect);
7561 if (next_maximized == FULLSCREEN_HEIGHT
7562 || (next_maximized == -1
7563 && abs ((int)(defaultFrame.size.height - result.size.height))
7564 > FRAME_LINE_HEIGHT (emacsframe)))
7567 NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7568 maximized_height = result.size.height = defaultFrame.size.height;
7569 maximized_width = -1;
7570 result.origin.y = defaultFrame.origin.y;
7571 if (ns_userRect.size.height != 0)
7573 result.origin.x = ns_userRect.origin.x;
7574 result.size.width = ns_userRect.size.width;
7576 [self setFSValue: FULLSCREEN_HEIGHT];
7577 #ifdef NS_IMPL_COCOA
7578 maximizing_resize = YES;
7581 else if (next_maximized == FULLSCREEN_WIDTH)
7583 NSTRACE_MSG ("FULLSCREEN_WIDTH");
7584 maximized_width = result.size.width = defaultFrame.size.width;
7585 maximized_height = -1;
7586 result.origin.x = defaultFrame.origin.x;
7587 if (ns_userRect.size.width != 0)
7589 result.origin.y = ns_userRect.origin.y;
7590 result.size.height = ns_userRect.size.height;
7592 [self setFSValue: FULLSCREEN_WIDTH];
7594 else if (next_maximized == FULLSCREEN_MAXIMIZED
7595 || (next_maximized == -1
7596 && abs ((int)(defaultFrame.size.width - result.size.width))
7597 > FRAME_COLUMN_WIDTH (emacsframe)))
7599 NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7601 result = defaultFrame; /* second click */
7602 maximized_width = result.size.width;
7603 maximized_height = result.size.height;
7604 [self setFSValue: FULLSCREEN_MAXIMIZED];
7605 #ifdef NS_IMPL_COCOA
7606 maximizing_resize = YES;
7612 NSTRACE_MSG ("Restore");
7613 result = ns_userRect.size.height ? ns_userRect : result;
7614 NSTRACE_RECT ("restore (2)", result);
7615 ns_userRect = NSMakeRect (0, 0, 0, 0);
7616 #ifdef NS_IMPL_COCOA
7617 maximizing_resize = fs_state != FULLSCREEN_NONE;
7619 [self setFSValue: FULLSCREEN_NONE];
7620 maximized_width = maximized_height = -1;
7624 if (fs_before_fs == -1) next_maximized = -1;
7626 NSTRACE_RECT ("Final ns_userRect", ns_userRect);
7627 NSTRACE_MSG ("Final maximized_width: %d", maximized_width);
7628 NSTRACE_MSG ("Final maximized_height: %d", maximized_height);
7629 NSTRACE_FSTYPE ("Final next_maximized", next_maximized);
7631 [self windowWillResize: sender toSize: result.size];
7633 NSTRACE_RETURN_RECT (result);
7639 - (void)windowDidDeminiaturize: sender
7641 NSTRACE ("[EmacsView windowDidDeminiaturize:]");
7642 if (!emacsframe->output_data.ns)
7645 SET_FRAME_ICONIFIED (emacsframe, 0);
7646 SET_FRAME_VISIBLE (emacsframe, 1);
7647 windows_or_buffers_changed = 63;
7651 emacs_event->kind = DEICONIFY_EVENT;
7652 EV_TRAILER ((id)nil);
7657 - (void)windowDidExpose: sender
7659 NSTRACE ("[EmacsView windowDidExpose:]");
7660 if (!emacsframe->output_data.ns)
7663 SET_FRAME_VISIBLE (emacsframe, 1);
7664 SET_FRAME_GARBAGED (emacsframe);
7666 if (send_appdefined)
7667 ns_send_appdefined (-1);
7671 - (void)windowDidMiniaturize: sender
7673 NSTRACE ("[EmacsView windowDidMiniaturize:]");
7674 if (!emacsframe->output_data.ns)
7677 SET_FRAME_ICONIFIED (emacsframe, 1);
7678 SET_FRAME_VISIBLE (emacsframe, 0);
7682 emacs_event->kind = ICONIFY_EVENT;
7683 EV_TRAILER ((id)nil);
7687 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7688 - (NSApplicationPresentationOptions)window:(NSWindow *)window
7689 willUseFullScreenPresentationOptions:
7690 (NSApplicationPresentationOptions)proposedOptions
7692 return proposedOptions|NSApplicationPresentationAutoHideToolbar;
7696 - (void)windowWillEnterFullScreen:(NSNotification *)notification
7698 NSTRACE ("[EmacsView windowWillEnterFullScreen:]");
7699 [self windowWillEnterFullScreen];
7701 - (void)windowWillEnterFullScreen /* provided for direct calls */
7703 NSTRACE ("[EmacsView windowWillEnterFullScreen]");
7704 fs_before_fs = fs_state;
7707 - (void)windowDidEnterFullScreen:(NSNotification *)notification
7709 NSTRACE ("[EmacsView windowDidEnterFullScreen:]");
7710 [self windowDidEnterFullScreen];
7713 - (void)windowDidEnterFullScreen /* provided for direct calls */
7715 NSTRACE ("[EmacsView windowDidEnterFullScreen]");
7716 [self setFSValue: FULLSCREEN_BOTH];
7717 if (! [self fsIsNative])
7719 [self windowDidBecomeKey];
7720 [nonfs_window orderOut:self];
7724 BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
7725 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 \
7726 && MAC_OS_X_VERSION_MIN_REQUIRED <= 1070
7727 unsigned val = (unsigned)[NSApp presentationOptions];
7729 // Mac OS X 10.7 bug fix, the menu won't appear without this.
7730 // val is non-zero on other macOS versions.
7733 NSApplicationPresentationOptions options
7734 = NSApplicationPresentationAutoHideDock
7735 | NSApplicationPresentationAutoHideMenuBar
7736 | NSApplicationPresentationFullScreen
7737 | NSApplicationPresentationAutoHideToolbar;
7739 [NSApp setPresentationOptions: options];
7742 [toolbar setVisible:tbar_visible];
7746 - (void)windowWillExitFullScreen:(NSNotification *)notification
7748 NSTRACE ("[EmacsView windowWillExitFullScreen:]");
7749 [self windowWillExitFullScreen];
7752 - (void)windowWillExitFullScreen /* provided for direct calls */
7754 NSTRACE ("[EmacsView windowWillExitFullScreen]");
7755 if (!FRAME_LIVE_P (emacsframe))
7757 NSTRACE_MSG ("Ignored (frame dead)");
7760 if (next_maximized != -1)
7761 fs_before_fs = next_maximized;
7764 - (void)windowDidExitFullScreen:(NSNotification *)notification
7766 NSTRACE ("[EmacsView windowDidExitFullScreen:]");
7767 [self windowDidExitFullScreen];
7770 - (void)windowDidExitFullScreen /* provided for direct calls */
7772 NSTRACE ("[EmacsView windowDidExitFullScreen]");
7773 if (!FRAME_LIVE_P (emacsframe))
7775 NSTRACE_MSG ("Ignored (frame dead)");
7778 [self setFSValue: fs_before_fs];
7780 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7781 [self updateCollectionBehavior];
7783 if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
7785 [toolbar setVisible:YES];
7786 update_frame_tool_bar (emacsframe);
7787 [self updateFrameSize:YES];
7788 [[self window] display];
7791 [toolbar setVisible:NO];
7793 if (next_maximized != -1)
7794 [[self window] performZoom:self];
7799 return fs_is_native;
7802 - (BOOL)isFullscreen
7808 res = (nonfs_window != nil);
7812 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7813 res = (([[self window] styleMask] & NSWindowStyleMaskFullScreen) != 0);
7819 NSTRACE ("[EmacsView isFullscreen] " NSTRACE_FMT_RETURN " %d",
7825 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7826 - (void)updateCollectionBehavior
7828 NSTRACE ("[EmacsView updateCollectionBehavior]");
7830 if (! [self isFullscreen])
7832 NSWindow *win = [self window];
7833 NSWindowCollectionBehavior b = [win collectionBehavior];
7834 if (ns_use_native_fullscreen)
7835 b |= NSWindowCollectionBehaviorFullScreenPrimary;
7837 b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
7839 [win setCollectionBehavior: b];
7840 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7841 if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7843 fs_is_native = ns_use_native_fullscreen;
7848 - (void)toggleFullScreen: (id)sender
7856 NSTRACE ("[EmacsView toggleFullScreen:]");
7860 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7861 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7862 if ([[self window] respondsToSelector: @selector(toggleFullScreen:)])
7864 [[self window] toggleFullScreen:sender];
7870 onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
7873 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7874 (FACE_FROM_ID (f, DEFAULT_FACE_ID)),
7877 if (fs_state != FULLSCREEN_BOTH)
7879 NSScreen *screen = [w screen];
7881 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
7882 /* Hide ghost menu bar on secondary monitor? */
7884 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
7885 && [NSScreen respondsToSelector: @selector(screensHaveSeparateSpaces)]
7888 onFirstScreen = [NSScreen screensHaveSeparateSpaces];
7890 /* Hide dock and menubar if we are on the primary screen. */
7893 #ifdef NS_IMPL_COCOA
7894 NSApplicationPresentationOptions options
7895 = NSApplicationPresentationAutoHideDock
7896 | NSApplicationPresentationAutoHideMenuBar;
7898 [NSApp setPresentationOptions: options];
7900 [NSMenu setMenuBarVisible:NO];
7904 fw = [[EmacsFSWindow alloc]
7905 initWithContentRect:[w contentRectForFrameRect:wr]
7906 styleMask:NSWindowStyleMaskBorderless
7907 backing:NSBackingStoreBuffered
7911 [fw setContentView:[w contentView]];
7912 [fw setTitle:[w title]];
7913 [fw setDelegate:self];
7914 [fw setAcceptsMouseMovedEvents: YES];
7915 #if !defined (NS_IMPL_COCOA) \
7916 || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7917 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7918 if ([fw respondsToSelector: @selector(useOptimizedDrawing:)])
7920 [fw useOptimizedDrawing: YES];
7922 [fw setBackgroundColor: col];
7923 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7926 f->border_width = 0;
7930 [self windowWillEnterFullScreen];
7931 [fw makeKeyAndOrderFront:NSApp];
7932 [fw makeFirstResponder:self];
7934 r = [fw frameRectForContentRect:[screen frame]];
7935 [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
7936 [self windowDidEnterFullScreen];
7947 #ifdef NS_IMPL_COCOA
7948 [NSApp setPresentationOptions: NSApplicationPresentationDefault];
7950 [NSMenu setMenuBarVisible:YES];
7954 [w setContentView:[fw contentView]];
7955 [w setBackgroundColor: col];
7956 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7959 f->border_width = bwidth;
7961 // To do: consider using [NSNotificationCenter postNotificationName:] to
7962 // send notifications.
7964 [self windowWillExitFullScreen];
7965 [fw setFrame: [w frame] display:YES animate:ns_use_fullscreen_animation];
7967 [w makeKeyAndOrderFront:NSApp];
7968 [self windowDidExitFullScreen];
7969 [self updateFrameSize:YES];
7975 NSTRACE ("[EmacsView handleFS]");
7977 if (fs_state != emacsframe->want_fullscreen)
7979 if (fs_state == FULLSCREEN_BOTH)
7981 NSTRACE_MSG ("fs_state == FULLSCREEN_BOTH");
7982 [self toggleFullScreen:self];
7985 switch (emacsframe->want_fullscreen)
7987 case FULLSCREEN_BOTH:
7988 NSTRACE_MSG ("FULLSCREEN_BOTH");
7989 [self toggleFullScreen:self];
7991 case FULLSCREEN_WIDTH:
7992 NSTRACE_MSG ("FULLSCREEN_WIDTH");
7993 next_maximized = FULLSCREEN_WIDTH;
7994 if (fs_state != FULLSCREEN_BOTH)
7995 [[self window] performZoom:self];
7997 case FULLSCREEN_HEIGHT:
7998 NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7999 next_maximized = FULLSCREEN_HEIGHT;
8000 if (fs_state != FULLSCREEN_BOTH)
8001 [[self window] performZoom:self];
8003 case FULLSCREEN_MAXIMIZED:
8004 NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
8005 next_maximized = FULLSCREEN_MAXIMIZED;
8006 if (fs_state != FULLSCREEN_BOTH)
8007 [[self window] performZoom:self];
8009 case FULLSCREEN_NONE:
8010 NSTRACE_MSG ("FULLSCREEN_NONE");
8011 if (fs_state != FULLSCREEN_BOTH)
8013 next_maximized = FULLSCREEN_NONE;
8014 [[self window] performZoom:self];
8019 emacsframe->want_fullscreen = FULLSCREEN_NONE;
8024 - (void) setFSValue: (int)value
8026 NSTRACE ("[EmacsView setFSValue:" NSTRACE_FMT_FSTYPE "]",
8027 NSTRACE_ARG_FSTYPE(value));
8029 Lisp_Object lval = Qnil;
8032 case FULLSCREEN_BOTH:
8035 case FULLSCREEN_WIDTH:
8038 case FULLSCREEN_HEIGHT:
8041 case FULLSCREEN_MAXIMIZED:
8045 store_frame_param (emacsframe, Qfullscreen, lval);
8049 - (void)mouseEntered: (NSEvent *)theEvent
8051 NSTRACE ("[EmacsView mouseEntered:]");
8053 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
8054 = EV_TIMESTAMP (theEvent);
8058 - (void)mouseExited: (NSEvent *)theEvent
8060 Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
8062 NSTRACE ("[EmacsView mouseExited:]");
8067 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
8068 = EV_TIMESTAMP (theEvent);
8070 if (emacsframe == hlinfo->mouse_face_mouse_frame)
8072 clear_mouse_face (hlinfo);
8073 hlinfo->mouse_face_mouse_frame = 0;
8078 - (instancetype)menuDown: sender
8080 NSTRACE ("[EmacsView menuDown:]");
8081 if (context_menu_value == -1)
8082 context_menu_value = [sender tag];
8085 NSInteger tag = [sender tag];
8086 find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
8087 emacsframe->menu_bar_vector,
8091 ns_send_appdefined (-1);
8096 - (EmacsToolbar *)toolbar
8102 /* This gets called on toolbar button click. */
8103 - (instancetype)toolbarClicked: (id)item
8106 int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
8108 NSTRACE ("[EmacsView toolbarClicked:]");
8113 /* Send first event (for some reason two needed). */
8114 theEvent = [[self window] currentEvent];
8115 emacs_event->kind = TOOL_BAR_EVENT;
8116 XSETFRAME (emacs_event->arg, emacsframe);
8117 EV_TRAILER (theEvent);
8119 emacs_event->kind = TOOL_BAR_EVENT;
8120 /* XSETINT (emacs_event->code, 0); */
8121 emacs_event->arg = AREF (emacsframe->tool_bar_items,
8122 idx + TOOL_BAR_ITEM_KEY);
8123 emacs_event->modifiers = EV_MODIFIERS (theEvent);
8124 EV_TRAILER (theEvent);
8129 - (instancetype)toggleToolbar: (id)sender
8131 NSTRACE ("[EmacsView toggleToolbar:]");
8136 emacs_event->kind = NS_NONKEY_EVENT;
8137 emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
8138 EV_TRAILER ((id)nil);
8143 - (void)drawRect: (NSRect)rect
8145 int x = NSMinX (rect), y = NSMinY (rect);
8146 int width = NSWidth (rect), height = NSHeight (rect);
8148 NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
8149 NSTRACE_ARG_RECT(rect));
8151 if (!emacsframe || !emacsframe->output_data.ns)
8154 ns_clear_frame_area (emacsframe, x, y, width, height);
8156 expose_frame (emacsframe, x, y, width, height);
8160 drawRect: may be called (at least in Mac OS X 10.5) for invisible
8161 views as well for some reason. Thus, do not infer visibility
8164 emacsframe->async_visible = 1;
8165 emacsframe->async_iconified = 0;
8170 /* NSDraggingDestination protocol methods. Actually this is not really a
8171 protocol, but a category of Object. O well... */
8173 -(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
8175 NSTRACE ("[EmacsView draggingEntered:]");
8176 return NSDragOperationGeneric;
8180 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
8186 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
8191 NSEvent *theEvent = [[self window] currentEvent];
8193 NSDragOperation op = [sender draggingSourceOperationMask];
8196 NSTRACE ("[EmacsView performDragOperation:]");
8201 position = [self convertPoint: [sender draggingLocation] fromView: nil];
8202 x = lrint (position.x); y = lrint (position.y);
8204 pb = [sender draggingPasteboard];
8205 type = [pb availableTypeFromArray: ns_drag_types];
8207 if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
8208 // URL drags contain all operations (0xf), don't allow all to be set.
8211 if (op & NSDragOperationLink)
8212 modifiers |= NSEventModifierFlagControl;
8213 if (op & NSDragOperationCopy)
8214 modifiers |= NSEventModifierFlagOption;
8215 if (op & NSDragOperationGeneric)
8216 modifiers |= NSEventModifierFlagCommand;
8219 modifiers = EV_MODIFIERS2 (modifiers);
8224 else if ([type isEqualToString: NSFilenamesPboardType])
8227 NSEnumerator *fenum;
8230 if (!(files = [pb propertyListForType: type]))
8233 fenum = [files objectEnumerator];
8234 while ( (file = [fenum nextObject]) )
8236 emacs_event->kind = DRAG_N_DROP_EVENT;
8237 XSETINT (emacs_event->x, x);
8238 XSETINT (emacs_event->y, y);
8239 emacs_event->modifiers = modifiers;
8240 emacs_event->arg = list2 (Qfile, build_string ([file UTF8String]));
8241 EV_TRAILER (theEvent);
8245 else if ([type isEqualToString: NSURLPboardType])
8247 NSURL *url = [NSURL URLFromPasteboard: pb];
8248 if (url == nil) return NO;
8250 emacs_event->kind = DRAG_N_DROP_EVENT;
8251 XSETINT (emacs_event->x, x);
8252 XSETINT (emacs_event->y, y);
8253 emacs_event->modifiers = modifiers;
8254 emacs_event->arg = list2 (Qurl,
8255 build_string ([[url absoluteString]
8257 EV_TRAILER (theEvent);
8259 if ([url isFileURL] != NO)
8261 NSString *file = [url path];
8262 ns_input_file = append2 (ns_input_file,
8263 build_string ([file UTF8String]));
8267 else if ([type isEqualToString: NSStringPboardType]
8268 || [type isEqualToString: NSTabularTextPboardType])
8272 if (! (data = [pb stringForType: type]))
8275 emacs_event->kind = DRAG_N_DROP_EVENT;
8276 XSETINT (emacs_event->x, x);
8277 XSETINT (emacs_event->y, y);
8278 emacs_event->modifiers = modifiers;
8279 emacs_event->arg = list2 (Qnil, build_string ([data UTF8String]));
8280 EV_TRAILER (theEvent);
8285 fprintf (stderr, "Invalid data type in dragging pasteboard");
8291 - (id) validRequestorForSendType: (NSString *)typeSent
8292 returnType: (NSString *)typeReturned
8294 NSTRACE ("[EmacsView validRequestorForSendType:returnType:]");
8295 if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
8296 && typeReturned == nil)
8298 if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
8302 return [super validRequestorForSendType: typeSent
8303 returnType: typeReturned];
8307 /* The next two methods are part of NSServicesRequests informal protocol,
8308 supposedly called when a services menu item is chosen from this app.
8309 But this should not happen because we override the services menu with our
8310 own entries which call ns-perform-service.
8311 Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
8312 So let's at least stub them out until further investigation can be done. */
8314 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
8316 /* We could call ns_string_from_pasteboard(pboard) here but then it should
8317 be written into the buffer in place of the existing selection.
8318 Ordinary service calls go through functions defined in ns-win.el. */
8322 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
8324 NSArray *typesDeclared;
8327 NSTRACE ("[EmacsView writeSelectionToPasteboard:types:]");
8329 /* We only support NSStringPboardType. */
8330 if ([types containsObject:NSStringPboardType] == NO) {
8334 val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8335 if (CONSP (val) && SYMBOLP (XCAR (val)))
8338 if (CONSP (val) && NILP (XCDR (val)))
8341 if (! STRINGP (val))
8344 typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
8345 [pb declareTypes:typesDeclared owner:nil];
8346 ns_string_to_pasteboard (pb, val);
8351 /* setMini = YES means set from internal (gives a finder icon), NO means set nil
8352 (gives a miniaturized version of the window); currently we use the latter for
8353 frames whose active buffer doesn't correspond to any file
8354 (e.g., '*scratch*'). */
8355 - (instancetype)setMiniwindowImage: (BOOL) setMini
8357 id image = [[self window] miniwindowImage];
8358 NSTRACE ("[EmacsView setMiniwindowImage:%d]", setMini);
8360 /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
8361 about "AppleDockIconEnabled" notwithstanding, however the set message
8362 below has its effect nonetheless. */
8363 if (image != emacsframe->output_data.ns->miniimage)
8365 if (image && [image isKindOfClass: [EmacsImage class]])
8367 [[self window] setMiniwindowImage:
8368 setMini ? emacsframe->output_data.ns->miniimage : nil];
8375 - (void) setRows: (int) r andColumns: (int) c
8377 NSTRACE ("[EmacsView setRows:%d andColumns:%d]", r, c);
8382 - (int) fullscreenState
8387 @end /* EmacsView */
8391 /* ==========================================================================
8393 EmacsWindow implementation
8395 ========================================================================== */
8397 @implementation EmacsWindow
8399 #ifdef NS_IMPL_COCOA
8400 - (id)accessibilityAttributeValue:(NSString *)attribute
8402 Lisp_Object str = Qnil;
8403 struct frame *f = SELECTED_FRAME ();
8404 struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
8406 NSTRACE ("[EmacsWindow accessibilityAttributeValue:]");
8408 if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
8409 return NSAccessibilityTextFieldRole;
8411 if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
8412 && curbuf && ! NILP (BVAR (curbuf, mark_active)))
8414 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8416 else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
8418 if (! NILP (BVAR (curbuf, mark_active)))
8419 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8423 ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
8424 ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
8425 ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
8427 if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
8428 str = make_uninit_multibyte_string (range, byte_range);
8430 str = make_uninit_string (range);
8431 /* To check: This returns emacs-utf-8, which is a superset of utf-8.
8432 Is this a problem? */
8433 memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
8440 if (CONSP (str) && SYMBOLP (XCAR (str)))
8443 if (CONSP (str) && NILP (XCDR (str)))
8448 const char *utfStr = SSDATA (str);
8449 NSString *nsStr = [NSString stringWithUTF8String: utfStr];
8454 return [super accessibilityAttributeValue:attribute];
8456 #endif /* NS_IMPL_COCOA */
8458 /* Constrain size and placement of a frame.
8460 By returning the original "frameRect", the frame is not
8461 constrained. This can lead to unwanted situations where, for
8462 example, the menu bar covers the frame.
8464 The default implementation (accessed using "super") constrains the
8465 frame to the visible area of SCREEN, minus the menu bar (if
8466 present) and the Dock. Note that default implementation also calls
8467 windowWillResize, with the frame it thinks should have. (This can
8468 make the frame exit maximized mode.)
8470 Note that this should work in situations where multiple monitors
8471 are present. Common configurations are side-by-side monitors and a
8472 monitor on top of another (e.g. when a laptop is placed under a
8474 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
8476 NSTRACE ("[EmacsWindow constrainFrameRect:" NSTRACE_FMT_RECT " toScreen:]",
8477 NSTRACE_ARG_RECT (frameRect));
8479 #ifdef NS_IMPL_COCOA
8480 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
8481 // If separate spaces is on, it is like each screen is independent. There is
8482 // no spanning of frames across screens.
8484 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
8485 [NSScreen respondsToSelector: @selector(screensHaveSeparateSpaces)] &&
8487 [NSScreen screensHaveSeparateSpaces])
8489 NSTRACE_MSG ("Screens have separate spaces");
8490 frameRect = [super constrainFrameRect:frameRect toScreen:screen];
8491 NSTRACE_RETURN_RECT (frameRect);
8495 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 */
8497 // Check that the proposed frameRect is visible in at least one
8498 // screen. If it is not, ask the system to reposition it (only
8499 // for non-child windows).
8501 if (!FRAME_PARENT_FRAME (((EmacsView *)[self delegate])->emacsframe))
8503 NSArray *screens = [NSScreen screens];
8504 NSUInteger nr_screens = [screens count];
8507 BOOL frame_on_screen = NO;
8509 for (i = 0; i < nr_screens; ++i)
8511 NSScreen *s = [screens objectAtIndex: i];
8512 NSRect scrRect = [s frame];
8514 if (NSIntersectsRect(frameRect, scrRect))
8516 frame_on_screen = YES;
8521 if (!frame_on_screen)
8523 NSTRACE_MSG ("Frame outside screens; constraining");
8524 frameRect = [super constrainFrameRect:frameRect toScreen:screen];
8525 NSTRACE_RETURN_RECT (frameRect);
8531 return constrain_frame_rect(frameRect,
8532 [(EmacsView *)[self delegate] isFullscreen]);
8536 - (void)performZoom:(id)sender
8538 NSTRACE ("[EmacsWindow performZoom:]");
8540 return [super performZoom:sender];
8543 - (void)zoom:(id)sender
8545 NSTRACE ("[EmacsWindow zoom:]");
8547 ns_update_auto_hide_menu_bar();
8549 // Below are three zoom implementations. In the final commit, the
8550 // idea is that the last should be included.
8553 // Native zoom done using the standard zoom animation. Size of the
8554 // resulting frame reduced to accommodate the Dock and, if present,
8556 [super zoom:sender];
8559 // Native zoom done using the standard zoom animation, plus an
8560 // explicit resize to cover the full screen, except the menu-bar and
8561 // dock, if present.
8562 [super zoom:sender];
8564 // After the native zoom, resize the resulting frame to fill the
8565 // entire screen, except the menu-bar.
8567 // This works for all practical purposes. (The only minor oddity is
8568 // when transiting from full-height frame to a maximized, the
8569 // animation reduces the height of the frame slightly (to the 4
8570 // pixels needed to accommodate the Doc) before it snaps back into
8571 // full height. The user would need a very trained eye to spot
8573 NSScreen * screen = [self screen];
8576 int fs_state = [(EmacsView *)[self delegate] fullscreenState];
8578 NSTRACE_FSTYPE ("fullscreenState", fs_state);
8580 NSRect sr = [screen frame];
8581 struct EmacsMargins margins
8582 = ns_screen_margins_ignoring_hidden_dock(screen);
8584 NSRect wr = [self frame];
8585 NSTRACE_RECT ("Rect after zoom", wr);
8589 if (fs_state == FULLSCREEN_MAXIMIZED
8590 || fs_state == FULLSCREEN_HEIGHT)
8592 newWr.origin.y = sr.origin.y + margins.bottom;
8593 newWr.size.height = sr.size.height - margins.top - margins.bottom;
8596 if (fs_state == FULLSCREEN_MAXIMIZED
8597 || fs_state == FULLSCREEN_WIDTH)
8599 newWr.origin.x = sr.origin.x + margins.left;
8600 newWr.size.width = sr.size.width - margins.right - margins.left;
8603 if (newWr.size.width != wr.size.width
8604 || newWr.size.height != wr.size.height
8605 || newWr.origin.x != wr.origin.x
8606 || newWr.origin.y != wr.origin.y)
8608 NSTRACE_MSG ("New frame different");
8609 [self setFrame: newWr display: NO];
8613 // Non-native zoom which is done instantaneously. The resulting
8614 // frame covers the entire screen, except the menu-bar and dock, if
8616 NSScreen * screen = [self screen];
8619 NSRect sr = [screen frame];
8620 struct EmacsMargins margins
8621 = ns_screen_margins_ignoring_hidden_dock(screen);
8623 sr.size.height -= (margins.top + margins.bottom);
8624 sr.size.width -= (margins.left + margins.right);
8625 sr.origin.x += margins.left;
8626 sr.origin.y += margins.bottom;
8628 sr = [[self delegate] windowWillUseStandardFrame:self
8630 [self setFrame: sr display: NO];
8635 - (void)setFrame:(NSRect)windowFrame
8636 display:(BOOL)displayViews
8638 NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT " display:%d]",
8639 NSTRACE_ARG_RECT (windowFrame), displayViews);
8641 [super setFrame:windowFrame display:displayViews];
8644 - (void)setFrame:(NSRect)windowFrame
8645 display:(BOOL)displayViews
8646 animate:(BOOL)performAnimation
8648 NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT
8649 " display:%d performAnimation:%d]",
8650 NSTRACE_ARG_RECT (windowFrame), displayViews, performAnimation);
8652 [super setFrame:windowFrame display:displayViews animate:performAnimation];
8655 - (void)setFrameTopLeftPoint:(NSPoint)point
8657 NSTRACE ("[EmacsWindow setFrameTopLeftPoint:" NSTRACE_FMT_POINT "]",
8658 NSTRACE_ARG_POINT (point));
8660 [super setFrameTopLeftPoint:point];
8663 - (BOOL)canBecomeKeyWindow
8665 return !FRAME_NO_ACCEPT_FOCUS (((EmacsView *)[self delegate])->emacsframe);
8667 @end /* EmacsWindow */
8670 @implementation EmacsFSWindow
8672 - (BOOL)canBecomeKeyWindow
8677 - (BOOL)canBecomeMainWindow
8684 /* ==========================================================================
8686 EmacsScroller implementation
8688 ========================================================================== */
8691 @implementation EmacsScroller
8693 /* for repeat button push */
8694 #define SCROLL_BAR_FIRST_DELAY 0.5
8695 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
8697 + (CGFloat) scrollerWidth
8699 /* TODO: if we want to allow variable widths, this is the place to do it,
8700 however neither GNUstep nor Cocoa support it very well. */
8702 #if defined (NS_IMPL_COCOA) \
8703 && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
8704 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
8705 if ([NSScroller respondsToSelector:
8706 @selector(scrollerWidthForControlSize:scrollerStyle:)])
8708 r = [NSScroller scrollerWidthForControlSize: NSControlSizeRegular
8709 scrollerStyle: NSScrollerStyleLegacy];
8710 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
8713 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
8714 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 \
8715 || defined (NS_IMPL_GNUSTEP)
8716 r = [NSScroller scrollerWidth];
8721 - (instancetype)initFrame: (NSRect )r window: (Lisp_Object)nwin
8723 NSTRACE ("[EmacsScroller initFrame: window:]");
8725 if (r.size.width > r.size.height)
8730 [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
8731 [self setContinuous: YES];
8732 [self setEnabled: YES];
8734 /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
8735 locked against the top and bottom edges, and right edge on macOS, where
8736 scrollers are on right. */
8737 #ifdef NS_IMPL_GNUSTEP
8738 [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
8740 [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
8743 window = XWINDOW (nwin);
8746 pixel_length = NSWidth (r);
8748 pixel_length = NSHeight (r);
8749 if (pixel_length == 0) pixel_length = 1;
8750 min_portion = 20 / pixel_length;
8752 frame = XFRAME (window->frame);
8753 if (FRAME_LIVE_P (frame))
8756 EmacsView *view = FRAME_NS_VIEW (frame);
8757 NSView *sview = [[view window] contentView];
8758 NSArray *subs = [sview subviews];
8760 /* Disable optimization stopping redraw of other scrollbars. */
8761 view->scrollbarsNeedingUpdate = 0;
8762 for (i =[subs count]-1; i >= 0; i--)
8763 if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
8764 view->scrollbarsNeedingUpdate++;
8765 [sview addSubview: self];
8768 /* [self setFrame: r]; */
8774 - (void)setFrame: (NSRect)newRect
8776 NSTRACE ("[EmacsScroller setFrame:]");
8778 /* block_input (); */
8780 pixel_length = NSWidth (newRect);
8782 pixel_length = NSHeight (newRect);
8783 if (pixel_length == 0) pixel_length = 1;
8784 min_portion = 20 / pixel_length;
8785 [super setFrame: newRect];
8786 /* unblock_input (); */
8792 NSTRACE ("[EmacsScroller dealloc]");
8796 wset_horizontal_scroll_bar (window, Qnil);
8798 wset_vertical_scroll_bar (window, Qnil);
8805 - (instancetype)condemn
8807 NSTRACE ("[EmacsScroller condemn]");
8813 - (instancetype)reprieve
8815 NSTRACE ("[EmacsScroller reprieve]");
8823 NSTRACE ("[EmacsScroller judge]");
8824 bool ret = condemned;
8829 /* Ensure other scrollbar updates after deletion. */
8830 view = (EmacsView *)FRAME_NS_VIEW (frame);
8832 view->scrollbarsNeedingUpdate++;
8836 wset_horizontal_scroll_bar (window, Qnil);
8838 wset_vertical_scroll_bar (window, Qnil);
8841 [self removeFromSuperview];
8849 - (void)resetCursorRects
8851 NSRect visible = [self visibleRect];
8852 NSTRACE ("[EmacsScroller resetCursorRects]");
8854 if (!NSIsEmptyRect (visible))
8855 [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
8857 #if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 101300
8858 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101300
8859 if ([[NSCursor arrowCursor] respondsToSelector:
8860 @selector(setOnMouseEntered)])
8862 [[NSCursor arrowCursor] setOnMouseEntered: YES];
8867 - (int) checkSamePosition: (int) position portion: (int) portion
8870 return em_position ==position && em_portion ==portion && em_whole ==whole
8871 && portion != whole; /* Needed for resizing empty buffer. */
8875 - (instancetype)setPosition: (int)position portion: (int)portion whole: (int)whole
8877 NSTRACE ("[EmacsScroller setPosition:portion:whole:]");
8879 em_position = position;
8880 em_portion = portion;
8883 if (portion >= whole)
8885 #ifdef NS_IMPL_COCOA
8886 [self setKnobProportion: 1.0];
8887 [self setDoubleValue: 1.0];
8889 [self setFloatValue: 0.0 knobProportion: 1.0];
8896 portion = max ((float)whole*min_portion/pixel_length, portion);
8897 pos = (float)position / (whole - portion);
8898 por = (CGFloat)portion/whole;
8899 #ifdef NS_IMPL_COCOA
8900 [self setKnobProportion: por];
8901 [self setDoubleValue: pos];
8903 [self setFloatValue: pos knobProportion: por];
8910 /* Set up emacs_event. */
8911 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
8915 NSTRACE ("[EmacsScroller sendScrollEventAtLoc:fromEvent:]");
8920 emacs_event->part = last_hit_part;
8921 emacs_event->code = 0;
8922 emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
8923 XSETWINDOW (win, window);
8924 emacs_event->frame_or_window = win;
8925 emacs_event->timestamp = EV_TIMESTAMP (e);
8926 emacs_event->arg = Qnil;
8930 emacs_event->kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT;
8931 XSETINT (emacs_event->x, em_whole * loc / pixel_length);
8932 XSETINT (emacs_event->y, em_whole);
8936 emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
8937 XSETINT (emacs_event->x, loc);
8938 XSETINT (emacs_event->y, pixel_length-20);
8943 n_emacs_events_pending++;
8944 kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
8947 hold_event (emacs_event);
8948 EVENT_INIT (*emacs_event);
8949 ns_send_appdefined (-1);
8953 /* Called manually through timer to implement repeated button action
8955 - (instancetype)repeatScroll: (NSTimer *)scrollEntry
8957 NSEvent *e = [[self window] currentEvent];
8958 NSPoint p = [[self window] mouseLocationOutsideOfEventStream];
8959 BOOL inKnob = [self testPart: p] == NSScrollerKnob;
8961 NSTRACE ("[EmacsScroller repeatScroll:]");
8963 /* Clear timer if need be. */
8964 if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
8966 [scroll_repeat_entry invalidate];
8967 [scroll_repeat_entry release];
8968 scroll_repeat_entry = nil;
8974 = [[NSTimer scheduledTimerWithTimeInterval:
8975 SCROLL_BAR_CONTINUOUS_DELAY
8977 selector: @selector (repeatScroll:)
8983 [self sendScrollEventAtLoc: 0 fromEvent: e];
8988 /* Asynchronous mouse tracking for scroller. This allows us to dispatch
8989 mouseDragged events without going into a modal loop. */
8990 - (void)mouseDown: (NSEvent *)e
8993 /* hitPart is only updated AFTER event is passed on. */
8994 NSScrollerPart part = [self testPart: [e locationInWindow]];
8995 CGFloat loc, kloc, pos UNINIT;
8998 NSTRACE ("[EmacsScroller mouseDown:]");
9002 case NSScrollerDecrementPage:
9003 last_hit_part = horizontal ? scroll_bar_before_handle : scroll_bar_above_handle; break;
9004 case NSScrollerIncrementPage:
9005 last_hit_part = horizontal ? scroll_bar_after_handle : scroll_bar_below_handle; break;
9006 case NSScrollerDecrementLine:
9007 last_hit_part = horizontal ? scroll_bar_left_arrow : scroll_bar_up_arrow; break;
9008 case NSScrollerIncrementLine:
9009 last_hit_part = horizontal ? scroll_bar_right_arrow : scroll_bar_down_arrow; break;
9010 case NSScrollerKnob:
9011 last_hit_part = horizontal ? scroll_bar_horizontal_handle : scroll_bar_handle; break;
9012 case NSScrollerKnobSlot: /* GNUstep-only */
9013 last_hit_part = scroll_bar_move_ratio; break;
9014 default: /* NSScrollerNoPart? */
9015 fprintf (stderr, "EmacsScroller-mouseDown: unexpected part %ld\n",
9020 if (part == NSScrollerKnob || part == NSScrollerKnobSlot)
9022 /* handle, or on GNUstep possibly slot */
9023 NSEvent *fake_event;
9026 /* compute float loc in slot and mouse offset on knob */
9027 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
9031 length = NSWidth (sr);
9032 loc = ([e locationInWindow].x - NSMinX (sr));
9036 length = NSHeight (sr);
9037 loc = length - ([e locationInWindow].y - NSMinY (sr));
9045 else if (loc >= length)
9055 kr = [self convertRect: [self rectForPart: NSScrollerKnob]
9058 kloc = ([e locationInWindow].x - NSMinX (kr));
9060 kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
9062 last_mouse_offset = kloc;
9064 /* if knob, tell emacs a location offset by knob pos
9065 (to indicate top of handle) */
9066 if (part == NSScrollerKnob)
9067 pos = (loc - last_mouse_offset);
9069 /* else this is a slot click on GNUstep: go straight there */
9072 /* If there are buttons in the scroller area, we need to
9073 recalculate pos as emacs expects the scroller slot to take up
9074 the entire available length. */
9075 if (length != pixel_length)
9076 pos = pos * pixel_length / length;
9078 /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
9079 fake_event = [NSEvent mouseEventWithType: NSEventTypeLeftMouseUp
9080 location: [e locationInWindow]
9081 modifierFlags: [e modifierFlags]
9082 timestamp: [e timestamp]
9083 windowNumber: [e windowNumber]
9085 eventNumber: [e eventNumber]
9086 clickCount: [e clickCount]
9087 pressure: [e pressure]];
9088 [super mouseUp: fake_event];
9092 pos = 0; /* ignored */
9094 /* Set a timer to repeat, as we can't let superclass do this modally. */
9096 = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
9098 selector: @selector (repeatScroll:)
9104 if (part != NSScrollerKnob)
9105 [self sendScrollEventAtLoc: pos fromEvent: e];
9109 /* Called as we manually track scroller drags, rather than superclass. */
9110 - (void)mouseDragged: (NSEvent *)e
9116 NSTRACE ("[EmacsScroller mouseDragged:]");
9118 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
9123 length = NSWidth (sr);
9124 loc = ([e locationInWindow].x - NSMinX (sr));
9128 length = NSHeight (sr);
9129 loc = length - ([e locationInWindow].y - NSMinY (sr));
9136 else if (loc >= length + last_mouse_offset)
9138 loc = length + last_mouse_offset;
9141 pos = (loc - last_mouse_offset);
9143 /* If there are buttons in the scroller area, we need to
9144 recalculate pos as emacs expects the scroller slot to take up
9145 the entire available length. */
9146 if (length != pixel_length)
9147 pos = pos * pixel_length / length;
9149 [self sendScrollEventAtLoc: pos fromEvent: e];
9153 - (void)mouseUp: (NSEvent *)e
9155 NSTRACE ("[EmacsScroller mouseUp:]");
9157 if (scroll_repeat_entry)
9159 [scroll_repeat_entry invalidate];
9160 [scroll_repeat_entry release];
9161 scroll_repeat_entry = nil;
9163 last_hit_part = scroll_bar_above_handle;
9167 /* Treat scrollwheel events in the bar as though they were in the main window. */
9168 - (void) scrollWheel: (NSEvent *)theEvent
9170 NSTRACE ("[EmacsScroller scrollWheel:]");
9172 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
9173 [view mouseDown: theEvent];
9176 @end /* EmacsScroller */
9179 #ifdef NS_IMPL_GNUSTEP
9180 /* Dummy class to get rid of startup warnings. */
9181 @implementation EmacsDocument
9187 /* ==========================================================================
9189 Font-related functions; these used to be in nsfaces.m
9191 ========================================================================== */
9195 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
9197 struct font *font = XFONT_OBJECT (font_object);
9198 EmacsView *view = FRAME_NS_VIEW (f);
9199 int font_ascent, font_descent;
9202 fontset = fontset_from_font (font_object);
9203 FRAME_FONTSET (f) = fontset;
9205 if (FRAME_FONT (f) == font)
9206 /* This font is already set in frame F. There's nothing more to
9210 FRAME_FONT (f) = font;
9212 FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
9213 FRAME_COLUMN_WIDTH (f) = font->average_width;
9214 get_font_ascent_descent (font, &font_ascent, &font_descent);
9215 FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
9217 /* Compute the scroll bar width in character columns. */
9218 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
9220 int wid = FRAME_COLUMN_WIDTH (f);
9221 FRAME_CONFIG_SCROLL_BAR_COLS (f)
9222 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
9226 int wid = FRAME_COLUMN_WIDTH (f);
9227 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
9230 /* Compute the scroll bar height in character lines. */
9231 if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0)
9233 int height = FRAME_LINE_HEIGHT (f);
9234 FRAME_CONFIG_SCROLL_BAR_LINES (f)
9235 = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
9239 int height = FRAME_LINE_HEIGHT (f);
9240 FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
9243 /* Now make the frame display the given font. */
9244 if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
9245 adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
9246 FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
9253 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
9254 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
9258 ns_xlfd_to_fontname (const char *xlfd)
9259 /* --------------------------------------------------------------------------
9260 Convert an X font name (XLFD) to an NS font name.
9261 Only family is used.
9262 The string returned is temporarily allocated.
9263 -------------------------------------------------------------------------- */
9265 char *name = xmalloc (180);
9269 if (!strncmp (xlfd, "--", 2))
9270 sscanf (xlfd, "--%*[^-]-%179[^-]-", name);
9272 sscanf (xlfd, "-%*[^-]-%179[^-]-", name);
9274 /* stopgap for malformed XLFD input */
9275 if (strlen (name) == 0)
9276 strcpy (name, "Monaco");
9278 /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
9279 also uppercase after '-' or ' ' */
9280 name[0] = c_toupper (name[0]);
9281 for (len =strlen (name), i =0; i<len; i++)
9287 name[i+1] = c_toupper (name[i+1]);
9289 else if (name[i] == '_')
9293 name[i+1] = c_toupper (name[i+1]);
9296 /* fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name); */
9297 ret = [[NSString stringWithUTF8String: name] UTF8String];
9304 syms_of_nsterm (void)
9306 NSTRACE ("syms_of_nsterm");
9308 ns_antialias_threshold = 10.0;
9310 /* From 23+ we need to tell emacs what modifiers there are. */
9311 DEFSYM (Qmodifier_value, "modifier-value");
9312 DEFSYM (Qalt, "alt");
9313 DEFSYM (Qhyper, "hyper");
9314 DEFSYM (Qmeta, "meta");
9315 DEFSYM (Qsuper, "super");
9316 DEFSYM (Qcontrol, "control");
9317 DEFSYM (QUTF8_STRING, "UTF8_STRING");
9319 DEFSYM (Qfile, "file");
9320 DEFSYM (Qurl, "url");
9322 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
9323 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
9324 Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
9325 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
9326 Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
9328 DEFVAR_LISP ("ns-input-file", ns_input_file,
9329 "The file specified in the last NS event.");
9330 ns_input_file =Qnil;
9332 DEFVAR_LISP ("ns-working-text", ns_working_text,
9333 "String for visualizing working composition sequence.");
9334 ns_working_text =Qnil;
9336 DEFVAR_LISP ("ns-input-font", ns_input_font,
9337 "The font specified in the last NS event.");
9338 ns_input_font =Qnil;
9340 DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
9341 "The fontsize specified in the last NS event.");
9342 ns_input_fontsize =Qnil;
9344 DEFVAR_LISP ("ns-input-line", ns_input_line,
9345 "The line specified in the last NS event.");
9346 ns_input_line =Qnil;
9348 DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
9349 "The service name specified in the last NS event.");
9350 ns_input_spi_name =Qnil;
9352 DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
9353 "The service argument specified in the last NS event.");
9354 ns_input_spi_arg =Qnil;
9356 DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
9357 "This variable describes the behavior of the alternate or option key.\n\
9358 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9360 Set to none means that the alternate / option key is not interpreted by Emacs\n\
9361 at all, allowing it to be used at a lower level for accented character entry.");
9362 ns_alternate_modifier = Qmeta;
9364 DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
9365 "This variable describes the behavior of the right alternate or option key.\n\
9366 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9368 Set to left means be the same key as `ns-alternate-modifier'.\n\
9369 Set to none means that the alternate / option key is not interpreted by Emacs\n\
9370 at all, allowing it to be used at a lower level for accented character entry.");
9371 ns_right_alternate_modifier = Qleft;
9373 DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
9374 "This variable describes the behavior of the command key.\n\
9375 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9377 ns_command_modifier = Qsuper;
9379 DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
9380 "This variable describes the behavior of the right command key.\n\
9381 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9383 Set to left means be the same key as `ns-command-modifier'.\n\
9384 Set to none means that the command / option key is not interpreted by Emacs\n\
9385 at all, allowing it to be used at a lower level for accented character entry.");
9386 ns_right_command_modifier = Qleft;
9388 DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
9389 "This variable describes the behavior of the control key.\n\
9390 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9392 ns_control_modifier = Qcontrol;
9394 DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
9395 "This variable describes the behavior of the right control key.\n\
9396 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9398 Set to left means be the same key as `ns-control-modifier'.\n\
9399 Set to none means that the control / option key is not interpreted by Emacs\n\
9400 at all, allowing it to be used at a lower level for accented character entry.");
9401 ns_right_control_modifier = Qleft;
9403 DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
9404 "This variable describes the behavior of the function key (on laptops).\n\
9405 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9407 Set to none means that the function key is not interpreted by Emacs at all,\n\
9408 allowing it to be used at a lower level for accented character entry.");
9409 ns_function_modifier = Qnone;
9411 DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
9412 "Non-nil (the default) means to render text antialiased.");
9413 ns_antialias_text = Qt;
9415 DEFVAR_LISP ("ns-use-thin-smoothing", ns_use_thin_smoothing,
9416 "Non-nil turns on a font smoothing method that produces thinner strokes.");
9417 ns_use_thin_smoothing = Qnil;
9419 DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
9420 "Whether to confirm application quit using dialog.");
9421 ns_confirm_quit = Qnil;
9423 DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
9424 doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
9425 Only works on Mac OS X. */);
9426 ns_auto_hide_menu_bar = Qnil;
9428 DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
9429 doc: /* Non-nil means to use native fullscreen on Mac OS X 10.7 and later.
9430 Nil means use fullscreen the old (< 10.7) way. The old way works better with
9431 multiple monitors, but lacks tool bar. This variable is ignored on
9432 Mac OS X < 10.7. Default is t. */);
9433 ns_use_native_fullscreen = YES;
9434 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
9436 DEFVAR_BOOL ("ns-use-fullscreen-animation", ns_use_fullscreen_animation,
9437 doc: /* Non-nil means use animation on non-native fullscreen.
9438 For native fullscreen, this does nothing.
9439 Default is nil. */);
9440 ns_use_fullscreen_animation = NO;
9442 DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
9443 doc: /* Non-nil means to use sRGB colorspace on Mac OS X 10.7 and later.
9444 Note that this does not apply to images.
9445 This variable is ignored on Mac OS X < 10.7 and GNUstep. */);
9446 ns_use_srgb_colorspace = YES;
9448 DEFVAR_BOOL ("ns-use-mwheel-acceleration",
9449 ns_use_mwheel_acceleration,
9450 doc: /* Non-nil means use macOS's standard mouse wheel acceleration.
9451 This variable is ignored on macOS < 10.7 and GNUstep. Default is t. */);
9452 ns_use_mwheel_acceleration = YES;
9454 DEFVAR_LISP ("ns-mwheel-line-height", ns_mwheel_line_height,
9455 doc: /* The number of pixels touchpad scrolling considers one line.
9456 Nil or a non-number means use the default frame line height.
9457 This variable is ignored on macOS < 10.7 and GNUstep. Default is nil. */);
9458 ns_mwheel_line_height = Qnil;
9460 DEFVAR_BOOL ("ns-use-mwheel-momentum", ns_use_mwheel_momentum,
9461 doc: /* Non-nil means mouse wheel scrolling uses momentum.
9462 This variable is ignored on macOS < 10.7 and GNUstep. Default is t. */);
9463 ns_use_mwheel_momentum = YES;
9465 /* TODO: Move to common code. */
9466 DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
9467 doc: /* SKIP: real doc in xterm.c. */);
9468 Vx_toolkit_scroll_bars = Qt;
9470 DEFVAR_BOOL ("x-use-underline-position-properties",
9471 x_use_underline_position_properties,
9472 doc: /* SKIP: real doc in xterm.c. */);
9473 x_use_underline_position_properties = 0;
9474 DEFSYM (Qx_use_underline_position_properties,
9475 "x-use-underline-position-properties");
9477 DEFVAR_BOOL ("x-underline-at-descent-line",
9478 x_underline_at_descent_line,
9479 doc: /* SKIP: real doc in xterm.c. */);
9480 x_underline_at_descent_line = 0;
9481 DEFSYM (Qx_underline_at_descent_line, "x-underline-at-descent-line");
9483 /* Tell Emacs about this window system. */
9484 Fprovide (Qns, Qnil);
9486 DEFSYM (Qcocoa, "cocoa");
9487 DEFSYM (Qgnustep, "gnustep");
9489 #ifdef NS_IMPL_COCOA
9490 Fprovide (Qcocoa, Qnil);
9493 Fprovide (Qgnustep, Qnil);